ปัญหาที่นักพัฒนาพบเจอเป็นประจำก็คือ Legacy code (Code ที่ไม่มี test)
ซึ่งมีคุณสมบัติเฉพาะตัวนั่นก็คือ พังง่าย !!
อาการประมาณว่า
แก้ไขตรงนั้นนิดตรงนี้หน่อยแล้วส่วนอื่นพังไปด้วย !!
เหมือนกับการแก้ไข bug เพียงตัวเดียวแล้วได้ bug มาอีกเป็นฝูง
โดย code เหล่านี้นักพัฒนาต้องเจ็บตัวกันมาทุกคน ไม่ว่าจะมากหรือน้อยก็ตาม
เพื่อทำการแก้ไข และ ปรับปรุง code เหล่านี้ให้ดีขึ้น
คำถามที่น่าสนใจคือ แล้วเราจะหลีกเลี่ยง code แบบนี้ได้อย่างไร ?
ปล. ปัจจุบันผมก็ยังคงอยู่กับ code เหล่านี้อยู่
เพียงแต่เราจะจัดการมันอย่างไร
เพื่อลดความเจ็บปวดลง
เพื่อวันข้างหน้าที่ดีกว่า
อ่านเจอบทความเรื่อง How to avoid brittle code
จึงนำมาแปลและสรุปวิธีการจัดการ Legaay code กันหน่อย
ซึ่งน่าจะพอมีประโยชน์ต่อนักพัฒนาบ้างนะ
เริ่มต้นด้วยการ update สิ่งต่าง ๆ อยู่อย่างเสมอ
ตัวอย่างเช่น IDE ที่ใช้งาน
เจอว่าจะใช้ IDE version เก่า ๆ ไม่ยอม update version ใหม่ ๆ
ด้วยเหตุผลคือ เดี๋ยวงานเข้า !!
ประเด็นหลักคือ ขี้เกียจ และ กลัวว่าจะต้องทำการแก้ไข
เพื่อทำให้กลับมาใช้งานได้เหมือนเดิม
รวมไปถึงพวก library และ framework ต่าง ๆ
เนื่องจากผู้สร้างจะทำการแก้ไขข้อผิดพลาด
ตลอดจนแก้ไข technical debt ต่าง ๆ ให้อีกด้วย แต่เราไม่ !!
ดังนั้นอย่างกลัวที่จะเปลี่ยนแปลง
อะไรที่มันทำแล้วเจ็บก็ลงมือทำบ่อย ๆ
เดี๋ยวก็รู้และเข้าใจไปเองว่าต้องทำอย่างไร
เพื่อลดความเจ็บปวด และแน่นอนว่า จะดีขึ้นเรื่อย ๆ
สรุปคือ อะไรที่มันทำแล้วเจ็บก็ทำมันบ่อย ๆ
เพื่อลด และ หลีกเลี่ยงความเจ็บปวด
ผมคิดว่า เป็นหนทางที่ดีมาก ๆ
และจงเรียนรู้กับความผิดพลาดและเจ็บปวดด้วยนะ
ถ้าเราทำอยู่เป็นประจำแล้ว
ก็ไม่จำเป็นต้องมาขอเวลาในการ update โน่นนี่นั่นอีกต่อไปนะครับ
แต่มีคำถามว่า
เมื่อทำการ update แล้วจะส่งผลกระทบต่อระบบอย่างไรบ้าง ?
แน่นอนว่า ตอบได้ยากมาก ๆ
เนื่องจาก Legacy code คือ code ที่ไม่มี test
ดังนั้นสิ่งที่ต้องทำคือ เขียน test ขึ้นมานะ (Automated test)
ซึ่งผมจะเน้นในเรื่องของ Unit test
เพื่อทำให้เราแน่ใจและมั่นใจว่า
เมื่อมีใครก็ตามทำการแก้ไข code แล้ว
จะไม่ส่งผลต่อการทำงานของ code ส่วนอื่น ๆ
หรือถ้าส่งผลกระทบก็จะรู้ได้อย่างรวดเร็ว
ดังนั้นจงตอบคำถามต่อไปนี้
- เราเขียน unit test แล้วหรือยัง ?
- unit test ที่เขียนมันครอบคลุม code เพื่อทำให้เรามั่นใจหรือไม่ ?
- ชุด unit test ทั้งหมดทำงานได้อย่างรวดเร็วหรือไม่ ?
- ชุด unit test สามารถทดสอบบนเครื่องของนักพัฒนาทุกคนได้หรือไม่ ?
ถ้าต้องการเปลี่ยนแปลงหรือถอดระบบเดิมออกไป เพื่อใส่ของใหม่เข้าไป !!
เป็นสิ่งปกติมาก ๆ สำหรับระบบที่มีอายุสูง ๆ
จะต้องมีคนดูแลจำนวนมาก หรือมี tech lead เยอะ ๆ
เพื่อดูแลในส่วนต่าง ๆ
แน่นอนว่าต้องมีการเปลี่ยนแปลงหรือแทนที่ด้วย technology ใหม่ ๆ
ดังนั้นจึงมีแผนที่สวยงามสำหรับการเปลี่ยนแปลงดังนี้
- สร้าง abstraction layer หนึ่งขึ้นมาอยู่หน้า component เก่า
- สร้าง component ใหม่ขึ้นมา เพื่อจะมาแทนที่ของเก่า
- โดยการใช้งานจะผ่าน abstraction layer นี้เสมอ เพื่อให้จัดการว่าจะไปทำงานที่ component เก่าหรือใหม่
- จากนั้นจะเริ่มประกาศหรือแจ้งออกไปว่าจะไม่ใช้งาน component เก่าแล้วนะ
- เมื่อเวลาผ่านไปสักพักจะทำการลบ component เก่าออกไป
- แน่นอนว่าabstraction layer ก็ต้องถูกลบออกไปด้วย !!! แต่ …
เรากลับพบว่าขั้นตอนเหล่านี้ล้มเหลวอย่างไม่เป็นท่า
เนื่องจากมันเป็นการยากมาก ๆ ที่จะลบ component เก่าออกไปทั้งหมด
รวมทั้ง abstraction layer ก็ไม่สามารถลบออกไปได้อีก
ดังนั้นสิ่งที่ควรตกลงร่วมกันก็คือ Timebox
ของ abstraction layer และ component เก่า
ว่าจะใช้งานนานเท่าไร (ยิ่งนานยิ่งลบออกยาก)
เพื่อกำหนดกรอบเวลาในการทำงาน
ไม่ใช่ทำไปเรื่อย ๆ
ไม่ใช่ว่าคอยหลบปัญหาไปเรื่อย ๆ
ไม่ใช่ว่ามีข้ออ้างไปตลอด
เรื่องต่อมาคือ เราจัดการ Technical Debt กันหรือไม่ อย่างไร ?
มิฉะนั้น code เหล่านี้มันจะกลับมาทำร้ายคุณ และ คนรอบข้างเองนะ
เนื่องจากเราชอบพูดว่า เดี๋ยวเอาไว้ก่อน
เนื่องจากเราชอบพูดว่า เดี๋ยวค่อยกลับมาทำ
เนื่องจากเราชอบพูดว่า เผื่อเอาไว้ก่อน
เนื่องจากเราชอบพูดว่า ทำ ๆ ไปก่อน
เนื่องจากเราชอบพูดว่า ทำอันโน้นก่อนก็ได้
และเมื่อเวลาผ่านไป เรากลับพบว่า มีสิ่งที่ต้องทำรออยู่เพียบเลย !!
คำถามที่น่าสนใจคือ แล้วที่ผ่านมาเราทำอะไรกันอยู่
แต่เมื่อเราต้องการแก้ไข Technical debt เหล่านั้น
ซึ่งมีจำนวนเยอะมาก ๆ
ทีมก็ไม่อยากจะแก้ไข เพราะว่ามันเยอะมาก ๆ แก้ไขไม่ได้หรอกนะ
แต่ตอนสร้างสามารถทำได้ !!
ส่วนทีม business ก็มองว่าแก้ไขแล้ว ก็ไม่ได้ประโยชน์อะไรนะ
feature ก็ไม่ได้เพิ่มขึ้น
งานก็ไม่คืบหน้า
ดังนั้นทุกคนจึงรู้สึกว่า มันยากเกินไป ทำไม่ได้หรอก
สุดท้ายคือ ปล่อยมันไป !!
แต่สิ่งที่ทีมพัฒนาดี ๆ เขาทำกันก็คือ
ถ้ารู้ว่าสิ่งใดที่มันทำให้เกิด Technical Debt ขึ้นมาแล้ว
จะไม่ทำสิ่งนั้นซ้ำ ๆ ขึ้นมาอีก
นั่นหมายถึง ถ้าของเก่าไม่ลดหรือถูกแก้ไข
ก็อย่าสร้างของใหม่เพิ่มขึ้นมา
ที่สำคัญคือ ทีมต้องตกลงร่วมกันว่า
Technical Debt เหล่านั้นเป็นของทีม
ไม่ใช่หน้าที่ของใครคนใดคนหนึ่ง
ดังนั้นทุกคนในทีมต้องช่วยเหลือกัน ช่วยกันแก้ไข
นั่นหมายถึงทุกคนต้องมีความไว้เนื้อเชื่อใจซึ่งกันและกันด้วย
ทีมพัฒนาที่ดีต้องเข้าใจและจัดเรียงงานตามความสำคัญทาง business
ทีม business ที่ดีต้องรู้ว่าจะต้องทำการส่งมอบ product ที่มีคุณค่าออกไป
ดังนั้นทั้งสองฝ่ายจึงต้องคุยกันในเรื่องของ
- ความเสี่ยงต่าง ๆ
- ค่าใช้จ่ายต่าง ๆ
- ประโยชน์ต่าง ๆ
เนื่องจากถ้าเราไม่สามารถส่งมอบ product ได้แล้ว
เมื่อนั้นแหละที่ Technical Debt จะขึ้นมาเป็นปัญหาทาง business
และแน่นอนว่า มันส่งผลไม่ดีต่อทุกฝ่าย
ดังนั้นมาจัดการ Technical Debt กันเถอะนะ
อย่าลืมว่า
code ที่เขาเขียนขึ้นมานั้น มีไว้สำหรับอ่าน
และมีไว้สำหรับการดูแลรักษาในอนาคตต่อไป
ดังนั้นมาสร้าง code ที่ดี ๆ ขึ้นมาเถอะนะ
สุดท้ายแล้ว เราได้เรียนรู้อะไรจาก Legacy code เหล่านี้กันบ้าง ?
หรือว่าสร้างมันขึ้นมาในทุก ๆ ระบบที่เข้าไปเกี่ยวข้อง !!