简介: 软件工程也是工程,所以传统工程制图的一些基本理论,在软件行业一样适用。但另外一方面,软件与实体制造业之间仍是有着本质区别,因此在制图方面的需求和方式也截然不同,没法直接套用。做为软件行业的从业者,你能够彻底不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。ios
做者 | 楚衡git
“架构制图”这词乍一听彷佛有些晦涩,但若是提起“工程制图”,相信绝大部分工科背景的程序员们都不会陌生,甚至还能共同感慨下那些年一块儿伏在宿舍左手圆规,右手直尺,徒手做图到深夜的日子。程序员
软件工程也是工程,所以传统工程制图的一些基本理论,在软件行业一样适用。但另外一方面,软件与实体制造业之间仍是有着本质区别,因此在制图方面的需求和方式也截然不同,没法直接套用。做为软件行业的从业者,你能够彻底不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。github
本文在后半段将介绍如何用图去描述(describe)和传达(communicate)你的架构设计。值得强调的是,本文并不会侧重于单一的方法和工具,而是更但愿关注那些优秀方法背后的通用方法论,即架构制图的本质、共性和最佳实践。但愿本文能起到引子做用,激发你们对本身平常工做中关于架构和制图部分的关注、审视与思考;若是还真能帮助你们提高一点点制图效率和效果,那就更好不过了。数据库
IEEE 给出的定义:架构是环境中该系统的一组基础概念(concepts)和属性(properties),具体表现就是它的元素(elements)、关系(relationships),以及设计与演进的基本原则(principles)。编程
CMU 软件工程研究院的定义:架构是用于推演出该系统的一组结构(structures),具体是由软件元素(elements)、元素之间的关系(relationships),以及各自的属性(properties)共同组成。设计模式
Uncle Bob 在 Clean Architecture 一书中给出的定义:架构是建立者给予该系统的形态(shape)。这个形态的具体形式来源于对系统组件(components)的划分和排列,以及这些组件之间互相通信的方式。安全
综合上述各类权威定义,软件系统的架构一般须要包含以下四类核心要素:网络
最近有部很火的网剧叫《摩天大楼》,讲述了一段匪夷所思的悬疑故事。为何扯这个呢?由于我想借用这个剧的标题来问个问题:摩天大楼是由谁建起来的?也许你内心会默念:废话,不就是建筑工人们一砖一瓦堆起来的嘛。仔细再想一想?背后是否是还有一堆操碎了心的建筑设计师(好比剧中帅气的林大森)和土木工程师们?他们虽然不搬砖也不扛水泥,但若是没有他们产出的那些繁琐严谨的设计图纸,摩天大楼是是不可能像农村自建房同样仅凭工人们各自的经验与想象力就能快速平稳地竖立起来的。架构
正是靠着这些图纸所描绘出来的工程蓝图(blueprints),才让成百上千工人们的分工合做和验收标准有了依据:你们只须要照着蓝图,循序渐进地把本身所负责的那些砖瓦添上去就好了;只要蓝图正确,且施工过程也没有误差,最终顺利完工只是个时间问题。
与建筑、汽车或者任何其余工程行业同样,软件在落地实现(编码)以前也须要先有蓝图;而其中最重要的一份蓝图,就是架构设计。没有架构,仅凭程序员本身脑子里的模糊设想,也许你能够像传统手艺人同样独自创造出一些美好有用的小东西(好比 Linux 0.01 版本),但不太可能以工程的方式协同一个团队共同建造起一个与摩天大楼规模相似的复杂软件系统(好比现代的 Linux 系统)。一方面,人类的思惟能力终归有限,必须依靠架构这种高度抽象和简化的蓝图,才能让复杂系统的创造、理解、分析和治理变得可行;另外一方面,量级达到必定程度的大型系统,也只能依靠多人分工合做才能完成,而架构也正是多人沟通协做的重要基础。
软件项目的最终价值产出就是软件系统,而架构做为软件系统的灵魂和骨架,能够起到以下做用:
如何衡量一个软件产品的质量?上图是 ISO/IEC 25010 标准定义的软件产品质量模型,包括如下 8 个大类:
上述质量模型中列出的全部点,都是架构设计须要着重考虑的。其中除了功能适合性之外,其余全部点都属于非功能需求的范畴,这也是区分架构好坏的真正分水岭 —— 好的架构设计,不会停留在仅知足功能需求这一最基本的需求层次上(最坏的架构设计也一样能作到),更重要且更难以应对的是其余众多的非功能需求。
固然,鱼与熊掌不可兼得。架构与人生同样,也是一场权衡的游戏,弄很差就跟第八季的龙母同样的下场:既要又要还要,最后反而什么都得不到。好的架构师更应该像雪诺同志学习,表面上“know nothing”,实际上“know everthing”:清楚系统全部利益相关者(stakeholders),努力挖掘各方的主要述求(concerns),相应平衡本身的架构决策(decisions),最终实现你好我好你们好的终极架构目标。
要不是篇幅所限,这一页 PPT 显然不够装:
理解了架构的概念和重要性后,真正的架构师修炼之路才刚刚开始。如何设计一个好的架构?这显然是一个很是博大精深的主题,但并非本文的重点,所以这里只简单列举了一些基本思想(原则)和经典套路(模式)。固然,架构设计更接近一门经验学科,仅停留在能脱口而出一些玄乎而高大上的理论概念确定是不够的,须要结合实际工做内容和业务场景多多实践和揣摩才行,不然只能算是徘徊在架构的门外,连入门都谈不。
SOLID 原则是一套比较经典且流行的架构原则(主要仍是名字起得好):
此外,咱们作架构设计时也会尽可能遵循以下一些原则(与上述 SOLID 原则在本质上也是相通的):
架构模式(architectural patterns)与咱们常讨论的设计模式(design patterns)并非一码事,但若是仅从“模式”这个角度去解读,二者的理念都是一致的:针对给定上下文中常常出现的问题的通用、可复用的解决方案。最主要的区别在于,架构模式会更高维抽象和偏全局总体(毕竟是运用在架构设计层面)。
常见的架构模式,既包括一些传统模式(e.g. 分层、C/S、MVC、事件驱动),也包括一些新兴玩法(e.g. 云原生、微服务、Serverless)。不一样模式有不一样的适用场景,没有哪种模式能通杀全部需求。成熟的架构师应该像一个冷静到冒得感情的杀手,永远只会客观地评估和选择最适合当下的解决手段,即便那么作会显得简单乏味;相反,不成熟的架构师,一心总想着搞事情(e.g. 强行套用微服务架构),而不是真正搞定问题。
有了良好的架构设计,万里长征之路就已经走了一大半。就像是青年导演第一次赶上好剧本,心潮澎湃两眼放光,仿佛已经预见了电影上映后的票房盛况。固然,剩下的一小半路,并不会如想象中那么平坦 —— 一样的剧本,不一样导演拍出来会有质同样的区别。好的“最佳导演”,即便面对不是“最佳剧本”的剧本,也有能力拍出“最佳影片”。一样,好的架构师,也应该有能力描述好一个不错的架构设计;即便作不到为精彩的内容加分,也不该该由于形式上没描述好而丢分,不然就会像高考做文丢了卷面分同样憋屈和心酸。
为何要描述架构?让它只存在我深深的脑海里不行吗?西方人有句谚语:好记性不如烂笔头。任何没有持久化的东西都是易失的(volatile),就跟内存同样。另外一方面,就如前文所述,架构是沟通协做的基础,不经过架构描述(Architecture Description)沉淀下来让全部项目干系人都能看到,那就失去了沟通和传播的惟一载体。
根据我的观察,你们对“架构须要描述”这一点都没异议,因此绝大部分项目都或多或少会产出一些有模有样的架构描述文档。但“有架构描述”和“有好的架构描述”,这之间的鸿沟是巨大的,甚至比“没有”和“有”之间的差异还大。若是你也跟我同样,饱经沧桑阅尽无数架构文档,曾拍手叫好心怀感激过,也曾拍着大腿愤怒不已过,应该也能感同身受。
对于同一件事物,做家会选择用文字来叙述,而画家却会用图画。尽管二者想要传达的信息是一致的,但描述方式的不一样也会带来效果上的巨大差别。架构描述也分文字(Text)和图(Diagram)两种形式,二者各有千秋:
聪明的你冷笑了一声:哼,又不是小孩子非得作选择题,难道不能够文字与图都要吗?固然能够,理想的架构描述必定是图文并茂的。但现实世界显然比理想残酷,实际软件项目中很难给你留足时间先憋出一篇完美的架构文档。若是以成年人的思惟去考虑投入产出比(ROI),那么你必定会优先选择画图。
敏捷软件开发宣言中提到:相比详尽的文档,可运做的软件更加剧要(Working software over comprehensive documentation)。这么说固然不表明就不用写文档了,只是提倡不必写过于详尽的文档。为何?由于详尽的文档须要耗费大量的编写和维护成本,不符合敏捷开发的小步迭代和快速响应变化等原则。
那么,在现在这个全面敏捷开发的时代,如何也顺应潮流更加敏捷地编写架构文档呢?ROI is your friend —— 不求多,但求精,尽可能用最少的笔墨表达出最核心的内容。从内容上来讲,ROI 高的部分通常是偏顶层的总体架构或最核心的关键链路,这点在后文的 C4 模型理念中也有体现。而从形式上来讲,图在文字面前具备无与伦比的表达力优点,显然是 ROI 更高的选择。
多画图是没错,但有必要专门学习吗?又不是素描彩笔水墨画,只是画一堆条条框框而已,稍微有点工程常识的都能上。画的有点丑?那不要紧,顶多再动用点与生俱来的艺术美感,把这几条线对对齐那几个框摆摆正,再整点五彩斑斓的背景色啥的,不就显得很专业了嘛?
看到这里,屏幕前的你又轻蔑一笑:哼,显然没这么简单。确实,道理说出来你们都懂,架构制图与工程制图同样,都是一件须要下功夫认真严谨对待的事情。但现实中大部分人还真没这工夫去下那功夫,好比上面贴的两幅很常见的架构图。第一张图不用多说,这种草图本身涂涂抹抹挺好,但拿出来见人就是你的不对了。那第二张图呢,看上去彷佛还挺像那么回事的?并非,若是你更仔细地去揣摩,就能发现这张图底下所隐藏的不少模糊和不严谨之处(可参考这张图的来源文章:The Art of Crafting Architectural Diagrams)。
因此,能画图并不表明能画好图;要想制得一手既漂亮又可读的好图,仍是须要通过持续学习与刻意练习的,很难仅凭直觉和悟性就能掌握其中的关键要领。此外,错误的图每每比没有图还要糟糕,即便你只是抱着“有图就行,差很少那个意思得了”的心态,也至少应该理解一些科学制图的关键要素,避免给原本就已经很复杂难作的项目又蒙上一层模糊滤镜,甚至起到混淆和误导的副作用。
讨论具体的制图方法和工具前,咱们须要先竖立清晰的制图目标。工具是人类进化的阶梯,但若是理解和利用不当,则很容易反过来被工具所限制甚至奴役,忘了最初发明和使用工具的初心。对于架构制图而言,已经有那么多形形色色的方法与工具,使用它们的初心是什么呢?我认为本质上都是想把制图这个过程从一门自由的手艺变成一项科学的工程:系统、严谨、完整、标准化,同时能作到可重复、可持续和高效。
P.S:当时作 PPT 太赶,因此从这个章节开始的配图,只能被迫走极简路线了,还请见谅。。。
通过前面几个章节的“简短”铺垫,相信你们对架构制图的背景知识都已经产生了足够的认知。本章节将会具体列举和描述一些典型的架构制图方法与工具,其中有常见的也有罕见的,重点是但愿能经过各类方法的横向对比,加深你们对制图方法本质的理解。
UML 应该是大部分人最熟悉的制图方法了,最新的 UML 2.x 版本由如下两大类图组成:
做为通用的“统一建模语言”,UML 总共包含了 14 种不一样类型的图,能够全面覆盖软件设计领域各类制图需求,固然也包括了架构制图。同时,也正是由于 UML 把本身当成了一门语言,所以其各类记号(notion)和语义(sematics)都有很是严谨的定义,不会出现模糊或者歧义问题。最后,UML 通过几十年的发展和推广,也早已成为世界范围内普遍使用的标准规范,其所带来的的隐性价值就是:在团队内使用 UML 进行沟通的成本是比较低的,由于能够假定绝大部分技术人员都能理解UML的含义和用法。
然而,UML 也非万能(虽然历史上曾一度把它当成软件设计的银弹),它最被人诟病的缺点就是过于复杂。这也不能怪 UML,毕竟它就是要被设计为足够通用、严谨和强大的,这些目标都与“简单”背道而驰,并让它一步步演化到了今天这个复杂刻板的庞然大物模样。虽然上面咱们自信地假定了技术人员大多都懂 UML,但这个“懂”若是带上一个程度量词,我以为平均能到 20% 就不错了 —— 绝大部分也就能认识几个常见的类图、时序图,估计都很难准确说出类图中各类箭头的含义。
不管怎么说,UML依然应该是每一个程序员的制图工具箱中最经常使用和必备的工具之一。固然,也不该该是惟一,由于下面也还有些不能错过的好东西。
“4+1”是啥?不知道不要紧,听过“6+1”吗?对,就是那个小时候常看的“很是6+1”节目。它跟“4+1”之间的关系,就跟它们与邵佳1、张嘉译和沈佳宜之间的关系同样,除了赶巧共用了同一个后缀发音之外,八竿子打不着。
因此,“4+1”究竟是指什么?让咱们来 Wiki 一下:“4+1”是一种视图模型(view model),能够经过多种共存的视图描述软件密集型系统的架构。这些视图基于不一样项目干系人(利益相关者)的视点(viewpoint),例如:终端用户、开发者、系统工程师和项目经理。“4+1”由 4 种基础视图和一些通过挑选的用例或场景(即额外的“+1”视图)组成,各自的具体含义以下:
虽然上面提到“4+1”的各类视图通常都是用UML图来表示,但实际上“4+1”自己是一种通用的视图模型,并无限制绘图的记号和工具。对于工程师而言,这种偏学院派的方法可能这辈子都不会直接用到,但其中蕴含的一个关键架构制图思想很是有价值:架构须要经过多种视图来描述,而这些视图是来源于不一样项目干系人的视点(角度);只有这样才能产生一整套全面、立体且客观的架构描述。
C4 模型是一种“抽象优先”(abstraction-first)的架构制图方法,它也是受前面的 UML 和“4+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 模型名称的来历。
系统上下文图做为第一级(L1),提供了一个展现系统全貌的顶层大图(big picture)视角,包括最中心的软件系统、周边的用户以及其余有交互的系统。其中最关键的两个概念分别是:
在绘制系统上下文图时,不须要关心诸如技术栈、协议等任何底层细节。这类图的受众是最广的,由于任何人均可以理解并从中获取到足够的信息,包括技术人员和非技术人员,也包括团队内成员和团队外成员。
经过 L1 的上下文图理解了系统在整个 IT 环境中的定位后,下一步就是把系统这个框框放大,详细看下其中包含了哪些“容器”(Container,注意不要跟 Docker 容器搞混了噢!)。C4 模型中的容器是指单个应用或数据存储,一般能够独立部署和运行(有独立的进程空间,经过 IPC 机制互相通信),例如:SpringBoot 微服务、React SPA、移动 App、数据库、Serverlss 函数、Shell 脚本。
L2 的容器图不只展现了系统的进一步职责拆分,还包括了主要的技术选型、容器之间的通信方式等关键架构信息。这类图能够面向所有的技术人员,既包括架构师、开发者,也包括运维人员、技术支持等。
继续前面的套路,下一步就是把系统中各个容器再分别进行局部放大,将每一个容器进一步拆分红多个组件(Component)。在 C4 模型中,组件是指一组经过良好接口定义封装在一块儿的相关功能(一般运行在同一个进程空间内),例如:Spring 里的一个Controller(不仅包括定义了 REST 接口的 Controller 主类,也包括背后全部相关联的实现类,如 Service/Repository 等)。
与容器图相似,L3 的组件图也不仅包含了容器的组件划分,还包括各个组件的职责定义、技术与实现细节等。随着层次的下沉和细节的增多,组件图的受众范围进一步缩窄,通常只适用于软件架构师和开发者(其余角色不必理解,通常也理解不了)。
再继续对组件进行放大,所能看到的最底层和细节的信息,就是 L4 的代码(Code)了。固然,这里所谓的“代码”仍是以图的形式(e.g. UML 类图、数据库 E/R 图)展现类或文件粒度的代码结构,并非真正的代码自己。即使如此,代码图在 99% 的架构描述场景下也依然过于详尽,一方面数量庞大,绘制成本很高;另外一方面易于变化,维护成本也很是高。所以,通常只有很是重要和复杂的组件才须要用到这一层级进行描述。若是确实须要绘制,也应该优先考虑自动化的方式,好比不少 IDE 就支持自动生成 UML 类图。
除了上述各个层次的静态结构图,C4 模型还提出了一系列的补充图(Supplementary diagrams),包括:
结合了这些补充图后的 C4 模型,才是能够全面与立体地描述出软件架构方方面面的彻底体架构制图方法。
严格来讲,arc42 并非一种架构制图方法,而是一个架构文档模板。虽然如前文所说,在架构描述中“图”是比“文字”更高优的选择,但实际项目过程当中你终究仍是须要产出一份相对完整、有图有文字的架构文档。arc42 就是专门用于帮助你们更好地编写架构文档;而做为架构文档中最重要的架构图,显然 arc42 也不会放过 —— 其中多个核心章节都与架构图有关,且详细描述了相应的制图方法。这里不会详细展开介绍 arc42(不能抢了下一篇文章的饭碗),只会简单介绍下 arc42 中制图方法与 C4 模型的异同。
伟大的思想都是类似的,arc42 也不例外。上方左图的右侧部分,归纳了 arc42 模板中与制图相关的几个核心章节,分别是:
所以,本质上 arc42 中提倡的制图方法与C4模型是等价和兼容的,彻底能够配合使用:以 arc42 做为架构文档框架,其中的架构制图采用更具体的 C4 模型。这也是目前咱们项目中实际采用的方法。
除了上述几种方法之外,在软件行业蓬勃发展的数十年间也涌现出过不少其余的优秀架构制图方法,其中既包括一些通用方法,如:SysML、AADL、ArchiMate,也包括一些领域特定方法,好比在企业中后台业务建模场景中很常见的 BPMN。再详细地展开描述各个方法,显然会让本文又臭又长(虽然写到这里时彷佛就已经注定了),有兴趣的读者能够自行检索和探索。
到这里为止,本章节介绍的都是架构制图的各类方法;而实际从方法到落地的过程当中,还有一个绕不开的环节:选用什么样的工具去制图?总不能真的跟写工程制图做业同样用纸和笔吧?做为数字化改革的推进者,程序员们固然要全面拥抱数字化工具;你们平常工做中必然也已经积累了不少顺手的画图工具,所以这里我只推荐两个本身用得比较多的:
古有云:授人以鱼,不如授人以渔。推而广之:授人以方法,也不如授人以方法论。什么是方法论?虽然这个词在公司里已经用烂了,但确实有它的价值和意义:方法论(methodology)是对方法的更高维度抽象,由它能够推导出解决问题的具体方法(method)。理解了方法论,才能融会贯通,掌握解决问题的本质要点;你也不会再受限于单一的具体方法,由于使用任何方法都能快速上手和灵活运用,并获得差很少的同等效果。
所以,本文最后这一章节将对各类架构制图方法进行概括总结,并尝试提炼出一个通用的架构制图方法论,指望能帮助你们更好地理解架构制图背后的原理和思想。即使如今所熟知的各类方法与工具终会过期,也依然能风轻云淡地看待它们的新老交替:过去是 UML,如今是 C4,将来是什么呢?这并不关键,由于即便方法过期了,背后的方法论也不会过期。
因此,那些茫茫多的方法背后,到底是什么样的核心方法论在支撑着呢?通过做者呕心沥血左思右想了近 15 秒钟,终于总结出了以下这套经典方法论(p.s:就是凑数的,不要太当真~ )。因为其中包含了 5 个环环相扣的要点,咱们姑且称它为:五环理论。
架构制图的第一要点,是须要先深入理解制图目标。正所谓“以始为终”,有了目标咱们才能清晰地前行;不然漫无目的地乱窜,每每会多走很多弯路,甚至南辕北辙。架构制图的目标是什么?其实前文已经提到过不少,这里再简单总结下:
架构制图的第二要点,是要找准你制图的受众(audience)以及他们各自的关注点(concern)。找不许的话,要么效果大打折扣(不是他们想听的),要么犹如对牛弹琴(他们根本就听不懂)。常见的一些受众和关注点可包括:
架构制图的第三要点,是合理运用层次化(hierarchical)的套路,自顶向下逐层描述。不管是 C4 模型仍是 arc42 模板,背后都深入运用并显著强调了这一点。为何必定要这么作?其中蕴含了两个普适的原理:
架构制图的第四要点,是在向传统的工程制图方法论致敬:使用多种架构视图来描述你的架构。在工程制图的世界里,任何立体的制品,大到机床小到零件,都至少须要经过三种视图(主视图、俯视图、左视图)来描述。做为现实世界的映射,软件系统也是多维和立体的,只用单一视图不可能覆盖全部关键的架构信息;即便强行把这些信息都塞在一张图里,那也必定会复杂到让人没法理解。
在架构设计领域,架构视图(architectural view)有专门的定义:针对系统架构某一个方面(aspect)的一种描述;每一个视图都会覆盖项目干系人的一种或多种关注点。从上述定义能够看出来,不一样的架构视图会有不一样的侧重点,同时在描述本身所专一的方面时也会略去与当前视图无关的其余细节 —— 这其实也是一种与层次化拆分相似的分而治之思想,只不过这里是针对完整系统的维度分解,而层次化则是针对某一具体视图再作自顶向下的垂直下钻(drill-down);二者是正交且能够相互配合的,例如前面说到的结构视图、部署视图甚至动态视图,均可以分别再进行层次化拆分。
架构制图的第五要点,其实只是一句正确的废话:遵循规范和最佳实践。这一点已经不限于架构制图,而是上升到了工程实践领域的通用方法论层面。正如前面章节所说,“学习架构制图的目标,就是要把它从一门手艺变成一项工程”,所以架构制图的“施工”过程也理所应当符合工程化思惟:
国际上对架构描述其实创建了专门的标准(ISO / IEC / IEEE 42010:2011),其中的不少概念词汇在本文中都有提到(e.g. Stakeholder、Concern、View、Viewpoint),有兴趣的同窗能够进一步研究下。
若是你从头至尾耐着性子看到了这里,那么不用怀疑,你必定就是咱们团队要找的那种能成大事儿的人:
欢迎各位技术同路人加入阿里云云原生应用研发平台EMAS团队,咱们专一于普遍的云原生技术(Backend as a Service、Serverless、DevOps、低代码平台等),致力于为企业、开发者提供一站式的应用研发管理服务,内推直达邮箱:pengqun.pq # alibaba-inc.com,有信必回。