C4 模型 - 可视化架构设计
前言
世界上最难的两件事是:
1. 把我的思想放进你的脑袋
2. 把你的钱放进我的口袋
第二点我们不探讨,因为这是众所周知的,不信?过来试试:)
对于第一点,对我们程序员来说,其实也是我个人一直强调的,很多事情的成败,其实就在于掌舵人的思想层面是否认知是一致的,当我们对于一个事物的认知不在同一层面,就好比我们的划桨是不统一的,这是不能发挥最大的生产力。
你碰到过吗?
当我们进入一家新公司的时候,每个人都需要对公司的业务系统进行了解,当你不得不向别人解释系统是如何工作的,业务模块是如何串联的,子系统是如何各司其职的,特别是对于非技术人员来说,你会从代码开始解释吗?
如果是这样的话,这将是最低效且会让人陷入无穷无尽的技术细节里面,如何清晰描述系统让不同人找到自己的关注点,将成为难题。
通常我们会从宏观的架构设计上进行讲解,然而当我们在探讨架构设计的时候,每个人对架构的抽象层次理解都不一样,抽象这种东西,说起来好像存在,但是要具体描述乃至落笔下来,还是非常有难度的。
所以我们需要的是:让程序员和业务人员在讨论系统时候,能有统一的维度和统一标准,这就像是领域驱动设计里面所提倡的统一语言,让所有人在统一的认识中有效的沟通。
鉴于这样的背景,C4 model提出这样的概念来解决这个问题。
C4 模型
C4的理念是,具体把系统分为:System Context(上下文), Container(容器), Component(部件), Code(代码)这四层,每层代表着不同的视图架构,关注点也会不同,所以每层适用于不同的人员,我们会针对当前的人员的角色,找到共同的关注点(合适的层级)来统一认识,然后拓展话题。

当我们使用C4模型来描述自己的软件架构时,可以通过不停的放大,把架构从宏观到细节具体地描述出来。就好比我们看地图一样,总览(System Context)关注的是国家层面,然后到省(Container)的层面,由多个省来构成国家,再下一层,到市(Container),再到市是如何建设起来的(Code)。这四种不同的抽象层次的定义会让我们更容易固定住我们讨论的层次以及共同认识。

我们来看一下每一层的具体含义。
第一层 - System Context
在这一层,我们将不会关注细节,这里提供的是系统级别的总览关系图,这层的关注点应该是用户和系统的交互,而不是协议,技术点等一些具体的体现。所以它的使用人群是非技术人员,这里面描述的是系统级别的交互,谁使用。

在这里,我们可以理解这是一个可供终端用户使用的完整系统(或者多个系统)的描述和专注于该层的使用人员,这里的一个系统可由一个或者多个服务(进程)组成,能完成我们业务的服务组合。所以看到我们用户直接面对的是可用的系统,而一些邮件和权限系统,则属于子系统。
在这里的一些特定技术术语需要澄清一下:一个系统可由多个服务(微服务)组成,也可只有一个服务组成(邮件系统很可能只有一个邮件的收发服务)。
需要特别注意的是,在跟别人探讨这层的时候,尽可能不要引入技术术语,因为这层更多的是使用人员关注的,大家的认知应该是在对系统的正常理解。
第二层 - Container
这一层是上一层Context的继续(我们这里选择的是用业务系统这个系统作为例子),是我们将各个System Context放大(Zoom in)的效果,我们将会看到一个技术栈以及各模块的一个职责和依赖。

这层是给具有技术背景的人员看,这里面描述的是进程级别的应用,这是可直接部署和运行的,通过这层,我们将可以看清软件整体形态以及职责描述。
这里的Container也可以理解为容器,因为我们的应用进程也是按容器为单位部署的。
第三层 - Component
这一层是Container层的继续放大,这里将看到服务的具体组成,如我们的订单服务包含哪些职责的类

我们可以看到,这一层是给开发人员看,这里描述的是系统组成部件、部件之间的层级关系和依赖。
这层的Component,可以理解为java里面的包或者c#里面的程序集,这里描述的是内部的包/程序集相互引用(调用)关系以及包对外部系统的程序的依赖
第四层 - Code
这一层是持续将Component放大的效果(借用一下官网的类图:))。

这一层的使用对象是开发人员,这里描述的是基于UML等图形来描述实现的技术细节,直接反映了代码层面。
找到共同语言
好了,当我们把整个系统通过通过C4 模型设计把不同层次的抽象软件架构描述了出来,我们可以找到各自所关心的层次进行快乐的交流了。
什么?你想给刚来的产品经理讲Component级别的架构?不,你不想,你也不能想,因为他并不关心这个,你能讲的,就是基于Context级别,讲述我们公司的整个产品体系是如何运行以及关联依赖的。
所以,回到我们的前言:让所有人在统一的认识中有效的沟通。这让我们在探讨之前,先找好各自关心的层次,然后再进行交流。这也是C4 模型给我们带来的巨大价值。
我们如何落地?
说了那么多概念,可以来点干货了,如何动手把脑袋中的架构展示出来?
PlantUML
什么是PlantUML? PlantUml是一个支持快速绘制的开源项目,其定义了一套完整的语言,通过文字、代码等工具用于实现UML关系图的描述。
通过PlantUML,我们可以轻松通过代码形式画出自己想要的图形。
这里采用一个流程图作为例子:
@startuml
用户 -> 认证中心: 登录操作
认证中心 -> 缓存: 存放(key=token+ip,value=token)token 用户 <- 认证中心 : 认证成功返回token
用户 -> 认证中心: 下次访问头部携带token认证
认证中心 <- 缓存: key=token+ip获取token
其他服务 <- 认证中心: 存在且校验成功则跳转到用户请求的其他服务
其他服务 -> 用户: 信息
@enduml

PlantUML不仅仅能画出C4 模型架构,还能轻松画出常用的UML图,以及通过安装插件,实现draw.io ,xmind等插件的图形绘画。
使用PlantUML刻画C4
在VSCode中下载PlantUML插件,然后在GitHub上搜索一些好用的PlantUML开源库,直接代码形式画图吧。

补充个人上面图形的PlantUML源码:)

总结
软件架构图是一种非常好的表达方式,可以用它们来表达你将如何构建一个软件系统或者现有的软件系统是如何工作的,而C4 模型则能很好的解决这个问题,它是由一系列分层的软件架构图组成,这些架构图用于描述不同层次的不同的抽象,每层的抽象都会有不同的适用人群。
当我们拥有了C4 模型的方法论之后,面对不同角色人员,我们将清楚的知道,应该宣讲哪层以及该把关注点放在哪层,这样我们将会在统一的意识层面上探讨,做到意识上的统一。
C4 模型 - 可视化架构设计的更多相关文章
- 京东云开发者|软件架构可视化及C4模型:架构设计不仅仅是UML
软件系统架构设计的目标不在于设计本身,而在于架构设计意图的传达.图形化有助于在团队间进行高效的信息同步,但不同的图形化方式需要语义一致性和效率间实现平衡.C4模型通过不同的抽象层级来表达系统的静态结构 ...
- 工程能力之C4模型
概述 刚在InfoQ上看到一篇介绍C4Model的文章,觉得这个模型设计的很赞,很有指导意义,做个简单的记录. Why,为什么需要架构图? ThoughtWorks中国 文章中有几句话我觉得很有道理, ...
- .net架构设计读书笔记--第三章 第9节 域模型实现(ImplementingDomain Model)
我们长时间争论什么方案是实现域业务领域层架构的最佳方法.最后,我们用一个在线商店案例来说明,其中忽略了许多之前遇到的一些场景.在线商店对很多人来说更容易理解. 一.在线商店项目简介 1. 用例 ...
- .net架构设计读书笔记--第三章 第8节 域模型简介(Introducing Domain Model)
一.数据--行为转变 很长的时间,典型的分析方法或多或少是以下两种,第一,收集需求并做一些分析,找出有关实体 (例如,客户. 订单. 产品) 和进程来实现. 第二,手持这种理解你尝试推断一个物 ...
- 支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型
支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型 原创 杨翊(席翁) 阿里巴巴云原生 2020-12-28
- Unity3d 引擎原理详细介绍、Unity3D引擎架构设计
体系结构 为了更好地理解游戏的软件架构和对象模型,它获得更好的外观仅有一名Unity3D的游戏引擎和编辑器是非常有用的,它的主要原则. Unity3D 引擎 Unity3D的是一个屡获殊荣的工具,用于 ...
- Unity3d 引擎原理详细介绍、Unity3D引擎架构设计 - zhibolife
时间 2014-03-24 11:18:00 博客园-所有随笔区原文 http://www.cnblogs.com/zhibolife/p/3620440.html 体系结构 为了更好地理解游戏的 ...
- 解构C#游戏框架uFrame兼谈游戏架构设计
1.概览 uFrame是提供给Unity3D开发者使用的一个框架插件,它本身模仿了MVVM这种架构模式(事实上并不包含Model部分,且多出了Controller部分).因为用于Unity3D,所以它 ...
- Swing程序最佳架构设计—以业务对象为中心的MVC模式(转)
前言: 我打算写一系列关于Swing程序开发的文章.这是由于最近我在做一个Swing产品的开发.长期做JavaEE程序,让我有些麻木了.Swing是设计模式的典范,是一件优雅的艺术品,是一件超越时代的 ...
随机推荐
- guitar pro系列教程(十三):Guitar Pro教程之打谱使用技巧
前面我们有讲过关于{cms_selflink page='index' text='Guitar Pro'}在声音方面的一些使用技巧,Guitar Pro在打谱,试听,伴奏方面对于刚学吉他作谱的朋友们 ...
- FL studio系列教程(十一):FL Studio中如何混音
要想得到"商业"品质的声音,我们就要学会混音.混音就是声音从乐器通道到路由到混音器.混音器中可以设置电平并添加各种效果,比如,添加混响.合唱以及延迟等等,这就是所谓的混音.那么FL ...
- redis启动报错Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接。
报错内容 解决办法 启动redis-server服务 测试 连接成功
- github搭建html网站到外网
最近想自己弄个网站,但又没有服务器可以用,只好借用强大得github来帮忙了,不过GitHub确实有这个功能. 感谢以下大佬得教程,非常得详细,但我觉得还是有必要记录下来. 大佬链接: https:/ ...
- 【ACwing 93】【模版】非递归实现组合型枚举——模拟递归
(题面来自ACwing) 从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案. 输入格式 两个整数 n,m ,在同一行用空格隔开. 输出格式 按照从小到大的顺序输出所有方案,每行1个 ...
- I/O中的 同步异步,阻塞非阻塞
I/O中的同步和异步的概念和线程中不太一样. I/O写的时候,默认是写到页高速缓存就返回的,然后异步刷到磁盘上.而同步的I/O指的是改动写到磁盘上之后才会返回结果.可以通过fsync(),和fdata ...
- dubbo协议之编码请求对象体
上节我们看了如何编码请求头,这节一起看下过程中,对请求对象的编码,涉及对接口,方法,方法参数类型,方法参数进行编码,DubboCodec中重写了这个方法: request.getData向下转型成Rp ...
- jvm系列(二)jvm垃圾收集器与内存分配策略
众所周知,在java语言中,内存分配和回收是由jvm自动管理的.因此内存的分配和回收也是jvm三大功能之一.垃圾收集器(GC)需要完成三件事情: 哪些内存需要回收? 什么时候进行回收? 如何回收? 本 ...
- 技术应用丨DWS 空间释放(vacuum full) 最佳实践
摘要:本文主要介绍如何进行正常的VACUUM FULL 维护,及时释放磁盘存储. 1.背景 目前根据某项目情况,其DWS的磁盘IO性能低.库内数据量大.对象多.数据膨胀严重.若毫无目的性的进行空间释放 ...
- MySQL索引(一)索引基础
索引是数据库系统里面最重要的概念之一.一句话简单来说,索引的出现其实是为了提高数据查询的效率,就像书的目录一样. 常见模型 索引的出现是为了提高查询效率,但是实现索引的方式却有很多种,这里就介绍三种常 ...