2 điểm bởi GN⁺ 2023-10-23 | 1 bình luận | Chia sẻ qua WhatsApp
  • Mô hình C4 là một cách tiếp cận thân thiện với lập trình viên để tạo sơ đồ kiến trúc phần mềm, giúp quan sát cấu trúc phức tạp theo từng bước
  • Mức độ trừu tượng được hạ dần theo thứ tự software systems → containers → components → code, xử lý kiến trúc theo dạng phân cấp
  • Các sơ đồ cũng được tổ chức theo cấu trúc system context → container → component → code
  • Khi cần, có thể bổ sung các sơ đồ system landscape, dynamic, deployment để hoàn thiện góc nhìn về toàn bộ cấu trúc cũng như khía cạnh thực thi và triển khai
  • Đây là cách tiếp cận notation independenttooling independent, không bị ràng buộc vào một ký pháp hay công cụ cụ thể, nên có thể áp dụng phù hợp với môi trường sẵn có

Cấu thành của mô hình C4

  • Mô hình C4 là một mô hình để trực quan hóa kiến trúc phần mềm, do Simon Brown tạo ra
  • Điểm cốt lõi là sử dụng đồng thời trừu tượng phân cấpsơ đồ phân cấp

Sơ đồ và tính độc lập

  • Các sơ đồ cơ bản được cấu thành để có thể xem kiến trúc ở những độ sâu khác nhau
  • Các sơ đồ bổ trợ giúp bù đắp những góc nhìn mà chỉ các tầng cơ bản thôi là chưa đủ
  • Mô hình này notation independenttooling independent, nên không ép buộc phải chọn một ký pháp hay công cụ cụ thể
  • Tài liệu liên quan gồm video Visualising software architecture with the C4 model được ghi hình tại “Agile on the Beach 2019” vào tháng 7/2019 và tài liệu The C4 model

1 bình luận

 
GN⁺ 2023-10-23
Ý kiến Hacker News
  • Tôi cho rằng vấn đề lớn nhất của sơ đồ kiến trúc là nó bị lệch khỏi codebase
    Những sơ đồ như vậy cần được tạo tự động. Nếu không, đội ngũ sẽ không có cách nào biết liệu hình họ đang xem có phản ánh chính xác trạng thái mới nhất của hệ thống hay không

    • Sơ đồ cũng giống tài liệu văn bản, nên nhìn chung rất khó tự động tạo ra thứ gì hữu ích từ mã, trừ khi trong mã có thêm markup để chỉ định cần tạo cái gì
      Sơ đồ thể hiện một góc nhìn cụ thể, nhấn mạnh một số đặc điểm và lược bỏ những đặc điểm khác. Với cùng một đối tượng, có thể có nhiều sơ đồ khác nhau để giải thích các khía cạnh hay kịch bản khác nhau. Cuối cùng, cũng như tài liệu văn bản, sơ đồ phải được bảo trì cùng với mã và kiến trúc ứng dụng, và không còn cách nào khác ngoài việc biến đó thành công việc thường xuyên trong quản lý thay đổi
    • Cách này không hiệu quả vì khoảng cách giữa mã và mô hình
      Trong nhiều dự án, mã không được tổ chức theo cùng cách với mô hình tinh thần trong đầu, và hầu như mọi ngôn ngữ đều không cung cấp cách giải quyết việc này. Việc đánh dấu trong mã bằng chú thích cũng gặp cùng vấn đề như việc giữ sơ đồ, chú thích và tài liệu luôn cập nhật
    • Những sơ đồ đủ tầm thường để có thể tự động tạo từ codebase thường không bổ sung nhiều giá trị
    • Sơ đồ kiến trúc là để ghi lại phần mềm nên được tổ chức như thế nào
      Nó thể hiện trạng thái mục tiêu, chứ không phải trạng thái hiện tại. Mã nên đi theo sơ đồ, chứ không phải ngược lại. Trường hợp việc tạo sơ đồ từ mã có ý nghĩa là để giúp người mới tham gia vào một dự án không có tài liệu, và ngay cả khi đó cũng là kiểu tạo một lần rồi loại bỏ nhiễu, tinh chỉnh lại và sau đó dùng như tài liệu chuẩn
    • Tôi còn cho rằng tài liệu tự động làm mất đi khả năng tư duy ở mức trừu tượng cao hơn của nhóm
      Sơ đồ cấp cao phải có thể được tạo nhanh rồi bỏ đi, và điều bị lược bỏ cũng quan trọng không kém điều được thể hiện
  • Tôi thích C4. Trước đây tôi từng nghĩ các sơ đồ ngữ cảnh kiểu “User -{do their job}-> System-of-Record” là vô dụng, nhưng giờ thì tôi hiểu tại sao
    Tôi đang dùng C4 để triển khai thiết kế mới cho một hệ thống phức tạp cùng với các nhóm mở rộng. Lần này khi vẽ bức tranh cấp cao nhất, tôi nhận ra rằng ngoài web UI còn có một ứng dụng di động có thể bị ngắt kết nối một phần, nên khi offline hoặc backend chậm, nếu một số kết quả vẫn chưa có thì cần để một phần hành vi suy giảm một cách mềm mại. Ở lớp tiếp theo, điều này dẫn đến hàng đợi công việc, rồi lại dẫn đến UX, nhờ đó có thể nói rõ loại yêu cầu nào có thể mất thời gian không xác định để hoàn thành. Có lẽ sớm muộn gì tôi cũng sẽ đi đến đó, nhưng việc phân tích đã đưa vấn đề này ra ngay trước mắt. Tất cả là vì tôi buộc phải vẽ một hình “Remote-User --{Mobile Stuff}--> Backend”. Dùng công cụ gì cũng được, chẳng hạn tôi dùng draw.io và chia tab theo từng tầng. Khi cụ thể hơn, tôi dự định tách các tầng thấp hơn ra thành file riêng

  • Tôi hiểu lập luận rằng sơ đồ không cần một hệ thống quá hình thức, nhưng theo tôi C4 vẫn khá gọn nhẹ. Tôi không đi xuống đến mức mã nguồn
    Dù vậy, structurizr để xuất sơ đồ C4 đã giúp tăng năng suất rất nhiều. Cách tạo nhiều góc nhìn với các mức độ chi tiết khác nhau từ một mô hình duy nhất thật tuyệt vời so với mermaid hay plantuml, nơi mỗi sơ đồ lại phải tiếp tục định nghĩa và định nghĩa lại cùng các thành phần một cách độc lập. Quy trình tách branch, sửa mô hình rồi trình bày ý tưởng rất hợp với tôi

    • Tôi đã thử structurizr một chút nhưng thấy nó quá thiếu linh hoạt
      Không có cách nào để vẽ những khái niệm không hoàn toàn thuộc C4. Ví dụ, tôi muốn đặt hai component vào trong một hộp để thể hiện thực tế rằng hiện tại chúng được triển khai như một service duy nhất, nhưng lại không làm được. Không có nghĩa đó là thiết kế tuyệt đối tốt, nhưng có lẽ nó vẫn sẽ giúp đội ngũ hiểu hơn. Ý tưởng mô tả kiến trúc một cách hình thức thì hay, nhưng sự thiếu tùy biến trong đầu ra sơ đồ quá khó chịu
    • Tôi ủng hộ structurizr. Nhờ cách tiếp cận hướng mô hình, việc giữ sơ đồ nhất quán với mã trở nên dễ dàng hơn nhiều
      Bạn mô tả kiến trúc và structurizr sẽ render sơ đồ
    • Mermaid rõ ràng không phù hợp lắm với lượng văn bản và định dạng văn bản mà C4 yêu cầu
      Vẫn làm được, nhưng khá phiền, và nếu phần mô tả mũi tên giữa các hộp dài ra thì bố cục tự động sẽ nhanh chóng bị vỡ
  • Tôi có xu hướng xem kiến trúc phần mềm là tập hợp các quyết định thiết kế dẫn dắt việc triển khai
    Theo kinh nghiệm của tôi, đa số kiến trúc sư phần mềm đưa ra định hướng và cấu trúc cho kỹ sư phần mềm. Nhưng cách C4 mô tả là “tạo một bản đồ của mã hiện có ở nhiều mức độ chi tiết” lại nghe khác hẳn. Tôi không hiểu vì sao sơ đồ mã lại được gọi là kiến trúc phần mềm. Xét cho cùng đó là mức mã nguồn, sao lại là kiến trúc được? Giống như đòi đưa sơ đồ mạch của ổ cắm vào bản thiết kế ngôi nhà vậy. Nếu nói “nên dùng công cụ tự động hóa”, thì có phải là muốn tài liệu hóa codebase hiện có tới cấp độ hàm không? Tôi không hiểu điều đó hữu ích thế nào cho việc thiết kế và lập kế hoạch phần mềm. Một bản đồ mô tả cấu trúc phần mềm hiện có có thể trông rất hay, nhưng khi nói về design pattern thì đâu ai đưa ra bản đồ theo từng hàm cho một triển khai Singleton. Chỉ cần nói là cần Singleton hay Repository pattern là đủ. Bản thân thiết kế phần mềm rõ ràng là có thật và cách này cũng có vẻ hợp lý với thiết kế, nhưng theo kinh nghiệm của tôi thì thiết kế phần mềm, triển khai và kiến trúc không phải là một, và cũng không phải do cùng một nhóm người làm. Cái này trông gần với thiết kế hệ thống hơn, còn kiến trúc sư phần mềm có lẽ đóng vai trò tư vấn để thiết kế hệ thống đó phù hợp với các nguyên tắc kiến trúc tốt. Có thể tôi đang soi quá kỹ

    • Tôi đồng ý với ý “kiến trúc phần mềm là tập hợp các quyết định thiết kế dẫn dắt việc triển khai”
      Tôi cho rằng một vai trò thiết yếu của kiến trúc phần mềm là cung cấp thông tin để lập trình viên có thể tự đưa ra quyết định thiết kế thay vì lúc nào cũng phải đẩy việc phán đoán lên cho một người có thẩm quyền. Tuy vậy, ranh giới nơi kiến trúc kết thúc và phát triển bắt đầu thì rất khác nhau. Tôi nghĩ chính kiến trúc quyết định điều gì là quan trọng dưới góc nhìn kiến trúc. Nếu kiến trúc cho rằng một chi tiết ứng dụng cấp thấp nào đó là quan trọng, thì nó cũng trở thành một chi tiết kiến trúc. Trên thực tế, ở đa số tổ chức, kiến trúc ít nhất kiểm soát thiết kế cấp cao như component, communication pattern, API, và công nghệ sử dụng. Ở một số tổ chức, nó còn đi xuống tới từng class riêng lẻ. Không phải mọi class, mà là các class mô hình hóa problem domain, đặc biệt khi mô hình đó được dùng làm ngôn ngữ chung cho nhiều dự án hoặc được triển khai thành artifact dùng chung. C4 phù hợp với những tổ chức xem cả cấu trúc cấp thấp hơn, vượt ra ngoài danh sách ứng dụng và giao diện tích hợp, cũng là mối quan tâm kiến trúc
    • Nếu ví C4 với ngôi nhà, thì đó sẽ là bản thiết kế cấp cao của ngôi nhà cho người bình thường, bản thiết kế chi tiết cho nhà thầu thi công, sơ đồ cho các hệ thống hạ tầng như điện, và tùy chọn là đặc tả chi tiết của mọi ổ cắm và thiết bị cố định
      Về cơ bản, ý tưởng là có một sơ đồ cho mỗi mức độ riêng biệt hoặc hữu ích trong hệ thống. Nếu bạn cần sơ đồ cấp độ mã, thì rất có thể bạn đang làm một công việc tùy biến phức tạp, hoặc đang đặc tả quá mức một thiết kế lẽ ra nên để lại cho chi tiết triển khai
    • Tôi phần nào đồng ý rằng nên vạch ranh giới giữa kiến trúc phần mềm, thiết kế và triển khai
      Nó giống như trong xây dựng ngoài đời thật, nơi vai trò của kiến trúc sư, kỹ sư và người phụ trách công trường là khác nhau. Tôi muốn biết nên kẻ ranh giới ở đâu trong kiến trúc, thiết kế và triển khai, và mỗi phần nên xử lý những mối quan tâm nào
    • Tôi thắc mắc ý ở đây là “kiến trúc phần mềm tương đương với tập hợp các quyết định thiết kế”, hay là “kiến trúc phần mềm chính là tập hợp các quyết định thiết kế”
  • Khá thú vị, nhưng khó nói là nó bổ sung được điều gì đặc biệt
    Sơ đồ cấp cao thì tốt, nhưng bạn đã có thể tạo chúng từ lâu mà không cần đọc một website mô hình trực quan hào nhoáng. Bản thân website đó thực ra cũng gần như thừa nhận điều này. Nhận xét rằng ngành đã có UML, ArchiMate, SysML, nhưng nhiều đội lại chọn các sơ đồ “box và line” đơn giản hơn nhiều, là rất đúng. Nhưng dường như họ phớt lờ câu hỏi vì sao UML class diagram lại thất bại hoàn toàn. Dù có thừa nhận là chẳng ai thích nó, chữ C thứ tư của mô hình là code thì rốt cuộc vẫn chính là UML class diagram. Không cần những thứ đó. Chỉ cần vẽ các sơ đồ tùy ý một cách rõ ràng và gắn nhãn cho các mũi tên là được. Ba sơ đồ đầu tiên thực ra lại là ví dụ tốt cho điều đó

    • Tôi cũng làm vậy. Vẽ các hộp và các đường nối giữa chúng
      Nó cũng cực kỳ hữu ích khi nghĩ ra khái niệm mới hoặc brainstorming, vì công cụ không cản trở mình. Hiện tôi dùng Freeform; nó rất đơn giản nhưng hoạt động tốt. Chỉ cần chọn hai đối tượng rồi cmd-click hoặc nhấp phải và bấm “add connecting line”
    • Giấc mơ sinh code từ sơ đồ đã thất bại, nhưng UML vẫn được dùng nhiều ở vị trí điều phối kiến trúc
      Mới chỉ vài tháng trước thôi, tôi còn vừa hoàn thành thêm một tài liệu kiến trúc có đủ class diagram, sequence diagram và use case
    • Trong môi trường doanh nghiệp, cách này thực sự không vận hành tốt
      Các box rất dễ trở thành một mớ trộn lẫn những thứ ở các cấp độ khác nhau. Có cái thì trừu tượng, có cái thì cụ thể, có cái thì chỉ mang tính tùy tiện. Vì vậy, khi cần ghép các mảnh kiến trúc lớn hơn, chẳng hạn như chuỗi cung ứng, thì gần như phải làm lại từ đầu. Rất lãng phí, và cũng không có ai nhìn thấy toàn bộ kiến trúc đủ rõ để tránh những lãng phí khác cùng các vấn đề chất lượng. Kỳ lạ là nhiều kỹ sư lại phản ứng phòng thủ với cách tiếp cận hình thức hơn; tôi nghĩ có lẽ vì không thấy lợi ích ngay lập tức hoặc chưa từng xử lý kiến trúc ở quy mô lớn nên không nhìn ra vấn đề
    • Nếu muốn nhiều người cùng có nhiều cuộc trao đổi về kiến trúc và cũng muốn rút ra insight từ sơ đồ, thì các quy ước kiến trúc có cấu trúc sẽ trở nên quan trọng hơn
  • Điều này cho thấy kỹ nghệ phần mềm vẫn còn là một lĩnh vực chưa trưởng thành
    Với tôi, đã hơn 25 năm trôi qua mà chúng ta vẫn còn bàn đi bàn lại những thứ gần như “cơ bản” như thế này. Điều đó không có nghĩa là xấu, nhưng tiến bộ thì chậm, và cũng không thể chỉ đổ cho một công ty cụ thể, một consortium nào đó, hay các lợi ích thương mại

    • Nói thật thì ngoài kỹ thuật cũng có vấn đề tương tự. Xét cho cùng, C4 là một cách để tập trung cuộc trò chuyện vào một mức độ trừu tượng nhất định
      Đã bao nhiêu lần bạn gặp ai đó cứ liên tục nhảy qua lại trong cùng một mạch suy nghĩ giữa mức chi tiết cao, độ phức tạp cao và sự đơn giản khi nhìn từ xa, khiến rất khó hiểu họ đang cố nói gì? Vấn đề tương tự cũng xảy ra khi một lập trình viên nghĩ rằng “cứ vẽ đại vài box với mũi tên lên bảng này là được, trong đầu tôi nó có nghĩa nên thế là sơ đồ tốt rồi”
  • Ngay cả khi không phải kỹ sư xây dựng dân dụng, người ta vẫn có thể hiểu ngay mặt bằng hay bản vẽ tương tự và thấy nó hữu ích
    Nhưng dù là kỹ sư phần mềm chuyên nghiệp, tôi vẫn thấy các sơ đồ ví dụ này không đủ hữu ích hoặc đủ thông tin để xứng đáng với công sức bỏ ra. Mã nguồn quá đa chiều, nên khó xấp xỉ bằng hình vẽ 2 chiều, và cách đó không hoạt động tốt. Hướng có tiềm năng hơn có lẽ là các pattern mã kiến trúc được quy ước hóa hơn. Chẳng hạn như structured concurrency, và có thể là thứ gì đó ở mức còn cao hơn nữa

    • Vì sơ đồ kiến trúc phần mềm hoặc là cần rất nhiều ngữ cảnh, hoặc phải nằm trong một ngữ cảnh cụ thể và phạm vi khá hẹp
      Mặt bằng xây dựng có ngữ cảnh rất cố định và phạm vi hạn chế. Ví dụ, bạn không cần phải giải thích cửa sổ là gì. Nhưng trong phần mềm thì phần lớn thời gian bạn thực sự phải giải thích “cửa sổ” là gì. Mọi “cửa sổ” hay mọi thành phần đều khác nhau, nên không thể chỉ nói đây là cửa sổ rồi copy nó 20 lần được
  • Nếu bạn thấy mô hình C4 quá tùy ý và bị đặc tả quá mức, thì đầu năm nay tôi đã viết về một cách thực hành thay thế: https://www.ilograph.com/blog/posts/concrete-diagramming-mod...

  • Tôi thích mô hình này, và cũng đã có lúc phải dùng UML trong kiến trúc bảo mật. Ở mảng đó, tính nhất quán từ ngữ cảnh cấp cao nhất xuống tới mã là điều cốt lõi.
    Sự đơn giản của mô hình C4 là một dạng cơ chế cưỡng chế. Nếu có ngữ cảnh hay thành phần ẩn, chúng phải lộ ra trong mô hình. Nếu ngay cả sự đơn giản như vậy cũng gặp phản kháng, thì tôi xem đó là dấu hiệu có yếu tố ẩn. Trong các dự án lớn, thực tế thường là có những yếu tố như thế. Khi buộc mọi người làm rõ tư duy theo cách này, họ sẽ phải cam kết với phát biểu và ý tưởng của mình, thay vì chỉ giữ quyền đề xuất rồi phê phán, nhờ đó quyền lực được phân tán hơn. Điều này cũng có thể tạo ra khá nhiều phản ứng chống đối. Tuy vậy, đó không phải vấn đề của mô hình, mà là chuyện xảy ra khi mô hình gặp con người. Tôi thích tính nhất quán này, nên có lẽ sẽ dùng cách này làm tài liệu tham khảo cho thiết kế bảo mật.

  • C4 rất thú vị và theo tôi xử lý rất tốt một vấn đề cụ thể của kiến trúc phần mềm.
    Nó đẩy các lớp thấp của kiến trúc, tức chủ yếu là phần cứng và phần mềm hệ thống, vào một mức trừu tượng rộng hơn, và cho phép tập trung công sức vào những thứ nằm ở các tầng phía trên của stack. Nó phù hợp đáng ngạc nhiên với cách tiếp cận hiện đại dựa trên cloud, container hóa và khả năng mở rộng. Liên quan tới đó, ArchiMate cũng tốt và có nhiều phần chồng lấn, nhưng bám chắc hơn về phía hạ tầng. Trước đây tôi đã dùng một cách tiếp cận sơ đồ gần giống ArchiMate để giảm xung đột giữa các hệ thống và nguồn dữ liệu, đồng thời cho thấy những thứ chúng tôi mua về rồi ghép vào hỗ trợ các yêu cầu workflow cụ thể của doanh nghiệp và người dùng như thế nào. Nhận xét rằng những thứ này dễ lệch khỏi codebase là hoàn toàn đúng. Nhưng khi cần phân tích các hệ thống phức tạp hoặc truyền đạt hệ thống và kế hoạch cho một nhóm lớn hơn, chúng có thể là công cụ tuyệt vời. Có nhiều trường hợp đáng ngạc nhiên là hoàn toàn không có tài liệu mạch lạc nào, và chỉ cần ngồi vài tuần để vẽ hộp và đường nối cũng có thể gỡ rối, đơn giản hóa những công việc bế tắc vốn không tiến lên được. Điều này đặc biệt đúng khi nhiều team cùng làm trong một khu vực. C4, ArchiMate, UML và các mô hình tương tự chỉ là những ngôn ngữ sơ đồ có ràng buộc để nắm bắt nội dung cụ thể mà bạn muốn truyền đạt, phân tích hoặc ghi chép. Tôi không nghĩ chúng đặc biệt phù hợp như công cụ lập kế hoạch hay thiết kế từ trước. Rất nhiều người đã khổ sở trong thời kỳ UML bùng nổ. Khi đó người ta cho rằng các tổ chức kiến trúc sư trưởng phải mô tả mọi khía cạnh của hệ thống một cách đau đớn tới mức chi tiết, xuống cả định nghĩa class, trước khi viết lấy một dòng code, và kiểu điên rồ như “chỉ cần sinh code từ sơ đồ” đã hành hạ không ít người. Khi việc lập trình thực sự bắt đầu, hàng nghìn giờ lập kế hoạch đó thường bị bỏ qua, và các developer cuối cùng vẫn làm theo cách họ muốn.