C4 模型是...

1. 一组层次化的抽象(软件系统、容器、组件和代码)。
2. 一组层次化的图表(系统上下文、容器、组件和代码)。
3. 与符号无关。
4. 与工具无关。


用途与优势

C4 模型是一种易于学习、开发者友好的软件架构绘图方法。 优秀的软件架构图有助于软件开发/产品团队内外的沟通、快速引导新员工上岗、架构评审/评估、风险识别(例如 风险风暴)、 威胁建模等。

简介

如果你请建筑行业的人通过视觉方式传达一栋建筑的架构,你会看到的是场地平面图、楼层平面图、立面图、剖面图和细节图。 相比之下,如果你请一个软件开发人员使用图表传达软件系统的架构,你很可能会得到一个混乱的方框和线条的集合…… 不一致的符号(颜色编码、形状、线条样式等),模糊的命名,未标记的关系,通用的术语,缺失的技术选择,混合的抽象层次等。

一个软件架构草图

一个软件架构草图

一个软件架构草图

一个软件架构草图

在我们这个行业中,虽然我们有统一建模语言(UML)、ArchiMate 和 SysML, 但这些是否能够有效地传达软件架构往往是个无关紧要的问题,因为许多团队已经抛弃了它们,转而使用更简单的“方框和线条”图。 放弃这些建模语言是一回事,但或许在追求敏捷的过程中,许多软件开发团队已经失去了视觉传达能力。



代码的地图

C4 模型的创建是为了帮助软件开发团队在前期设计会话中以及在回顾现有代码库时描述和传达软件架构。 这是一种创建代码地图的方式,可以在不同的细节层次上,就像使用 Google 地图一样,可以放大和缩小你感兴趣的区域。


Google 地图
Google 地图
Google 地图
Google 街景

第 1 级:系统上下文图提供了一个起点,展示了处于讨论范围内的软件系统如何融入其周围的世界。

第 2 级:容器图放大了讨论范围内的软件系统,展示了高层次的技术构建块。

第 3 级:组件图放大了一个单独的容器,展示了其内部的组件。

第 4 级:代码图(如 UML 类图)可用于放大单个组件,展示该组件是如何实现的。



C4 模型是一种“抽象优先”的软件架构图绘制方法,它基于反映软件架构师和开发人员如何思考和构建软件的抽象。 这一小组抽象和图表类型使得 C4 模型易于学习和使用。 请注意,你不需要使用所有 4 个级别的图表;只需使用那些能够增加价值的图表——系统上下文图和容器图对于许多软件开发团队来说已经足够了。


C4 模型概览

不同的放大级别可以让你对不同的受众讲述不同的故事。

将鼠标悬停在图表上,找到带有 的元素,并双击以放大。

抽象

为了创建这些代码地图,我们首先需要一组共同的抽象概念,以创建一个通用的语言,用于描述软件系统的静态结构。 软件系统 由一个或多个 容器(应用程序和数据存储)组成, 每个容器包含一个或多个 组件, 这些组件又由一个或多个 代码元素(类、接口、对象、函数等)实现。 并且 人员 可能会使用我们构建的软件系统。


Abstractions



人员

人员代表你软件系统的一个人类用户(例如,演员、角色、人物角色等)。


软件系统

软件系统是最高层次的抽象,描述了向其用户(无论是人类还是其他系统)提供价值的事物。 这包括你正在建模的软件系统,以及你的软件系统依赖的其他软件系统(或反之亦然)。

不幸的是,“软件系统” 这个术语是 C4 模型中最难定义的抽象之一,这种情况也因为每个组织有自己描述同一事物的术语(通常使用“应用程序”、“产品”、“服务”等)而没有得到改善。 一种理解方式是,软件系统是一个单一的软件开发团队正在构建、拥有、负责,并能看到其内部实现细节的事物。 也许这个软件系统的代码位于一个源代码仓库中,并且团队中的任何人都可以修改它。 在许多情况下,软件系统的边界将对应于一个单一团队的边界。 也可能是软件系统边界内的所有内容会同时部署。


容器 (应用程序和数据存储)

不是 Docker!在 C4 模型中,容器代表一个 应用程序数据存储。一个容器是指在整体软件系统运行时需要运行的事物。在实际中,容器可以是:

  • 服务器端 Web 应用程序:一个在 Apache Tomcat 上运行的 Java EE Web 应用程序,一个在 Microsoft IIS 上运行的 ASP.NET MVC 应用程序,一个在 WEBrick 上运行的 Ruby on Rails 应用程序,一个 Node.js 应用程序等。
  • 客户端 Web 应用程序:一个在浏览器中运行的 JavaScript 应用程序,使用 Angular、Backbone.JS、jQuery 等。
  • 客户端桌面应用程序:一个使用 WPF 编写的 Windows 桌面应用程序,一个使用 Objective-C 编写的 OS X 桌面应用程序,一个使用 JavaFX 编写的跨平台桌面应用程序等。
  • 移动应用程序:一个 Apple iOS 应用程序,一个 Android 应用程序,一个 Microsoft Windows Phone 应用程序等。
  • 服务器端控制台应用程序:一个独立的(例如“public static void main”)应用程序,一个批处理过程等。
  • 无服务器函数:一个单独的无服务器函数(例如 Amazon Lambda、Azure Function 等)。
  • 数据库:关系数据库管理系统中的一个模式或数据库,文档存储,图数据库等,如 MySQL、Microsoft SQL Server、Oracle Database、MongoDB、Riak、Cassandra、Neo4j 等。
  • Blob 或内容存储:一个 Blob 存储(例如 Amazon S3、Microsoft Azure Blob Storage 等)或内容交付网络(例如 Akamai、Amazon CloudFront 等)。
  • 文件系统:一个完整的本地文件系统或更大网络文件系统的一部分(例如 SAN、NAS 等)。
  • Shell 脚本:一个用 Bash 编写的单独 Shell 脚本等。
  • 等等

组件

“组件” 这个词在软件开发行业中是一个过度使用的术语,但在此上下文中,组件是指封装在一个明确定义的接口后面的相关功能的集合。 如果你使用像 Java 或 C# 这样的语言,最简单的理解组件的方式是,它是接口后面的实现类的集合。有关这些组件如何打包(例如,一个组件与每个 JAR 文件、DLL、共享库中的多个组件)的问题是一个独立且正交的关注点。

需要注意的一个重要点是,容器内的所有组件通常在同一个进程空间中执行。 在 C4 模型中,组件不是单独可部署的单元。

1. 系统上下文图 链接

系统上下文图

图例

系统上下文图是绘制和记录软件系统的一个很好的起点,它让你退后一步,看到大局。绘制一个图示,将你的系统显示为中央的一个框,周围是其用户和它互动的其他系统。

这里的细节不重要,因为这是你的缩小视图,展示了系统景观的大图。重点应放在人员(演员、角色、人物角色等)和软件系统上,而不是技术、协议和其他低级细节。这是一种你可以向非技术人员展示的图示。

范围: 一个单一的软件系统。

主要元素: 范围内的软件系统。
支持元素: 直接连接到范围内的软件系统的人员(例如用户、演员、角色或人物角色)和软件系统(外部依赖)。通常这些其他软件系统位于你自己软件系统的范围或边界之外,你不负责或拥有它们。

目标受众: 所有人,包括技术人员和非技术人员,软件开发团队内外。

是否推荐给大多数团队: 是。

2. 容器图 链接

容器图

图例

一旦你了解了你的系统如何融入整体 IT 环境,接下来的一个非常有用的步骤是通过容器图缩小到系统边界。 “容器”是指像服务器端 web 应用程序、单页应用程序、桌面应用程序、移动应用、数据库模式、文件系统等。 本质上,容器是一个独立的可运行/部署单元(例如,单独的进程空间),它执行代码或存储数据。

容器图展示了软件架构的高层次结构,以及职责如何分布在其中。它还展示了主要的技术选择和容器之间的通信方式。这是一种简单的、高层次的技术聚焦图示,对软件开发人员和支持/运维人员都很有用。

范围: 单一的软件系统。

主要元素: 范围内软件系统的容器。
支持元素: 直接连接到容器的人员和软件系统。

目标受众: 软件开发团队内外的技术人员,包括软件架构师、开发人员和运维/支持人员。

是否推荐给大多数团队: 是。

备注: 此图未涉及集群、负载均衡器、复制、故障转移等,因为这些在不同环境(例如生产、预发布、开发等)中可能会有所不同。这些信息更适合通过一个或多个部署图来捕捉。

3. 组件图 链接

组件图

图例

接下来,你可以进一步缩小并解构每个容器,以识别主要的结构构建块及其交互。

组件图展示了一个容器如何由多个“组件”组成,这些组件是什么、它们的职责以及技术/实现细节。

范围: 单一容器。

主要元素: 范围内容器中的组件。
支持元素: 组件直接连接的容器(在软件系统范围内),以及人员和软件系统。

目标受众: 软件架构师和开发人员。

是否推荐给大多数团队: 否,仅在你觉得它们能带来价值时创建组件图,并考虑为长期文档化自动生成它们。

4. 代码图 链接

UML 类图

最后,你可以深入到每个组件,展示它是如何以代码实现的;使用 UML 类图、实体关系图或类似工具。

这是一个可选的细节级别,通常可以通过 IDE 等工具按需获得。理想情况下,这种图示应通过工具(例如 IDE 或 UML 建模工具)自动生成,并且你应考虑仅显示那些能够讲述你想讲的故事的属性和方法。这个细节级别不推荐用于除最重要或复杂组件之外的任何内容。

范围: 单一组件。

主要元素: 组件中范围内的代码元素(例如类、接口、对象、函数、数据库表等)。

目标受众: 软件架构师和开发人员。

是否推荐给大多数团队: 否,特别是对于长期文档,因为大多数 IDE 可以按需生成这种细节。

系统景观图 链接

系统景观图

图例

C4 模型提供了一个 单一软件系统 的静态视图,但在现实世界中,软件系统从不孤立存在。 因此,特别是当你负责一个软件系统集合/组合时,了解这些软件系统在特定企业、组织、部门等中的互相配合通常是非常有用的。 本质上,这是一张在所选范围内的软件系统地图, 每个感兴趣的软件系统都有一个 C4 级别的详细图示。

从实际角度来看,系统景观图实际上就是一个系统上下文图,但没有针对特定软件系统的特定焦点。

范围: 一个企业/组织/部门等。

主要元素: 与所选范围相关的人员和软件系统。

目标受众: 技术人员和非技术人员,软件开发团队内部和外部。

动态图 链接

动态图

图例

动态图可以用于展示静态模型中的元素如何在运行时协作来实现用户故事、用例、功能等。 该动态图基于UML 通信图 (之前称为“UML 协作图”)。它类似于UML 时序图 ,但允许以自由形式排列图示元素,并用编号的交互来指示顺序。

范围: 特定功能、故事、用例等。

主要和支持元素: 你可以选择 - 你可以展示运行时的软件系统、容器或组件的交互。

目标受众: 技术人员和非技术人员,软件开发团队内部和外部。

备注: 如果你更喜欢 UML 时序图的视觉风格,也可以使用它。

部署图 链接

部署图

图例

AWS 部署图示例

部署图允许你展示静态模型中的软件系统和/或容器实例如何部署到特定的部署环境 (例如生产、预发布、开发等)中的基础设施上。 它基于UML 部署图

部署节点 代表了软件系统/容器实例运行的位置; 可能是物理基础设施(例如物理服务器或设备), 虚拟化基础设施(例如 IaaS、PaaS、虚拟机), 容器化基础设施(例如 Docker 容器), 执行环境(例如数据库服务器、Java EE Web/应用程序服务器、Microsoft IIS)等。 部署节点可以嵌套。

你还可能需要包括如 DNS 服务、负载均衡器、防火墙等基础设施节点

随意使用 Amazon Web Services、Azure 等提供的图标来补充你的部署图 … 只需确保你使用的任何图标都包含在你的图例中。

范围: 一个或多个软件系统在单一部署环境中的(例如生产、预发布、开发等)。

主要元素: 部署节点、软件系统实例和容器实例。
支持元素: 用于软件系统部署的基础设施节点。

目标受众: 软件架构师、开发人员、基础设施架构师和运维/支持人员等技术人员。

记号

C4 模型是 与记号无关 的,并不规定任何特定的记号。不过,作为起点,一个在白板、纸张、便签、索引卡和各种绘图工具上都适用的简单记号如下所示。

Person

人员

Software System

软件系统

Container

容器

Component

组件

Relationship

关系

然后,您可以使用颜色和形状来补充图示,既可以添加额外的信息,也可以使图示更加美观。

C4 与 UML

虽然上面的示例图使用了“框和线”的记号,但核心图示也可以使用 UML 来表示,采用适当的包、组件和立场。结果 UML 图确实缺乏相同程度的描述性文本,因为有些 UML 工具无法(或不容易)添加这些文本。

以下是系统上下文图、容器图和组件图的三个示例以供比较。

A system context diagram
A container diagram
A component diagram
系统上下文图
容器图
组件图
A system context diagram
A container diagram
A component diagram
A system context diagram
A container diagram
A component diagram

C4 与 ArchiMate

有关如何使用 ArchiMate 创建 C4 模型图的详细信息,请参见 C4 模型、架构视角和 Archi 4.7



图示关键/图例

任何使用的记号应尽可能自解释,但 所有图示应有一个关键/图例 以明确记号的含义。这也适用于使用 UML、ArchiMate 和 SysML 等记号创建的图示,因为并非所有人都了解所使用的记号。

Diagram key



记号、记号、记号

尽管 C4 模型是一个以抽象为优先的方法,并且与记号无关,但您仍需要确保图示记号有意义,并且图示是易于理解的。一种很好的思考方式是问自己每个图示是否可以独立存在,并且在没有叙述的情况下(大致上)能被理解。您可以使用这个简短的 软件架构图示审查清单 来帮助自己。以下是一些与记号相关的建议。

图示

  • 每个图示应有一个标题,描述图示类型和范围(例如,“我的软件系统的系统上下文图”)。
  • 每个图示应有一个关键/图例,解释所使用的记号(例如,形状、颜色、边框样式、线条类型、箭头等)。
  • 缩略语和简称(业务/领域或技术)应为所有受众所理解,或在图示关键/图例中进行解释。

元素

  • 每个元素的类型应明确指定(例如,人员、软件系统、容器或组件)。
  • 每个元素应有简短的描述,以提供关键责任的“一目了然”的视图。
  • 每个容器和组件应明确指定技术。

关系

  • 每条线应表示单向关系。
  • 每条线应标记,标签应与关系的方向和意图一致(例如,依赖关系或数据流)。尽量具体,避免使用像“使用”这样的单一词汇。
  • 容器之间的关系(通常代表进程间通信)应明确标记技术/协议。


替代可视化

最后,不要觉得必须始终使用传统的“框和箭头”图示。尽管这是通常的默认方法,但还有其他往往是交互式的可视化方式,可以用来以非常不同的方式展示相同的 C4 模型抽象。

传统的“框和箭头”图示是文档和演示的默认方法。

D3.js 力导向图是一种非常简洁的方式来可视化较大的软件架构,也提供了方便的方式来探索依赖关系。

Ilograph 的交互式图示提供了一种选择性缩放的方式,使您可以探索整个软件架构模型。

工具

对于设计会议,您可能会发现白板或翻页纸更适合协作和快速迭代。对于长期文档,有许多工具可以帮助基于 C4 模型创建软件架构图。

在选择工具时,请不要忘记问自己一些问题,以了解您需要的功能。图示的作者是谁,他们的技术水平如何?使用“拖放”界面还是“代码即图示”?数据是存储在与源代码相邻的 git 中,还是存储在工具/云服务中?封闭格式还是开放格式?互动图示还是静态图示?免费、付费还是开源?短期文档还是长期文档?仅团队图示还是企业范围的建模?图示的受众是谁,他们如何访问图示/文档?


(例如:系统上下文图、容器图和组件图)
(例如:协作图或序列图)
(例如:显示部署和基础设施问题的图示)
(免费,支持分叉/定制等)
(便于版本控制和集成到构建管道/其他工具中)
(当重命名元素时自动保持多个图示同步)
推荐
(支持使用不同的工具或可视化格式(例如图示、图表等)渲染图示)

常见问题解答

C4 模型的背景是什么?

C4 模型由 Simon Brown 创建,他在担任软件开发者/架构师期间开始教授软件架构。Simon 的培训课程的一部分是一个设计练习,参与者被给予一些需求,要求进行设计,并绘制图示来表达设计。

尽管这是一个以设计为重点的练习,但各种不同的图示显示出大多数人缺乏可视化思想的技能。C4 模型本质上是 Simon 过去用来可视化软件架构的一个形式化表达,经过多年的演变而来。

精确的时间难以确定,但 C4 模型的根源可以追溯到 2006-2009 年左右,图示类型(“上下文”、“容器”、“组件”、“代码”)在 2010 年初命名,"C4" 名称首次使用是在 2011 年初。第四种图示类型在 2015-2016 年期间从“类”重命名为“代码”。

C4 模型的灵感来源是什么?

C4 模型是在一个受敏捷运动影响的时期创建的,那时团队对使用 统一建模语言 (UML) 来记录软件架构并不热衷,甚至不创建图示。尽管如此,C4 模型的灵感来自于 UML 和 4+1 软件架构模型。 总的来说,您可以把 C4 模型看作是这些基本概念的简化版本,旨在 (1) 使软件开发人员更容易描述和理解软件系统的工作原理,(2) 减少软件架构模型/描述与源代码之间的差距。

C4 模型不是倒退吗?为什么要重新发明 UML?为什么不直接使用 UML?

您是否认为 C4 模型是前进还是倒退,取决于您所在的位置。如果您正在使用 UML(或 SysML、ArchiMate 等)并且效果良好,那就继续使用。不幸的是,UML 的使用似乎在下降,许多团队再次退回到使用临时的框图。 鉴于许多团队不想使用 UML(出于各种原因),C4 模型有助于将一些结构和规范引入到软件架构的沟通方式中。对于许多团队来说,C4 模型已经足够了。而对于其他人,也许它是通向 UML 的一个跳板。

有多少人使用 C4 模型?

说实话,没有人知道。Simon 已经亲自教授了超过 10,000 人在 30 多个国家的 C4 模型;会议讲座、视频、书籍和文章也触及了更多的人。其他人也在教授、演讲和撰写关于 C4 模型的内容。 不过,它确实在使用中,从初创公司到全球知名企业都有涉及。

为什么使用“容器”这个词?

像“进程”、“应用”、“服务器”、“可部署单元”等术语都有相应的含义,因此选择了“容器”作为描述组件所在的通用术语。从某种角度来看,容器化的流行使得许多软件开发人员将“容器”一词与 Docker 联系在一起,这是不幸的。 从另一个角度来看,C4 模型中的容器与基础设施(例如 Docker)容器之间有时有很好的对等关系。

虽然许多团队成功地使用 C4 模型,但如果需要,您可以随意修改术语。

我们可以更改术语吗?

这种术语(上下文、容器、组件和代码)对许多组织和各种类型的软件有效。然而,有时一个组织会有现有的术语,人们已经熟悉了。 或者“组件”和“类”可能与使用的技术不容易映射(例如,函数式语言通常使用术语“模块”和“函数”)。

您可以修改描述软件架构的术语,以适应不同的抽象级别。只要确保大家明确理解即可。

如何建模微服务和无服务器架构?

广义上说,当使用 C4 模型来绘制微服务时,有两个选项,尽管这取决于您对“微服务”的定义。

方法 1: 每个“微服务”由一个独立团队拥有
如果您的软件系统依赖于一些在您控制之外的微服务(例如,它们由不同的团队拥有和/或运营),将这些微服务建模为外部软件系统,您无法内部查看。

方法 2: 单个团队拥有多个“微服务”

想象您有一个 API 应用(例如 Spring Boot、ASP.NET MVC 等),读取/写入关系数据库模式。不论您认为“微服务”一词指的是仅 API 应用,还是 API 应用和数据库模式的组合…… 如果这些微服务是您构建的软件系统的一部分(即您拥有它们),则将每个可部署的东西建模为一个容器。 换句话说,您将展示两个容器:API 应用和数据库模式。可以在这两个容器周围画一个框,表示它们是相关/分组的。

无服务器函数/ Lambdas 等也是如此;根据所有权将它们视为软件系统或容器。

如何绘制大型和复杂的软件系统?

即使对于相对较小的软件系统,也很容易尝试将整个故事包含在一个单一的图示中。例如,如果您有一个 Web 应用程序,似乎合乎逻辑的是创建一个组件图,显示构成该 Web 应用程序的所有组件。除非您的软件系统确实如此小,否则您可能会发现图示画布上的空间不足,或者难以发现不会被大量重叠线条困扰的布局。使用更大的图示画布有时可以有所帮助,但大型图示通常难以解释和理解,因为认知负担太重。如果没有人理解图示,那么也没有人会查看它。

相反,不要害怕将那个单一的复杂图示分解为更多的简单图示,每个图示专注于一个特定的业务区域、功能区域、功能分组、界限上下文、用例、用户交互、功能集等。关键是确保每个单独的图示讲述相同总体故事的不同部分,并保持相同的抽象级别。 您还可以使用 替代可视化

图示会很快过时吗?

由于 C4 模型的层级性质,每个图示会以不同的速度变化。

  • 系统上下文图: 在大多数情况下,系统上下文图变化非常缓慢,因为它描述了软件系统所处的环境。
  • 容器图: 除非您正在构建一个大量使用微服务或无服务器函数的系统,否则容器图也会变化缓慢,因为它描述了主要的可部署单元。
  • 组件图: 组件图通常会变化得比前两个更快,因为它描述了容器内部的结构。
  • 代码图: 代码图通常变化得最快,因为它描述了容器内部的类、接口等。代码图的变化是最频繁的。

如果图示随着时间推移而变化不大,那么您应该在长期保存图示,以减少维护的精力。

更多信息

如果您想了解更多关于可视化软件架构和 C4 模型的信息,以下资源是推荐的。

The C4 model for visualising software architecture

这是 Simon Brown 的 《The C4 model for visualising software architecture》 电子书, 可从 Leanpub 购买,格式包括 PDF、EPUB 和 MOBI。 这是一本简短的指南,讲述如何使用 C4 模型可视化您的软件架构。

使用 C4 模型可视化软件架构
Agile on the Beach 2019 - 英国法尔茅斯 - 2019年7月

作为代码的图示 2.0
JBCNConf - 西班牙巴塞罗那 - 2022年7月