เรื่องแรกๆ ที่ developer หน้าใหม่ หรือ หน้าเก่า จะต้องเรียนรู้ก็คือ
code ที่เขียนขึ้นมา ต้องไม่มี code ที่ซ้ำซ้อนกัน (Duplication)
แนวปฏิบัติที่สามารถช่วยลด code ที่ซ้ำซ้อนเหล่านี้ เช่น การ refactor code
หรือการสร้าง utility class, library และ framework ขึ้นมา กลายเป็น reuse code
แต่ว่ามันไม่ได้มาแบบฟรีๆ นะเออ

ตัวอย่างเช่น
เมื่อเราทำการ refactor code ที่มันซ้ำกันจาก class A และ B แล้ว
พบว่า class A และ B มันจะผูกมัดกันแบบอ้อมๆ (Indirect coupling)
มันอาจจะไม่ได้เป็นสิ่งที่แย่ แต่มันมักจะมีผลตามมา
ซึ่งเรามักจะมองข้ามกันไป ดังรูป

Screen Shot 2557-10-13 at 2.34.55 PM

และเมื่อมี class X มาใช้ส่วนที่แยกออกมา จะเรียกว่าการ Reuse code ดังรูป

Screen Shot 2557-10-13 at 2.37.14 PM

อยู่มาวันหนึ่ง class A ต้องการเปลี่ยนการทำงานของ function/method ที่ใช้ร่วมกัน

ระหว่าง A, B และ X  แล้วจะทำอย่างไรดี ?

คำตอบ
มีทางเลือกให้ 2 ทางก็คือ

  1. ทำการแก้ไข function/method ที่ใช้งานร่วมกัน
  2. ทำการแก้ไขเฉพาะที่ class A เท่านั้น

แต่ส่วนใหญ่ เราก็มักจะเลือกข้อ 1 คือแก้ไขในจุดที่มันใช้ร่วมกันนั่นแหละ
เพราะว่า แก้ไขเพียงที่เดียว มันก็น่าจะทำงานได้ดี
แต่สิ่งที่เราห้ามละเลยเด็ดขาดคือ การแก้ไขนั้นต้องไม่ไปกระทบกับ class B และ X นะ
ซึ่งในการทำงานจริงๆ มันยากมากที่จะไม่ส่งผลกระทบว่าไหม ?
และบ่อยครั้ง เราจะพบว่าแก้ไขที่หนึ่ง แล้วไปกระทบการทำงานอีกที่หนึ่ง !!

จากเหตุการณ์ดังกล่าว มันจึงทำให้เกิดสิ่งที่เรียกว่า Continuous Integration ขึ้นมา
เพื่อช่วยตรวจสอบว่า ทุกๆ การแก้ไขนั้น ระบบโดยรวมยังทำงานได้ปกตินะ
แต่สิ่งที่คุณต้องมีเลยก็คือ test ต่างๆ เพื่อช่วยทดสอบนะครับ …
มาถึงตรงนี้ การ refactoring code และ reuse code มันเริ่มมีค่าใช้จ่ายแล้วใช่ไหม

บางคนอาจจะบอกว่า เราสามารถแก้ไขการแก้ไขด้วย การกำหนด version ของ code ที่ใช้งานร่วมกันซะ
แต่สิ่งที่แลกมาก็คือ  การดูแลรักษา code หลากหลาย version
ลองคิดดูว่า ถ้าเป็นระบบใหญ่มันจะได้ไม่คุ้มเสียหรือเปล่า
ถ้ามันดีก็ทำกันต่อไปนะ !!

คำถาม
แล้วทำอย่างไรดีล่ะ ? ตอนนี้มันกลืนไม่เข้าคายไม่ออก เพราะคำว่า reuse นี่แหละ

คำตอบ
ก็คือ ทางเลือกที่ 2 ไงล่ะ
ถ้าเมื่อไรก็ตามที่ code ที่มัน reuse หรือใช้งานร่วมกัน
ดันไปก่อให้เกิดข้อจำกัดต่อการทำงานของส่วนอื่นๆ ที่ใช้งาน
นั่นหมายถึง ส่วนที่ reuse มันสามารถใช้งานในปัญหาที่เฉพาะเจาะจงเกินไป
แน่นอนว่า ข้อจำกัดมันทำให้เกิดสิ่งที่แย่ๆ ตามมาเสมอ
แล้วเรายังจะใช้งานมันอยู่หรอ ?

ดังนั้น สิ่งที่เราทำได้แบบง่ายๆ เลยก็คือ การสร้าง Duplication code ขึ้นมา
เพื่อใช้งานเฉพาะส่วนที่เราต้องการไปได้เลย แก้ไขให้เข้ากับสิ่งที่เราต้องการสิ
ต่อไปอาจจะถูก refactor code ใหม่อีกรอบก็เป็นได้ …

จากที่อธิบายมาตั้งแต่ต้นพบว่า

การลด duplication code นั้นมันก็ทำให้เกิดความเสี่ยงต่อการใช้งาน code ที่ใช้งานร่วมกันได้ด้วย
ดังนั้น ถึงจะบอกว่า เราต้อง reuse code ให้ได้มากที่สุดนะ เพราะว่า จะได้ไม่ต้องแก้ไข code หลายๆ ที่
แต่ถ้ามองในทางกลับกัน ถ้าต้องทำการแก้ไข reuse code ล่ะ มันจะส่งผลกลับไปยังผู้ใช้งาน code อย่างไร
แต่ถ้าแต่ละส่วนก็พัฒนา code ของใครของมันไป ก็ทำให้เกิด duplication code ขึ้นมาจำนวนมากอีก
โดยเหตุการณ์ และ ปัญหานี้ มักจะเกิดขึ้นอยู่บ่อยๆ ทั้งระบบขนาดเล็กและขนาดใหญ่

ดังนั้น ก่อนที่จะ refactor code และสร้าง reuse code นั้น
ควรจะต้องมั่นใจก่อนว่า code ที่เราสร้างขึ้นมามันทำงานได้ดีตามที่ต้องการ
ต่อจากนั้น จึงมาพิจารณาดูว่า code ที่มันซ้ำซ้อนนั้น มันอยู่ในขอบเขตของปัญหาเดียวกันหรือไม่ ?

เมื่อไรก็ตามที่เราสร้าง reuse code ขึ้นมา มันคือการผูกมัด code ขึ้นมาแบบไม่รู้ตัว
ซึ่งมันจะมีค่าใช้จ่ายอยู่เสมอ  ดังนั้น ควรเลือก refactor code และ reuse code ให้เหมาะสมครับ
ไม่ใช่ตั้งหน้าตั้งตา refactor code และ reuse code กันอย่างเดียว
แล้วจะหาว่าไม่เตือนนะครับ