โมเดล C4 สำหรับการทำภาพสถาปัตยกรรมซอฟต์แวร์ (2017)
(c4model.com)- โมเดล C4 เป็นแนวทางที่ เป็นมิตรกับนักพัฒนา สำหรับการสร้างไดอะแกรมสถาปัตยกรรมซอฟต์แวร์ ช่วยให้มองโครงสร้างที่ซับซ้อนแบบแยกเป็นลำดับขั้นได้
- การทำ abstraction จะไล่ระดับจาก software systems → containers → components → code ทำให้จัดการสถาปัตยกรรมแบบมีลำดับชั้น
- ตัวไดอะแกรมก็ถูกจัดให้เป็นไปตามโครงสร้าง system context → container → component → code เช่นกัน
- ตามความจำเป็น ยังสามารถเสริมมุมมองของโครงสร้างทั้งหมด การทำงานขณะรัน และการ deploy ได้ด้วยไดอะแกรม system landscape, dynamic, และ deployment
- เป็นแนวทางแบบ notation independent และ tooling independent ที่ไม่ผูกกับสัญลักษณ์หรือเครื่องมือเฉพาะ จึงนำไปใช้ให้เข้ากับสภาพแวดล้อมเดิมได้
องค์ประกอบของโมเดล C4
- โมเดล C4 คือโมเดลสำหรับการทำภาพสถาปัตยกรรมซอฟต์แวร์ โดยผู้สร้างคือ Simon Brown
- แกนสำคัญคือการใช้ hierarchical abstraction และ hierarchical diagrams ควบคู่กัน
ไดอะแกรมและความเป็นอิสระ
- ไดอะแกรมหลักถูกออกแบบมาเพื่อให้มองสถาปัตยกรรมได้ในระดับความลึกที่ต่างกัน
- ไดอะแกรมเสริมช่วยเติมเต็มมุมมองที่ลำดับชั้นหลักเพียงอย่างเดียวอาจยังไม่พอ
- โมเดลนี้เป็นทั้ง notation independent และ tooling independent จึงไม่บังคับให้ต้องเลือกใช้สัญลักษณ์หรือเครื่องมือใดโดยเฉพาะ
- เอกสารที่เกี่ยวข้องมีวิดีโอ Visualising software architecture with the C4 model ที่บันทึกไว้ในงาน “Agile on the Beach 2019” เมื่อเดือนกรกฎาคม 2019 และเอกสาร The C4 model
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ผมมองว่าปัญหาใหญ่ที่สุดของ ไดอะแกรมสถาปัตยกรรม คือมันไม่ตรงกับ codebase
ไดอะแกรมแบบนี้จำเป็นต้องสร้างอัตโนมัติ ไม่อย่างนั้นทีมจะไม่มีทางรู้ได้เลยว่าภาพที่กำลังดูอยู่แสดงสถานะล่าสุดของระบบได้ถูกต้องหรือไม่
ไดอะแกรมแสดงมุมมองเฉพาะอย่าง เน้นคุณลักษณะบางอย่างและละเว้นบางอย่างออกไป สำหรับสิ่งเดียวกันอาจมีไดอะแกรมหลายแบบที่อธิบายแง่มุมหรือสถานการณ์ที่ต่างกัน สุดท้ายไดอะแกรมก็ต้องได้รับการบำรุงรักษาไปพร้อมกับโค้ดและสถาปัตยกรรมแอปพลิเคชันเหมือนเอกสารข้อความ และคงต้องทำให้เป็นงานประจำของการจัดการการเปลี่ยนแปลง
ในหลายโปรเจกต์ไม่ได้จัดโครงสร้างโค้ดในแบบเดียวกับโมเดลในหัว และแทบทุกภาษาก็ไม่มีวิธีแก้ปัญหานี้ การทำเครื่องหมายไว้ในโค้ดด้วยคอมเมนต์ก็มีปัญหาเดียวกับการทำให้ไดอะแกรม คอมเมนต์ และเอกสารยังทันสมัยอยู่เสมอ
มันแสดง สถานะเป้าหมาย ไม่ใช่สถานะปัจจุบัน โค้ดควรทำตามไดอะแกรม ไม่ใช่กลับกัน กรณีที่การสร้างไดอะแกรมจากโค้ดมีความหมายก็แค่ช่วยคนที่เพิ่งเข้าร่วมโปรเจกต์ที่ไม่มีเอกสาร และถึงตอนนั้นก็มักเป็นการสร้างขึ้นมาครั้งหนึ่ง แล้วตัดสัญญาณรบกวนออก ปรับแต่งให้เรียบร้อย จากนั้นใช้เป็นเอกสารอ้างอิงต่อไป
ไดอะแกรมระดับสูง ควรสร้างได้เร็วและทิ้งได้ง่าย และสิ่งที่ละเว้นก็สำคัญพอ ๆ กับสิ่งที่แสดงให้เห็น
ผมชอบ C4 เมื่อก่อนเคยมองว่า context diagram แบบ “User -{do their job}-> System-of-Record” ไม่มีประโยชน์ แต่ตอนนี้เข้าใจเหตุผลแล้ว
เรากำลังออกแบบระบบซับซ้อนตัวใหม่ร่วมกับทีมขยายหลายทีมโดยใช้ C4 ครั้งนี้พอวาดภาพระดับบนสุด ก็พบว่านอกจากเว็บ UI แล้วยังมีแอปมือถือที่อาจเชื่อมต่อได้แบบครึ่ง ๆ กลาง ๆ อยู่ด้วย จึงตระหนักว่าเวลาที่ออฟไลน์หรือแบ็กเอนด์ช้า หากผลลัพธ์บางอย่างยังไม่พร้อม ก็ต้องลดระดับการทำงานบางอย่างอย่างนุ่มนวล ประเด็นนี้นำไปสู่คิวงานในชั้นถัดไป และต่อไปถึง UX ทำให้สามารถพูดได้ชัดเจนว่าคำขอแบบใดอาจใช้เวลานานไม่มีกำหนดกว่าจะเสร็จ สักวันคงไปถึงจุดนั้นอยู่แล้ว แต่การวิเคราะห์ทำให้ปัญหานี้ถูกยกขึ้นมาตรงหน้า ทั้งหมดก็เพราะต้องวาดภาพ “Remote-User --{Mobile Stuff}--> Backend” จะใช้เครื่องมืออะไรก็ไม่สำคัญ ผมใช้เช่น draw.io โดยแยกแท็บตามแต่ละชั้น พอทำให้เป็นรูปธรรมมากขึ้น ก็จะแยกชั้นล่าง ๆ ออกเป็นไฟล์ต่างหาก
ผมเข้าใจข้อโต้แย้งที่ว่าไดอะแกรมไม่จำเป็นต้องมีระบบแบบเป็นทางการ แต่คิดว่า C4 ค่อนข้างเบา ผมเองไม่ลงไปถึงระดับโค้ด
ถึงอย่างนั้น structurizr ที่สร้างไดอะแกรม C4 ก็ช่วยเพิ่มประสิทธิภาพได้มาก วิธีสร้างมุมมองหลายระดับรายละเอียดจากโมเดลเดียว ถือว่ายอดเยี่ยมเมื่อเทียบกับ mermaid หรือ plantuml ที่แต่ละไดอะแกรมต้องนิยามและนิยามซ้ำคอมโพเนนต์เดิม ๆ อย่างเป็นอิสระ เวิร์กโฟลว์ที่สร้าง branch แก้โมเดล แล้วนำเสนอไอเดีย เข้ากับผมได้ดีมาก
ไม่มีวิธีวาดแนวคิดที่ไม่ได้อยู่ใน C4 อย่างเคร่งครัด เช่น ผมอยากใส่คอมโพเนนต์สองตัวไว้ในกล่องเดียว เพื่อแสดงว่าตอนนี้ถูก deploy เป็น service เดียวกัน แต่ทำไม่ได้ นั่นไม่ได้หมายความว่าเป็นการออกแบบที่ดีโดยสมบูรณ์ แต่คงช่วยให้ทีมเข้าใจได้ แนวคิดการอธิบายสถาปัตยกรรมอย่างเป็นทางการนั้นดี แต่ การขาดการปรับแต่งเอง ของผลลัพธ์ไดอะแกรมทำให้ใช้งานลำบากมาก
เมื่ออธิบายสถาปัตยกรรมแล้ว structurizr จะเรนเดอร์ไดอะแกรมให้
ทำได้ก็จริง แต่ค่อนข้างยุ่งยาก และเมื่อคำอธิบายลูกศรระหว่างกล่องยาวขึ้น การจัดวางอัตโนมัติ ก็พังได้อย่างรวดเร็ว
ผมมองว่าสถาปัตยกรรมซอฟต์แวร์คือ ชุดของการตัดสินใจด้านการออกแบบ ที่ชี้นำการนำไปใช้งาน
จากประสบการณ์ของผม สถาปนิกซอฟต์แวร์ส่วนใหญ่ให้แนวทางและโครงสร้างแก่ซอฟต์แวร์เอนจิเนียร์ แต่ประโยคในคำอธิบาย C4 ที่ว่า “สร้างแผนที่ของโค้ดเดิมในหลายระดับรายละเอียด” ฟังดูเป็นอีกอย่างหนึ่ง ผมไม่เข้าใจว่าทำไมถึงเรียกไดอะแกรมโค้ดว่าสถาปัตยกรรมซอฟต์แวร์ นั่นมันระดับโค้ดตามตัวอักษร แล้วจะเป็นสถาปัตยกรรมได้อย่างไร คล้ายกับการเอาผังวงจรในปลั๊กไปใส่ไว้ในพิมพ์เขียวบ้าน ถ้าบอกว่า “ควรใช้เครื่องมืออัตโนมัติ” หมายความว่าจะทำเอกสาร codebase เดิมในระดับฟังก์ชันหรือเปล่า? ผมไม่เห็นว่ามันมีประโยชน์ต่อการออกแบบและวางแผนซอฟต์แวร์อย่างไร แผนที่ที่อธิบายโครงสร้างของซอฟต์แวร์เดิมอาจดูดีได้ แต่เวลาพูดถึง design pattern เราไม่ได้ให้แผนที่การ implement singleton แยกตามฟังก์ชัน แค่บอกว่าต้องการ singleton หรือ repository pattern ก็พอ ตัวการออกแบบซอฟต์แวร์มีอยู่จริงแน่นอน และวิธีนี้ก็ดูสมเหตุสมผลสำหรับงานออกแบบ แต่จากประสบการณ์ของผม การออกแบบซอฟต์แวร์ การ implement และสถาปัตยกรรมไม่ใช่สิ่งเดียวกัน และไม่ได้ทำโดยคนกลุ่มเดียวกันด้วย สิ่งนี้ดูใกล้เคียงกับการออกแบบระบบมากกว่า และสถาปนิกซอฟต์แวร์น่าจะมีบทบาทให้คำแนะนำเพื่อให้การออกแบบระบบนั้นสอดคล้องกับหลักสถาปัตยกรรมที่ดี ผมอาจจะจู้จี้เกินไปก็ได้
ผมคิดว่าบทบาทสำคัญของสถาปัตยกรรมซอฟต์แวร์คือการให้ข้อมูลเพื่อให้นักพัฒนาตัดสินใจด้านการออกแบบได้เอง โดยไม่ต้องโยนการตัดสินใจให้ผู้มีอำนาจทุกครั้ง แต่เส้นแบ่งว่าสถาปัตยกรรมจบตรงไหนและการพัฒนาเริ่มตรงไหนนั้นแตกต่างกันมาก ผมคิดว่าสถาปัตยกรรมเองเป็นตัวกำหนดว่าอะไรสำคัญจากมุมมองด้านสถาปัตยกรรม ถ้าสถาปัตยกรรมตัดสินว่ารายละเอียดระดับต่ำบางอย่างของแอปพลิเคชันสำคัญ สิ่งนั้นก็กลายเป็นรายละเอียดทางสถาปัตยกรรม ในทางปฏิบัติ องค์กรส่วนใหญ่ควบคุมการออกแบบระดับสูงอย่างน้อยก็เรื่อง component, communication pattern, API และเทคโนโลยีที่ใช้ผ่านสถาปัตยกรรม บางองค์กรลงไปถึงระดับ class รายตัวด้วย ไม่ใช่ทุก class แต่เป็น class ที่ model โดเมนปัญหา โดยเฉพาะเมื่อ model นั้นถูกใช้เป็นภาษาร่วมกันของหลายโปรเจกต์ หรือถูก implement เป็น deliverable ที่แชร์กัน C4 เหมาะกับองค์กรที่มองว่าโครงสร้างระดับต่ำกว่ารายชื่อแอปพลิเคชันและ integration interface ก็เป็นประเด็นทางสถาปัตยกรรมด้วย
โดยพื้นฐานคือมีไดอะแกรมสำหรับทุกระดับที่มีความเฉพาะหรือมีประโยชน์อย่างชัดเจนในระบบ ถ้าจำเป็นต้องมี ไดอะแกรมระดับโค้ด ก็มีความเป็นไปได้สูงว่าคุณกำลังทำงาน custom ที่ซับซ้อน หรือกำลังระบุสเปกการออกแบบมากเกินไป ทั้งที่ควรปล่อยให้เป็นรายละเอียดการ implement
คล้ายกับในการก่อสร้างอสังหาริมทรัพย์จริงที่บทบาทของสถาปนิก วิศวกร และผู้ควบคุมหน้างานแตกต่างกัน ผมสงสัยว่าในสถาปัตยกรรม การออกแบบ และการ implement แต่ละส่วน ควรขีดเส้นไว้ตรงไหน และควรจัดการกับประเด็นอะไรบ้าง
น่าสนใจ แต่ยากจะบอกว่ามันเพิ่มอะไรเป็นพิเศษ
ไดอะแกรมระดับสูงเป็นเรื่องดี แต่เราก็ทำได้อยู่แล้วโดยไม่ต้องอ่านเว็บไซต์โมเดล visualization สุดหรู ตัวเว็บไซต์เองก็แทบจะยอมรับเรื่องนี้อยู่แล้ว ประโยคที่ว่าในวงการมี UML, ArchiMate, SysML แต่หลายทีมเลือกไดอะแกรม “กล่องกับเส้น” ที่เรียบง่ายกว่ามากนั้นถูกต้องมาก แต่ดูเหมือนจะมองข้ามไปว่าทำไม UML class diagram ถึงล้มเหลวโดยสิ้นเชิง แม้จะยอมรับว่าไม่มีใครชอบมัน แต่ C ตัวที่สี่ของโมเดลคือ Code ก็สุดท้ายแล้วเป็น UML class diagram นั่นเอง ของแบบนี้ไม่จำเป็น แค่วาดไดอะแกรมอะไรก็ได้ให้ชัดเจน แล้วใส่ label บนลูกศรก็พอ ไดอะแกรมสามอันแรกกลับเป็นตัวอย่างที่ดีของเรื่องนั้น
เวลาคิดคอนเซปต์ใหม่หรือ brainstorm ก็ช่วยได้มาก เพราะเครื่องมือไม่มาถ่วง ตอนนี้ใช้ Freeform ซึ่งเรียบง่ายมากแต่ทำงานได้ดี แค่เลือก object สองชิ้นแล้ว cmd-click หรือคลิกขวา จากนั้นกด “add connecting line” ก็พอ
แค่ไม่กี่เดือนก่อน ผมก็เพิ่งปิดเอกสารสถาปัตยกรรมอีกฉบับที่มี class diagram, sequence diagram และ use case อยู่พอสมควร
กล่องต่าง ๆ มักกลายเป็นของคนละระดับปนกัน บางอย่างเป็นนามธรรม บางอย่างเป็นรูปธรรม และบางอย่างก็แค่ตามใจชอบ ดังนั้นถ้าต้องประกอบชิ้นส่วนสถาปัตยกรรมที่ใหญ่กว่า เช่น supply chain ก็แทบต้องทำใหม่ทั้งหมด สิ้นเปลืองมาก และไม่มีใครมองเห็นสถาปัตยกรรมทั้งหมดได้ชัดพอ จนนำไปสู่ความสูญเปล่าและปัญหาคุณภาพอื่น ๆ น่าแปลกที่เอนจิเนียร์จำนวนมากมีท่าทีตั้งรับต่อแนวทางที่เป็นทางการกว่า อาจเพราะไม่เห็นประโยชน์ทันที หรือไม่เคยจัดการสถาปัตยกรรมขนาดใหญ่จึงไม่เห็นปัญหา
แสดงให้เห็นว่าวิศวกรรมซอฟต์แวร์ยังเป็นสาขาที่ยังไม่โตเต็มที่
ในกรณีของผม ผ่านมา มากกว่า 25 ปี แล้ว แต่ก็ยังคุยเรื่องเดิม ๆ ที่ใกล้กับ “พื้นฐาน” อยู่ นี่ไม่ได้แปลว่าเป็นเรื่องแย่ แต่ความคืบหน้าช้า และจะโยนความผิดให้บริษัทใดบริษัทหนึ่ง กลุ่ม consortium ใดกลุ่มหนึ่ง หรือผลประโยชน์เชิงพาณิชย์อย่างเดียวก็ไม่ได้
มีสักกี่ครั้งที่ใครบางคนสลับไปมาระหว่างรายละเอียดสูง ความซับซ้อนสูง และความเรียบง่ายเมื่อมองจากไกล ๆ ในความคิดเดียวกัน จนเราเข้าใจยากว่าเขาต้องการจะพูดอะไร? ปัญหาเดียวกันเกิดขึ้นเมื่อนักพัฒนาคิดว่า “ก็แค่วาดกล่องกับลูกศรบนบอร์ดนี้แบบพอประมาณก็พอ มันสมเหตุสมผลในหัวผม ดังนั้นมันเป็นไดอะแกรมที่ดี”
แม้ไม่ใช่วิศวกรโยธา เราก็เข้าใจของอย่างแปลนพื้นได้ทันทีและรู้สึกว่ามีประโยชน์
แต่แม้ผมจะเป็นซอฟต์แวร์เอนจิเนียร์มืออาชีพ ไดอะแกรมตัวอย่างเหล่านี้ก็ดูไม่มีประโยชน์หรือมีข้อมูลมากพอให้คุ้มความพยายาม โค้ดมีความเป็น หลายมิติ เกินไปจนยากจะประมาณด้วยภาพ 2 มิติ และมันทำงานได้ไม่ดี สิ่งที่พอมีศักยภาพคือ pattern ของโค้ดสถาปัตยกรรมที่เป็นแบบแผนมากขึ้น เช่น structured concurrency และอาจมีอะไรที่ระดับสูงกว่านั้นอีก
แปลนพื้นมีบริบทที่ตายตัวมากและขอบเขตจำกัด เช่น ไม่จำเป็นต้องอธิบายหน้าต่าง แต่ในซอฟต์แวร์ ส่วนใหญ่เราต้องอธิบาย “หน้าต่าง” จริง ๆ เพราะ “หน้าต่าง” หรือองค์ประกอบทุกอย่างแตกต่างกัน จึงไม่สามารถแค่บอกว่านี่คือหน้าต่างแล้วคัดลอก 20 ครั้งได้
หากรู้สึกว่าโมเดล C4 ดูกำหนดตามอำเภอใจเกินไปและระบุรายละเอียดมากเกินไป ผมเคยเขียนถึงแนวปฏิบัติทางเลือกไว้เมื่อต้นปีนี้: https://www.ilograph.com/blog/posts/concrete-diagramming-mod...
ชอบโมเดลนี้ และเคยมีช่วงที่ต้องใช้ UML ในสถาปัตยกรรมความปลอดภัยด้วย เพราะในด้านนั้น ความสอดคล้อง ตั้งแต่ context ระดับบนสุดไปจนถึงโค้ดคือหัวใจสำคัญ
ความเรียบง่ายของโมเดล C4 เป็นเหมือนกลไกบังคับอย่างหนึ่ง ถ้ามี context หรือ component ที่ซ่อนอยู่ ก็ควรต้องปรากฏในโมเดล หากแม้แต่สิ่งที่เรียบง่ายแบบนี้ยังมีแรงต้าน ก็ถือเป็นสัญญาณว่าอาจมีองค์ประกอบที่ซ่อนอยู่ ในโปรเจกต์ขนาดใหญ่โดยทั่วไปก็มีองค์ประกอบแบบนั้นจริง ๆ การทำให้ผู้คนคิดให้ชัดเจนด้วยวิธีนี้ จะทำให้พวกเขาต้อง commit กับถ้อยแถลงและไอเดีย แทนที่จะเพียงแค่สงวนสิทธิ์ในการเสนอและวิจารณ์ไว้ ทำให้อำนาจกระจายออกไป ซึ่งอาจก่อให้เกิดแรงต้านได้มากเช่นกัน อย่างไรก็ตาม นี่ไม่ใช่ปัญหาของโมเดล แต่เป็นสิ่งที่เกิดขึ้นเมื่อโมเดลไปพบกับผู้คน ผมชอบความสอดคล้องของมัน จึงน่าจะใช้แนวทางแบบนี้เป็นข้อมูลอ้างอิงสำหรับการออกแบบความปลอดภัย
C4 น่าสนใจมาก และผมคิดว่ามันจัดการกับปัญหาเฉพาะบางอย่างของสถาปัตยกรรมซอฟต์แวร์ได้ดี
มันทำให้ชั้นล่างของสถาปัตยกรรม ซึ่งส่วนใหญ่คือฮาร์ดแวร์และซอฟต์แวร์ระบบ ถูกมองเป็น abstraction กว้าง ๆ แล้วให้ไปโฟกัสความพยายามกับสิ่งที่อยู่สูงขึ้นไปในสแต็ก แนวคิดนี้เข้ากับแนวทางแบบ cloud-based, containerized และ scalable ในปัจจุบันได้ดีอย่างน่าประหลาด ในเรื่องที่เกี่ยวข้องกัน ArchiMate ก็ดีเช่นกันและมีส่วนที่ทับซ้อนกันมาก แต่ยืนอยู่บนฝั่งโครงสร้างพื้นฐานอย่างมั่นคงกว่า ในอดีตเคยใช้แนวทางไดอะแกรมที่คล้ายกับ ArchiMate เพื่อลดความขัดแย้งระหว่างระบบกับแหล่งข้อมูล และได้ผลดีมากในการแสดงให้เห็นว่าสิ่งที่เราซื้อมาเชื่อมต่อรองรับธุรกิจเฉพาะและข้อกำหนดของ workflow ผู้ใช้อย่างไร ที่ว่าของพวกนี้มักไม่ตรงกับ codebase นั้นถูกต้องทั้งหมด แต่เมื่อจำเป็นต้องวิเคราะห์ระบบที่ซับซ้อน หรือสื่อสารระบบและแผนงานให้กลุ่มคนขนาดใหญ่ขึ้นรับรู้ มันก็เป็นเครื่องมือที่ยอดเยี่ยมได้ มีหลายกรณีอย่างน่าประหลาดที่แทบไม่มีเอกสารที่เป็นหนึ่งเดียวเลย และเพียงแค่นั่งวาดกล่องกับเส้นเชื่อมต่อกันสักไม่กี่สัปดาห์ ก็สามารถคลี่คลายและทำให้งานที่ติดขัดจนเดินหน้าไม่ได้เรียบง่ายขึ้นได้ โดยเฉพาะเมื่อมีหลายทีมทำงานในพื้นที่เดียวกัน C4, ArchiMate, UML ฯลฯ เป็นเพียงภาษาสำหรับวาดไดอะแกรมที่มีข้อจำกัด เพื่อจับประเด็นเฉพาะที่ต้องการสื่อสาร วิเคราะห์ และบันทึกไว้เท่านั้น ผมไม่คิดว่ามันเหมาะมากนักในฐานะเครื่องมือสำหรับการวางแผนล่วงหน้าหรือการออกแบบ หลายคนเคยลำบากมากในยุคกระแส UML ขนาดใหญ่ ตอนนั้นเหมือนกับว่าองค์กรสถาปนิกหลักต้องปูรายละเอียดทุกแง่มุมของระบบอย่างเจ็บปวดไปจนถึงการนิยามคลาส ก่อนจะเขียนโค้ดแม้แต่บรรทัดเดียว และความบ้าคลั่งทำนอง “แค่ generate โค้ดจากไดอะแกรมก็พอ” ก็ทำให้ผู้คนจำนวนมากต้องทุกข์ทรมาน พอเริ่มเขียนโค้ดจริง แผนงานหลายพันชั่วโมงนั้นก็มักถูกละเลย และสุดท้ายนักพัฒนาก็ทำตามที่ตัวเองอยากทำ