Mô hình C4: Hướng dẫn tạo sơ đồ kiến trúc phần mềm hiệu quả
Trong quá trình phát triển phần mềm, việc đọc hiểu một codebase phức tạp có thể giống như đọc một cuốn tiểu thuyết đồ sộ. Mô hình C4 ra đời như một giải pháp giúp các nhóm phát triển phần mềm mô tả và giao tiếp kiến trúc phần mềm một cách rõ ràng và hiệu quả.
Mô hình C4 là gì?
Là một lập trình viên, bạn sẽ có lúc phải làm việc trên một dự án phức tạp, nơi việc giải mã codebase giống như đọc một cuốn tiểu thuyết dài tập. Các kỹ sư là những phù thủy code, nhưng ngay cả những người giỏi nhất cũng có thể lạc lối trong một mớ code đồ sộ.
Đây là lý do tại sao việc tạo và duy trì các sơ đồ hiệu quả và rõ ràng cần phải dễ dàng. Hình ảnh trực quan cập nhật đảm bảo mọi người đều nắm bắt được thông tin chung, loại bỏ sự nhầm lẫn và lãng phí thời gian.
Mô hình C4 được tạo ra như một cách để giúp các nhóm phát triển phần mềm mô tả và giao tiếp kiến trúc phần mềm.
C4 là viết tắt của “Context, Containers, Components, và Code” . Đó là bốn cấp độ đủ để mô tả một hệ thống phức tạp.
Cách tốt nhất để giải thích khái niệm này là nghĩ về cách chúng ta sử dụng Google Maps. Khi khám phá một khu vực trong Google Maps, chúng ta thường bắt đầu thu nhỏ để có cái nhìn tổng quan. Khi đã tìm thấy khu vực muốn tìm hiểu, chúng ta có thể phóng to để xem chi tiết hơn.
Cấp Độ 1: Context
Cấp độ này là cấp độ thu nhỏ nhất. Nó là cái nhìn tổng quan về hệ thống trong bối cảnh rộng lớn hơn của thế giới. Sơ đồ tập trung vào các tác nhân và hệ thống.
Đối với các ví dụ dưới đây, chúng ta sẽ sử dụng một Hệ thống Phần mềm Quản lý Công việc đơn giản để minh họa cho cả 4 cấp độ này.
Sơ đồ này mô tả các tương tác của Hệ thống Phần mềm Quản lý Công việc với các hệ thống bên ngoài và các nhóm người dùng khác nhau sử dụng nó. Chúng ta có thể thấy rằng phần mềm Quản lý Công việc dựa trên hai hệ thống bên ngoài: Email và Lịch, và hai loại tác nhân (người dùng) sử dụng nó: Khách hàng và Quản trị viên.
Cấp Độ 2: Container
Cấp độ Container là chế độ xem chi tiết hơn về hệ thống của bạn (không nhầm lẫn vùng chứa C4 với vùng chứa Docker).
Nó cho thấy cách các đơn vị chức năng khác nhau như ứng dụng và cơ sở dữ liệu hoạt động cùng nhau và phân phối trách nhiệm.
Sơ đồ này cũng nêu bật các công nghệ chính được sử dụng và thể hiện luồng giao tiếp giữa các vùng chứa này. Nó trình bày một cái nhìn đơn giản hóa, tập trung vào công nghệ về các thành phần cốt lõi của hệ thống và sự tương tác của chúng.
Nếu bạn có kiến trúc Microservice, thì mỗi Microservice sẽ là một vùng chứa.
Ví dụ về Container để bạn có thể dễ hiểu:
- Ứng dụng một trang
- Máy chủ web
- Hàm không máy chủ
- Cơ sở dữ liệu
- API
- Bus tin nhắn
- Và nhiều hơn nữa.
Cấp độ này đi sâu vào thành phần bên trong của Hệ thống Phần mềm Quản lý Công việc. Nó cho thấy hệ thống phần mềm Quản lý Công việc của chúng ta bao gồm các Container như Giao diện Người dùng Web, Giao diện Người dùng Web Quản trị, API và Cơ sở dữ liệu. API cũng là vùng chứa được kết nối với các hệ thống bên ngoài, ví dụ: để gửi email hoặc tạo sự kiện trong lịch.
Cấp độ 3: Components
Cấp độ tiếp theo chính là Components (Thành phần). Điều này cho thấy các khối xây dựng cấu trúc chính của ứng dụng của bạn và thường là chế độ xem khái niệm của ứng dụng. Thuật ngữ thành phần ở đây khá chung chung. Nó có thể đại diện cho bộ điều khiển hoặc dịch vụ chứa logic nghiệp vụ.
Sơ đồ này tập trung vào cấu trúc bên trong của vùng chứa API trong Hệ thống Phần mềm Quản lý Công việc. Nó cho thấy vùng chứa API chứa các chức năng quan trọng như các thao tác CRUD (Tạo, Đọc, Cập nhật, Xóa) để thao tác dữ liệu và cơ chế xác thực người dùng. Các thành phần CRUD là thành phần giao tiếp với cơ sở dữ liệu.
Cấp độ 4: Code
Cấp độ sâu nhất trong mô hình C4 chính là sơ đồ mã. Mặc dù sơ đồ này tồn tại, nhưng nó thường không được sử dụng vì mã đã thể hiện một bức tranh rất tương tự. Tuy nhiên, trong môi trường được kiểm soát chặt chẽ và các dự án kế thừa phức tạp, cấp độ này có thể giúp phác họa rõ hơn về sự phức tạp bên trong của phần mềm.
Cấp độ bổ sung khác
Ngoài 4 cấp độ trong mô hình C4 kể trên, chúng ta còn một số cấp độ hay sơ đồ khác có thể đề cập đến như:
- Sơ đồ triển khai
- Sơ đồ động: để mô tả quy trình hoặc luồng
Trên sơ đồ này, chúng ta thấy Luồng Đăng nhập, không phải là Container hoặc Components, mà là một quy trình phần mềm diễn ra trong hệ thống phần mềm của chúng ta. Nó cho thấy Giao diện Người dùng Web/Quản trị sử dụng xác thực dựa trên JWT để giao tiếp với API và mã thông báo JWT được lưu trữ trong bộ nhớ cục bộ ở phía máy khách.
Sơ đồ dưới dạng mã
Sức mạnh của mô hình C4 đi kèm với cách tiếp cận sơ đồ dưới dạng mã. Điều này có nghĩa là coi sơ đồ của bạn giống như codebase của bạn:
- Kiểm soát phiên bản: Lưu trữ chúng trong hệ thống kiểm soát nguồn (như Git) để dễ dàng theo dõi và cộng tác.
- Cộng tác: Làm việc cùng nhau trên các sơ đồ bằng cách sử dụng yêu cầu kéo, tương tự như đánh giá mã.
- Tự động hóa: Tích hợp chúng vào quy trình xây dựng của bạn để tự động hiển thị bằng các công cụ ưa thích của bạn.
Công cụ hữu ích giúp lập mô hình và vẽ sơ đồ
Có một số công cụ giúp lập mô hình và vẽ sơ đồ, nhưng phổ biến nhất hiện nay là Structurizr với DSL (Ngôn ngữ miền cụ thể) tùy chỉnh của họ.
Tất cả những gì bạn cần là làm quen với cú pháp DSL, khá đơn giản. Miễn là bạn quen với nó, bạn sẽ có thể tạo hoặc cập nhật sơ đồ trong nháy mắt.
Dưới đây, bạn có thể thấy DSL cho Hệ thống Phần mềm Quản lý Công việc của chúng ta.
workspace {
model {
# Actors
customer = person "Customer" "" "person"
admin = person "Admin User" "" "person"
# External systems
emailSystem = softwareSystem "Email System" "Mailgun" "external"
calendarSystem = softwareSystem "Calendar System" "Calendly" "external"
# Task Management System
taskManagementSystem = softwareSystem "Task Management System"{
webContainer = container "User Web UI" "" "" "frontend"
adminContainer = container "Admin Web UI" "" "" "frontend"
dbContainer = container "Database" "PostgreSQL" "" "database"
apiContainer = container "API" "Go" {
authComp = component "Authentication"
crudComp = component "CRUD"
}
}
# Relationships (Actors & Systems)
customer -> webContainer "Manages tasks"
admin -> adminContainer "Manages users"
apiContainer -> emailSystem "Sends emails"
apiContainer -> calendarSystem "Creates tasks in Calendar"
# Relationships (Containers)
webContainer -> apiContainer "Uses"
adminContainer -> apiContainer "Uses"
apiContainer -> dbContainer "Persists data"
# Relationships (Components & Containers)
crudComp -> dbContainer "Reads from and writes to"
webContainer -> authComp "Authenticates using"
adminContainer -> authComp "Authenticates using"
}
}
Chúng ta hãy cùng tìm hiểu những phần quan trọng nhất:
workspace [name] [description] {
model {
}
}
Ở đây, chúng ta xác định không gian làm việc của mình, nơi phải có ít nhất một mô hình. Không gian làm việc có thể được đặt tên và mô tả tùy chọn.
customer = person "Customer" "" "person"
admin = person "Admin User" "" "person"
Trong phần này, chúng ta xác định người của mình (ví dụ: người dùng, tác nhân, vai trò hoặc persona) theo định dạng sau: person <name> [description] [tags].
Bạn có thể sử dụng định dạng tương tự (tên, mô tả, thẻ) để xác định các hệ thống bên ngoài:
emailSystem = softwareSystem "Email System" "Mailgun" "external"
calendarSystem = softwareSystem "Calendar System" "Calendly" "external"
Để mô tả hệ thống phần mềm nội bộ, chúng ta cần viết một khối cũng hiển thị các Container và Components của nó:
taskManagementSystem = softwareSystem "Task Management System"{
webContainer = container "User Web UI" "" "" "frontend"
adminContainer = container "Admin Web UI" "" "" "frontend"
dbContainer = container "Database" "PostgreSQL" "" "database"
apiContainer = container "API" "Go" {
authComp = component "Authentication"
crudComp = component "CRUD"
}
}
- Định dạng container: container <name> [description] [technology] [tags]
- Định dạng components: component <name> [description] [technology] [tags] Phần còn lại của mô hình là phần thú vị nhất, nơi chúng ta xác định mối quan hệ giữa tất cả các phần (hệ thống, container, components):
apiContainer -> emailSystem "Sends emails"
Định dạng sau được sử dụng: <identifier> -> <identifier> [description] [technology] [tags].
Có các tính năng khác có sẵn trong Structurizr DSL, chẳng hạn như tạo kiểu, chủ đề, khả năng hiển thị, v.v. Bạn có thể tìm thấy chúng ở đây.
Tự động hóa hiển thị trong CI của bạn
Vì bạn có thể lưu trữ các mô hình của mình trên GitHub, nên việc tự động hóa quy trình hiển thị các sơ đồ trong các công cụ bạn chọn rất dễ dàng.
Trong trường hợp của chúng tôi, Structurizr có GitHub Action cho phép bạn chạy structurizr-cli, một tiện ích dòng lệnh cho Structurizr cho phép bạn tạo các mô hình kiến trúc phần mềm dựa trên mô hình C4 bằng cách sử dụng ngôn ngữ miền cụ thể bằng văn bản (DSL).
Kho lưu trữ mẫu này chứa một quy trình làm việc chỉ đơn giản là tạo một trang tĩnh và xuất bản nó lên GitHub Pages.
name: Deploy static content to Github Pages
on:
push:
branches: ["main"]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
container:
image: ghcr.io/avisi-cloud/structurizr-site-generatr
options: --user root
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Create site
run: |
/opt/structurizr-site-generatr/bin/structurizr-site-generatr generate-site -w diagram.dsl
- uses: actions/upload-artifact@v3
with:
name: website
path: build/site
deploy:
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: website
path: build/site
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: "build/site"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
GitHub Action này sử dụng hành động Structurizr CLI để biên dịch tệp DSL của chúng ta thành HTML và xuất bản nó lên GitHub Pages.
Kết luận
Tôi tin rằng việc tạo và duy trì các sơ đồ hiệu quả và rõ ràng cần phải dễ dàng. Hình ảnh trực quan cập nhật đảm bảo mọi người đều nắm bắt được thông tin chung, loại bỏ sự nhầm lẫn và lãng phí thời gian.
Mô hình C4 và một chút tự động hóa với Structurizr DSL có thể giúp quá trình này nhanh hơn và giữ cho sơ đồ gần với codebase. Toàn bộ quy trình giờ đây cũng có thể được tự động hóa trong SDLC của bạn. Cảm ơn các bạn đã theo dõi.
All rights reserved