用于可视化软件架构的 C4 模型
上下文(Context), 容器(Containers), 组件(Components), 和代码(Code)
1. 一组层次化的抽象(软件系统、容器、组件和代码)。
2. 一组层次化的图表(系统上下文、容器、组件和代码)。
3. 与符号无关。
4. 与工具无关。
C4 模型是一种易于学习、开发者友好的软件架构绘图方法。 优秀的软件架构图有助于软件开发/产品团队内外的沟通、快速引导新员工上岗、架构评审/评估、风险识别(例如 风险风暴)、 威胁建模等。
简介
如果你请建筑行业的人通过视觉方式传达一栋建筑的架构,你会看到的是场地平面图、楼层平面图、立面图、剖面图和细节图。 相比之下,如果你请一个软件开发人员使用图表传达软件系统的架构,你很可能会得到一个混乱的方框和线条的集合…… 不一致的符号(颜色编码、形状、线条样式等),模糊的命名,未标记的关系,通用的术语,缺失的技术选择,混合的抽象层次等。
在我们这个行业中,虽然我们有统一建模语言(UML)、ArchiMate 和 SysML, 但这些是否能够有效地传达软件架构往往是个无关紧要的问题,因为许多团队已经抛弃了它们,转而使用更简单的“方框和线条”图。 放弃这些建模语言是一回事,但或许在追求敏捷的过程中,许多软件开发团队已经失去了视觉传达能力。
代码的地图
C4 模型的创建是为了帮助软件开发团队在前期设计会话中以及在回顾现有代码库时描述和传达软件架构。 这是一种创建代码地图的方式,可以在不同的细节层次上,就像使用 Google 地图一样,可以放大和缩小你感兴趣的区域。
![Google 地图](https://c4model.com/img/map-4.jpg)
![Google 地图](https://c4model.com/img/map-3.jpg)
![Google 地图](https://c4model.com/img/map-2.jpg)
![Google 街景](https://c4model.com/img/map-1.jpg)
第 4 级:代码图(如 UML 类图)可用于放大单个组件,展示该组件是如何实现的。
C4 模型是一种“抽象优先”的软件架构图绘制方法,它基于反映软件架构师和开发人员如何思考和构建软件的抽象。 这一小组抽象和图表类型使得 C4 模型易于学习和使用。 请注意,你不需要使用所有 4 个级别的图表;只需使用那些能够增加价值的图表——系统上下文图和容器图对于许多软件开发团队来说已经足够了。
抽象
为了创建这些代码地图,我们首先需要一组共同的抽象概念,以创建一个通用的语言,用于描述软件系统的静态结构。 软件系统 由一个或多个 容器(应用程序和数据存储)组成, 每个容器包含一个或多个 组件, 这些组件又由一个或多个 代码元素(类、接口、对象、函数等)实现。 并且 人员 可能会使用我们构建的软件系统。
人员
人员代表你软件系统的一个人类用户(例如,演员、角色、人物角色等)。
软件系统
软件系统是最高层次的抽象,描述了向其用户(无论是人类还是其他系统)提供价值的事物。 这包括你正在建模的软件系统,以及你的软件系统依赖的其他软件系统(或反之亦然)。
不幸的是,“软件系统” 这个术语是 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. 系统上下文图 ![链接](https://c4model.com/img/glyphicons-basic-351-link.svg)
系统上下文图是绘制和记录软件系统的一个很好的起点,它让你退后一步,看到大局。绘制一个图示,将你的系统显示为中央的一个框,周围是其用户和它互动的其他系统。
这里的细节不重要,因为这是你的缩小视图,展示了系统景观的大图。重点应放在人员(演员、角色、人物角色等)和软件系统上,而不是技术、协议和其他低级细节。这是一种你可以向非技术人员展示的图示。
范围: 一个单一的软件系统。
主要元素: 范围内的软件系统。
支持元素: 直接连接到范围内的软件系统的人员(例如用户、演员、角色或人物角色)和软件系统(外部依赖)。通常这些其他软件系统位于你自己软件系统的范围或边界之外,你不负责或拥有它们。
目标受众: 所有人,包括技术人员和非技术人员,软件开发团队内外。
是否推荐给大多数团队: 是。
2. 容器图 ![链接](https://c4model.com/img/glyphicons-basic-351-link.svg)
一旦你了解了你的系统如何融入整体 IT 环境,接下来的一个非常有用的步骤是通过容器图缩小到系统边界。 “容器”是指像服务器端 web 应用程序、单页应用程序、桌面应用程序、移动应用、数据库模式、文件系统等。 本质上,容器是一个独立的可运行/部署单元(例如,单独的进程空间),它执行代码或存储数据。
容器图展示了软件架构的高层次结构,以及职责如何分布在其中。它还展示了主要的技术选择和容器之间的通信方式。这是一种简单的、高层次的技术聚焦图示,对软件开发人员和支持/运维人员都很有用。
范围: 单一的软件系统。
主要元素: 范围内软件系统的容器。
支持元素: 直接连接到容器的人员和软件系统。
目标受众: 软件开发团队内外的技术人员,包括软件架构师、开发人员和运维/支持人员。
是否推荐给大多数团队: 是。
备注: 此图未涉及集群、负载均衡器、复制、故障转移等,因为这些在不同环境(例如生产、预发布、开发等)中可能会有所不同。这些信息更适合通过一个或多个部署图来捕捉。
部署图 ![链接](https://c4model.com/img/glyphicons-basic-351-link.svg)
部署图允许你展示静态模型中的软件系统和/或容器实例如何部署到特定的部署环境 (例如生产、预发布、开发等)中的基础设施上。 它基于UML 部署图。
部署节点 代表了软件系统/容器实例运行的位置; 可能是物理基础设施(例如物理服务器或设备), 虚拟化基础设施(例如 IaaS、PaaS、虚拟机), 容器化基础设施(例如 Docker 容器), 执行环境(例如数据库服务器、Java EE Web/应用程序服务器、Microsoft IIS)等。 部署节点可以嵌套。
你还可能需要包括如 DNS 服务、负载均衡器、防火墙等基础设施节点。
随意使用 Amazon Web Services、Azure 等提供的图标来补充你的部署图 … 只需确保你使用的任何图标都包含在你的图例中。
范围: 一个或多个软件系统在单一部署环境中的(例如生产、预发布、开发等)。
主要元素: 部署节点、软件系统实例和容器实例。
支持元素: 用于软件系统部署的基础设施节点。
目标受众: 软件架构师、开发人员、基础设施架构师和运维/支持人员等技术人员。
记号
C4 模型是 与记号无关 的,并不规定任何特定的记号。不过,作为起点,一个在白板、纸张、便签、索引卡和各种绘图工具上都适用的简单记号如下所示。
然后,您可以使用颜色和形状来补充图示,既可以添加额外的信息,也可以使图示更加美观。
C4 与 UML
虽然上面的示例图使用了“框和线”的记号,但核心图示也可以使用 UML 来表示,采用适当的包、组件和立场。结果 UML 图确实缺乏相同程度的描述性文本,因为有些 UML 工具无法(或不容易)添加这些文本。
以下是系统上下文图、容器图和组件图的三个示例以供比较。
C4 与 ArchiMate
有关如何使用 ArchiMate 创建 C4 模型图的详细信息,请参见 C4 模型、架构视角和 Archi 4.7。
图示关键/图例
任何使用的记号应尽可能自解释,但 所有图示应有一个关键/图例 以明确记号的含义。这也适用于使用 UML、ArchiMate 和 SysML 等记号创建的图示,因为并非所有人都了解所使用的记号。
记号、记号、记号
尽管 C4 模型是一个以抽象为优先的方法,并且与记号无关,但您仍需要确保图示记号有意义,并且图示是易于理解的。一种很好的思考方式是问自己每个图示是否可以独立存在,并且在没有叙述的情况下(大致上)能被理解。您可以使用这个简短的 软件架构图示审查清单 来帮助自己。以下是一些与记号相关的建议。
图示
- 每个图示应有一个标题,描述图示类型和范围(例如,“我的软件系统的系统上下文图”)。
- 每个图示应有一个关键/图例,解释所使用的记号(例如,形状、颜色、边框样式、线条类型、箭头等)。
- 缩略语和简称(业务/领域或技术)应为所有受众所理解,或在图示关键/图例中进行解释。
元素
- 每个元素的类型应明确指定(例如,人员、软件系统、容器或组件)。
- 每个元素应有简短的描述,以提供关键责任的“一目了然”的视图。
- 每个容器和组件应明确指定技术。
关系
- 每条线应表示单向关系。
- 每条线应标记,标签应与关系的方向和意图一致(例如,依赖关系或数据流)。尽量具体,避免使用像“使用”这样的单一词汇。
- 容器之间的关系(通常代表进程间通信)应明确标记技术/协议。
替代可视化
最后,不要觉得必须始终使用传统的“框和箭头”图示。尽管这是通常的默认方法,但还有其他往往是交互式的可视化方式,可以用来以非常不同的方式展示相同的 C4 模型抽象。
常见问题解答
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 模型的信息,以下资源是推荐的。
这是 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月
以下是一些提到 C4 模型的重要资源:
- InfoQ: C4 模型软件架构
- InfoQ: O modelo C4 de documentação para Arquitetura de Software
- InfoQ: 用于软件架构的 C4 模型
- InfoQ: ソフトウェアアーキテクチャのためのC4モデル
- Spotify Engineering: 软件可视化 - 挑战,接受
- The Engineering Leader: 关于 C4 架构设计的片刻与 Amar Mehan
- Open Agile Architecture™,The Open Group 的标准
- 使用 ArchiMate® 语言进行敏捷架构建模
- 软件架构基础 (Mark Richards, Neal Ford)
- 设计它! (Michael Keeling)
- Spring 5.0 软件架构 (René Enríquez, Alberto Salazar)
- 软件架构 (Cesare Pautasso)
- Martin Fowler: 建设基础设施平台 - 传达您的技术愿景 (Poppy Rowse 和 Chris Shepherd)
- 维基百科
旨在支持 C4 模型的 Structurizr DSL 也出现在 ThoughtWorks 技术雷达 - 技术 - 作为代码的图示 上。