Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

แปลง Rails Controller ที่وضั่วให้ Clean และ Testable

ราวๆ ใน карьера Rails คุณจะเจอ controller ที่อยากเลิกเขียนโปรแกรมทุกอย่าง อาจมีโค้ดทุกบรรทัดสำหรับ feature เหมือนกัน 15 before_filters สื่อสารผ่าน instance variables ต้องเรียงลำดับเฉพาะไม่งั้นพัง และ tests ดูแบบนี้:

test "index" do
  get :index
  assert_response :success
end

เก๋า 100% test coverage หรอ?

แม้อยากปิดตาทิ้ง แต่วันหนึ่งต้อง fix bug ใน controllers เหล่านี้ และเป็น good developer อยากทิ้งโค้ดดีกว่าเดิม

แตจะ refactor ยังไง โดยเฉพาะโดยไม่มีทดสอบดีให้พึ่งพา?

ทดสอบมันให้ได้ (อย่างไรก็ตาม)

ต้องการทดสอบดีเพื่อรู้สึกปลอดภัยตอน refactor แตไม่เขียนทดสอบดีได้ จนกว่า จะ refactor ทำยังไง?

ไม่ว่า controller เขียนแย่แค่ไหน ยังเขียน integration tests ส่ง data ไป controller คาดหวัง response ได้ ตอนนี้เขียนทดสอบให้แน่ใจว่า existing behavior ไม่เปลี่ยน ระหว่าง refactor

ทดสอบเหล่านี้ไม่ focused เท่า unit tests แต high-level tests ให้ความมั่นใจ refactor จะไม่พังทั้งหมด กระบวนการเขียนช่วยเข้าใจโค้ดดีขึ้น ช่วยตัดสินใจ refactor

ทำลาย Dependencies

อะไรทำให้ controller code แย่? ส่วนใหญ่คือ implicit dependencies ระหว่าง before_filters, helper methods, หรือส่วนต่างๆ ของ 200-line functions อาจเป็น refactor ไว้เกินไป ทำให้ดี ต้องทำลาย dependencies

สำหรับ Rails controllers มีวิธีง่าย copy โค้ดจาก before_filters, helper methods, superclasses, และที่ไหนที่ controller-ish code ซ่อนอยู่ แทนที่ calls ไป methods นั้นด้วยโค้ดที่ copy

คุณ temporarily un-DRY โค้ด เพื่อ refactor อย่างเข้าใจได้ภายหลัง ดู醜 แตโค้ดทั้งหมดออกมาในแสง สามารถเห็น pieces ไหน interact และ flow ยังไง

(ระหว่างกระบวนการ รันทดสอบหลังทุกการเปลี่ยนแปลง ให้แน่ใจว่า inlining ไม่ทำให้แตก)

Refactor ไปสู่ testable code

พร้อม re-refactor โค้ด จะใช้ basic extract method, extract object, pull up method ลอง refactor หลายวิธี ดูว่ารู้สึกดีไหน

รอบแรกๆ พึ่ง high-level integration tests เป็น safety net แตเร็วๆ นี้อยากอะไรดีกว่า

ระหว่าง refactor หาโอกาสทำให้โค้ด testable มากขึ้น ปกติหมายถึงสร้างที่ inject test doubles, ลด dependencies ระหว่าง objects, ทำให้ controller พึ่ง objects ที่สร้างและ unit test ได้ง่าย โดยย้ายโค้ดเข้า testable objects controllers จะเล็กลง เข้าใจง่าย ทดสอบง่าย

ได้ในรูป numbered list ไหม?

อีกครั้ง ขั้นตอนแยก large controller:

  1. รัน high-level integration tests ต่อ controller
  2. รันทดสอบ ให้ผ่าน
  3. Inline before_filters, superclass methods, abstractions ที่ซ่อนโค้ด
  4. รันทดสอบ ให้ยังผ่าน
  5. ทำ refactoring (extract method, extract service object, replace instance variable with local, etc.) ดูรู้สึกดีไหม
  6. รันทดสอบ ให้ยังผ่าน
  7. ถ้าเพิ่ง extract โค้ด เขียน unit tests ต่อ object หรือ method ที่ extract
  8. รันทดสอบ ให้ยังผ่าน
  9. ถ้า controller ยังต้องงาน กลับขั้น 5

ต่อไปอะไร?

อยากเรียนเพิ่ม Working Effectively with Legacy Code คือ bible ของการรับ unmaintainable code ไม่มีทดสอบ ทำให้ทำงานได้ แนะนำอย่างแรง ถ้าเจอ monolithic controllers บ่อย (และ refactor สนุกเท่าผม)

มาแล้ว horror stories ของคุณ! Controller code แย่ที่สุดที่เคยทำงานดูยังไง?