de_DEen_USes_ESfa_IRfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

一个全面的分步案例研究:将C4模型应用于互联网银行系统(Big Bank plc)

C4模型,由西蒙·布朗创建,是一种简单、分层且对开发者友好的软件架构可视化方法。它使用四个抽象层次(因此称为“C4”),从最高层次的概览逐步描述到代码级别的细节:

  1. 系统上下文(第1层)——整体视图:系统及其用户/外部依赖关系。
  2. 容器(第2层)——高层次的技术选择与职责。
  3. 组件(第3层)——容器内部的主要逻辑构建块。
  4. 代码(第4层)——可选的类级别或代码结构细节。

它还支持三种额外的图表类型:

  • 系统全景图
  • 动态图
  • 部署图

该模型与符号表示无关(您可以使用任何绘图工具),并注重清晰性、一致性和适合目标受众的细节。它被广泛采用,因为它避免了“混乱的泥球”式架构图,并能从白板草图扩展到自动化文档。

针对这一针对性案例研究,我们采用C4官网提供的标准示例:互联网银行系统,针对虚构的“Big Bank plc”银行。业务目标是让个人客户能够在线查看账户并进行支付,同时与银行现有的核心系统集成。

我们将逐一讲解每一层,包括:

  • 目的与受众
  • 关键元素 + 职责
  • 关系
  • 一个即用型的PlantUML C4图表(PlantUML 支持 C4 语法,并在大多数 Markdown 查看器中渲染得非常美观)
  • 设计理由与关键决策
  • 该图如何帮助利益相关者

第一步:定义范围并创建系统上下文图(第1级)

目的:展示新的网上银行系统如何融入世界。受众:业务利益相关者、非技术人员、新团队成员。

元素 (来自官方示例):

  • 个人银行客户 (人)—— 拥有一个或多个个人银行账户的客户。
  • 网上银行系统 (软件系统)—— 我们正在构建的新系统。
  • 核心银行系统 (软件系统,现有)—— 处理客户数据、账户和交易的大型机。
  • 邮件系统 (软件系统,外部)—— 用于发送确认邮件的亚马逊网络服务简单邮件服务(AWS SES)。

关系:

  • 客户 → 使用 → 网上银行系统(用于查看账户和付款)
  • 网上银行系统 → 使用 → 核心银行系统(用于账户数据和付款)
  • 网上银行系统 → 通过 → 邮件系统发送邮件

这就是 PlantUML C4 上下文图:


@startuml
!include https://static.visual-paradigm.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml

LAYOUT_TOP_DOWN()
LAYOUT_WITH_LEGEND()

title 网上银行系统(第1级)系统上下文图

Person(customer, "个人银行客户", "拥有一个或多个个人银行账户的客户。")
System(internet_banking_system, "网上银行系统", "用于查看账户和付款的新系统。")
System(core_banking_system, "核心银行系统", "现有大型机,负责处理客户数据、账户和交易。")
System_Ext(email_system, "邮件系统", "用于发送确认邮件的亚马逊网络服务简单邮件服务(AWS SES)。")

Rel(customer, internet_banking_system, "使用")
Rel(internet_banking_system, core_banking_system, "使用")
Rel(internet_banking_system, email_system, "通过...发送邮件")

Lay_D(customer, internet_banking_system)
Lay_D(internet_banking_system, core_banking_system)
Lay_U(email_system, internet_banking_system)
@enduml

设计理由与价值:这张图能立即回答“我们正在构建什么,它与谁通信?”它通过明确外部依赖关系来防止范围蔓延。业务利益相关者喜欢它,因为目前还没有技术细节。

步骤 2:容器图(第 2 级)

目的: 聚焦于网上银行系统,展示主要可部署/可运行单元(容器)及其技术选型。目标受众:架构师、首席开发人员、运维人员。

网上银行系统内部的容器:

  • 单页应用(Web 浏览器 – JavaScript + Angular)– 完整的网上银行用户界面。
  • 移动应用(移动设备 – iOS/Android 原生或 React Native)– 用于移动场景的有限功能。
  • API 应用(服务器端 – Java + Spring Boot)– 由两个前端共同使用的 JSON/HTTPS API。
  • 数据库(关系型数据库 – PostgreSQL)– 存储会话数据、用户偏好、缓存的账户摘要(核心数据仍保留在主机系统中)。

关键关系(与第 1 级相同的外部系统):

  • 单页应用与移动应用 → 调用 → API 应用
  • API 应用 ↔ 数据库
  • API 应用 → 核心银行系统与邮件系统

PlantUML C4 容器图:


@startuml
!include https://static.visual-paradigm.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/angular.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/java.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/postgresql.puml

LAYOUT_TOP_DOWN()
LAYOUT_WITH_LEGEND()

title 网上银行系统的 C4 容器图

Person(customer, "个人银行客户", "拥有一个或多个个人银行账户的客户。")

System_Boundary(internet_banking_system, "网上银行系统", "用于查看账户和进行支付的新系统。") {
Container(spa, "单页应用", "JavaScript + Angular", "完整的网上银行用户界面", $sprite="angular")
Container(mobile_app, "移动应用", "iOS/Android(React Native)", "用于移动场景的有限功能", $sprite="react")
Container(api_app, "API 应用", "Java + Spring Boot", "由两个前端共同使用的 JSON/HTTPS API", $sprite="java")
ContainerDb(database, "数据库", "PostgreSQL", "存储会话数据、用户偏好、缓存的账户摘要", $sprite="postgresql")
}

System(core_banking_system, "核心银行系统", "现有的主机系统,用于处理客户数据、账户和交易。")
System_Ext(email_system, "邮件系统", "用于发送确认信息的亚马逊云服务简单邮件服务(AWS SES)。")

' 关系
Rel(customer, spa, "使用", "HTTPS")
Rel(customer, mobile_app, "使用", "HTTPS")
Rel(spa, api_app, "调用", "JSON/HTTPS")
Rel(mobile_app, api_app, "调用", "JSON/HTTPS")
Rel(api_app, database, "读取和写入", "JDBC/SQL")
Rel(api_app, core_banking_system, "查询/更新", "JSON/HTTPS")
Rel(api_app, email_system, "通过...发送邮件", "HTTPS")

' 布局提示(可选 – 帮助 PlantUML 更好地排列元素)
Lay_D(customer, internet_banking_system)
Lay_D(internet_banking_system, core_banking_system)
Lay_U(email_system, internet_banking_system)

@enduml

设计理由: 我们为网页选择了现代的单页应用 + API 后端模式,为性能选择了原生移动应用,并保持数据库轻量化(大部分数据仍存在于遗留主机系统中)。该图是高层次技术决策的唯一真实来源,有助于 DevOps 规划基础设施。

步骤 3:组件图(第 3 级)

目的: 聚焦于一个容器(通常是其中最复杂的——API 应用)并展示其主要逻辑组件。目标受众:开发团队。

示例:API 应用内部的组件:

  • 账户控制器(Spring MVC)
  • 认证控制器
  • 重置密码控制器
  • 安全组件(处理认证、JWT等)
  • 账户管理组件(协调对核心银行系统的调用)
  • 邮件通知组件

PlantUML C4 组件图(专注于API应用程序):


@startuml
!include https://static.visual-paradigm.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml

LAYOUT_WITH_LEGEND()

title 互联网银行系统 - API应用程序的组件图

Container(spa, "单页应用", "javascript和angular", "通过用户的网络浏览器为客户提供所有互联网银行功能。")
Container(ma, "移动应用", "Xamarin", "通过客户的移动设备提供有限的互联网银行功能子集。")
ContainerDb(db, "数据库", "关系型数据库模式", "存储用户注册信息、哈希认证凭证、访问日志等。")
System_Ext(mbs, "主机银行系统", "存储关于客户、账户、交易等的所有核心银行信息。")

Container_Boundary(api, "API应用程序") {
    Component(accounts, "账户控制器", "Spring MVC", "为客户提供账户概要和余额信息。")
    Component(auth, "认证控制器", "Spring MVC", "处理用户登录、会话管理及令牌生成。")
    Component(reset, "重置密码控制器", "Spring MVC", "允许用户通过电子邮件重置密码。")
    Component(security, "安全组件", "Spring Bean", "处理认证、JWT令牌生成和密码哈希。")
    Component(accountmgmt, "账户管理组件", "Spring Bean", "协调对核心银行系统的调用以执行账户操作。")
    Component(email, "邮件通知组件", "Spring Bean", "通过SMTP发送密码重置邮件和账户验证邮件。")

    Rel(accounts, security, "使用")
    Rel(auth, security, "使用")
    Rel(reset, security, "使用")
    Rel(accountmgmt, mbs, "使用", "XML/HTTPS")
    Rel(email, db, "读取", "JDBC")
}

Rel(spa, accounts, "使用", "JSON/HTTPS")
Rel(spa, auth, "使用", "JSON/HTTPS")
Rel(spa, reset, "使用", "JSON/HTTPS")
Rel(ma, accounts, "使用", "JSON/HTTPS")
Rel(ma, auth, "使用", "JSON/HTTPS")
Rel(ma, reset, "使用", "JSON/HTTPS")
@enduml

理由:此层级展示了职责是如何划分的(关注点分离),并能显著加快新开发人员的入职速度。只有当容器足够复杂时,才需要绘制组件图。

步骤4:代码图(第4层)——可选

目的:展示单个组件的内部结构(类图、序列图等)。受众:正在开发该代码的开发人员。

例如认证控制器组件——在PlantUML中的一个简单UML类图:


@startuml
classDiagram

skinparam {
roundcorner 8
ArrowColor #444444
ArrowFontColor #444444
BorderColor #444444

Class {
BorderColor #1A237E
BackgroundColor #E8EAF6
FontColor #1A237E
}
}

class "AuthenticationController" {
+login(credentials)
+refreshToken()
}

class "JwtTokenProvider" {
+generateToken(user)
+validateToken(token)
}

class "UserRepository" {
+findByUsername()
}

AuthenticationController ..> JwtTokenProvider : "使用"
AuthenticationController ..> UserRepository : "使用"
@enduml

在实际项目中,你通常会跳过第4层,直接指向实际的源代码。

步骤5:支持性图表

动态图(例如:“查看账户摘要”流程)


@startuml
!include https://static.visual-paradigm.com/plantuml-stdlib/C4-PlantUML/master/C4_Deployment.puml

title 查看账户概览的动态图

Person(customer, "个人银行客户") {
Container(spa, "单页应用") {
Container(api, "API 应用") {
ContainerDb(db, "数据库") {
System_Ext(coreBanking, "核心银行系统")
}
}
}
}

Rel(customer, spa, "1. 点击 '账户'", "")
Rel(spa, api, "2. GET /accounts", "JSON/HTTPS")
Rel(api, db, "3. 读取缓存的概要", "")
Rel(api, coreBanking, "4. 获取最新数据", "")
Rel(api, spa, "5. 返回 JSON", "")

SHOW_LEGEND()
@enduml

部署图 (高层次物理映射):


@startuml
!include https://static.visual-paradigm.com/plantuml-stdlib/C4-PlantUML/master/C4_Deployment.puml

title 互联网银行系统的部署图

Deployment_Node(aws, "亚马逊网络服务", "云") {
Deployment_Node(ec2, "EC2 自动伸缩组", "Linux") {
Container(api, "API 应用", "Java Spring Boot")
}
Deployment_Node(rds, "RDS", "PostgreSQL") {
ContainerDb(db, "数据库")
}
}

Deployment_Node(customerDevice, "客户设备", "Web/移动") {
Container(spa, "单页应用")
Container(mobile, "移动应用")
}

System_Ext(coreBanking, "核心银行系统(本地主机)")

Rel(spa, api, "发起 API 调用", "HTTPS")
Rel(mobile, api, "发起 API 调用", "HTTPS")
Rel_U(api, spa, "交付至客户的网页浏览器")
Rel_U(api, mobile, "交付至移动应用")

SHOW_LEGEND()
@enduml

如何在实践中使用此案例研究

  1. 从工作坊开始:在白板上绘制上下文图。
  2. 使用 PlantUML C4 迭代至容器和组件。
  3. 将图表保留在代码仓库中(作为代码!),以确保它们保持最新。
  4. 自动生成动态文档。

这个互联网银行系统示例是西蒙·布朗创建的官方参考,被全球数千家组织使用。通过遵循这些步骤,你现在拥有了一个完整的、可投入生产的架构描述,无论从 CEO 到新入职的初级开发人员,任何人都能在合适的细节层次上理解它。

C4 图表文章