Service per Team
คุณมีชุด service ที่ดี วาดเส้นตาม capability และ subdomain มาแล้ว และออกแบบให้รันแยกกันได้ เป้าหมายของงานทั้งหมดนั้นคือความเร็ว คือให้ทีมส่งงานขนานกันไปโดยไม่ต้องรอกัน แต่ความเป็นเจ้าของกลับถูกปล่อยให้คลุมเครือ หลายทีมเข้าไปแตะ Order service ทีม platform เป็นทีมเดียวที่มีสิทธิ์ deploy Billing และการแก้ Shipping ต้องขออนุมัติจากกลุ่มที่ไม่ได้ลงมือทำจริง สถาปัตยกรรมถูก decompose แล้วก็จริง แต่องค์กรรอบ ๆ ไม่ได้ถูก decompose ตาม ความเป็นอิสระที่สัญญาไว้จึงไม่เคยมาถึง
Conway’s law ชี้ว่าโครงสร้างของระบบมักสะท้อนโครงสร้างการสื่อสารขององค์กรที่สร้างระบบนั้น นี่ไม่ใช่คำคม แต่เป็นข้อจำกัดจริง ถ้าสามทีมช่วยกันสร้าง service ตัวเดียว service นั้นจะงอกรอยต่อขึ้นมาสามชุดตามจำนวนทีม และทุกการเปลี่ยนแปลงต้องเจรจากันสามฝ่าย ในทางกลับกัน ถ้าทีมเดียวต้องแตะสี่ service เพื่อส่ง feature หนึ่ง service ทั้งสี่ก็จะ couple เข้ากับตาราง release ของทีมนั้นแบบเงียบ ๆ ความเป็นเจ้าของร่วมเปลี่ยนทุกการ deploy ให้กลายเป็นปัญหาการประสานงาน ทั้งใครมีสิทธิ์ merge ใครต้อง review เทสของใครต้องผ่าน และใคร on call เวลาพัง สุดท้ายต้นทุนของการเปลี่ยนแปลงถูกกำหนดด้วยจำนวนคนที่ต้องเห็นพ้องกัน ไม่ใช่ด้วย code
ดังนั้นแรงต่าง ๆ คือ คุณต้องการให้แต่ละ service ถูกเปลี่ยนแปลงและ deploy ได้อย่างรวดเร็วและมั่นใจ แต่ความเป็นเจ้าของที่กระจายไปทั่วหลายทีม (หรือหลายทีมที่อัดแน่นอยู่บน service เดียว) นำการประสานงานข้ามทีมที่การ decompose ตั้งใจจะกำจัดกลับมาเสียพอดี
วิธีแก้
หัวข้อที่มีชื่อว่า “วิธีแก้”Service per Team ทำให้ความเป็นเจ้าของชัดเจนและผูกขาด คือ แต่ละ service ถูกเป็นเจ้าของโดยทีมเดียวเท่านั้น และทีมหนึ่งเป็นเจ้าของชุด service ที่เกี่ยวข้องกันขนาดเล็กแบบ end to end — ออกแบบ, เขียน code, ทดสอบ, deploy, และทำงาน ไม่มีทีมอื่น deploy service ของคุณ ไม่มี service ใดมีสองนาย ที่สำคัญคือ คุณไม่ปล่อยให้ผังองค์กรหลุดออกมาโดยบังเอิญ — คุณปฏิบัติต่อ Conway’s law เป็นเครื่องมือออกแบบ (inverse Conway manoeuvre) และปั้นทีมอย่างจงใจให้เข้ากับเส้นแบ่งของ service ที่คุณต้องการ
ขนาดของทีมต้องพอดีกับการดูแล service ที่ถืออยู่ คือเล็กพอจะคุยกันเองรู้เรื่อง แต่ใหญ่พอจะแบกทั้งภาระ on-call และการส่งมอบ ทีมทำงานร่วมกันแบบเดียวกับที่ service ทำ คือผ่าน API และ contract ที่นิ่งและเผยแพร่ไว้แล้ว ไม่ใช่ผ่าน code ร่วมหรือ deployment pipeline ร่วม เวลาทีม A ต้องการอะไรจาก service ของทีม B ก็ขอผ่าน interface ที่มีเวอร์ชันกำกับ ไม่ใช่เข้าไปแก้ code ของ B เอง
ผลลัพธ์คือองค์กรและสถาปัตยกรรมเสริมแรงซึ่งกันและกัน เส้นแบ่งที่สอดคล้องกันหมายความว่าการเปลี่ยนแปลงส่วนใหญ่อยู่ภายใน service ของทีมเดียว ดังนั้นทีมนั้นจึงสามารถตัดสินใจ, สร้าง, ทดสอบ, และ release ตามจังหวะของตัวเองได้ — ที่เป็นความเป็นอิสระที่ความพยายามทั้งหมดนี้มีไว้เพื่อสิ่งนั้น
flowchart TB
subgraph TeamA[Team Checkout]
direction TB
SA1[Order Service]
SA2[Cart Service]
end
subgraph TeamB[Team Billing]
direction TB
SB1[Billing Service]
SB2[Invoice Service]
end
subgraph TeamC[Team Fulfilment]
direction TB
SC1[Shipping Service]
SC2[Inventory Service]
end
TeamA -. published API .-> TeamB
TeamA -. published API .-> TeamC
TeamB -. published API .-> TeamC
Note[One team owns each service end to end;<br/>teams collaborate only through stable contracts] ผลลัพธ์ที่ตามมา
หัวข้อที่มีชื่อว่า “ผลลัพธ์ที่ตามมา”สิ่งที่คุณได้:
- ความเป็นอิสระและความเร็วที่แท้จริง ทีมที่เป็นเจ้าของ service ของตนแบบ end to end สามารถออกแบบ, สร้าง, ทดสอบ, และ deploy ได้โดยไม่ต้องรอใคร ดังนั้นการเปลี่ยนแปลงส่วนใหญ่จึงส่งมอบได้ตามจังหวะของทีมเอง
- ความรับผิดชอบชัดเจน แต่ละ service มีทีมเดียวเป็นเจ้าของ คำถามว่า “ใครรับผิดชอบ” จึงหมดไป ทั้งเรื่อง review code เรื่อง deploy pipeline และเรื่องใครรับสายเวลาระบบพัง
- สถาปัตยกรรมเข้ากับองค์กร พอปั้นทีมให้ตรงกับเส้นแบ่ง service ที่ต้องการ คุณก็เลิกฝืน Conway’s law แล้วหันมาใช้ประโยชน์จากกฎนี้แทน รอยต่อในระบบจะไปลงตรงกับรอยต่อระหว่างทีมพอดี
สิ่งที่คุณต้องจ่าย:
- การประสานงานถูกผลักไปอยู่ที่เส้นแบ่ง ความเป็นอิสระภายในทีมแลกมาด้วยวินัยเรื่อง contract ระหว่างทีม การเปลี่ยนแปลงที่ข้ามเส้นแบ่ง service ก็ยังต้องตกลงกันข้ามทีมอยู่ดี ถ้าเส้นแบ่งวางไม่ดี ก็แค่ย้ายความเจ็บปวดไปอีกที่ ไม่ได้กำจัดออกไปจริง ๆ
- การปรับองค์กรเป็นเรื่องยากและการเมือง การจัดทีมให้เข้ากับ service อาจหมายถึงการเปลี่ยนสายการรายงานและจำนวนคน — การเปลี่ยนแปลงเชิงองค์กรที่ช้ากว่าและละเอียดอ่อนกว่าการเปลี่ยน code ใด ๆ
- ความเสี่ยงของ coupling และความซ้ำซ้อน หากไม่ระวัง ทีมก็จะ couple ผ่าน library และ database ร่วม (สร้าง distributed monolith ขึ้นมาใหม่) หรือทำงานซ้ำซ้อนเพราะไม่มีใครเป็นเจ้าของพื้นที่ส่วนกลาง ทั้งสองอย่างต้องการการกำกับดูแลอย่างจริงจังเพื่อหลีกเลี่ยง
เนื้อหาที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “เนื้อหาที่เกี่ยวข้อง”- Decompose by Business Capability — capability แมปลงทีมได้อย่างหมดจด ทำให้การกำหนดความเป็นเจ้าของง่าย
- Decompose by Subdomain — bounded context ให้แต่ละทีมมีส่วนที่ self-contained ไว้เป็นเจ้าของ
- Self-Contained Service — ความเป็นอิสระตอน runtime และความเป็นอิสระของทีมเสริมแรงซึ่งกันและกัน ทีมที่ไม่ขึ้นกับใครตอน deploy ก็ต้องการ service ที่ไม่ขึ้นกับใครตอน runtime เช่นกัน
| ข้อดี | ข้อแลกเปลี่ยน |
|---|---|
| ทีมเป็นเจ้าของ service ชัดเจน — ไม่มีสองทีมแย่งแก้ service เดียว | ต้องออกแบบ team topology ก่อน service boundary |
| team autonomy สูง — deploy ได้โดยไม่ต้องรอทีมอื่น | service ใหญ่เกินถ้าทีมใหญ่เกิน |
| accountability ชัด — ถ้า service พัง รู้ว่าใครดูแล | Conway’s Law ทำงานสองทาง — org เปลี่ยนต้องปรับ service |
| ลด governance overhead | ทีมใหม่อาจได้รับ legacy service ที่ยาก |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”Service ที่ไม่มีเจ้าของ — service ที่ “เป็นของทุกคน” แปลว่าไม่มีใครรับผิดชอบ อาการ:
- bug ใน service ไม่มีทีมไหนรับไป fix
- ไม่มีทีมไหน on-call สำหรับ service นั้น
- technical debt สะสมเพราะไม่มีใครรู้สึกเป็นเจ้าของ
Team Silos — ทีมแยกกันทำงานแต่ service ยังพึ่งพากันสูง อาการ:
- deploy service A ต้องรอทีม B approve
- interface ระหว่าง service ไม่มี contract — break บ่อย
💡 ตัวอย่างจากของจริง
Spotify:
- “Squad” model — แต่ละ squad เป็นเจ้าของ service ของตัวเอง
- squad มี full-stack capability — frontend, backend, data, ops
- deploy อิสระ ไม่ต้องรอ squad อื่น
Amazon:
- “You build it, you run it” — ทีมที่ build service คือทีมที่ on-call
- ownership ชัดเจนทำให้ทีมใส่ใจ reliability มากขึ้น