Series:
Bài 1: Giới thiệu hệ thống demo và quy trình phát triển.
Bài 2: EventStorming: Lý thuyết
Bài 3: EventStorming: Áp dụng Big Picture (1)
Bài 4: EventStorming: Áp dụng Big Picture (2)
Bài 5: Thiết kế kiến trúc (1) - Decisions
Bài 6: Bài này.
--------------
Góc nhìn hệ thống: Tĩnh, Động, và Triển khai
Khi nói về sơ đồ thiết kế hệ thống nơi thể hiện các service, database, messaging và sự kết nối giữa chúng, có thể bạn thường thấy dạng "box and line". Đây là một sự không chính thống vì ta dùng nó để thể hiện hệ thống cả mức tĩnh và động. Để làm rõ hơn, ta đi qua sơ lược một số lý thuyết. Ở đây, tôi sẽ sử dụng "Tiêu chuẩn về tài liệu kiến trúc hệ thống ISO/IEC/IEEE 42010" để mô tả.
ISO/IEC/IEEE 42010
ISO/IEC/IEEE 42010 là một tiêu chuẩn quốc tế cung cấp các nguyên tắc và yêu cầu để mô tả kiến trúc của các hệ thống phần mềm và phần cứng. Đây là một tiêu chuẩn quan trọng trong lĩnh vực kỹ thuật hệ thống và kỹ thuật phần mềm, giúp các tổ chức và chuyên gia phát triển, tài liệu hóa và truyền đạt kiến trúc của các hệ thống một cách hiệu quả và nhất quán.
Tiêu chuẩn này nhấn mạnh vào các yếu tố kiến trúc (architectural elements) - là các thành phần cơ bản mà từ đó hệ thống được xây dựng. Từ trước tới giờ, ta dùng khá "bừa bãi" các từ như "module", "thành phần", chúng chính là một dạng yếu tố kiến trúc nhưng nghiêng về cấp độ lập trình nhiều hơn. Yếu tố kiến trúc rộng hơn thế, đó có thể là:
- Một bộ trách nhiệm được xác định rõ ràng
- Một ranh giới được xác định rõ ràng
- Một tập hợp giao diện (interface) được xác định rõ ràng, định nghĩa các dịch vụ mà yếu tố cung cấp cho các yếu tố kiến trúc khác.
Hệ thống phần mềm không chỉ được sử dụng: Chúng phải được xây dựng và kiểm thử, phải được vận hành, có thể phải được sửa chữa, thường xuyên được nâng cấp, và tất nhiên, chúng phải được trả tiền. Do đó, nó không chỉ tạo sự ảnh hưởng tới người dùng, mà còn ảnh hưởng tới nhiều đối tượng người dùng khác, ta gọi là stakeholders - bên liên quan.
Mỗi bên liên quan lại có những mối quan tâm - concern khác nhau về hệ thống. Một concern về kiến trúc là một yêu cầu, một mục tiêu, một ràng buộc, một dự định, hoặc một khát vọng mà một bên liên quan có đối với kiến trúc đó. Nhiều concern sẽ là chung giữa các bên liên quan, nhưng một số concern sẽ là đặc thù và thậm chí có thể mâu thuẫn. Việc giải quyết các mâu thuẫn như vậy sao cho các bên liên quan hài lòng có thể là một thử thách lớn.
Và do đó, ta có quy tắc:
Kiến trúc được tạo ra hoàn toàn để đáp ứng nhu cầu của các bên liên quan.
Và cũng vì vậy, nếu một hệ thống không đáp ứng đầy đủ nhu cầu của các bên liên quan, thì không thể coi đó là một thành công — bất kể nó có tuân thủ tốt các thực hành kiến trúc tốt đến đâu. Nói cách khác, các kiến trúc phải được đánh giá không chỉ dựa trên các nguyên lý kiến trúc trừu tượng và kỹ thuật phần mềm, mà còn phải xem xét đến nhu cầu của các bên liên quan.
Phân loại sơ đồ kiến trúc
Sơ đồ kiến trúc về tổng quan có thể chia thành ba nhóm: Module views, C&C views, và Allocation views.
Module views:
Module views đề cập tới một tập các tài liệu mô tả cấu trúc module của một hệ thống phần mềm. Trong đó, liệt kê các đơn vị thực thi chính, hay các module, của một hệ thống cùng với các mối quan hệ giữa chúng.
Trong nhóm tài liệu module thì module chính là những phần tử chính. Một module là một đơn vị thực thi cung cấp một tập hợp các nhiệm vụ có quan hệ mật thiết với nhau. Một module có thể có dạng một class, một tập hợp class, một layer, một aspect, hoặc bất kỳ một dạng phân rã nào của đơn vị thực thi. Mọi module đều có một danh sách thuộc tính. Các thuộc tính này có mục đích diễn đạt các thông tin quan trọng cũng như những ràng buộc của module đó. Ví dụ như trách nhiệm, thông tin hiện hữu, và tác giả cũng như người sở hữu. Các mối quan hệ mà module có với các module khác bao gồm is part of, depends on, và is a.
Một số module views:
- Decomposition views (nhóm sơ đồ phân rã): Nhóm sơ đồ này thể hiện mối quan hệ giữa các phần tử ở dạng is-part-of, qua đó biểu diễn sự tổ chức về mặt source code dưới dạng các module và sub-module cùng trách nhiệm của chúng.
- Uses views (nhóm sơ đồ sử dụng): Uses thể hiện mối quan hệ sử dụng, trong đó, ta hay dùng nhất là quan hệ phụ thuộc depends-on. Một module uses module khác nếu sự chính xác của nó phụ thuộc vào sự chính xác của thành phần kia.
- Generalization views (nhóm sơ đồ tổng quát hóa): Thể hiện mối quan hệ is-a giữa các phần tử. Dạng sơ đồ này hữu dụng khi ta muốn thể hiện khả năng mở rộng, tiến hóa của kiến trúc.
- Data model: Khi áp dụng DDD, đây có thể coi là Domain Model của hệ thống. Cần chú ý mức độ chi tiết của thông tin theo từng level.
- ...
Thông thường, ta có thể kết hợp nhiều nhóm sơ đồ vào cùng một sơ đồ để thể hiện đồng thời nhiều khía cạnh nhưng không nên ôm đồm quá nhiều khiến sơ đồ trở nên rối. Ví dụ, Decomposition, Uses, và Generalization rất dễ đi cùng với nhau.
Component-and-connector (C&C) views
C&C view trình bày các phần tử có hiện thân tại môi trường chạy, ví dụ như các processes, objects, clients, servers, và data stores. Những phần tử này được gọi là những components-thành phần. Ngoài ra, C&C view còn chứa đựng các phần tử thể hiện sự tương tác, như các communication links và protocols – kết nối và giao thức kết nối, luồng dữ liệu, và các truy cập vào tầng lưu trữ.
C&C thường được sử dụng để developers cũng như những stakeholders khác biết được cách mà hệ thống hoạt động.
Một số C&C views:
- Data Flow views: Dạng sơ đồ này cho thấy một mô hình tính toán của hệ thống mà trong đó các component đóng vai trò là các bộ biến đổi dữ liệu và các connector là các đường vận chuyển dữ liệu từ output của component này tới input của các component khác.
- Call-Return views: Call-Return thể hiện mô hình tính toán mà các component cung cấp một tập dịch vụ mà có thể được sử dụng bởi các component khác. Dạng thường gặp nhất là Client-Server, Peer-to-Peer.
- Repository views: Dạng sơ đồ này biểu diễn các thành phần mà được gọi là các repository, được dùng để chứa dữ liệu lâu dài. Các component khác đọc và ghi dữ liệu vào chúng. Thường gặp nhất là các DBMS như MySQL, PostgreSQL.
- ...
Allocation views
Allocation views thể hiện sự ánh xạ giữa các phần tử phần mềm (trong Module views hoặc C&C views) vào các phần tử phi phần mềm trong môi trường của phần mềm.
Nói một cách đơn giản hơn, allocation views cho chúng ta thấy phần mềm của chúng ta được "đặt" hay "phân bổ" như thế nào trên các thành phần không phải phần mềm mà nó tương tác. Những thành phần phi phần mềm này có thể bao gồm:
- Deployment views: thể hiện sự ánh xạ giữa các phần tử trong C&C và phần cứng thực thi chúng: Ví dụ như các máy chủ, bộ xử lý, mạng, v.v.
- Install views: mô tả cách phần mềm được sắp xếp trong file system của môi trường production.
- Work assignment views: thể hiện sự phân công công việc giữa các module phần mềm và những người hoặc nhóm chịu trách nhiệm phát triển chúng.
Mục đích chính của allocation views là giúp chúng ta lý giải về hệ thống bằng cách hiển thị các mối quan hệ giữa phần mềm và các yếu tố môi trường của nó, từ đó hỗ trợ việc phân tích hiệu suất, quản lý hệ thống trong sản xuất và các hoạt động quản lý dự án.
Quay lại demo
Như vậy, chúng ta có rất nhiều sơ đồ khác nhau để thể hiện hầu hết khía cạnh của hệ thống. Qua đúc rút kinh nghiệm, tôi thấy rằng những tập sơ đồ sau mang lại nhiều giá trị cho những dự án phát triển với tốc độ nhanh:
- Module views: Thể hiện cấu trúc ứng dụng với các cấp chi tiết khác nhau, Level 0 là mức tổng quát nhất. Thông thường, với tài liệu kiến trúc thì "Level 2 (Whitebox)" là mức giới hạn chấp nhận được.
- C&C views: Dạng view này có thể kết hợp các sơ đồ khác nhau tùy theo dự án. Với những dự án có luồng xử lý phức tạp, ta có thể sử dụng Sequence diagram. Thông thường, nên có một bức tranh C&C giống "box-and-line" để thể hiện bức tranh chung.
- Deployment views: Tài liệu thể hiện cài đặt triển khai ứng dụng là rất quan trọng, đặc biệt với những hệ thống phức tạp hoặc công nghệ mới. Đây là nguồn hữu ích cho developers, security, infrastructure tham khảo sau này.
Do đó, trong bài demo này, tôi sẽ thể hiện các sơ đồ thuộc ba nhóm trên.
Module views
Level 0 (blackbox)

Sơ đồ này là một system context, nơi định nghĩa ranh giới giữa hệ thống hoặc một phần của hệ thống với môi trường mà nó thuộc về, trong đó thể hiện các thực thể tương tác với nó.
Level 0: là cấp độ nhìn hệ thống ở mức cao nhất, khi đó, toàn bộ hệ thống mà ta muốn thiết kế sẽ tụ về một khối thống nhất.
Blackbox: là thông tin cho thấy đối tượng thể hiện không cho biết cấu trúc bên trong. Ngược lại với blackbox là whitebox. Nếu ta để “level 0 (whitebox)” thì lúc này, bên trong khối hình chữ nhật “E-Commerce System” sẽ xuất hiện một số cấu trúc ở mức level 1 (mức chi tiết hơn, ngay sau cấp level 0).
System context diagram thể hiện sự tập trung vào các thực thể và các sự kiện bên ngoài cần được xem xét trong quá trình phát triển một tập đầy đủ các yêu cầu và ràng buộc của hệ thống. Loại sơ đồ này được sử dụng trong giai đoạn sớm của dự án để đạt được thỏa thuận về phạm vi phát triển hệ thống.
Như vậy, hệ thống mà ta phát triển sẽ tiếp nhận hai thực thể Merchant và Customer với các tương tác về quản lý sản phẩm, tồn kho (merchant) và mua hàng (customer). Đây là những tương tác chính, những hành vi khác có thể (và chắc chắn) tồn tại nhưng không nên được thể hiện trong này vì sẽ làm rối mô hình. Tư tưởng của các thông tin trong tài liệu kiến trúc là luôn giữ ở mức quan trọng, ảnh hưởng tới cách phát triển, hoạt động của hệ thống. Merchant và customer bên trái đóng vai trò chủ động (active) trong mối quan hệ với hệ thống.
Hệ thống cũng có những giao tiếp chủ động ra bên ngoài, như trên hình là Banking System, Customer, và Merchant. Lúc này, các actor có vai trò thụ động (passive) tiếp nhận tương tác. Trong sơ đồ trên, Customer và Merchant có thể được lược bỏ vì các thông báo này được đánh giá là không quan trọng, nhưng giao tiếp với Banking System là quan trọng.
Những stakeholder nào nên quan tâm tới sơ đồ này? Có lẽ là phần lớn trong dự án.
- Người thụ hưởng (nhà tài trợ) và user: Rõ ràng 2 đối tượng này quan tâm tới phạm vi yêu cầu hệ thống. Họ cần biết những chức năng nào hệ thống sẽ cung cấp và những chức năng nào không.
- Nhà phát triển: Cần biết hệ thống sẽ bao gồm những gì và đặc biệt là những hệ thống ngoại vi hay những tổ chức nào mà hệ thống này phải tương tác.
- Nhân viên vận hành: Cần biết được những hệ thống bên ngoài mà hệ thống này tương tác để có thể lên kế hoạch xử lý hoặc các công cụ cần thiết để phục vụ giám sát cũng như hỗ trợ.
- Tester: Cần hiểu được phạm vi của dữ liệu để họ có thể lên kế hoạch về việc test tích hợp và test mẫu.
Level 1 (blackbox)

Zoom thêm sâu hơn vào system context bên trên, ta có góc nhìn ở level 1. Vì ta không thể hiện chi tiết cấu trúc bên trong từng thành phần của level 1 này, nó là blackbox.
Mức 1 trên đây cho thấy những thành phần logic cốt lõi của hệ thống theo các quyết định đã đưa ra bên trên. Các thành phần nằm trong các khung hình chữ nhật bo tròn là những thành phần mà các đội ngũ tích cực thay đổi để đảm bảo quy trình xử lý nghiệp vụ hệ thống.
Chú ý rằng, sơ đồ trên thể hiện cấu trúc hệ thống ở mức logic: Mỗi thành phần có vai trò riêng góp sức lại với nhau tạo thành một hệ thống toàn vẹn. Trong môi trường chạy (runtime), chúng có thể không đứng tách biệt như hình vẽ logic này. Các instance của API Gateway có thể nằm cùng namespace với các microservices nghiệp vụ trên cùng một hạ tầng ảo hóa. Service Discovery có thể cũng là những dịch vụ chuyên trách và chạy lẫn cùng microservices nghiệp vụ giống như API Gateway instances, cũng có thể đó là thành phần được cung cấp sẵn bởi hạ tầng triển khai (như Kubernetes). Do đó, tổng quát lên ta thấy rằng việc đưa ra quyết định triển khai thế nào có thể phong phú, miễn sao quyết định đó đảm bảo tuân theo mô hình logic.
Nguyên tắc của tài liệu kiến trúc là đưa ra các thành phần kiến trúc độc lập với triển khai. Ví dụ, việc đưa vào một API Gateway cùng các hướng dẫn triển khai nó là một quyết định kiến trúc, và quyết định này không đề cập đến khi triển khai ta dùng API Gateway nào (tự xây dựng hay một API Gateway đang có trên thị trường như Netflix Eureka.) Tuy nhiên, với định hướng của tổ chức là xây dựng trên cùng một nền tảng ngôn ngữ và framework nhằm tối ưu tính sử dụng lại, tối ưu chuyên sâu techstack thì có thể coi đó là kim chỉ nam cho những quyết định triển khai sớm cho kiến trúc của ta ở một số thành phần.
Level 2 (whitebox): Microservices
Nếu dừng lại ở sơ đồ level 1 (blackbox) bên trên, có thể chấp nhận được ở tiêu chuẩn thường gặp. Nhưng sơ đồ này chưa thể hiện được thông tin như kế thừa, phụ thuộc giữa các thành phần. Để định hướng tốt hơn cho team phát triển từng microservice, ta cần mức chi tiết hơn nữa.
Zoom vào vùng Microservices (là vùng cần tích cực maintain nhất trong hệ thống), ta có các microservices (tạm thời coi chúng là các bounded context), cần tăng thông tin vùng này.

Sơ đồ trên cho thấy một số điểm đáng chú ý sau:
- Các bounded context sử dụng các thư viện dùng chung.
- Các thư viện dùng chung bao gồm:
- DDD Module: chứa các class, interface chung giúp các bounded dễ dàng triển khai tactical DDD hơn.
- Event Module: thư viện này giúp việc triển khai Transactional Outbox, publish event trực tiếp lên một message queue hay consume message dễ dàng hơn. Lý tưởng nhất là người sử dụng chỉ cần cấu hình.
- Security Module: Tuy API Gateway trở thành điểm thực thi các chính sách bảo mật tập trung nhưng trong một số hệ thống vẫn yêu cầu thực hiện tại từng bounded context, lúc này, ta cần triển khai một module như vậy.
- Tracing Module: API Gateway sinh ra Correlation ID còn việc bảo toàn nó qua một loạt lời gọi giữa các bounded context là việc cần làm của chính các bounded context đó. Việc này được đảm bảo và trong suốt với người dùng qua Tracing Module.
- Resiliency Module: Các chính sách bảo vệ bounded context nên được thực hiện nhất quán, điều nầy được đảm bảo bởi module này. Module cần chìa ra các tham số cấu hình bên cạnh mặc định để người dùng lựa chọn.
- Và còn nhiều module khác trong quá trình phát triển. Ứng viên thường gặp là những việc mà hầu hết các bounded context phải làm trong quá trình xây dựng. Nếu ta gom những việc đó lại thành các module dùng chung, không chỉ giúp ta tối ưu nguồn lực mà chất lượng sản phẩm cũng sẽ tăng lên.
- Những thông tin này sẽ được mô tả chi tiết trong tài liệu thiết kế cho từng bounded context.
Component & Connector views
System overall

Giải thích sơ đồ:
- Hạ tầng Kubernetes. Đây là một quyết định triển khai cụ thể. Điều này ảnh hưởng đến cấu phần như Service Discovery khi ta có thể tận dụng chức năng có sẵn này của Kubernetes. Chi tiết hơn ở phía dưới.
- Business Service Namespace: Cụm này chứa các microservices nghiệp vụ và API Gateway. Mỗi dịch vụ triển khai với nhiều instance để đảm bảo khả năng mở rộng, tính sẵn sàng. Giao tiếp giữa các dịch vụ có thể diễn ra trực tiếp qua cơ chế đồng bộ hoặc gián tiếp qua cơ chế bất đồng bộ. Trong sơ đồ, các dịch vụ trong cụm giao tiếp trực tiếp qua giao thức RESTful để đảm bảo tính đơn giản và hiệu năng cao. Các API Gateway instance được triển khai trong cùng vùng logic nhằm tối ưu hóa hiệu năng, tăng tính sẵn sàng thông qua phân tải, và hỗ trợ khả năng mở rộng khi có thể dễ dàng thêm instance khi lưu lượng tăng.
- Messaging Namespace và Integration Namespace: Các dịch vụ trong Business Service Namespace giao tiếp bất đồng bộ với Messaging Namespace, nơi triển khai các hệ thống messaging. Messages được định tuyến thông qua các dịch vụ trong Integration Namespace, nơi áp dụng các thuật toán và pattern định tuyến. Nhờ đó, các microservices nghiệp vụ không giao tiếp trực tiếp với Integration Namespace, đảm bảo tính tách biệt và linh hoạt trong xử lý luồng dữ liệu.
- Configuration Namespace: Cụm này chứa Config Server, quản lý cấu hình cho các microservices, API Gateway, và các dịch vụ trong Security Namespace, Monitoring & Scaling Namespace, Logging & Tracing Namespace. Configuration Namespace nằm độc lập, phục vụ cả Production Zone, Dev Zone, và Testing Zone. Cấu hình có thể được áp dụng khi khởi động dịch vụ hoặc tại thời điểm runtime, hỗ trợ khả năng bảo trì.
- Security Namespace: Cụm này triển khai các dịch vụ chuyên trách bảo mật, cho phép đội Security chủ động phát triển và vận hành các ứng dụng bảo mật mà không ảnh hưởng đến hoạt động của các dịch vụ nghiệp vụ. Tuy nhiên, một số triển khai bảo mật cần được phân tán vào thư viện hoặc các hệ thống chuyên trách khác, được thể hiện qua các ô hình oval Security trong biểu đồ. Security Namespace chủ yếu thu thập và giám sát hệ thống qua cơ chế bất đồng bộ, nhưng các hành động phản ứng nhanh (như Rate Limiting) sử dụng cơ chế đồng bộ để tương tác với các dịch vụ khác, đảm bảo tuân thủ bảo mật.
- Logging & Tracing Namespace: Cụm này thu thập, lập chỉ mục và khai thác log vận hành cùng các trace (CorrelationID) thông qua các dịch vụ chuyên trách (như ELK Stack và OpenTelemetry). Log và trace được sử dụng để truy vấn hoặc trực quan hóa qua biểu đồ, hỗ trợ phát hiện sự cố. Giao tiếp với các dịch vụ sinh log/trace chủ yếu diễn ra qua cơ chế bất đồng bộ để tránh ảnh hưởng hiệu năng.
- Monitoring & Scaling Namespace: Cụm này triển khai các dịch vụ giám sát hiệu năng và trạng thái ứng dụng, giúp phát hiện, cảnh báo lỗi kịp thời và hỗ trợ tự động mở rộng/thu hẹp tài nguyên (Kubernetes HPA) dựa trên lưu lượng. Giao tiếp với các microservices chủ yếu qua cơ chế bất đồng bộ, đảm bảo không ảnh hưởng đến hiệu năng hệ thống.
Main data flows
Ở tài liệu thiết kế kiến trúc, ta không cần và cũng không thể mô tả được tất cả các dataflow trong hệ thống. Thay vào đó, hãy trừu tượng hóa chúng lên thành những luồng đại diện.
Luồng nghiệp vụ
Luồng này mô tả cách một yêu cầu từ client được xử lý qua API Gateway, Security, và các microservices nghiệp vụ.

Mô tả
Luồng logging and tracing
Luồng này mô tả cách log và trace được sinh ra từ microservices, thu thập tại Logging & Tracing Namespace, và khai thác bởi người dùng để tìm lỗi.

Mô tả
Luồng monitoring and scaling

Mô tả
Luồng cấu hình dịch vụ
Cập nhật
Luồng bảo mật và phản ứng nhanh
Cập nhật
Luồng tích hợp với hệ thống bên ngoài
Cập nhật
Allocation views
Work allocation view
Chúng ta đang có một số bounded context bao gồm cả nghiệp vụ và cross-cutting concerns như bức tranh dưới đây:

Các bounded context có tốc độ cập nhật khác nhau do bản chất công việc mà chúng phụ trách, tốc độ này được đại diện bởi màu sắc. Hơn nữa, căn cứ theo nguồn lực dự án, loại subdomain của từng bounded context, ta nhóm chúng lại để cho một team sử dụng.
- Màu đỏ: Những bounded context chính của dự án. Ở giai đoạn này, chúng được tích cực xây dựng và cập nhật.
- Order Management và Payment: Order Management là core subdomain, có những người giỏi nhất, được hỗ trợ nhất về nguồn lực. Team này có thể thêm một tỷ lệ nhỏ nguồn lực nữa để kiêm thêm Payment. Quyết định này đến từ việc Payment đang có mối quan hệ chặt tới Order Mangement, và hiện tại đang tương đối đơn giản nên để một team giỏi phụ trách.
- Catalog và Inventory: Đây là hai bounded context thuộc supporting subdomain, nơi có nhiều hơn các bạn trẻ cũng như yêu cầu nghiệp vụ tại thời điểm này không cao. Đồng thời, tính gắn kết của hai bounded context này khiến ta có quyết định để một team phụ trách.
- Các team phụ trách bốn dự án này kiêm cả các đầu việc hoặc tạo yêu cầu tới các team liên quan, đặc biệt là:
- Configuration Server: Đề xuất tự tác động thêm tham số cấu hình.
- Logging & Tracing: Tự log trong dự án của team phụ trách, có thể có công cụ xây dựng dashboard.
- Security: Tự cài đặt các chính sách bảo mật bằng cách sử dụng thư viện chung.
- Messaging: Yêu cầu các message queues và các cơ chế sharding.
- Integration: Đưa ra yêu cầu định tuyến messages.
- Màu da cam: Những bounded context hướng tới tích hợp hệ thống, chủ yếu là routing (API Gateway và Camel Routes), lượng thay đổi không nhiều như nhóm màu đỏ nhưng đòi hỏi kỹ năng hơi khác biệt, đặc biệt là Camel K.
- Màu trắng: Tĩnh hơn nữa vì đây là các thành phần chuyên trách trên toàn bộ hệ thống, có cấu hình chung. Các bounded context này có thể để team Infrastructure phụ trách. Riêng Security do team Security phụ trách. Tại đây, sẽ có các dịch vụ chuyên trách về bảo mật hoặc các chính sách bảo mật quy định.
Deployment view
Cập nhật