ปัญหา
ระบบ legacy สำคัญเกินกว่าจะปิดทิ้ง และแพงเกินกว่าจะแก้ต่อไปเรื่อย ๆ การ rewrite ใหม่ทีเดียวทั้งระบบดูน่าลอง แต่มันแปลว่าต้องผ่านหลายเดือนหรือหลายปีที่ไม่ได้ส่งคุณค่าอะไรใหม่ออกไปเลย ต้องคอยทำให้สองระบบตรงกัน และปิดท้ายด้วยวัน cut-over ที่น่ากลัวสุด ๆ อีกหนึ่งวัน การ rewrite หลายครั้งไปไม่ถึงวันนั้นด้วยซ้ำ
ทำงานยังไง
- ดักไว้ก่อน วาง facade ไว้หน้าระบบ legacy ทุก request จะได้ผ่านอะไรสักอย่างที่คุณคุมได้
- แทนที่ทีละส่วน สร้าง implementation ใหม่ของ capability เดียว ปกติก็คือหนึ่ง route หรือหนึ่ง bounded context
- เปลี่ยนเส้นทาง แก้ routing ของ facade ให้ส่วนนั้นไปที่ implementation ใหม่ และเปลี่ยนให้ module legacy อื่น ๆ ที่เรียกส่วนนั้นอยู่ไปเรียกตัวใหม่ด้วย โค้ด legacy ของส่วนนั้นก็จะเงียบไป
- ทำซ้ำ แล้วปลดระวาง ทำต่อไปเรื่อย ๆ จนไม่มีอะไรถูก route ไปที่ระบบเก่าแล้ว จากนั้นก็ปิดมันทิ้ง
การย้ายระบบเลยกลายเป็น release เล็ก ๆ ที่ย้อนกลับได้ต่อกันเป็นสายยาว แทนที่จะเป็นการกระโดดครั้งเดียวที่ย้อนกลับไม่ได้
ใช้ตอนไหนดี
- ตอนแทนที่หรือย้าย platform ของระบบใหญ่ที่ต้องให้บริการต่อไปตลอดช่วงนั้น
- ตอนที่ดักระบบได้ที่ขอบเขตบางจุด: HTTP route, message topic, UI shell, การวางไฟล์
- ตอนที่อยากส่งคุณค่าใหม่ ๆ ออกไประหว่างย้ายระบบ ไม่ใช่รอส่งแค่ตอนจบ
ได้อะไร เสียอะไร
- ข้อมูลที่ใช้ร่วมกันคือส่วนที่ยาก ย้าย route ง่าย แต่ service ใหม่กับ monolith มักใช้ database ร่วมกันอยู่ช่วงหนึ่ง ต้องวางแผนให้ชัดเรื่องความเป็นเจ้าของข้อมูล การ sync (เช่น CDC) และการ cut-over ในที่สุด
- Facade เป็น infrastructure สำคัญ มันต้องมี high availability และเร็ว และต้องไม่งอก business logic ของตัวเองขึ้นมา
- มีสองโลกอยู่ช่วงหนึ่ง เตรียมใจไว้ว่าจะมีเรื่องที่ซ้ำกัน (auth, logging, deployment) จนกว่าการย้ายจะจบ รักษาจังหวะให้เดินต่อ ของที่ "ชั่วคราว" จะได้ไม่กลายเป็นของถาวร
- ไม่ใช่ทุกระบบจะหั่นเป็นส่วนได้ batch job ที่ผูกกันแน่น หรือ UI ที่ไม่มีรอยต่อ อาจต้องใช้ branch by abstraction หรือ parallel run แทน
ข้อควรรู้ตอนลงมือทำ
- facade มักเป็นของที่คุณรันอยู่แล้ว: API gateway, ingress controller, CDN หรือ load balancer ที่ route ตาม path ได้ หรือ BFF
- วาง anti-corruption layer ไว้ระหว่าง service ใหม่กับ model ของ legacy ตัว domain model เก่าจะได้ไม่รั่วเข้ามาในโค้ดใหม่
- ใช้ feature flag หรือ weighted routing เพื่อทยอยย้าย route (1% → 10% → 100%) และใช้ shadow traffic หรือ parallel run เทียบผลลัพธ์ก่อนสลับ
- ติดตามความคืบหน้าให้เห็นชัด: route ที่ย้ายแล้ว สัดส่วน traffic ที่ยังไปที่ legacy และ module ที่ลบไปแล้ว