28 คะแนน โดย GN⁺ 2025-05-10 | 10 ความคิดเห็น | แชร์ทาง WhatsApp
  • การรีบแยกโค้ดออกเป็นไมโครเซอร์วิสในสตาร์ตอัประยะเริ่มต้น ก่อให้เกิด ประสิทธิภาพการทำงานที่ลดลงอย่างมาก และความซับซ้อนที่เพิ่มขึ้น
  • สถาปัตยกรรมแบบโมโนลิทิก (ระบบเดียว) ให้การเพิ่มประสิทธิภาพเพื่อการอยู่รอดผ่านการดีพลอยที่ง่าย การปล่อยฟีเจอร์ใหม่ได้รวดเร็ว และการทำงานร่วมกันอย่างมีประสิทธิภาพ
  • ไมโครเซอร์วิส ให้ประโยชน์จากการแยกออกจากกันก็ต่อเมื่อมีความต้องการด้านการขยายระบบขนาดใหญ่ เวิร์กโหลดที่หลากหลาย หรือข้อกำหนดด้านรันไทม์ที่แตกต่างกันเท่านั้น
  • การแยกบริการมากเกินไป การมีรีโพซิทอรีจำนวนมาก สภาพแวดล้อมการพัฒนาในเครื่องที่ไม่เสถียร และเทคสแต็กที่ไม่สอดคล้องกัน ล้วนเชื่อมโยงไปสู่ ความเร็วที่ช้าลงและขวัญกำลังใจทีมที่ถดถอย
  • สตาร์ตอัปควรเริ่มจากโมโนลิท และค่อยแยกเมื่อเกิดคอขวดที่ชัดเจนเท่านั้น ซึ่งเป็นแนวทางที่เหมาะสมที่สุด

บทนำและภูมิหลัง

  • การอยู่รอด ของสตาร์ตอัปถูกกำหนดโดยการทำซ้ำอย่างรวดเร็ว การส่งมอบฟีเจอร์ใหม่ และการสร้างคุณค่าให้ผู้ใช้
  • การเลือกสถาปัตยกรรมพื้นฐานของโปรเจกต์ เทคสแต็ก และภาษาโปรแกรม มีผลต่อ ความเร็วของทีม
  • การนำไมโครเซอร์วิสมาใช้เร็วเกินไปอาจดูหรูหราในเชิงภาพลักษณ์ แต่ในความเป็นจริงกลับก่อให้เกิด ผลิตภาพที่ลดลง บริการที่ยังไม่เสร็จสมบูรณ์ และความซับซ้อนเกินจำเป็น
  • ข้อมูล: เกิดต้นทุนในการพัฒนาหลากหลายด้าน เช่น การออร์เคสเทรตบริการ ปัญหา Docker/สคริปต์ CI/CD ที่ซ้ำซ้อน การผูกกันระหว่างบริการ ต้นทุนด้าน observability และการกระจายตัวของการทดสอบ
  • แทนที่จะพุ่งไปสู่สถาปัตยกรรมที่ซับซ้อนโดยไม่จำเป็น บทความนี้เน้นความสำคัญของ สถาปัตยกรรมที่คุ้มค่าและใช้งานได้จริง

จุดแข็งของโมโนลิท

  • ไม่ว่าจะเป็น SaaS หรือเพียงตัวครอบฐานข้อมูลแบบง่าย เมื่อเวลาผ่านไปแอปย่อมซับซ้อนขึ้น แต่ สถาปัตยกรรมแบบโมโนลิทมักคงความเรียบง่ายและยืดหยุ่นได้ง่ายกว่า
  • ดีพลอยได้ง่าย ได้รับการสนับสนุนจากเฟรมเวิร์กยอดนิยม (Django, ASP.Net, Nest.js เป็นต้น) และได้ประโยชน์มากจากชุมชนโอเพนซอร์ส
  • กรณีจริง: สตาร์ตอัปด้านอสังหาริมทรัพย์แห่งหนึ่งใช้ Laravel แบบโมโนลิทเพื่อขยายฟีเจอร์และเชื่อมต่อกับ third-party จำนวนมากได้อย่างราบรื่น
  • ทำให้ทีมสามารถโฟกัสกับความต้องการทางธุรกิจและความคาดหวังของผู้ใช้ได้ โดยไม่ต้องรีบนำ อินฟราสตรักเจอร์ที่ซับซ้อน หรือการแยกเป็นไมโครเซอร์วิสเข้ามาใช้
  • บทเรียน: ความกระชับของสถาปัตยกรรมช่วยให้ทีมโฟกัสกับการดีพลอยได้ดีขึ้น และตราบใดที่ไม่ล้มเหลวในการทำโมดูลภายใน ระบบก็ยังรองรับการเติบโตได้เพียงพอ

ไมโครเซอร์วิสดีที่สุดเสมอหรือไม่?

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

เหตุผลที่ไมโครเซอร์วิสมักล้มเหลว โดยเฉพาะในระยะเริ่มต้น

1. ขอบเขตของบริการที่กำหนดขึ้นเองโดยพลการ

  • ความพยายามแบ่งบริการตาม business logic โดยอ้างอิงแนวคิด domain-driven design หรือ clean architecture มักลงเอยที่ ตรรกะจริงกับขอบเขตของบริการไม่สอดคล้องกัน
  • ตัวอย่าง: การแยกผู้ใช้ การยืนยันตัวตน และสิทธิ์การเข้าถึงออกจากกัน ทำให้ความซับซ้อนในการดีพลอยและความยากของการพัฒนา API เพิ่มสูงขึ้น
  • การแยกในช่วงที่ยังไม่มีคอขวดจริง ๆ จะยิ่ง ทำให้ระบบไม่เสถียรและช้าลง
  • การจำลองการแยกในอนาคตด้วยแฟลกหรือท็อกเกิลภายใน และค่อย ๆ สำรวจขอบเขตที่เหมาะสมแบบเป็นธรรมชาติ มีประสิทธิภาพกว่าการรีบทำงานอินฟรา
  • บทเรียน: ตัดสินใจแยกโดยอิงจากคอขวดที่เกิดขึ้นจริง ไม่ใช่จากทฤษฎี

2. รีโพซิทอรี/อินฟราที่มากเกินไป

  • สไตล์โค้ด การทดสอบ การตั้งค่า เอกสาร และ CI/CD ล้วนเพิ่มขึ้นตามจำนวนบริการ
  • หากใช้โครงสร้าง monorepo จะสามารถจัดการการตั้งค่าทั้งหมดจากจุดเดียว เพิ่มความสม่ำเสมอของโค้ดและประสิทธิภาพการทำงานร่วมกัน
  • ในกรณีของ Node.js เครื่องมืออย่าง nx หรือ turborepo ช่วยให้การจัดการ dependency และ build ระหว่างบริการภายใน ง่ายขึ้น
  • ข้อเสียคืออาจมีความสัมพันธ์ของ dependency ที่ซับซ้อน ต้องปรับจูนประสิทธิภาพของ CI และอาจต้องใช้เครื่องมือ build ที่เร็วขึ้น
  • สำหรับ ecosystem ของ Go ก็เช่นกัน ช่วงแรกอาจจัดการใน workspace เดียวก่อน แล้วค่อยพิจารณาแยกโมดูลเมื่อระบบเติบโต
  • บทเรียน: ทีมเล็กสามารถประหยัดเวลาได้มากด้วย monorepo และอินฟราที่ใช้ร่วมกัน

3. สภาพแวดล้อมการพัฒนาในเครื่องที่ไม่เสถียร

  • การรันในเครื่องที่ใช้เวลามากเกินไป สคริปต์ที่ซับซ้อน และ dependency ที่ต่างกันในแต่ละระบบ ล้วนทำให้ การ onboarding ช้าลงและผลิตภาพลดลง
  • การขาดเอกสาร ปัญหาความเข้ากันได้ และการแก้เฉพาะทางของแต่ละ OS (เช่น สคริปต์ที่ใช้ได้เฉพาะ macOS) ล้วนเป็นอุปสรรค
  • ในโปรเจกต์หนึ่ง มีการใช้ Node.js proxy เพื่อลดความซับซ้อนของ Docker และลดเวลา onboarding ของนักพัฒนา
  • บทเรียน: ถ้าแอปรันได้แค่บน OS เดียว ผลิตภาพของทีมก็จะขึ้นอยู่กับความน่าเชื่อถือของแล็ปท็อปเพียงเครื่องเดียวในท้ายที่สุด

4. เทคสแต็กที่ไม่สอดคล้องกัน

  • Node.js และ Python เหมาะกับการทำซ้ำอย่างรวดเร็ว แต่ในสภาพแวดล้อมแบบไมโครเซอร์วิสมักเกิดปัญหา ความไม่สอดคล้องกันระหว่าง build และ runtime บ่อยครั้ง
  • Go มีข้อดีในเรื่องไบนารีแบบ static การ build ที่รวดเร็ว และความเรียบง่ายในการปฏิบัติการ
  • ควรเลือกเทคสแต็กอย่างรอบคอบตั้งแต่ต้น และหากจำเป็นก็สามารถใช้โปรโตคอลอย่าง gRPC เพื่อรองรับการใช้หลายภาษาได้
  • หากไม่มีความต้องการพิเศษอย่าง ML หรือ ETL การใช้หลายสแต็กมักเพิ่มแต่ความซับซ้อนโดยไม่จำเป็น
  • บทเรียน: เลือกสแต็กให้เหมาะกับความเป็นจริงของทีม ไม่ใช่ความฝันที่ดูดี

5. ความซับซ้อนที่ซ่อนอยู่: การสื่อสารและการมอนิเตอร์

  • ในระบบไมโครเซอร์วิส service discovery, API versioning, distributed tracing และการจัดการล็อกแบบศูนย์กลาง เป็นสิ่งจำเป็น
  • การตามหาบั๊กหรือเหตุขัดข้องในโมโนลิทอาจดูจาก stack trace เดียวได้ แต่ในระบบกระจายจะซับซ้อนกว่ามาก
  • หากจะทำให้ถูกต้อง จำเป็นต้องนำเครื่องมือเฉพาะทางอย่าง OpenTelemetry มาใช้ และสร้าง observability stack ขึ้นมา
  • ต้องตระหนักว่าระบบกระจายคือการยอมรับภาระลงทุนด้านวิศวกรรมเพิ่มเติมโดยตรง

สถานการณ์ที่ไมโครเซอร์วิสมีประโยชน์จริง

  • การแยกเวิร์กโหลด: การแยกงาน asynchronous บางประเภท เช่น การประมวลผลภาพหรือ OCR ออกมา จะช่วยให้มีประสิทธิภาพมากขึ้น
  • ความต้องการในการขยายระบบที่ไม่เท่ากัน: หากเว็บ API และ ML workload มีข้อกำหนดด้านฮาร์ดแวร์และการปฏิบัติการต่างกัน ก็ควรแยกออกจากกัน
  • ต้องการรันไทม์ที่ต่างออกไป: องค์ประกอบที่ไม่เข้ากันกับรันไทม์หลักของแอป เช่น โค้ด C++ แบบ legacy ควรถูกเก็บไว้เป็นบริการแยก
  • จากกรณีขององค์กรวิศวกรรมขนาดใหญ่ (เช่น Uber) จะเห็นว่าเหมาะสมก็ต่อเมื่อมี ความจำเป็นเชิงองค์กรที่ชัดเจน และมีความสามารถในการปฏิบัติการที่สุกงอมแล้ว
  • แม้ในทีมเล็ก บางครั้งการแยกก็อาจใช้ได้จริง เช่น บริการวิเคราะห์ภายนอกที่จัดการได้ไม่ยุ่งยาก
  • บทเรียน: ควรเลือกใช้เฉพาะกับเวิร์กโหลดที่มีประโยชน์จากการแยกอย่างชัดเจนในทางปฏิบัติเท่านั้น

คู่มือภาคสนามสำหรับสตาร์ตอัป

  • เริ่มต้นด้วยโมโนลิท และใช้เฟรมเวิร์กที่พิสูจน์แล้วเพื่อโฟกัสกับงานหลัก
  • รีโพซิทอรีเดียว ให้ประโยชน์กับทีมระยะเริ่มต้นมากกว่า ทั้งในด้านประสิทธิภาพการดำเนินงาน การจัดการ และความปลอดภัย
  • การทำให้สภาพแวดล้อมการพัฒนาในเครื่องเรียบง่าย เป็นเรื่องสำคัญ และหากยังยาก ควรมีเอกสารหรือวิดีโอแนะนำอย่างละเอียด
  • ควร ลงทุนกับ CI/CD ตั้งแต่เนิ่น ๆ เพื่อทำงานซ้ำให้เป็นอัตโนมัติและลดภาระทางจิตใจของทีม
  • แยกเฉพาะเมื่อมีคอขวดที่ชัดเจนเท่านั้น และหากยังไม่มี ก็ควรโฟกัสกับการทำโมดูลภายในโมโนลิทและเสริมการทดสอบให้แข็งแรง
  • เป้าหมายสูงสุดคือการรักษาความเร็วในการพัฒนา
  • บทเรียน: เริ่มจากความเรียบง่าย แล้วค่อยสเกลตามความจำเป็นของการแยก

ถ้าจำเป็นต้องใช้ไมโครเซอร์วิสจริง ๆ

  • ประเมินเทคสแต็กและลงทุนกับเครื่องมือด้านประสบการณ์นักพัฒนา: ต้องมีระบบอัตโนมัติในแต่ละบริการ สคริปต์ที่ชัดเจน และเครื่องมือจัดการการดีพลอยแบบรวมศูนย์
  • กำหนดโปรโตคอลการสื่อสารระหว่างบริการที่เชื่อถือได้และมีมาตรฐาน: ต้องเข้าใจงานเพิ่มเติมที่เกี่ยวข้อง เช่น ความสม่ำเสมอของ message schema การทำเอกสาร และการจัดการข้อผิดพลาด
  • ทำให้โครงสร้างการทดสอบเสถียร: การทดสอบระดับ unit, integration และ E2E ต้องขยายตามการแยกบริการได้อย่างเหมาะสม
  • พิจารณาใช้ไลบรารีร่วม: โค้ดส่วนกลางสำหรับ observability และการสื่อสารควรถูกจำกัดให้เล็กที่สุด เพื่อหลีกเลี่ยงการ rebuild ทุกบริการบ่อยเกินไป
  • ควรเริ่มต้น observability ตั้งแต่เนิ่น ๆ: อย่างน้อยควรมี structured JSON logs และ correlation ID เป็นเครื่องมือพื้นฐานในการล็อก
  • สรุปคือ เมื่อยอมรับความซับซ้อนแล้ว ก็ต้องออกแบบระบบที่สามารถจัดการมันได้อย่างจริงจังและรอบด้าน

บทสรุป

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

10 ความคิดเห็น

 
kuil09 2025-05-12

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

 
dhlee0305 2025-05-12

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

 
mhj5730 2025-05-12

ผมคิดว่าแค่มีโมโนลิทิกแบบ synchronous ล้วน กับโมโนลิทิกแบบ asynchronous ล้วน แค่ 2 แบบก็เพียงพอแล้ว... ผมมองว่าการนำ microservices มาใช้นั้นสุดท้ายขึ้นอยู่กับขนาดของตารางที่ต้องจัดการด้วย DB ถ้าจำนวนตารางเยอะและซับซ้อนแบบเกินเหตุ ก็ค่อยต้องกังวลเรื่อง MSA แต่ถ้าเรียบง่าย โมโนลิทิกนี่แหละเหมาะที่สุด

 
roxie 2025-05-12

เมื่อคลื่นทั้งหมดนี้ผ่านพ้นไป คนรุ่นหลังจะจดจำยุคสมัยนี้อย่างไร

 
n1ghtc4t 2025-05-12

ตอนนั้นก็เป็นอีกระลอกคลื่นของตอนนั้น...

 
bungker 2025-05-11

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

  • เมื่อทิศทางของผลิตภัณฑ์มีการเปลี่ยนแปลง ในไมโครเซอร์วิสจุดที่ต้องแก้ไขจะชัดเจนและน้อยกว่าแบบโมโนลิธิก ผมคิดว่านี่เป็นข้อดีที่ใหญ่มากจริง ๆ
  • ในยุคของการพัฒนาด้วย AI หน่วยย่อยเล็ก ๆ ของไมโครเซอร์วิสพัฒนาได้ง่ายกว่าผ่าน AI (ไม่ได้หมายความว่าโมโนลิธิกทำไม่ได้)
  • ผมยอมรับว่าภาระของ CI/CD มีอยู่ แต่ก็มีบริการที่ถูกยุติไปตั้งแต่ยังอยู่ในขั้นกำหนดทิศทาง สุดท้ายแล้วต่อให้ค่อยสร้างตอนที่กำหนดทิศทางได้ชัดเจนแล้ว ก็แทบจะเป็นระดับคัดลอกวางและสร้างเสร็จได้ภายในหนึ่งสัปดาห์
  • โอเพนซอร์สที่แต่ละภาษามีจุดแข็งนั้นค่อนข้างชัดเจน เช่น ทำ Security และ business logic ด้วย Java และทำ AI ด้วย Python ในโครงสร้างแบบไมโครเซอร์วิสจะสามารถใช้โอเพนซอร์สได้ให้มากที่สุด
 
andone 2025-05-11

ผมเห็นด้วยว่าในยุคการพัฒนา AI การออกแบบให้เป็นหน่วยเล็ก ๆ และมีความรับผิดชอบเดียวเป็นสิ่งจำเป็น

 
bus710 2025-05-10

มีพูดไว้เล็กน้อยในคอมเมนต์เหมือนกัน แต่สาย beam/otp นี่ค่อนข้างยืดหยุ่นและดีทีเดียวครับ ในกรณีของ Gleam นั้น ด้วยการผสานไวยากรณ์ที่ดีของทั้ง go และ rust เข้ากับเสถียรภาพของ beam เลยกลายเป็นภาษาที่น่าประทับใจมากพอสมควร อยากลองค่อย ๆ เอามาใช้กับโปรเจ็กต์ขนาดเล็กดูเหมือนกันครับ

 
ndrgrd 2025-05-10

ถ้าแบ่งทีมยิบย่อยเกินไป แม้แต่การมารวมตัวกันเพื่อแลกเปลี่ยนความเห็นก็จะกลายเป็นงานใหญ่มหาศาล

 
GN⁺ 2025-05-10
ความเห็นจาก Hacker News
  • ตระหนักว่า ถ้าไม่มีปัญหาเรื่องการสเกลจริง ๆ ไม่มีทีมขนาดใหญ่ หรือไม่มีโดเมนที่ต้องพัฒนาแยกจากกันอย่างอิสระ การใช้ไมโครเซอร์วิสมีแต่ต้นทุนและแทบไม่ได้ประโยชน์ โดย Segment เองก็เคยย้อนกลับจากการแยกเป็นไมโครเซอร์วิสด้วยเหตุผลนี้เช่นกัน ประเด็นสำคัญคือมันเป็นรูปแบบเชิงองค์กร ไม่ใช่เทคโนโลยี โดยทั่วไปมักเริ่มจากโมโนลิธเดียว แล้วค่อยแยกเฉพาะฝั่งฟรอนต์เอนด์ แบ็กเอนด์ หรืองานที่ใช้เวลานาน เช่น การสร้าง PDF ออกเป็นบริการแยก จากนั้นเมื่อจำนวนบริการเพิ่มขึ้นจึงค่อยเริ่มคิดเรื่องมาตรฐานและสถาปัตยกรรม แต่ในองค์กรที่มีวิศวกรน้อยกว่า 200 คน กลับมักเสียผลิตภาพมากกว่า ได้ข้อสรุปว่าไม่ได้อยู่รอดเพราะไมโครเซอร์วิส แต่เป็นอยู่รอดทั้งที่มีไมโครเซอร์วิสมากกว่า
    • นักพัฒนาบางคนมีแนวโน้มผลักดันไมโครเซอร์วิสเพื่อเพิ่มโปรไฟล์สำหรับไปทำงานบริษัทใหญ่ในอนาคต ซึ่งแทบไม่ช่วยสตาร์ทอัพจริง ๆ และการกันเรื่องแบบนี้ต้องอาศัยผู้นำด้านเทคนิคที่ฉลาดมาก
    • เคยเห็นสตาร์ทอัพที่มีวิศวกรราว 50 คน แต่แยกระบบเป็นบริการย่อยหลายสิบตัว คนใหม่ต้องใช้เวลาอย่างน้อย 6 เดือนกว่าจะเข้าใจระบบ ทั้งที่มีผู้ใช้เพียงไม่กี่ร้อยคน แต่ความซับซ้อนกลับมหาศาล เผาเงิน VC ไป $50 million แล้วสุดท้ายก็ล้มเหลว แม้ตัวผลิตภัณฑ์จะล้ำหน้าและออกแบบมาดีก็ตาม
    • เวลาจะแยกบริการ ยังมีอีกวิธีคือไม่ต้องแยกโค้ด แต่ใช้โมโนลิธปกติแล้วแยกการ deploy ตาม role flag เท่านั้น โดยให้ background worker รันร่วมกับเว็บเซิร์ฟเวอร์ ใช้ health check และ metrics แล้วให้ load balancer กระจายทราฟฟิกตามบทบาท
    • อย่างกรณีของ Khan Academy หลังจากสเกลโมโนลิธไปได้ไกลพอ ก็จะเริ่มตัดสินขอบเขตของบริการได้จากประสบการณ์ และตอนนั้นจึงเหมาะกับการนำไมโครเซอร์วิสมาใช้
    • แม้จะมีเหตุผลทางเทคนิคที่ทำให้ต้องแยก แต่การทำ service เดิมทีก็เป็นเรื่องยากอยู่แล้ว อย่างไรก็ตามถ้าจำเป็นจริง การตั้งใจพัฒนาความชำนาญก็สำคัญ ไม่ควรปฏิเสธเพียงเพราะมันเป็นกระแส ต้องพิจารณา trade-off ให้ดี
    • แค่มี "หลายทีม" ก็ไม่ได้แปลว่าต้องแยกองค์กรหรือแยกโมโนลิธเสมอไป แต่ในความเป็นจริงมี director บางคนที่เห็นว่าแค่มี Squad เล็ก ๆ สองทีมก็รีบจะผ่าโมโนลิธแล้ว ทั้งที่ทีมมักถูกปรับโครงสร้างบ่อยทุก 9 เดือน ถ้าตั้งขอบเขตสถาปัตยกรรมเร็วเกินไปอาจกลายเป็นหายนะ ต้องพิสูจน์ก่อนว่าทีมหนึ่งสามารถทำงานอย่างเสถียรต่อเนื่องอย่างน้อยราว 18 เดือน จึงค่อยพิจารณาให้เป็นขอบเขตสถาปัตยกรรมได้
    • คำจำกัดความของไมโครเซอร์วิสเดิมก็หมายถึง "โดเมนที่สามารถพัฒนาได้อย่างอิสระ" อยู่แล้ว จึงรู้สึกว่าไม่ได้มีอะไรใหม่
    • มีกรณีพิเศษที่มีเพียง URL เดียวซึ่งมีความต้องการด้านทราฟฟิกและหน่วยความจำต่างจากส่วนอื่นมาก จึงไม่เหมาะกับเซิร์ฟเวอร์ PHP และเพิ่มเซิร์ฟเวอร์อีกตัวด้วยภาษาอื่นแทน ได้ผลดีขึ้นทั้งด้านประสิทธิภาพและต้นทุนถึง 1000 เท่า อีกมุมหนึ่งคืออาจต้องลองมองแนวคิด service แบบ Java/Spring/Guava ใหม่ ว่าจะทำแบบ "นอก process" หรือ "ใน process" ก็ได้ หากมาตรฐานของ tech stack/เวอร์ชันและ serialization ดีพอ ผลิตภาพอาจดีขึ้นได้ แต่ถ้าขาดมาตรฐานก็จะสร้างความสับสน เช่น การสื่อสารผิดพลาดและปัญหาความเข้ากันได้
    • Conway's law (โครงสร้างโค้ดสะท้อนโครงสร้างองค์กร) เป็นเรื่องจริง
    • เน้นว่าคำว่า service เดิมทีคือสิ่งที่คนเป็นผู้ให้บริการ ส่วน microservice คือ service ในระบบเศรษฐกิจภายในบริษัท
    • ประสบการณ์เมื่อ 15 ปีก่อน จากเดิมที่ทีมเล็กดูแลโซลูชันเดียวได้สบาย พอเปลี่ยนไปใช้ไมโครเซอร์วิสกลับต้องลำบากกับการสตาร์ตและประสานงานของแต่ละ service ทำให้ซึมซับความสำคัญของ YAGNI (อย่าสร้างก่อนจำเป็น)
    • มีหลายเหตุผลทางเทคนิคที่ควรแยก เช่น แยกเฉพาะเส้นทางที่ทราฟฟิกสูงหรือสำคัญ แม้โดยทั่วไปจะไม่ค่อยเหมาะกับองค์กรเล็ก แต่ถ้าตัดเฉพาะเส้นทางโหลดสูงออกมา ก็อาจให้ผลดีมากกับสตาร์ทอัพได้
    • ในความเป็นจริง ข้อดีหลักของไมโครเซอร์วิสคือช่วยให้กลุ่มเล็ก ๆ ทำงานกันได้อย่างอิสระโดยไม่รบกวนกัน แต่เมื่อหลายทีมต่างถือครองไมโครเซอร์วิสของตัวเอง การประชุมเรื่องมาตรฐานก็ไม่จบไม่สิ้น และเพราะต้องระวังไม่ไปก้าวก่ายบริการของทีมอื่น ทักษะทางการทูตแบบ "อย่าไปยุ่งงานคนอื่น" กลับสำคัญกว่าความร่วมมือ
  • แม้จะเตือนทีมที่มีนักพัฒนา 2-3 คนว่าอย่าใช้ไมโครเซอร์วิสแค่เพราะมันดูเท่ แต่ก็ยังทำกันอยู่ จนอีก 2 ปีให้หลังถึงเริ่มเขียนระบบเดิมใหม่ และผ่านไป 3 ปีก็ยังแก้ปัญหาเรื่อง deployment และปัญหาอื่น ๆ ไม่ได้ ถ้าตอนแรกไม่เมินคำแนะนำและเลือก modular monolith คงไม่เจอปัญหาแบบนี้ เห็นด้วยกับบทความนี้มาก
    • ถ้าทิ้งไว้แค่ประวัติว่าเคยทำเทคโนโลยีหรือโปรเจกต์สุดหวือหวา แล้วรีบย้ายงาน คนที่เหลือต้องรับผลกระทบแทน
    • ไมโครเซอร์วิสจะมีประโยชน์จริงก็ต่อเมื่อมีหนึ่งทีมต่อหนึ่งบริการ ไม่ค่อยเคยเห็นกรณีที่หนึ่งทีมดูแลหลายบริการแล้วออกมาดี
    • ปัญหาจำนวนมากเกิดจากคนในทีมยังคิดกับไมโครเซอร์วิสราวกับมันเป็นระบบเดียวแบบโมโนลิธ ทำให้เกิดแรงเสียดทานตั้งแต่การออกแบบจนถึง deployment องค์กรทั้งองค์กรต้องเข้าใจและยอมรับแนวคิดนี้จริง ๆ จึงจะสำเร็จได้ และถ้านำระบบเดิมมาแปลงเป็นไมโครเซอร์วิส มักมีแรงต้านภายในสูง
    • ท้ายที่สุดก็รู้สึกว่าสตาร์ทอัพต่างต้องผ่านความลำบากคล้าย ๆ กัน
    • แม้แต่โปรเจกต์ UI ภายในที่ประกอบด้วยไมโครเซอร์วิส 8-12 ตัว แต่มีผู้ใช้จริงเพียง 5-10 คน ก็กลับเพิ่มแต่ความซับซ้อนโดยไม่จำเป็น และไม่รู้ว่าทำไปทำไม
    • เคยมีประสบการณ์นำไมโครเซอร์วิส+Java มาใช้เพราะ Thoughtworks consulting บริษัทที่ปรึกษาหาเงินเสร็จก็จากไป แต่ฝั่งองค์กรกลับต้องมางมกับการ reimplement โมโนลิธฟีเจอร์เยอะให้กลายเป็นไมโครเซอร์วิสแบบกระจาย สุดท้ายโปรเจกต์ล้มเหลวและบริษัทก็หายไป หลังจากนั้นจึงไม่ไว้ใจบริษัท consulting ขนาดใหญ่อีก
  • ในสไตล์สมองแบบ grug ก็สงสัยว่าทำไมต้องจงใจทำระบบให้แตกออกเป็นชิ้น ๆ แล้วเพิ่ม network call เข้าไปด้วย
    • รู้สึกเหมือนกับการพยายามเพิ่มความสามารถ "monkey patch" ให้กับภาษาที่ไม่มีมันเหมือน Python
    • มีความเห็นว่า network call ทำหน้าที่เปลี่ยนกฎ (rule) ให้กลายเป็นกฎหมาย (law)
    • มุกแบบ grug คือเมื่อมี grug สมองแบบ grug เยอะขึ้น พวกหัวหน้ากลุ่มก็เริ่มหลงคิดว่า grug 9 คนจะช่วยกันสร้าง baby grug ได้ภายใน 1 เดือน
  • ไมโครเซอร์วิสมีประสิทธิภาพในการแก้ปัญหาคนในองค์กรใหญ่ ลดอุปสรรคเชิงราชการ และเพิ่ม autonomy ให้กับนักพัฒนา แต่สำหรับสตาร์ทอัพขนาดเล็ก ประโยชน์จริงมักไม่มาก อย่างไรก็ตาม หากบางโดเมนต้องใช้ tech stack ผสมกัน เช่น Elixir กับ Python/Go การแยกแบบนี้ก็อาจจำเป็น
    • ถ้าในแอปมีภาระงานหรือความต้องการทรัพยากรที่ต่างกัน การสร้างบริการแยกก็มีข้อดีแม้ในสตาร์ทอัพเล็ก ๆ โดยเก็บ business logic ส่วนใหญ่ไว้ในโมโนลิธ และแยกเฉพาะงานพิเศษอย่าง GPU ออกไป แต่ไม่ควรปล่อยให้รูปแบบนี้ลุกลามเป็นการดูแล 100 บริการ โดยพื้นฐานยังชอบโมโนลิธ และค่อยแยกเมื่อจำเป็นจริง ๆ
    • ไมโครเซอร์วิสกลับสร้าง dependency เชิงองค์กรและความจำเป็นในการประสานงานขึ้นมาใหม่ เช่น นโยบายแบบ "หยิบ service ไหนก็ได้มาใช้" จะเพิ่มภาระการบำรุงรักษาอย่างมาก และทำให้ไม่ว่าใครก็ต้องเรียนรู้ทุกอย่างเพื่อให้ระบบเดินต่อได้ สุดท้ายจึงหมดเวลาไปกับการหาคนมารับช่วงงาน
    • ถ้ามีทีมที่ขัดแย้งกันหรือทำงานซ้ำซ้อน ประสิทธิภาพก็จะยิ่งแย่ลง
  • ไมโครเซอร์วิสในสถาปัตยกรรมซอฟต์แวร์คล้ายกับ Conway's Law (โครงสร้างองค์กรมีผลต่อโครงสร้างโค้ด) คือทุกขอบเขตทีมจะกลายเป็นขอบเขตที่ต้องข้ามไปมา และการสร้างขอบเขตสถาปัตยกรรมขนาดใหญ่ขึ้นมาภายในแบบฝืนธรรมชาติมักไม่เกิดผลิตภาพ ทางเลือกที่ดีกว่าคือใช้ modular monolith ผ่าน dependency injection การออกแบบขอบเขตโมดูล หรือ actor model และเมื่อจำเป็นจริงในภายหลังก็ค่อยแยกเป็น service ซึ่งทำได้ง่ายกว่า วิธีนี้คุ้มค่าต้นทุนมาก และมีประสบการณ์แยกโมโนลิธสำเร็จมาแล้ว 3-4 ครั้ง
    • Conway's Law เป็นกฎว่าด้วยการสื่อสารหรือ communication boundary ไม่จำเป็นต้องไปแตะทุกขอบเขตทีม ตรงกันข้าม อาจต้องปรับองค์กรให้เข้ากับซอฟต์แวร์แทน หมายความว่าทุกครั้งที่เปลี่ยนสถาปัตยกรรม ก็ต้อง reorganize บริษัทใหม่ ซึ่งวิธีนี้ยิ่งทำให้ทีมกับเป้าหมายทางธุรกิจแยกขาดจากกัน จึงไม่ควรศรัทธาวิธีแบบ Amazon มากเกินไป
  • ในเชิงเทคนิค กรณีที่ไมโครเซอร์วิสเหมาะกับสตาร์ทอัพจริง ๆ มีอยู่ไม่กี่แบบ คือ (1) แอปแกนหลักต้องใช้คนละภาษากับบางส่วน เช่น Rails+R (2) บางบริการมีความต่างด้านสเกลมหาศาล (3) ข้อมูลบางประเภทต้องมีข้อกำหนดด้านความปลอดภัยหรืออายุข้อมูลต่างออกไป เช่น ข้อมูลการแพทย์ นอกเหนือจากนั้นแทบไม่มีเหตุผลให้แยกย่อย และสำหรับองค์กรเล็กมักเสียมากกว่าได้
    • การแยกบริการใหม่ไม่กี่ตัวไม่เหมือนกับไมโครเซอร์วิสแท้ ๆ เพราะไมโครเซอร์วิสจริงคือการแยกแม้กระทั่งสิ่งที่ในแอปทั่วไปจะเก็บไว้เป็นโมดูล
    • ไม่ใช่แค่เรื่องสเกล หากข้อกำหนดด้าน reliability และ availability ต่างกันอย่างสุดขั้ว การแยก service ก็สมเหตุสมผล เพราะการแยก concern เพื่อรักษา SLA อาจช่วยลดความเสี่ยงและเพิ่มความเร็วในการ deploy ได้
    • แม้ในกรณีแบบนี้ ก็ยังมองว่าไม่ต่างจากการแยก DB server ออกมารันต่างหากมากนัก
  • ผลลัพธ์ที่แท้จริงของไมโครเซอร์วิสอยู่ที่มิติด้านองค์กร คือการแบ่งปัญหาออกเป็นชิ้น ๆ ให้แต่ละทีมเป็นเจ้าของอย่างสมบูรณ์ และรับผิดชอบตั้งแต่ต้นจนจบในการส่งมอบ จึงเกิดความเชี่ยวชาญเฉพาะทางได้ การเปลี่ยนแปลงจึงค่อยเป็นค่อยไปโดยธรรมชาติ และ API เป็นช่องทางเดียวของการปฏิสัมพันธ์ ไม่มีการแชร์ DB เดียว ระบบไฟล์เดียว หรือ API ร่วมกัน แต่สิ่งสำคัญคือการทำมาตรฐานและเครื่องมือจัดการ เช่น monitoring, testing, CI/CD ซึ่งไม่ว่าเป็นโมโนลิธหรืออะไรก็ตามก็ควรมีอยู่ระดับหนึ่ง
    • เรื่องอย่าง infrastructure, logging, authentication สามารถทำเป็นแพ็กเกจหรือจัดการผ่าน gRPC หรือ message queue ได้ ทำให้สร้าง service ใหม่ได้เร็ว และ merge request ภายในทีมก็เล็กลง ลดการชนกันและเพิ่มผลิตภาพ ตอนทีมมีขนาด 5-10 คน เคยมีปัญหาเรื่องการชนกัน deployment และ release บ่อยตอนใช้โมโนลิธ แต่หลังเปลี่ยนเป็นไมโครเซอร์วิส productivity และความคล่องตัวในการทำงานร่วมกันดีขึ้นมาก แม้จะต้องมีวินัยเรื่อง testing, documentation และ endpoint อย่างจริงจังก็ตาม
    • ก็มีกรณีที่จำเป็นต้องแยกทางเทคนิคด้วยเหตุผลด้าน performance เช่น การแยก DB แต่สำหรับสตาร์ทอัพทั่วไปอาจพบไม่บ่อย
  • จุดแข็งของ ecosystem อย่าง BEAM/OTP (Erlang, Elixir) คือช่วยให้ยังคงโมโนลิธไว้ได้ แต่ฝึกออกแบบแบบ "คล้ายไมโครเซอร์วิส" ไปพร้อมกัน และเมื่อถึงเวลาที่ต้องแยกจริงก็เปลี่ยนได้ง่าย ช่วงที่ระบบยังเล็กก็ได้ข้อดีของโมโนลิธ และเมื่อโตขึ้นก็ได้ทั้งการสเกลและความเป็นอิสระพร้อมกัน เพียงแต่ต้องเรียนรู้เรื่อง immutable object, การสื่อสารแบบ concurrency และการจัดการความล้มเหลว อีกทั้งยังอาจจ้างคนยาก
  • โดยรวมเห็นด้วย ส่วนใหญ่ในสภาพแวดล้อมของสตาร์ทอัพแทบเป็นไปไม่ได้ที่จะกำหนดขอบเขต service ได้ดี แต่ก็มีบางครั้งที่การทำเป็นไมโครเซอร์วิสคุ้มค่าสำหรับทีมเล็ก เช่น เมื่อต้องรับมือ external API หรือ dependency ที่ซับซ้อน เพราะกรณีแบบนี้ network boundary เป็นสิ่งจำเป็นอยู่แล้ว การแยกเป็น service จึงไม่ได้เพิ่มความซับซ้อนมากนัก หรือในกรณีที่ build/deploy ซับซ้อน การแยกก็อาจช่วยทำให้โมโนลิธง่ายขึ้น
  • ไมโครเซอร์วิสเหมาะก็ต่อเมื่อจำเป็นต้องสเกลขนาดใหญ่มาก หรือจำเป็นต้องมีการ micromanage ทีมเท่านั้น แต่ก็ไม่ควรละทิ้งขอบเขตโมดูลที่ชัดเจน สามารถดึงข้อดีของไมโครเซอร์วิสมาใช้ภายในโมโนลิธได้ผ่านแนวคิด object-oriented แบบ message passing และต้องฝึกไม่ให้แตะ DB โดยตรง ในภาษาอย่าง Java ก็สามารถจัดโมดูล แบ่ง namespace ของ DB schema เปิดเผยเฉพาะ interface ที่จำเป็น และทำให้ทดสอบหรือ monitoring ได้อย่างเป็นอิสระ รวมถึง deploy หลาย service พร้อมกันได้ง่าย
    • หากเข้าใจ logical boundary ดีพอ ก็มีวิธีบังคับใช้ด้วยเครื่องมืออย่าง ArchUnit ได้