ฉันเพิ่งดู"ทุกสิ่งเล็ก ๆ น้อย ๆ "จาก RailsConf 2014 ในระหว่างการพูดคุยนี้ Sandi Metz refactors ฟังก์ชั่นที่รวมถึงคำสั่ง if ซ้อนขนาดใหญ่:
def tick
if @name != 'Aged Brie' && @name != 'Backstage passes to a TAFKAL80ETC concert'
if @quality > 0
if @name != 'Sulfuras, Hand of Ragnaros'
@quality -= 1
end
end
else
...
end
...
end
ขั้นตอนแรกคือการแบ่งฟังก์ชั่นออกเป็นหลาย ๆ อันเล็ก ๆ :
def tick
case name
when 'Aged Brie'
return brie_tick
...
end
end
def brie_tick
@days_remaining -= 1
return if quality >= 50
@quality += 1
@quality += 1 if @days_remaining <= 0
end
สิ่งที่ฉันคิดว่าน่าสนใจคือวิธีที่ฟังก์ชั่นเล็ก ๆ เหล่านี้เขียนขึ้น brie_tick
ตัวอย่างเช่นไม่ได้เขียนโดยการแยกส่วนที่เกี่ยวข้องของtick
ฟังก์ชั่นดั้งเดิมแต่เริ่มต้นจากการอ้างอิงถึงการtest_brie_*
ทดสอบหน่วย เมื่อผ่านการทดสอบหน่วยเหล่านี้แล้วbrie_tick
ก็ถือว่าเสร็จสิ้น เมื่อฟังก์ชั่นขนาดเล็กทั้งหมดเสร็จสิ้นแล้วtick
ฟังก์ชั่นเสาหินเดิมจะถูกลบ
น่าเสียดายที่ผู้นำเสนอดูเหมือนไม่ทราบว่าวิธีการนี้นำไปสู่การสามในสี่*_tick
หน้าที่ผิด (และอีกอันว่างเปล่า!) มีกรณีขอบซึ่งพฤติกรรมของ*_tick
ฟังก์ชั่นที่แตกต่างจากtick
ฟังก์ชั่นเดิม ยกตัวอย่างเช่น@days_remaining <= 0
ในbrie_tick
ควรจะเป็น< 0
- เพื่อให้brie_tick
ไม่สามารถทำงานได้อย่างถูกต้องเมื่อเรียกด้วย และdays_remaining == 1
quality < 50
มีอะไรผิดพลาดที่นี่? นี่เป็นความล้มเหลวของการทดสอบ - เนื่องจากไม่มีการทดสอบสำหรับเคสขอบเหล่านี้โดยเฉพาะหรือไม่? หรือความล้มเหลวของการเปลี่ยนโครงสร้าง - เนื่องจากรหัสควรได้รับการแปลงทีละขั้นตอนแทนที่จะเขียนใหม่ตั้งแต่ต้น?