# เส้นทางสู่ไมโครเซอร์วิสของ Shoprocket ตอนที่ 1: สิ่งที่ผมเข้าใจผิดเรื่องการแยกโมโนลิธ

> โพสต์จากทีมวิศวกรรมในช่วงแรกของ Shoprocket เกี่ยวกับความพยายามครั้งแรกในการแยกเซอร์วิสออกจากโมโนลิธ PHP ทำไมผมเลือกเซอร์วิสแรกผิด การผูกกันแน่นสอนอะไรผม และคำแนะนำของ Newman ที่ผมควรทำตามให้เร็วกว่านี้

Winston Berty  - 17 มีนาคม 2559 - อ่าน 5 นาที

ไม่กี่เดือนหลังเข้าทำงานที่ Shoprocket ผมเริ่มหงุดหงิด เรามีแอปพลิเคชัน PHP ที่ดูแลโดยทีมนักพัฒนาฝีมือดีกลุ่มเล็กที่กระจายอยู่ทั่วโลก และสำหรับผม ดูเหมือนว่าการแก้บั๊กหนึ่งจุดก่อให้เกิดบั๊กใหม่ การรวมฟีเจอร์ใหม่ไม่ง่ายอย่างที่ควรเป็น และการดีพลอยก็ไม่บ่อยและเครียด สาเหตุคือโค้ดที่ผูกกันแน่นเกินไป

เรามีแอปพลิเคชันแบบโมโนลิธ เกือบทั้งหมดอยู่ใน GitHub repository เดียว การอัปเดตหรือแก้ไขฟีเจอร์หนึ่งมักต้องแก้หลายจุด สำหรับการทดสอบ เรามีขั้นตอนรีวิวโดยเพื่อนร่วมงาน ซึ่งต้องมีนักพัฒนาอย่างน้อยสองคนอนุมัติ branch ก่อนที่จะรวมเข้า master และดีพลอย ทั้งหมดนี้หมายความว่าเมื่อบั๊กหลุดเข้ามา มักหาจุดที่พังได้ยาก และเมื่อเจอแล้ว การแก้ไขก็ต้องผ่านขั้นตอนเดิม และต้องดีพลอยทั้งแอปใหม่

ในฐานะนักพัฒนาหนุ่มที่กระตือรือร้นและมองหาของใหม่เสมอ พอได้เจอไมโครเซอร์วิส ผมคิดว่านี่จะแก้ปัญหาทั้งหมดของเรา

## ผมคิดว่าไมโครเซอร์วิสคืออะไร

ไม่มีนิยามอย่างเป็นทางการของไมโครเซอร์วิส แต่จากที่ผมศึกษา ผมเข้าใจว่าสถาปัตยกรรมไมโครเซอร์วิสคือวิธีออกแบบแอปพลิเคชันซอฟต์แวร์เป็นระบบกระจายของเซอร์วิสอิสระ แต่ละตัวเชี่ยวชาญสูงและมีวงจรชีวิตของตัวเอง สำหรับบทนำโดยละเอียด [บทความ](https://martinfowler.com/articles/microservices.html)ของ Martin Fowler ยอดเยี่ยมมาก

สองแง่มุมที่ทำให้ผมติดใจ อย่างแรกคือแนวคิดการแบ่งแอปเป็นเซอร์วิสที่มีขอบเขตเข้มงวด ซึ่งลดโอกาสที่ตรรกะเฉพาะของบริบททางธุรกิจหนึ่งจะรั่วไปมาระหว่างส่วนประกอบ เพราะอินเทอร์เฟซระหว่างขอบเขตต้องวางแผนอย่างรอบคอบ มันไม่ง่ายเหมือนการเรียกฟังก์ชันภายใน อย่างที่สองคือแต่ละส่วนประกอบมีวงจรชีวิตอิสระของตัวเองได้ ทีมเป็นเจ้าของโค้ดของตัวเองและใช้สแตกที่เหมาะกับเซอร์วิสนั้นที่สุด และดีพลอยได้ทีละเซอร์วิสและย้อนกลับได้โดยไม่กระทบส่วนที่เหลือ

ผมถูกโน้มน้าวแล้ว Shoprocket จะแยกโมโนลิธ นี่คือตอนที่ 1 ของซีรีส์สั้นๆ ที่ตามเส้นทางนี้ ผมหวังว่าผู้อ่านที่กำลังวางแผนหรือผ่านการเปลี่ยนผ่านแบบเดียวกันจะได้เรียนรู้จากความสำเร็จและความล้มเหลวของเรา

## ความท้าทายแรกคือเรื่องคน ไม่ใช่เรื่องเทคนิค

ผมต้องขายไอเดียให้คนอื่นในทีม พวกเขาสนใจแต่ไม่ได้ตื่นเต้นเหมือนผม และไม่อยากเสียชั่วโมงพัฒนาในช่วงแรกของผลิตภัณฑ์ โชคดีที่ CTO อยากให้ผมดูเรื่องการจัดการเซสชัน ผมจึงคว้าโอกาสนั้น: ผมโน้มน้าวเขาว่าผมแยกเซอร์วิสเซสชันออกมาได้

เมื่อมองย้อนกลับไป นี่เป็นการเลือกเซอร์วิสแรกที่แย่ ผลิตภัณฑ์ของเรามีวิดเจ็ต JavaScript ที่ [ทำให้เว็บไซต์ใดก็ได้ขายของได้](https://v3.shoprocket.io/th/features/sell-on-any-website.md) เราถือว่าเซสชันเป็นทรัพยากร โดยเก็บข้อมูลเซสชันลงฐานข้อมูลเพื่อวิเคราะห์การทิ้งตะกร้าและ KPI อื่นๆ แต่ทรัพยากรนี้ไม่ได้จับต้องได้เท่าคำสั่งซื้อหรือรายการสินค้า และเราใช้เซสชันในแทบทุกการเปลี่ยนสถานะของแอป นั่นหมายความว่าเซอร์วิสนี้จะคุยกับส่วนอื่นของแอปบ่อยมากอย่างหลีกเลี่ยงไม่ได้ ซึ่งผมมองไม่เห็นล่วงหน้า และทำให้งานของผมยากขึ้น

## สิ่งที่ผมเรียนรู้จากการสร้างจริง

ผมเร่งศึกษาเพิ่ม นอกจาก Fowler แล้ว **Building Microservices** ของ Sam Newman กลายเป็นแหล่งอ้างอิงที่ขาดไม่ได้

คำแนะนำของ Newman เมื่อมองย้อนกลับไป คือคำแนะนำที่ผมควรทำตาม: ก่อนอื่นให้จัดโครงสร้างแอปที่มีอยู่เป็นโมดูลที่สะท้อน bounded context ของโดเมน เมื่อนักพัฒนาพอใจกับขอบเขตแล้ว *จึง* แยกโมดูลออกเป็นเซอร์วิสของตัวเอง เหตุผลคือการแยกและเขียนโมดูลที่ขอบเขตไม่ดีใหม่ง่ายกว่ามาก เมื่อเทียบกับการแยกและเขียนเซอร์วิสทั้งตัวใหม่ ที่มีโค้ดท่อส่งเพิ่มและทรัพยากรถาวรทั้งหมด

ผมไม่ได้ทำตามคำแนะนำนั้น ด้วยความอยากสร้างส่วนประกอบของตัวเอง ผมเดินหน้าทำเซอร์วิสเซสชัน

ผมเลือกสแตกที่ต่างจากโมโนลิธเพียงเล็กน้อยแล้วเริ่มสร้าง ตัวเซอร์วิสประกอบเสร็จเร็ว ใช้เวลาไม่กี่สัปดาห์ก็ได้แอปพลิเคชันแยกอิสระที่มี REST API ส่วนที่ยากไม่ใช่ตรงนั้น ส่วนที่ยากคือการทำให้เซอร์วิสคุยกับโมโนลิธ

การจัดการเซสชันกลายเป็นว่าผูกแน่นกับโค้ดส่วนอื่น การเปลี่ยนการเรียกฟังก์ชันเป็นการเรียก API เป็นงานช้า เพราะเซอร์วิสเซสชันกับโมโนลิธมี schema ฐานข้อมูลแยกกัน ผมต้องเขียนตรรกะใดๆ ในโมโนลิธที่ใช้ทรัพยากรเซสชันจากฐานข้อมูลเดิมใหม่ โดยจัดโครงสร้างข้อมูลใหม่ที่ขอบเขตของแอป เพื่อให้ไคลเอนต์อย่างวิดเจ็ต JavaScript ของเรายังใช้งานร่วมกันได้

การเชื่อมต่อใช้เวลานานกว่าการสร้าง และนั่นยังไม่รวมภาระส่วนใหญ่ที่ไมโครเซอร์วิสมักนำมา ทั้ง service discovery, logging, monitoring และ distributed tracing ที่แย่กว่านั้น การผูกกันแน่นหมายความว่าการเปลี่ยนแปลงกระจายไปหลายส่วนของโค้ด เนื่องจากทีมทำงานขนานกันในช่วงนั้น การรวมและนำเซอร์วิสเซสชันขึ้นโปรดักชันจะต้องประสานงานมากกว่าที่ผมประเมินไว้มาก

## ประเมินอย่างตรงไปตรงมา

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

ผมยังเชื่อในไมโครเซอร์วิสในฐานะแนวคิด ผมมองความพยายามของผมเป็นการทดลองที่มีประโยชน์ ผมได้เรียนรู้มากเกี่ยวกับสถาปัตยกรรมแอปพลิเคชัน การสร้างโมเดลโดเมน และหลักการ REST และบทเรียนเหล่านั้นส่งผลต่อเนื่องไปยังส่วนอื่นของโค้ดเรา

สำหรับใครที่กำลังคิดจะเปลี่ยนผ่านแบบเดียวกัน คำแนะนำตรงๆ ของผม:

- อ่านเรื่องนี้ให้มากที่สุดก่อนตัดสินใจ
- เลื่อนงานออกไปจนกว่าคุณจะมั่นใจกับโค้ดเบสและโมเดลโดเมนที่มีอยู่จริงๆ
- จำไว้ว่ามีวิธีอื่นในการเพิ่มเสถียรภาพและความยืดหยุ่นให้โมโนลิธ unit test และ functional test อัตโนมัติช่วยได้มหาศาล การพัฒนาแบบ test-driven ลด regression การขยายแนวนอนทำให้การดีพลอยเจ็บปวดน้อยลง
- เริ่มจากแบ่งโมดูลโมโนลิธก่อนแยกเซอร์วิส

Shoprocket จะเดินทางต่อไป ตอนที่ 2 คือจุดที่เรื่องเริ่มน่าสนใจขึ้น

---

*เผยแพร่ครั้งแรกเป็นตอนแรกของซีรีส์สั้นที่บันทึกการย้ายออกจากโมโนลิธ PHP ในช่วงแรกของ Shoprocket เส้นทางทั้งหมด รวมถึงความผิดพลาดที่แก้ไขในรอบถัดๆ มา ดำเนินต่อเนื่องผ่านการเขียนใหม่ครั้งใหญ่ทุกครั้งของแพลตฟอร์มนับแต่นั้น*

---

- HTML version: https://v3.shoprocket.io/th/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith
- Language: ไทย (th)
- Also in: [العربية](https://v3.shoprocket.io/ar/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Deutsch](https://v3.shoprocket.io/de/blog/shoprocket-microservices-teil-1-monolith-zerlegen-fehler.md), [Ελληνικά](https://v3.shoprocket.io/el/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [English](https://v3.shoprocket.io/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Español](https://v3.shoprocket.io/es/blog/shoprocket-microservicios-parte-1-lo-que-hice-mal-monolito.md), [Français](https://v3.shoprocket.io/fr/blog/shoprocket-vers-les-microservices-partie-1-decouper-le-monolithe.md), [עברית](https://v3.shoprocket.io/he/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [हिन्दी](https://v3.shoprocket.io/hi/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Bahasa Indonesia](https://v3.shoprocket.io/id/blog/perjalanan-shoprocket-menuju-microservices-bagian-1-salah-memecah-monolit.md), [Italiano](https://v3.shoprocket.io/it/blog/viaggio-di-shoprocket-verso-i-microservizi-parte-1-cosa-ho-sbagliato-sul-monolite.md), [日本語](https://v3.shoprocket.io/ja/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Lietuvių](https://v3.shoprocket.io/lt/tinklarastis/shoprocket-kelione-i-mikropaslaugas-1-dalis.md), [Norsk](https://v3.shoprocket.io/nb/blogg/shoprockets-vei-mot-mikrotjenester-del-1-hva-jeg-tok-feil-av.md), [Nederlands](https://v3.shoprocket.io/nl/blog/shoprocket-microservices-deel-1-monoliet-opknippen.md), [Polski](https://v3.shoprocket.io/pl/blog/droga-shoprocket-do-mikroserwisow-czesc-1-rozbijanie-monolitu.md), [Português](https://v3.shoprocket.io/pt/blog/jornada-do-shoprocket-para-microsservicos-parte-1-o-que-errei-ao-quebrar-o-monolito.md), [Română](https://v3.shoprocket.io/ro/blog/drumul-shoprocket-spre-microservicii-partea-1-ce-am-gresit-cu-monolitul.md), [Русский](https://v3.shoprocket.io/ru/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Türkçe](https://v3.shoprocket.io/tr/blog/shoprocket-mikroservis-yolculugu-1-monoliti-parcalarken-yanlis-yaptiklarim.md), [中文](https://v3.shoprocket.io/zh/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md)
