简介: 软件工程也是工程,因而传统工程制图的一些根本实践,在软件行业同样实用。但另一方面,软件与实体制造业之间还是有着本质区别,所以在制图方面的需要和形式也天壤之别,无奈间接套用。作为软件行业的从业者,你能够齐全不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。
作者 | 楚衡
前言
“架构制图”这词乍一听仿佛有些艰涩,但如果提起“工程制图”,置信绝大部分工科背景的程序员们都不会生疏,甚至还能独特感叹下那些年一起伏在宿舍左手圆规,右手直尺,徒手作图到深夜的日子。
软件工程也是工程,因而传统工程制图的一些根本实践,在软件行业同样实用。但另一方面,软件与实体制造业之间还是有着本质区别,所以在制图方面的需要和形式也天壤之别,无奈间接套用。作为软件行业的从业者,你能够齐全不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。
本文在后半段将介绍如何用图去 形容 (describe)和 传播 (communicate)你的架构设计。值得强调的是,本文并不会侧重于繁多的办法和工具,而是更心愿关注那些优良办法背地的通用方法论,即架构制图的 实质 、 共性 和最佳实际。心愿本文能起到引子作用,激发大家对本人日常工作中对于架构和制图局部的关注、扫视与思考;如果还真能帮忙大家晋升一点点制图效率和成果,那就更好不过了。
什么是软件架构?
- 软件架构定义
IEEE 给出的定义:架构是环境中该零碎的一组根底 概念(concepts)和 属性(properties),具体表现就是它的 元素(elements)、关系(relationships),以及设计与演进的 根本准则(principles)。
CMU 软件工程研究院的定义:架构是用于推演出该零碎的一组 构造(structures),具体是由软件 元素(elements)、元素之间的 关系(relationships),以及各自的 属性(properties)独特组成。
Uncle Bob 在 Clean Architecture 一书中给出的定义:架构是创建者给予该零碎的 状态(shape)。这个状态的具体模式来源于对系统 组件(components)的 划分 和排列 ,以及这些组件之间相互 通信 的形式。
- 架构外围因素
综合上述各种权威定义,软件系统的架构通常须要蕴含如下四类外围因素:
- 元素(elements):将零碎拆分为一组元素 – 模块、组件、构造体、子系统;
- 关系(relationships):不同元素之间的关系 – 交互、依赖、继承、组合、聚合;
- 属性(properties):每个元素具备的属性 – 名称、职责、接口、实现限度等;
- 原理(principles):为什么这么设计 – 拆分根据、设计准则、决策起因等。
为什么架构很重要?
- 架构是零碎实现的蓝图
最近有部很火的网剧叫《摩天大楼》,讲述了一段匪夷所思的悬疑故事。为什么扯这个呢?因为我想借用这个剧的题目来问个问题:摩天大楼是由谁建起来的?兴许你心里会默念:废话,不就是建筑工人们一砖一瓦堆起来的嘛。认真再想想?背地是不是还有一堆操碎了心的修建设计师(比方剧中帅气的林大森)和土木工程师们?他们尽管不搬砖也不扛水泥,但如果没有他们产出的那些繁琐谨严的 设计图纸,摩天大楼是是不可能像农村自建房一样仅凭工人们各自的教训与想象力就能疾速安稳地竖立起来的。
正是靠着这些图纸所描绘出来的 工程蓝图(blueprints),才让成千盈百工人们的分工合作和验收规范有了根据:大家只须要照着蓝图,循序渐进地把本人所负责的那些砖瓦添上去就行了;只有蓝图正确,且施工过程也没有偏差,最终顺利竣工只是个工夫问题。
与修建、汽车或者任何其余工程行业一样,软件在落地实现(编码)之前也须要先有蓝图;而其中最重要的一份蓝图,就是 架构设计 。没有架构,仅凭程序员本人脑子里的含糊构想,兴许你能够像传统手艺人一样单独发明出一些美妙有用的小东西(比方 Linux 0.01 版本),但不太可能 以工程的形式协同一个团队 独特建造起一个与摩天大楼规模相似的 简单软件系统(比方古代的 Linux 零碎)。一方面,人类的思维能力终归无限,必须依附架构这种高度形象和简化的蓝图,能力让简单零碎的发明、了解、剖析和治理变得可行;另一方面,量级达到肯定水平的大型零碎,也只能依附多人分工合作能力实现,而架构也正是多人沟通合作的重要根底。
- 架构是沟通合作的根底
软件我的项目的最终价值产出就是软件系统,而架构作为软件系统的灵魂和骨架,能够起到如下作用:
- 了解对齐 :所有软件系统的目标都是为了实现用户需要,但实现的路径有有限种可能性(相比传统工程行业,软件的灵活性更大、常识迭代更快)。架构设计就是去抉择其中一条最合适的实现路径,因而其中会波及十分多要害的 选路决策 (为什么要这么拆分?为什么抉择 A 技术而不是 B?)。这些重要的技术决策须要通过 架构形容 这种模式被记录和同步,能力让项目组所有成员对整个零碎的了解对齐,造成共识。
- 工作量化 :项目管理最重要的步骤之一就是 工时评估 ,它是确定我的项目排期和里程碑的间接根据。显然,只通过 PRD / 交互图是无奈迷信量化出我的项目工作量的,因为很难直观判断出一句简短需要或一个简略页面背地,到底要写多少代码、实现起来难度有多大。有了清晰明确的架构之后,实践上绝大部分开发工作都能做到 可见 、 可预测 和可拆解,自然而然也就可能被更精确地量化。当然,精准的工作量评估在 IT 行业内也始终是个未解之谜,理论的工期会受太多未知因素影响,包含程序员的技能熟练度、情绪好不好、有没有吃饱等。
- 规范术语 :编程作为一种具备创造力的工作,从某种角度看跟写科幻小说是相似的。好的科幻小说都喜爱造概念,比方三体中的智子,如果没看过小说必定不晓得这是个啥玩意儿。软件系统在造概念这一点上,相比科幻小说只有过之而无不及,毕竟小说里的世界通常还是以事实为背景,而软件中的世界就全凭造物者(程序员)的设想(建模)了。略微简单一点的软件系统,都会引入一些畛域特定甚至全新创作的概念。为了防止在我的项目过程中呈现鸡同鸭讲的沟通阻碍和了解歧义,就必须对形容这些概念的术语进行对立。而架构的一个重要目标,就是定义和解释分明零碎中波及的所有要害 概念 ,并在整个架构设计和形容过程中应用规范和统一的 术语,真正做到让大家的沟通都在一个频道上。
- 言之有物 :就跟探讨产品交互时须要对着原型图、探讨代码细节时须要间接看代码一样,架构是在探讨一些较高维技术问题时的 必要实物(具体的实物化模式就是所谓架构形容)。否则,要么一堆人对着空气谈(夸夸其谈都说不上),要么每次沟通时都从新找块白板画一画(费时费力且容易遗落信息,显然不是长久之计)。
- 常识积淀 & 新人培训 :架构应该被作为与代码等同重要的 文档资产 继续积淀和保护,同时也是我的项目新人疾速了解和上手零碎的重要依据。不要让你的零碎跟公司内某些祖传遗留零碎一样 —— 只有代码遗留了下来,架构文档却没有;只能靠一些口口相传的残留设计记忆,苦苦维系着我的项目的生命连续。
- 架构决定了产品质量
如何掂量一个软件产品的品质?上图是 ISO/IEC 25010 规范定义的软件产品品质模型,包含以下 8 个大类:
- 性能适宜性:性能残缺度、性能正确性和性能失当性;
- 性能效率:工夫体现(e.g. 响应工夫)、资源利用和容量;
- 兼容性:共存能力(e.g. 多版本组件共存)和互操作性;
- 可用性:可学习性、可运维性、用户谬误爱护(e.g. 主动纠错)、UI 好看度、可拜访性;
- 可靠性:成熟度、可用性、容错性、可恢复性;
- 安全性:机密性、完整性、不可伪造性、权威性和可审计;
- 可维护性:模块度、可复用性、可剖析性、可修改性、可测试性;
- 可移植性:可适配性、可安装性、可替代性。
上述品质模型中列出的所有点,都是架构设计须要着重思考的。其中除了性能适宜性以外,其余所有点都属于 非性能需要 的领域,这也是辨别架构好坏的真正分水岭 —— 好的架构设计,不会停留在仅满足性能需要这一最根本的需要档次上(最坏的架构设计也同样能做到),更重要且更难以应答的是其余泛滥的非性能需要。
当然,鱼与熊掌不可兼得。架构与人生一样,也是一场 衡量 的游戏,弄不好就跟第八季的龙母一样的下场:既要又要还要,最初反而什么都得不到。好的架构师更应该像雪诺同志学习,外表上“know nothing”,实际上“know everthing”:分明零碎所有 利益相关者 (stakeholders),致力开掘各方的 次要述求 (concerns),相应均衡本人的 架构决策(decisions),最终实现你好我好大家好的终极架构指标。
- 我还能说出更多理由
要不是篇幅所限,这一页 PPT 显然不够装:
- 架构蕴含零碎所有最重要的 晚期决策,这些决策会进而影响后续所有大大小小的技术决策。因而,晚期的架构设计须要十分谨严和谨慎,要尽可能“一次做对”(尽管很难),否则越往后纠错的老本越高;
- 架构在组织内具备十分高的 复用价值,因为同一组织内的产品之间肯定会具备很多共性(需要、限度、环境等),很适宜在架构层面进行最大化复用,防止反复解决类似的问题;
- 康威定律 指出,软件架构反映了组织构造。这个论断反过来也成立:好的架构也会 让组织构造变得更高效;
- 越宏大和简单的零碎,架构越重要,因为只有好的架构能力无效 管制、治理和升高零碎复杂度;
- 是不是越听越糊涂,好像架构有无数种诠释和意义?不用过于纠结,依照 GoF 的设计模式所述:Architecture is about the important stuff. Whatever that is. 对,管它是啥,记住架构很重要就够了。
如何设计一个好的架构?
了解了架构的概念和重要性后,真正的架构师修炼之路才刚刚开始。如何设计一个好的架构?这显然是一个十分博大精深的主题,但并不是本文的重点,因而这里只简略列举了一些根本思维(准则 )和经典套路( 模式)。当然,架构设计更靠近一门教训学科,仅停留在能脱口而出一些玄乎而高大上的实践概念必定是不够的,须要结合实际工作内容和业务场景多多实际和琢磨才行,否则只能算是彷徨在架构的门外,连入门都谈不。
- 架构准则(principles)
SOLID 准则 是一套比拟经典且风行的架构准则(次要还是名字起得好):
- 繁多职责:与 Unix 哲学所提倡的“Do one thing and do it well”不约而同;
- 开闭准则:用新增(扩大)来取代批改(毁坏现有封装),这与函数式的 immutable 思维也有殊途同归之妙;
- 里式替换:父类可能呈现的中央子类肯定可能呈现,这样它们之间才算是具备继承的“Is-A”关系;
- 接口隔离:不要让一个类依赖另一个类中用不到的接口,简略说就是最小化组件之间的接口依赖和耦合;
- 依赖反转:依赖抽象类与接口,而不是具体实现;让低层次模块依赖高层次模块的稳固形象,实现解耦。
此外,咱们做架构设计时也会尽量遵循如下一些准则(与上述 SOLID 准则在实质上也是相通的):
- 正交性:架构同一档次拆分出的各组件之间,应该尽量放弃正交,即彼此职责独立,边界清晰,没有重叠;
- 高内聚:同一组件外部应该是高度内聚的(cohesive),像是一个不可分割的整体(否则就应该拆开);
- 低耦合:不同组件之间应该尽量减少耦合(coupling),既升高互相的变动影响,也能加强组件可复用性;
- 隔离变动:许多架构准则与模式的实质都是在隔离变动 —— 将预期可能变动的局部都隔离到一块,缩小发生变化时受影响(须要批改代码、从新测试或产生故障隐患)的其余稳固局部。
- 架构模式(patterns)
架构模式(architectural patterns)与咱们常探讨的设计模式(design patterns)并不是一码事,但如果仅从“模式”这个角度去解读,两者的理念都是统一的:针对 给定上下文 中经常出现的问题的 通用、可复用的解决方案。最次要的区别在于,架构模式会更高维形象和偏全局整体(毕竟是使用在架构设计层面)。
常见的架构模式,既包含一些传统模式(e.g. 分层、C/S、MVC、事件驱动),也包含一些新兴玩法(e.g. 云原生、微服务、Serverless)。不同模式有不同的实用场景,没有哪一种模式能通杀所有需要。成熟的架构师应该像一个沉着到冒得感情的杀手,永远只会主观地评估和抉择最适宜当下的解决伎俩,即便那么做会显得简略乏味;相同,不成熟的架构师,二心总想着搞事件(e.g. 强行套用微服务架构),而不是真正搞定问题。
怎么形容你的架构设计?
有了良好的架构设计,万里长征之路就曾经走了一大半。就像是青年导演第一次遇上好剧本,心潮澎湃两眼放光,好像曾经预感了电影上映后的票房盛况。当然,剩下的一小半路,并不会如设想中那么平坦 —— 同样的剧本,不同导演拍进去会有质一样的区别。好的“最佳导演”,即便面对不是“最佳剧本”的剧本,也有能力拍出“最佳影片”。同样,好的架构师,也应该有能力形容好一个不错的架构设计;即便做不到为精彩的内容加分,也不应该因为模式上没形容好而丢分,否则就会像高考作文丢了卷面分一样憋屈和心酸。
- 架构形容的意义
为什么要形容架构?让它只存在我深深的脑海里不行吗?西方人有句谚语:好忘性不如烂笔头。任何没有长久化的货色都是易失的(volatile),就跟内存一样。另一方面,就如前文所述,架构是沟通合作的根底,不通过架构形容(Architecture Description)积淀下来让所有我的项目干系人都能看到,那就失去了沟通和流传的惟一载体。
依据集体察看,大家对“架构须要形容”这一点都没异议,所以绝大部分我的项目都或多或少会产出一些有模有样的架构形容文档。但“有架构形容”和“有好的架构形容”,这之间的鸿沟是微小的,甚至比“没有”和“有”之间的差异还大。如果你也跟我一样,饱经沧桑阅尽有数架构文档,曾拍手叫好心怀感谢过,也曾拍着大腿愤恨不已过,应该也能感同身受。
- 架构形容的形式
对于同一件事物,作家会抉择用文字来叙述,而画家却会用图画。只管两者想要传播的信息是统一的,但形容形式的不同也会带来成果上的微小差别。架构形容也分 文字(Text)和 图(Diagram)两种模式,两者各有千秋:
- 文字的背地是由一套谨严和齐备的语言作为撑持,因而其形容能够做到十分 精准 和详尽 ,而且编写起来也很不便,轻易关上个记事本软件都能写;此外,就跟写代码一样,文字很易于做 版本治理,借助简略的文本 diff 工具就能高深莫测地比照出不同版本之间的细节差别;
- 相比而言,图并不具备以上文字所独有的特点,但也有本人的独特劣势:图是 直观 而形象 的,适应了人类与生俱来的视觉辨认本能;图的 表达能力更强 ,很多时候一小张图所能传播出的信息(比方空间地位关系、色彩分类、图标形态),兴许用一千行字也不足以残缺精确地形容进去,即所谓“ 一图胜千言”。
聪慧的你冷笑了一声:哼,又不是小孩子非得做选择题,难道不能够文字与图都要吗?当然能够,现实的架构形容肯定是 图文并茂 的。但事实世界显然比现实残暴,理论软件我的项目中很难给你留足工夫先憋出一篇完满的架构文档。如果以成年人的思维去思考投入产出比(ROI),那么你肯定会优先选择画图。
- 为什么你应该优先画图?
麻利软件开发宣言中提到:相比详尽的文档,可运作的软件更加重要(Working software over comprehensive documentation)。这么说当然不代表就不必写文档了,只是提倡 没必要写过于详尽的文档。为什么?因为详尽的文档须要消耗大量的编写和保护老本,不合乎麻利开发的小步迭代和疾速响应变动等准则。
那么,在现在这个全面麻利开发的时代,如何也顺应潮流 更加敏捷地编写架构文档 呢?ROI is your friend —— 不求多,但求精,尽量用起码的笔墨表白出最外围的内容。从 内容 上来说,ROI 高的局部个别是偏顶层的整体架构或最外围的要害链路,这点在后文的 C4 模型理念中也有体现。而从 模式 上来说,图在文字背后具备无可比拟的表达力劣势,显然是 ROI 更高的抉择。
- 为什么你须要学习画图?
多画图是没错,但有必要专门学习吗?又不是素描彩笔水墨画,只是画一堆条条框框而已,略微有点工程常识的都能上。画的有点丑?那没关系,顶多再动用点与生俱来的艺术美感,把这几条线对对齐那几个框摆摆正,再整点五彩斑斓的背景色啥的,不就显得很业余了嘛?
看到这里,屏幕前的你又轻蔑一笑:哼,显然没这么简略。的确,情理说进去大家都懂,架构制图与工程制图一样,都是一件须要下功夫认真谨严看待的事件。但事实中大部分人还真没这时间去下那功夫,比方下面贴的两幅很常见的架构图。第一张图不必多说,这种草图本人涂涂抹抹挺好,但拿进去见人就是你的不对了。那第二张图呢,看上去仿佛还挺像那么回事的?并不是,如果你更认真地去琢磨,就能发现这张图底下所暗藏的很多含糊和不谨严之处(可参考这张图的起源文章:The Art of Crafting Architectural Diagrams)。
所以,能画图并不代表能画好图 ;要想制得一手既丑陋又 可读 的好图,还是须要通过继续学习与刻意练习的,很难仅凭直觉和悟性就能把握其中的要害要领。此外,谬误的图往往比没有图还要蹩脚,即便你只是抱着“有图就行,差不多那个意思得了”的心态,也至多应该了解一些迷信制图的要害因素,防止给原本就曾经很简单难做的我的项目又蒙上一层含糊滤镜,甚至起到混同和误导的副作用。
- 架构制图的指标
探讨具体的制图办法和工具前,咱们须要先竖立清晰的制图指标。工具是人类进化的阶梯,但如果了解和利用不当,则很容易反过来被工具所限度甚至奴役,忘了最后创造和应用工具的初心。对于架构制图而言,曾经有那么多不拘一格的办法与工具,应用它们的初心是什么呢?我认为实质上都是想把制图这个过程 从一门自在的手艺变成一项迷信的工程:零碎、谨严、残缺、标准化,同时能做到可反复、可继续和高效。
P.S:过后做 PPT 太赶,所以从这个章节开始的配图,只能被迫走极简路线了,还请见谅。。。
架构制图办法与工具
通过后面几个章节的“简短”铺垫,置信大家对架构制图的背景常识都曾经产生了足够的认知。本章节将会具体列举和形容一些典型的架构制图办法与工具,其中有常见的也有常见的,重点是心愿能通过各种办法的横向比照,加深大家对制图办法实质的了解。
- 办法一:UML
UML 应该是大部分人最相熟的制图办法了,最新的 UML 2.x 版本由以下两大类图组成:
- 结构图 (Structural Diagrams):通过对象、属性、操作和关系等形式,强调零碎的 动态构造,其中最常见的类型包含类图(Class Diagram)、组件图(Component Diagram)和部署图(Deployment Diagram);
- 行为图 (Behavioral Diagrams):通过展现对象之间的协作关系以及对象外部的状态扭转,强调零碎的 动静行为,其中最常见的类型包含用例图(Use Case Diagram)、流动图(Activity Diagram)、时序图(Sequence Diagram)和状态机图(State Machine Diagram)。
作为 通用 的“对立建模语言”,UML 总共蕴含了 14 种不同类型的图,能够全面笼罩软件设计畛域各种制图需要,当然也包含了架构制图。同时,也正是因为 UML 把本人当成了一门语言,因而其各种记号(notion)和语义(sematics)都有十分 谨严 的定义,不会呈现含糊或者歧义问题。最初,UML 通过几十年的倒退和推广,也早已成为世界范畴内 宽泛应用 的规范 标准,其所带来的的隐性价值就是:在团队内应用 UML 进行沟通的老本是比拟低的,因为能够假设绝大部分技术人员都能了解 UML 的含意和用法。
然而,UML 也非万能(尽管历史上曾一度把它当成软件设计的银弹),它最被人诟病的毛病就是过于简单。这也不能怪 UML,毕竟它就是要被设计为足够通用、谨严和弱小的,这些指标都与“简略”南辕北辙,并让它一步步演变到了明天这个简单刻板的硕大无朋模样。尽管下面咱们自信地假设了技术人员大多都懂 UML,但这个“懂”如果带上一个水平量词,我感觉均匀能到 20% 就不错了 —— 绝大部分也就能意识几个常见的类图、时序图,预计都很难精确说出类图中各种箭头的含意。
无论怎么说,UML 仍然应该是每个程序员的制图工具箱中最罕用和必备的工具之一。当然,也不应该是惟一,因为上面也还有些不能错过的好货色。
- 办法二:4+1 View Model
“4+1”是啥?不晓得没关系,听过“6+1”吗?对,就是那个小时候常看的“十分 6 +1”节目。它跟“4+1”之间的关系,就跟它们与邵佳一、张嘉译和沈佳宜之间的关系一样,除了赶巧共用了同一个后缀发音以外,八竿子打不着。
所以,“4+1”到底是指什么?让咱们来 Wiki 一下:“4+1”是一种 视图模型 (view model),能够通过多种共存的视图形容软件密集型零碎的架构。这些视图基于不同我的项目干系人(利益相关者)的 视点(viewpoint),例如:终端用户、开发者、零碎工程师和项目经理。“4+1”由 4 种根底视图和一些通过筛选的用例或场景(即额定的“+1”视图)组成,各自的具体含意如下:
- 逻辑视图(Logical view):形容零碎为终端用户提供的性能,个别会通过 UML 中的类图和状态图来示意;
- 过程视图(Process view):形容零碎的动静行为,包含流程和交互等,个别会通过 UML 中的时序图、流动图和通信图来示意;
- 开发视图(Development view):从程序员的视角来论述零碎,也被称为“实现视图”,个别会通过 UML 中的组件图和包图来示意;
- 物理视图(Physical view):从零碎工程师的角度来形容零碎,包含零碎组件的物理拓扑、各组件之间的物理连贯,也被称为“部署视图”,个别会通过 UML 中的部署图来示意;
- 场景(Scenarios):通过一小组用例或场景来形容架构,包含零碎中各种对象和过程之间的交互时序,也被称为“用例视图”。这些场景会被用于辨认架构元素(architectural elements)以及论述和验证整个架构设计,也能够被作为架构原型的测试终点。
尽管下面提到“4+1”的各种视图个别都是用 UML 图来示意,但实际上“4+1”自身是一种 通用 的视图模型,并没有限度绘图的记号和工具。对于工程师而言,这种偏学院派的办法可能这辈子都不会间接用到,但其中蕴含的一个要害架构制图思维十分有价值:架构须要通过多种 视图 来形容,而这些视图是来源于不同我的项目干系人的 视点(角度);只有这样能力产生一整套全面、平面且主观的架构形容。
- 办法三:C4 Model
C4 模型是一种“形象优先”(abstraction-first)的架构制图办法,它也是受后面的 UML 和“4+1”视图模型所启发,但相对而言要更加简略和轻量,只蕴含大量的一组形象和图表,很易于学习和应用。
1)定义、理念与要害思维
C4 模型通过容器、组件、代码以及人这几个 形象 来形容一个软件系统的 动态 构造,它的核心理念是心愿像 Google Map 一样,通过 不同档次 的细节,为代码建设一种能够 放大 和放大 的导览图。它最要害的思维就是 自顶向下 对系统的动态构造进行 逐级拆分,顺次形容各层次对象的职责、关系和内部依赖。除了外围的层次化动态构造视图,它还能够蕴含动静视图、部署视图等补充视图。
下面的左图展现了 C4 模型中各层次形象之间的 映射关系:1 个软件系统由 1~N 个容器组成,1 个容器由 1~N 个组件组成,1 个组件由 1~N 个代码构造组成。右图是以简略的 Spring PetClinic 我的项目为例,演示了一个实在软件系统在 C4 模型下的层次结构:最上层就是 PetClinic 软件系统,它能够拆分为数据库、Web 利用等几个容器;Web 利用又能够进一步拆分出 ClinicService 这个组件,而这个组件下又蕴含了 ClinicService 接口类、ClinicServiceImple 实现类、Owner / Pet / Visit 等畛域对象类。
应用 C4 模型进行架构制图,实质上就是对上述几种形象进行 可视化。具体的做法是顺次建设如下几类从粗到细的结构图:Context、Container、Component 和 Code(可选),这也是 C4 模型名称的来历。
2)Level 1:System Context diagram
零碎上下文图作为第一级(L1),提供了一个展现零碎全貌的 顶层大图(big picture)视角,包含最核心的软件系统、周边的用户以及其余有交互的零碎。其中最要害的两个概念别离是:
- 人(Person):即应用软件系统的用户,例如一个在线商城零碎的消费者、经营小二、系统管理员等;
- 软件系统(Software System):作为最高档次形象,形容了给用户发明价值的软件制品;既包含以后正在设计的软件系统,也包含该零碎所依赖(或被依赖)的其余软件系统。一个软件系统通常是由单个软件开发团队所负责。
在绘制零碎上下文图时,不须要关怀诸如技术栈、协定等任何底层细节。这类图的受众是最广的,因为任何人都能够了解并从中获取到足够的信息,包含技术人员和非技术人员,也包含团队内成员和团队外成员。
3)Level 2:Container diagram
通过 L1 的上下文图了解了零碎在整个 IT 环境中的定位后,下一步就是把零碎这个框框放大,具体看下其中蕴含了哪些“容器”(Container,留神不要跟 Docker 容器搞混了噢!)。C4 模型中的容器是指单个利用或数据存储,通常能够独立部署和运行(有独立的过程空间,通过 IPC 机制相互通信),例如:SpringBoot 微服务、React SPA、挪动 App、数据库、Serverlss 函数、Shell 脚本。
L2 的容器图不仅展现了零碎的进一步职责拆分,还包含了次要的技术选型、容器之间的通信形式等要害架构信息。这类图能够面向全副的技术人员,既包含架构师、开发者,也包含运维人员、技术支持等。
4)Level 3:Component diagram
持续后面的套路,下一步就是把零碎中各个容器再别离进行部分放大,将每个容器进一步拆分成多个组件(Component)。在 C4 模型中,组件是指一组通过良好接口定义封装在一起的相干性能(通常运行在 同一个过程空间内),例如:Spring 里的一个 Controller(不只包含定义了 REST 接口的 Controller 主类,也包含背地所有相关联的实现类,如 Service/Repository 等)。
与容器图相似,L3 的组件图也不只蕴含了容器的组件划分,还包含各个组件的职责定义、技术与实现细节等。随着档次的下沉和细节的增多,组件图的受众范畴进一步缩窄,个别只实用于软件架构师和开发者(其余角色没必要了解,个别也了解不了)。
5)Level 4:Code(可选)
再持续对组件进行放大,所能看到的最底层和细节的信息,就是 L4 的代码(Code)了。当然,这里所谓的“代码”还是以图的模式(e.g. UML 类图、数据库 E/R 图)展现类或文件粒度的代码构造,并不是真正的代码自身。即便如此,代码图在 99% 的架构形容场景下也仍然过于详尽,一方面数量宏大,绘制老本很高 ;另一方面易于变动, 保护老本 也十分高。因而,个别只有十分重要和简单的组件才须要用到这一层级进行形容。如果的确须要绘制,也应该优先思考 自动化 的形式,比方很多 IDE 就反对主动生成 UML 类图。
6)补充图:Landscape / Dynamic / Deployment Diagram
除了上述各个档次的动态结构图,C4 模型还提出了一系列的补充图(Supplementary diagrams),包含:
- 零碎全景图 (System Landscape diagram):全景图与零碎上下文图的绘制办法相似,区别在于它是从企业或组织角度全景地展现出所有软件系统(包含与以后零碎没有间接关联的)以及相干的用户和零碎交互,即 进一步放大架构图的 scope;
- 动态图 (Dynamic diagram):因为结构图天生只能形容出零碎的动态构造属性,因而 C4 模型中举荐应用 UML 中的通信图、时序图等,对系统中要害链路的动静行为进行补充形容,即“ 动静联合”;
- 部署图 (Deployment diagram):除了缺失动静属性,上述结构图还有一个局限性:只形容了零碎的形象逻辑架构,并没有形容出零碎理论部署时的具体物理架构。因而,C4 模型举荐再应用 UML 的部署图,对系统逻辑节点(个别是 L2 的“容器”粒度)与物理节点(e.g. 物理机 / 虚拟机 / Docker 容器 / 利用 Runtime)之间的映射关系进行补充形容,即“ 虚实联合”。
联合了这些补充图后的 C4 模型,才是能够全面与平面地形容出软件架构方方面面的 齐全体 架构制图办法。
- 办法四:arc42
严格来说,arc42 并不是一种架构制图办法,而是一个 架构文档模板 。尽管如前文所说,在架构形容中“图”是比“文字”更高优的抉择,但理论我的项目过程中你究竟还是须要产出一份绝对残缺、有图有文字的架构文档。arc42 就是专门用于帮忙大家更好地编写架构文档;而作为架构文档中最重要的架构图,显然 arc42 也不会放过 —— 其中多个外围章节都与架构图无关,且详细描述了相应的制图办法。这里不会具体开展介绍 arc42( 不能抢了下一篇文章的饭碗),只会简略介绍下 arc42 中制图办法与 C4 模型的异同。
平凡的思维都是类似的,arc42 也不例外。上方左图的右侧局部,概括了 arc42 模板中与制图相干的几个外围章节,别离是:
- 第 3 章 – Context:该章节用于介绍零碎的背景和上下文,因而其制图思路简直等同于 C4 模型中的 L1(零碎上下文图);
- 第 5 章 – Building block view:该章节用于介绍零碎的根本形成因素,依照官网指导思想也与 C4 模型中的自顶向下层次化拆分思维无异,惟一区是 arc42 并没有规定拆分的具体档次,只有有须要能够依照“黑盒 -> 白盒”的套路始终拆到底;
- 第 6 章 – Runtime view:看名字就无需解释了,就等同于 C4 模型中补充的运行时视图;
- 第 7 章 – Deployment view:同样地,这里也等同于 C4 模型中补充的部署视图;但有一点,arc42 强调部署视图也能够相似构造视图一样做自顶向下的层次化拆分(对于较为简单的部署架构,层次化的确很有必要)。
因而,实质上 arc42 中提倡的制图办法与 C4 模型是等价和兼容的,齐全能够配合应用:以 arc42 作为架构文档框架,其中的架构制图采纳更具体的 C4 模型。这也是目前咱们我的项目中理论采纳的办法。
- 其余办法 & 制图工具
除了上述几种办法以外,在软件行业蓬勃发展的数十年间也涌现出过很多其余的优良架构制图办法,其中既包含一些 通用办法 ,如:SysML、AADL、ArchiMate,也包含一些 畛域特定办法,比方在企业中后盾业务建模场景中很常见的 BPMN。再具体地开展形容各个办法,显然会让本文又臭又长(尽管写到这里时仿佛就曾经注定了),有趣味的读者能够自行检索和摸索。
到这里为止,本章节介绍的都是架构制图的各种办法;而理论从办法到落地的过程中,还有一个绕不开的环节:选用什么样的工具去制图?总不能真的跟写工程制图作业一样用纸和笔吧?作为数字化改革的推动者,程序员们当然要全面拥抱数字化工具;大家日常工作中必然也曾经积攒了很多棘手的画图工具,因而这里我只举荐两个本人用得比拟多的:
- draw.io:这是一个开源的在线绘图软件,置信很多人都有用过。思考到数据安全问题,举荐大家用齐全离线的桌面版。作为一个程序员敌对的绘图工具,draw.io 的最大长处就是 反对三方插件,比方这个开源的 c4-draw.io 插件,能够帮忙你更不便地在 draw.io 中绘制 C4 模型架构图;
- PlantUML:作为 文本制图 的代表性工具,PlantUML 能够用于绘制各种类型的 UML 图,以及其余一些实用于文本制图场景的图(比方这个开源的 C4-PlantUML 扩大)。在这些场景下,文本制图具备可视化制图所无法比拟的劣势:轻量、高效、版本化、自动化、一致性、易于复用等。尽管文本制图工具诞生已久(比方利用宽泛的 [Graphviz](),最早发行于 1991 年),但置信随着古代各种 XXX as Code 的意识沉睡,这类 Diagram as Code 工具也会取得更多青眼(btw,语雀文档早已反对内嵌 PlantUML 制图)。
架构制图方法论总结
古有云:授人以鱼,不如授人以渔。推而广之:授人以办法,也不如授人以方法论。什么是方法论?尽管这个词在公司里曾经用烂了,但的确有它的价值和意义:方法论(methodology)是对办法的更高维度形象,由它能够推导出解决问题的具体 办法(method)。了解了方法论,能力死记硬背,把握解决问题的实质要点;你也不会再受限于繁多的具体方法,因为应用任何办法都能疾速上手和灵活运用,并失去差不多的等同成果。
因而,本文最初这一章节将对各种架构制图办法进行演绎总结,并尝试提炼出一个通用的架构制图方法论,冀望能帮忙大家更好地了解架构制图背地的原理和思维。即使当初所熟知的各种办法与工具终会过期,也仍然能风轻云淡地对待它们的新老交替:过来是 UML,当初是 C4,将来是什么呢?这并不要害,因为即便办法过期了,背地的方法论也不会过期。
所以,那些茫茫多的办法背地,到底是什么样的外围方法论在撑持着呢?通过作者醉生梦死左思右想了近 15 秒钟,终于总结出了如下这套经典方法论(p.s:就是凑数的,不要太当真~)。因为其中蕴含了 5 个环环相扣的要点,咱们权且称它为:五环实践。
- 了解制图指标
架构制图的第一要点,是须要先深刻理解制图指标。正所谓“以始为终”,有了指标咱们能力清晰地前行;否则漫无目的地乱窜,往往会多走不少弯路,甚至背道而驰。架构制图的指标是什么?其实前文曾经提到过很多,这里再简略总结下:
- 精确(accurate):错的图比没有图还蹩脚;即便一开始是精确的,前面也须要定期更新校对;
- 残缺(complete):须要笼罩架构的外围因素和要害信息,为受众出现一个没有完好的残缺架构设计;
- 清晰(clear):制图时最好带上图例(形态、色彩、线型、箭头);用图形容不清的中央,还能够加上文字标注做补充;
- 统一(consistent):比方同一类型的图,最好应用雷同的记号格调,以升高受众的了解老本;不统一往往还会带来混同;
- 简洁(consise):在满足以上 4 点根底之上,还须要让图更加简洁,一方面是更容易被人承受(没人读 = 没写),另一方面更新保护老本也更低。
- 找准受众和关注点
架构制图的第二要点,是要找准你制图的 受众 (audience)以及他们各自的 关注点(concern)。找不准的话,要么成果大打折扣(不是他们想听的),要么犹如对牛弹琴(他们基本就听不懂)。常见的一些受众和关注点可包含:
- 研发:个别会关注很多实现相干细节,比方技术选型、实现可行性、可维护性等,毕竟他们是架构的最间接消费者;
- 运维:不太关怀利用内的具体技术实现(当成黑盒),但很关怀各个利用实例的物理部署形式、网络连通性、可运维性等;
- 平安:只关注零碎是否有平安危险,例如是否可能被注入恶意代码、是否有权限破绽等;如果经验过平安评审,应该很有体感;
- 产品:大部分状况下只关怀我的项目是否按期上线,其余方面 … 可能外表上示意些许关怀,实际上要么并不在乎要么真的不懂。
3. 自顶向下逐层形容
架构制图的第三要点,是正当使用 层次化(hierarchical)的套路,自顶向下逐层形容。无论是 C4 模型还是 arc42 模板,背地都粗浅使用并显著强调了这一点。为什么肯定要这么做?其中蕴含了两个普适的原理:
- 分而治之 :软件畛域中,分而治之是 管制和应答简单零碎 的最无效办法。而层次化拆分,实质上就是一种分而治之伎俩:将零碎依照从粗到细的粒度,一级一级地拆分成多个绝对独立和低耦合的元素(子系统、利用、组件等);
- 金字塔原理 :这本书的外围观点就是,依照自顶向下的形式,先抛出主观点再顺次用各个子观点去论证。这样的沟通形式更合乎人类的思维逻辑,也更容易让读者承受。简略来说,就是要“ 先说重点”,帮忙读者做演绎总结和划重点,而不是先抛出一大堆细枝末节的零散货色让读者本人去消化和推演。
- 应用多种架构视图
架构制图的第四要点,是在向传统的工程制图方法论致敬:应用多种架构视图来形容你的架构。在工程制图的世界里,任何平面的制品,大到机床小到整机,都至多须要通过三种视图(主视图、俯视图、左视图)来形容。作为事实世界的映射,软件系统也是多维和平面的,只用繁多视图不可能笼罩所有要害的架构信息;即便强行把这些信息都塞在一张图里,那也肯定会简单到让人无奈了解。
在架构设计畛域,架构视图 (architectural view)有专门的定义:针对零碎架构某一个方面(aspect)的一种形容;每个视图都会笼罩我的项目干系人的一种或多种关注点。从上述定义能够看进去,不同的架构视图会有不同的 侧重点 ,同时在形容本人所专一的方面时也会略去与以后视图无关的其余细节 —— 这其实也是一种与层次化拆分相似的 分而治之 思维,只不过这里是针对残缺零碎的 维度合成 ,而层次化则是针对某一具体视图再做自顶向下的 垂直下钻(drill-down);两者是正交且能够相互配合的,例如后面说到的构造视图、部署视图甚至动静视图,都能够别离再进行层次化拆分。
- 遵循标准和最佳实际
架构制图的第五要点,其实只是一句 正确的废话 :遵循标准和最佳实际。这一点曾经不限于架构制图,而是回升到了工程实际畛域的通用方法论层面。正如后面章节所说,“学习架构制图的指标,就是要把它从一门手艺变成一项工程”,因而 架构制图的“施工”过程也理所应当合乎工程化思维:
- 一方面,制图须要遵循明确的标准,在实践层面进行束缚和指引,确保过程和产物的高质量与标准化;
- 另一方面,制图还须要遵循业界最佳实际,在实际层面继续汲取优良教训,一直精进本人和团队的制图技能。
附:架构形容标准化概念模型
国内上对架构形容其实建设了专门的规范(ISO / IEC / IEEE 42010:2011),其中的很多概念词汇在本文中都有提到(e.g. Stakeholder、Concern、View、Viewpoint),有趣味的同学能够进一步钻研下。
结语
如果你从头到尾耐着性子看到了这里,那么不必狐疑,你肯定就是咱们团队要找的那种能成大事儿的人:
原文链接
本文为阿里云原创内容,未经容许不得转载。