de_DEen_USes_ESfa_IRfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

深入探討:理解 C4 程式碼圖 – 它們是什麼、何時具有價值,以及實用的 PlantUML 範例

什麼是 C4 程式碼圖?

程式碼圖是第 4 層——西蒙·布朗(Simon Brown)C4 模型中最深、最詳細的一層。

The Ultimate Guide to C4 Model Visualization with Visual Paradigm's AI Tools - ArchiMetric

它顯示:

  • 類別介面列舉記錄,或其他實作特定組件(來自第 3 層)。

  • 關係這些類別之間的關係(繼承、組合、依賴、介面的實作等)。

  • 關鍵設計元素例如組件內應用的設計模式(如儲存庫、服務、DTO、領域實體、工廠等)。

實際上,這一層幾乎總是UML 類別圖(或簡化版本),專注於一個(或極少數)組件。

重要說明:

  • 第 4 層是不是關於整個程式碼庫。

  • 它不是不是必須顯示每個類別。

  • 它映射僅顯示基本結構理解一個複雜或關鍵組件實際是如何構建的所必需的。

  • 官方C4建議:理想情況下自動產生從原始碼產生(透過Doxygen、Javadoc + UML外掛、yWorks、Structurizr、CodeSee等工具),而非手繪。

何時建立程式碼圖

應謹慎建立第4級圖——僅在以下情況下:

  • 組件為高度複雜任務關鍵,或難以理解僅從原始碼難以理解(例如:複雜的領域邏輯、大量使用設計模式、加密流程、狀態機、充滿技術負債的遺留程式碼)。

  • 您正在一個高度受監管的產業(金融、醫療、航太、國防)中,審計師或合規團隊要求明確的架構→設計→實作對應關係。

  • 重大重構逐步淘汰遺留組件,或引入新的架構模式(六邊形、乾淨、垂直切片、DDD聚合)——前後對照視圖有助於傳達變更內容。

  • 新進資深開發人員架構師需要快速掌握高風險程式碼中隱藏的內部結構的人。

  • 您已經投入了自動生成工具——因此維護 Level 4 的成本幾乎為零。

  • 團隊已同意「動態文件」在類別層級對此特定子系統具有價值。

當出現以下情況時,請勿建立 Level 4 圖表:

  • 組件結構可從良好的命名、小規模或乾淨的程式碼中明顯看出(大多數現代微服務屬於此類)。

  • 您已經擁有良好的單元/整合測試明確的介面,以及說明性註解.

  • 團隊大多數成員都能輕鬆導航程式碼。

  • 維護成本高於效益(手繪類別圖表會很快過時)。

Simon Brown 和大多數實務工作者強調:大多數團隊永遠不需要 Level 4Level 1 + 2涵蓋 80–90% 的溝通需求;Level 3處理剩餘的大部分情況。Level 4 是例外,而非常態。

為什麼要使用程式碼圖表?(當它們帶來價值時)

  • 架構 ↔ 實作之間的橋樑——顯示高階組件在程式碼中實際是如何實現的。

  • 釐清複雜的內部設計——揭露設計模式(策略、工廠、裝飾器、儲存庫)的使用、層級違反、緊密耦合,或巧妙的領域建模。

  • 支援審計與合規 — 展示架構決策是否確實落實到程式碼中。

  • 協助重構與遷移討論 — 前後類結構的對比使提案更具體可感。

  • 減少「部落知識」 — 協助新任資深成員比閱讀所有原始碼更快理解複雜部分。

  • 自動產生的版本成為「活文件」 — 若已具備工具支援,幾乎無需額外努力即可保持準確性。

如何創建出色的程式碼圖示(逐步指南 + 最佳實務)

  1. 選擇一個元件 — 通常來自第3級圖示,其內部複雜度足以支持放大檢視。

  2. 決定:手繪還是自動產生?

    • 手繪 → 僅適用於工作坊、提案,或自動工具難以處理的混亂區域。

    • 自動產生 → 優先選擇(仍可使用 PlantUML 來美化或調整輸出結果)。

  3. 聚焦於核心要點 — 展示:

    • 關鍵類別/介面

    • 重要關係(→ 依賴,— 組合,<| 實作,^ 繼承)

    • 聚合物、實體、值物件(DDD 風格)

    • 你希望強調的關鍵設計模式或反模式

  4. 保持簡潔 — 最多8至15個類別。若更大 → 拆分為專注的圖示(例如:「驗證片段」、「訂單處理實體」)。

  5. 最佳實務

    • 優先選擇 自動產生 在可能的情況下(減少過時)。

    • 使用 PlantUML classDiagram 語法 — 清晰且可版本控制。

    • 新增 註解 用於非明顯的決策(例如:「使用貧瘠領域模型 – 計畫重構」)。

    • 避免顯示 所有內容 — 忽略平凡的 getter/setter、工具類別。

    • 儲存在程式碼庫中 → 視為程式碼(將 .puml 檔案與元件附近一起提交)。

    • 謹慎使用 — 每個複雜元件僅使用一次,而非每個微服務都使用。

    • 與 結合動態檢視 (序列/協作)若執行時期流程比靜態結構更重要時。

PlantUML 範例 – 驗證元件(Big Bank plc 風格擴展)

這裡有一個真實的 Level 4 範例,深入探討 安全 / 驗證元件 來自先前的 API 應用程式圖示。

@startuml
title C4 Level 4 – 程式碼圖:API 應用程式內的驗證

skinparam monochrome true
skinparam shadowing false
skinparam class {
  BackgroundColor White
  BorderColor Black
  ArrowColor Black
}

抽象類別 AuthenticationProvider {
  + authenticate(credentials): Authentication
}

class JwtAuthenticationProvider {
  - tokenProvider: JwtTokenProvider
  - userDetailsService: UserDetailsService
  + authenticate(credentials): Authentication
}

class JwtTokenProvider {
  - secretKey: String
  - validityInMilliseconds: long
  + generateToken(userDetails): String
  + validateToken(token): boolean
  + getUsernameFromToken(token): String
}

介面 UserDetailsService {
  + loadUserByUsername(username): UserDetails
}

class DatabaseUserDetailsService {
  - userRepository: UserRepository
  + loadUserByUsername(username): UserDetails
}

class UserRepository {
  + findByUsername(username): Optional<User>
}

class User {
  - username: String
  - passwordHash: String
  - roles: Set<Role>
}

class JwtAuthenticationToken << (T,orchid) Authentication >> {
  - principal: UserDetails
  - credentials: Object
  - authorities: Collection<GrantedAuthority>
}

' 關係
JwtAuthenticationProvider -up-> JwtTokenProvider : 使用
JwtAuthenticationProvider -up-> UserDetailsService : 使用
DatabaseUserDetailsService .up.|> UserDetailsService
DatabaseUserDetailsService --> UserRepository : 使用
UserRepository --> User : 回傳

JwtAuthenticationToken .up.|> Authentication

note right of JwtAuthenticationProvider
  JWT 基礎的無狀態會話主要驗證流程
end note

note bottom of JwtTokenProvider
  使用 HS512 簽署與驗證 JWT
end note

@enduml

這個小型圖示:

  • 僅聚焦於驗證的內部實作

  • 顯示關鍵類別、介面與相依性

  • 強調設計模式(提供者、儲存庫)

  • 使用註解提供背景資訊

貼上至任何 PlantUML 渲染器中 — 根據您的領域進行自訂(例如:將 JWT 替換為 OAuth2,新增 MFA 類別等)。

總結提醒:Level 4 非常強大,但 罕見。應有目的地使用,優先選擇自動產生,絕不讓它變成瑣碎的工作。C4 的最大價值來自 Level 1–3。祝您(有選擇性地)愉快建模!

資源