架构制图:工具与方法论

简介:软件工程也是工程,因此传统工程制图的一些基本理论,在软件行业同样适用。但另一方面,软件与实体制造业之间还是有着本质区别,所以在制图方面的需求和方式也大相径庭,无法直接套用。作为软件行业的从业者,你可以完全不懂工程制图,但你不得不懂架构制图 —— 这是任何程序员职业生涯的的必修课。

什么是软件架构/h2>

1. 软件架构定义

综合上述各种权威定义,软件系统的架构通常需要包含如下四类核心要素:

  • 元素(elements):将系统拆分为一组元素 – 模块、组件、结构体、子系统;
  • 关系(relationships):不同元素之间的关系 – 交互、依赖 、继承、组合、聚合;
  • 属性(properties):每个元素具备的属性 – 名称、职责、接口、实现限制等;
  • 原理(principles):为什么这么设计 – 拆分依据、设计原则、决策原因等。

为什么架构很重要/h2>

1. 架构是系统实现的蓝图

如何衡量一个软件产品的质量图是 ISO/IEC 25010 标准定义的软件产品质量模型,包括以下 8 个大类:

  • 功能适合性:功能完整度、功能正确性和功能恰当性;
  • 性能效率:时间表现(e.g. 响应时间)、资源利用和容量;
  • 兼容性:共存能力(e.g. 多版本组件共存)和互操作性;
  • 可用性:可学习性、可运维性、用户错误保护(e.g. 自动纠错)、UI 美观度、可访问性;
  • 可靠性:成熟度、可用性、容错性、可恢复性;
  • 安全性:机密性、完整性、不可伪造性、权威性和可审计;
  • 可维护性:模块度、可复用性、可分析性、可修改性、可测试性;
  • 可移植性:可适配性、可安装性、可替代性。

上述质量模型中列出的所有点,都是架构设计需要着重考虑的。其中除了功能适合性以外,其他所有点都属于非功能需求的范畴,这也是区分架构好坏的真正分水岭 —— 好的架构设计,不会停留在仅满足功能需求这一最基本的需求层次上(最坏的架构设计也同样能做到),更重要且更难以应对的是其他众多的非功能需求。

要不是篇幅所限,这一页 PPT 显然不够装:

  • 架构包含系统所有最重要的早期决策,这些决策会进而影响后续所有大大小小的技术决策。因此,早期的架构设计需要非常严谨和慎重,要尽可能“一次做对”(虽然很难),否则越往后纠错的成本越高;
  • 架构在组织内具有非常高的复用价值,因为同一组织内的产品之间一定会具备很多共性(需求、限制、环境等),很适合在架构层面进行最大化复用,避免重复解决相似的问题;
  • 康威定律指出,软件架构反映了组织结构。这个结论反过来也成立:好的架构也会让组织结构变得更高效
  • 越庞大和复杂的系统,架构越重要,因为只有好的架构才能有效控制、管理和降低系统复杂度
  • 是不是越听越糊涂,仿佛架构有无数种诠释和意义必过于纠结,按照GoF的设计模式所述:Architecture is about the important stuff. Whatever that is. 对,管它是啥,记住架构很重要就够了。

如何设计一个好的架构/h2>

1. 架构原则(principles)

架构模式(architectural patterns)与我们常讨论的设计模式(design patterns)并不是一码事,但如果仅从“模式”这个角度去解读,两者的理念都是一致的:针对给定上下文中经常出现的问题的通用、可复用的解决方案。最主要的区别在于,架构模式会更高维抽象和偏全局整体(毕竟是运用在架构设计层面)。

常见的架构模式,既包括一些传统模式(e.g. 分层、C/S、MVC、事件驱动),也包括一些新兴玩法(e.g. 云原生、微服务、Serverless)。不同模式有不同的适用场景,没有哪一种模式能通杀所有需求。成熟的架构师应该像一个冷静到冒得感情的杀手,永远只会客观地评估和选择最适合当下的解决手段,即使那么做会显得简单乏味;相反,不成熟的架构师,一心总想着搞事情(e.g. 强行套用微服务架构),而不是真正搞定问题。

怎么描述你的架构设计/h2>

有了良好的架构设计,万里长征之路就已经走了一大半。就像是青年导演第一次遇上好剧本,心潮澎湃两眼放光,仿佛已经预见了电影上映后的票房盛况。当然,剩下的一小半路,并不会如想象中那么平坦 —— 同样的剧本,不同导演拍出来会有质一样的区别。好的“最佳导演”,即使面对不是“最佳剧本”的剧本,也有能力拍出“最佳影片”。同样,好的架构师,也应该有能力描述好一个不错的架构设计;即使做不到为精彩的内容加分,也不应该因为形式上没描述好而丢分,否则就会像高考作文丢了卷面分一样憋屈和心酸。

1. 架构描述的意义

对于同一件事物,作家会选择用文字来叙述,而画家却会用图画。尽管两者想要传达的信息是一致的,但描述方式的不同也会带来效果上的巨大差异。架构描述也分文字(Text)图(Diagram)两种形式,两者各有千秋:

  • 文字的背后是由一套严谨和完备的语言作为支撑,因此其描述可以做到非常精准详尽,而且编写起来也很方便,随便打开个记事本软件都能写;此外,就跟写代码一样,文字很易于做版本管理,借助简单的文本 diff 工具就能一目了然地对比出不同版本之间的细节差异;
  • 相比而言,图并不具备以上文字所独有的特点,但也有自己的独特优势:图是直观形象的,顺应了人类与生俱来的视觉识别本能;图的表达能力更强,很多时候一小张图所能传达出的信息(比如空间位置关系、颜色分类、图标形状),也许用一千行字也不足以完整准确地描述出来,即所谓“一图胜千言”。

聪明的你冷笑了一声:哼,又不是小孩子非得做选择题,难道不可以文字与图都要吗然可以,理想的架构描述一定是图文并茂的。但现实世界显然比理想残酷,实际软件项目中很难给你留足时间先憋出一篇完美的架构文档。如果以成年人的思维去考虑投入产出比(ROI),那么你一定会优先选择画图。

3. 为什么你应该优先画图/h2>

多画图是没错,但有必要专门学习吗不是素描彩笔水墨画,只是画一堆条条框框而已,稍微有点工程常识的都能上。画的有点丑没关系,顶多再动用点与生俱来的艺术美感,把这几条线对对齐那几个框摆摆正,再整点五彩斑斓的背景色啥的,不就显得很专业了嘛/p>

所以,能画图并不代表能画好图;要想制得一手既漂亮又可读的好图,还是需要经过持续学习与刻意练习的,很难仅凭直觉和悟性就能掌握其中的关键要领。此外,错误的图往往比没有图还要糟糕,即使你只是抱着“有图就行,差不多那个意思得了”的心态,也至少应该理解一些科学制图的关键要素,避免给本来就已经很复杂难做的项目又蒙上一层模糊滤镜,甚至起到混淆和误导的反作用。

5. 架构制图的目标

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依然应该是每个程序员的制图工具箱中最常用和必备的工具之一。当然,也不应该是唯一,因为下面也还有些不能错过的好东西。

2. 方法二:4+1 View Model

C4 模型通过容器、组件、代码以及人这几个抽象来描述一个软件系统的静态结构,它的核心理念是希望像 Google Map 一样,通过不同层次的细节,为代码建立一种可以放大缩小的导览图。它最关键的思想就是自顶向下对系统的静态结构进行逐级拆分,依次描述各层次对象的职责、关系和外部依赖。除了核心的层次化静态结构视图,它还可以包含动态视图、部署视图等补充视图。

系统上下文图作为第一级(L1),提供了一个展示系统全貌的顶层大图(big picture)视角,包括最中心的软件系统、周边的用户以及其他有交互的系统。其中最关键的两个概念分别是:

  • (Person):即使用软件系统的用户,例如一个在线商城系统的消费者、运营小二、系统管理员等;
  • 软件系统(Software System):作为最高层次抽象,描述了给用户创造价值的软件制品;既包括当前正在设计的软件系统,也包括该系统所依赖(或被依赖)的其他软件系统。一个软件系统通常是由单个软件开发团队所负责。

在绘制系统上下文图时,不需要关心诸如技术栈、协议等任何底层细节。这类图的受众是最广的,因为任何人都可以理解并从中获取到足够的信息,包括技术人员和非技术人员,也包括团队内成员和团队外成员。

3)Level 2:Container diagram

继续前面的套路,下一步就是把系统中各个容器再分别进行局部放大,将每个容器进一步拆分成多个组件(Component)。在 C4 模型中,组件是指一组通过良好接口定义封装在一起的相关功能(通常运行在同一个进程空间内),例如:Spring 里的一个Controller(不只包括定义了 REST 接口的 Controller 主类,也包括背后所有相关联的实现类,如 Service/Repository 等)。

与容器图类似,L3 的组件图也不只包含了容器的组件划分,还包括各个组件的职责定义、技术与实现细节等。随着层次的下沉和细节的增多,组件图的受众范围进一步缩窄,一般只适用于软件架构师和开发者(其他角色没必要理解,一般也理解不了)。

5)Level 4:Code(可选)

除了上述各个层次的静态结构图,C4 模型还提出了一系列的补充图(Supplementary diagrams),包括:

  • 系统全景图(System Landscape diagram):全景图与系统上下文图的绘制方法类似,区别在于它是从企业或组织角度全景地展示出所有软件系统(包括与当前系统没有直接关联的)以及相关的用户和系统交互,即进一步放大架构图的 scope
  • 动态图(Dynamic diagram):由于结构图天生只能描述出系统的静态结构属性,因此 C4 模型中推荐使用 UML 中的通讯图、时序图等,对系统中关键链路的动态行为进行补充描述,即“动静结合”;
  • 部署图(Deployment diagram):除了缺失动态属性,上述结构图还有一个局限性:只描述了系统的抽象逻辑架构,并没有描述出系统实际部署时的具体物理架构。因此,C4 模型推荐再使用 UML 的部署图,对系统逻辑节点(一般是 L2 的“容器”粒度)与物理节点(e.g. 物理机 / 虚拟机 / Docker 容器 / 应用 Runtime)之间的映射关系进行补充描述,即“虚实结合”。

结合了这些补充图后的 C4 模型,才是可以全面与立体地描述出软件架构方方面面的完全体架构制图方法。

4. 方法四:arc42

到这里为止,本章节介绍的都是架构制图的各种方法;而实际从方法到落地的过程中,还有一个绕不开的环节:选用什么样的工具去制图不能真的跟写工程制图作业一样用纸和笔吧为数字化改革的推动者,程序员们当然要全面拥抱数字化工具;大家日常工作中必然也已经积累了很多顺手的画图工具,因此这里我只推荐两个自己用得比较多的:

  • 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)。理解了方法论,才能融会贯通,掌握解决问题的本质要点;你也不会再受限于单一的具体方法,因为使用任何方法都能快速上手和灵活运用,并得到差不多的同等效果。

架构制图的第一要点,是需要先深刻理解制图目标。正所谓“以始为终”,有了目标我们才能清晰地前行;否则漫无目的地乱窜,往往会多走不少弯路,甚至南辕北辙。架构制图的目标是什么实前文已经提到过很多,这里再简单总结下:

  • 完整(complete):需要覆盖架构的核心要素和关键信息,为受众呈现一个没有残缺的完整架构设计;
  • 清晰(clear):制图时最好带上图例(形状、颜色、线型、箭头);用图描述不清的地方,还可以加上文字标注做补充;
  • 一致(consistent):比如同一类型的图,最好使用相同的记 风格,以降低受众的理解成本;不一致往往还会带来混淆;
  • 简洁(consise):在满足以上 4 点基础之上,还需要让图更加简洁,一方面是更容易被人接受(没人读 = 没写),另一方面更新维护成本也更低。

2. 找准受众和关注点

架构制图的第三要点,是合理运用层次化(hierarchical)的套路,自顶向下逐层描述。无论是 C4 模型还是 arc42 模板,背后都深刻运用并显著强调了这一点。为什么一定要这么做中蕴含了两个普适的原理:

  • 分而治之:软件领域中,分而治之是控制和应对复杂系统的最有效方法。而层次化拆分,本质上就是一种分而治之手段:将系统按照从粗到细的粒度,一级一级地拆分成多个相对独立和低耦合的元素(子系统、应用、组件等);
  • 金字塔原理:这本书的核心观点就是,按照自顶向下的方式,先抛出主观点再依次用各个子观点去论证。这样的沟通方式更符合人类的思维逻辑,也更容易让读者接受。简单来说,就是要“先说重点”,帮助读者做归纳总结和划重点,而不是先抛出一大堆细枝末节的零散东西让读者自己去消化和推演。

4. 使用多种架构视图

架构制图的第五要点,其实只是一句正确的废话:遵循规范和最佳实践。这一点已经不限于架构制图,而是上升到了工程实践领域的通用方法论层面。正如前面章节所说,“学习架构制图的目标,就是要把它从一门手艺变成一项工程”,因此架构制图的“施工”过程也理所应当符合工程化思维

  • 一方面,制图需要遵循明确的规范,在理论层面进行约束和指引,确保过程和产物的高质量与标准化;
  • 另一方面,制图还需要遵循业界最佳实践,在实践层面持续吸取优秀经验,不断精进自己和团队的制图技能。

附:架构描述标准化概念模型

35.png

结语

如果你从头到尾耐着性子看到了这里,那么不用怀疑,你一定就是我们团队要找的那种能成大事儿的人:

欢迎各位技术同路人加入阿里云云原生应用研发平台EMAS团队,我们专注于广泛的云原生技术(Backend as a Service、Serverless、DevOps、低代码平台等),致力于为企业、开发者提供一站式的应用研发管理服务,内推直达邮箱:pengqun.pq # alibaba-inc.com,有信必回。

原文链接:https://developer.aliyun.com/article/774446/p>

文章知识点与官方知识档案匹配,可进一步学习相关知识云原生入门技能树首页概览8766 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年8月25日
下一篇 2020年8月25日

相关推荐