@Lenciel

如何干好架构师(1)

在很多技术团队里,「架构师」好像是一个「岗位」或者「职称」。

甚至有些地方把它作为职级:你从「初级工程师」干到「高级工程师」,再往上就是「架构师」了。

所以,在简历里经常可以看到某位同学在某个公司担任「架构师」或者「首席架构师」。

很多研发也就自然把「架构师」当成职业通道的下一站,花很多时间甚至报培训班,想要成为「架构师」。

从我过往的经验来看,这样的岗位或者职级设置通常带来的问题比收益多。

就连这个流量很小的 blog,也可以在评论里里看到一些对架构师的吐槽。

本系列面向所有「架构师」或者希望成为「架构师」的同学,聊聊怎样干好这个似乎是「码农」的进阶,却又不太容易讨巧的角色。

第一篇我们争取先说清楚什么是我心里面的「架构师」。

目录

「师」在中文里的意思很多。

「架构师」里的「师」是掌握某领域专门的技术或知识,可以作为其他人学习对象的人,和「医师」或者「巫师」的「师」类似。

因此,就跟要讲清楚如何成为「巫师」得先定义我们在说的「巫」是什么一样,我们得先定义「架构」,才能说清楚,「架构师」是什么。

什么是「架构」

不幸的是,对于「架构」的定义没有一个标准意见。大体上,我把它分成「学界定义」和「业界定义」两大分支。

学界定义

「学界」主要是指「计算机科学」里面有一个专门的分支「软件工程(Software Engineering)」。在它的定义里,主要强调「架构」要说清楚:

  • 系统由哪些要素构成
  • 这些构成要素之间的关系

比如你搜索「Software Architecture」,排名靠前的维基百科的解释如下:

Software architecture refers to the fundamental structures of a software system and the discipline of creating such structures and systems. Each structure comprises software elements, relations among them, and properties of both elements and relations.

这很明显是从《Documenting Software Architectures: Views and Beyond》 里面摘抄的。这本书不那么好读,它的两位作者在另一本从名字看就好读多了的《Software Architecture in Practice》里有一个类似的定义:

The software architecture of a system is the set of structure needed to reason about the system, which comprises software elements, relations among them, and properties of both.

如果你注意到这本书是属于一个叫 SEI Collections 的系列的话,就很容易发现,CMU 的 Software Engineering Institute(SEI)对这些软件工程领域的方法论和术语定义很用心。它们还有一个官方的「数字图书馆」,检索「架构」的定义可以找到一个和前面的定义非常类似,但是打了 IEEE 龙标的定义:

Architecture is the fundamental organization of a system embodied in its components, their relationships to each other, and to the environment, and the principles guiding its design and evolution. –IEEE 1471

学界的这些定义,最大的问题是,系统里组件怎么定义,它们之间的关系怎么形成,现实中其实并没有真正「工程化」的方法可以干好1

业界定义

业界进行实际生产作业的人,对「架构」的定义强调的是因为问题域的复杂多变,做了什么「决策」或者说「选择」。

比如,在我自己还很热衷于成为一个架构师,同时也是软件工程的各种方法论走红的年代,十八摸那本著名的《The Rational Unified Process: An Introduction》里,Kruchten 做了如下的定义:

An architecture is the set of significant decisions about the organization of a software system, the selection of structural elements and their interfaces by which the system is composed, together with their behavior as specified in the collaborations among those elements, the composition of these elements into progressively larger subsystems, and the architectural style that guides this organization – these elements and their interfaces, their collaborations, and their composition.

再比如 Jan Bosch 和 Anton Jansen 在那篇著名的论文里说的:

We do not view a software architecture as a set of components and connectors, but rather as the composition of a set of architectural design decisions.

这种看法影响了很多人,比如 UML 它爹 Grady Booch 就说过:

All architecture is design but not all design is architecture. Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.

既然「架构」是「决策」,那么「架构师」就是「做决策的人」。因此,这个定义被「架构师」们欢迎几乎是人性上无法避免的。

于是,在这些「架构师」定义的「架构」里,你几乎完全看不到跟系统实际功能或者模块有关的描述,主要是围绕一些系统的体系特征进行的设计:

  • Availability
  • Scalability
  • Reliability
  • Maintainability
  • *bility

它导致的问题不仅仅在于公司里面开始出现「架构师」这样的职位,并且编码的同学把有朝一日成为「做决策」的人当成自己的奋斗目标。

更重要的是,很多不真正理解问题域也不参与编码的人,以「架构师」的特权进行各种各样的「决策」,迷恋「UML」或者「Design Pattern」这样的方法论,导致大量的资源浪费甚至是项目失败。

因此 Martin Fowler 在他那篇《Who needs an architect》里面引用 Ralph Johnson 的话有些嘲讽地说:

Architecture is the decisions that you wish you could get right early in a project, but that you are not necessarily more likely to get them right than any other.

问题出在哪里

「架构」两个字,无论「学界定义」还是「业界定义」都带来了问题,为什么?

我觉得本质上是因为我们尝试「工程化」软件开发。

在其他的工程领域,我们依赖数学或者物理的理论体系,构建领域内的理论体系。

软件世界比数理世界要「软」。

一方面,我们的问题域在不断的变化,你今天觉得地球上有 50 万人拍视频,明年就 5 个亿了。

所以我们面对的其实是一个动态平衡的系统: 在任何给定的时间点它可能处于一个平衡状态,但长期看,它只会不断演进,前往下一个不平衡的状态。

另一方面,我们打算拿来构建理论体系所依赖的「公理」,在不断地,快速地失效2

许多关于软件架构的书籍都是在一个与当今世界几乎完全不同的时代写成的。新的实践、工具、度量方法、模式和大量其他变化在时时刻刻发生。我们必须根据改进的工程实践、操作系统生态、软件开发过程等等,去不断地质疑「基本公理」。

作为一个软件开发人员,和其他工匠一样,很容易迷恋某种特定的,自己熟悉的技术或方法,然后因为手里拿着这把锤子,看什么都是个钉子。

合格的架构师,必须清醒地理解现实世界在变,软件技术也在变,因此几乎没有任何方便的,拿来就用的,非错即对的二元选择:要把软件开发看成一个对需要解决的问题和解决的技术进行学习的过程,把架构和代码都当成这个过程的副产品

那究竟什么是「架构」

我最喜欢的定义也来自 Ralph Johnson:

In most successful software projects, the expert developers working on that project have a shared understanding of the system design. This shared understanding is called ‘architecture’ .

我喜欢这个定义的地方是:

  1. 它强调了「架构」是为了体现大家的「共同理解」而不是体现某个智者的「决策」;
  2. 它暗示了不用说大家也可以共同理解的东西,就没有必要写到「架构」里;
  3. 它还暗示了「架构师」的职责是和所有涉众沟通,让大家达成「共同理解」。

关于最后一点,成功的「架构」不是「架构师」自己想好写出来的,而是跟所有涉众沟通之后形成的「共同理解」,我觉得可以多说几句。

在每个公司里面,其实一般有四个话语体系:

  • 宏观层面
  • 设计层面
  • 构建层面
  • 商业化层面

架构师要做好「架构」,就涉及跟这四个层面的人做好沟通。

怎么理解?

软件开发常常被类比成建筑行业,「architecture」这个词就这么用起来的,所以我用做门来打个比方。

第一个层面主要是跟客户、公司管理层或者业务负责人聊的。你们聊的可能是「门是空间的联通」这样有些凡尔赛的话,哪怕到细节,也是柯布为什么老用大旋转门,Zumthor 在老年公寓里做的门柜结合多么厉害,Bienefeld 那些古典比例的现代门如何引领了潮流。

第二个层面,主要是你在跟平级部门,深化产品、交互、系统等各个层面的设计细节。你开始说这是一道「防盗门」还是一扇「厕所门」,为了防火又美观中庭要不要有一扇卷帘,Lindt 博物馆里怎么做出来那么干净的大堂,罗氏、诺华那些精致的技术解决方案。基本上,在这块儿你能聊什么样的天,决定了你的整体段位:如果你轻易就被产品、设计等其他部门的人聊得无话可说,可能你的段位就还没有到。

第三种是构建工艺层面的,主要是对部门内部的沟通了。你这门,是无框的,隐框的,全玻璃的,平移的,下沉的,还是啥样的?柯布在萨伏依里面的大平移玻璃门,密斯在图根哈特别墅搞的大下沉窗,关门器、气密条、折页五金件,你得一清二楚。基本上,你这部分的基本功既决定了和下面同学们配合的愉快程度,其实也决定了你上面两个层面能到什么高度。比如下沉窗为什么会出现在图根哈特这么一个古典内核的建筑里,比如英国建筑师如何系统性的通过开窗与欧洲建筑师慢慢做出区分,没有搞明白,你去聊上面的那些天,容易穿帮露怯。

第四种是商业落地层面的,主要是对项目经理的沟通了。比如门窗就用旭格的,霍曼的,还是双流陈家的。是买过来装,还是需要二次开发局部定制。这部分,虽然往往不是你直接去找货给钱,但是往往你得脑子里面有方案:同样的门,粗野怎么做,极简怎么做,高技怎么做,低技怎么做,有钱怎么做,没钱怎么做。

所以,什么是「架构」?

架构不是最后那张设计图纸,而是你,怎么打通各个话语体系——从想法到落地,从前期到后期,从学术到实践,得到最后这张图纸。

所以,什么是「架构师」?

就是前脚标准构造尺寸倒背如流,后脚又开始聊建筑史观,左手柯布密斯怎么流畅,右手防火门该咋画还咋画的,这个能用一张嘴聊四套语言最后让大家形成共识的人。

因此,在我的团队,一直推行把「架构师」作为一个「角色」而不是一个岗位。

Summary

要说清楚「如何干好架构师」,我决定先说清楚我定义的「架构」是什么。这里主要说了三点:

  1. 架构在学界的定义围绕「系统的构成部分和这些构成部分之间的关系」展开,这个定义的问题是没有什么实操的工程办法可以真正设计和定义好系统由什么构成,它们的关系应该是怎样;
  2. 架构在业界的定义围绕「系统的构建过程中做了什么选择和决策」展开,这个定义的问题是让架构师往往无视问题域的不断演进和软件技术的不断发展,倚仗自己角色的权威,做出脱离实际的「决策」;
  3. 我觉得,「架构」就是在和四个不同层面的人进行充分沟通后,形成的对系统关键部分的「共同理解」。它是一个快照,会随着时间的变化变化。因此,「架构师」就是推动沟通并记录结论的一个角色,不是一个「岗位」或者「职称」。只不过你要进行这样的沟通,往往需要足够的经验和影响力,而已。
  1. 这也是我自己对「软件工程」的态度比较那啥的原因。它一直希望将软件开发从一门手艺转变为一个工程学科,这意味着可以清晰定义,严格执行,不断优化的可重复的流程。 但虽然有了一些进展,整体来看,软件开发离一个「工程学科」还有很大差距。 

  2. 一个很好的例子是容器技术带来的变化,它对软件的设计、开发、测试和部署的方方面面都带来了很多变化,有些变化是颠覆性的。 

如何写好系统架构文档

软件开发实际上是一个学习的过程,架构和代码只是它的副产品。

所以方案应该主要体现两个部分:

  1. 你对用户需求、关键路径等「领域知识」有了什么样的了解。
  2. 你因为这些了解,在:
  • 系统的核心模块准备采取什么样的设计
  • 模块之间通过什么方式通信或者暴露什么 API
  • 数据怎么进行读写和持久化

等关键选择上做了什么样的选择和权衡。

本文面向所有需要编写系统设计方案或者系统架构方案的工程师。

目录

一、基本步骤

1. 梳理和澄清系统

维基百科对「系统」的定义是:

A system is a group of interacting or interrelated entities that form a unified whole. A system, surrounded and influenced by its environment, is described by its boundaries, structure and purpose and expressed in its functioning.

因此,一个系统的定义主要有几个方面:

  • 目的
  • 边界
  • 模块(or 子系统)
  • 模块(or 子系统)间的协同关系

1.1 目的

系统的目的主要通过「用户故事」来表达。书写用户故事是产品经理的基本功,但同时,也是所有进行系统设计和分析的人的基本功。

用户故事的结构是三部分:

  • 角色(谁要使用,为谁而设计?)
  • 功能(这个功能有什么作用,怎么获得)
  • 价值(为什么用户需要这个功能)

在实际书写过程里面,「用户故事」可以是文本的,也可以是表格,甚至可以是用 UML 的用例图或者序列图。

以我们的镜子为例,下面是一个完整的用户故事:

成都天府软件园的一家中型互联网公司,有300人的规模。这家公司的CEO大凡在软件园CEO群里面得知,FITURE魔镜开始给企业提供三个月试用,于是安排公司中的HR同事小凡来负责跟进。小凡根据大凡提供的联系方式,联系到了FITURE的BD,在提交了必要的公司证明材料后,预约了3台FITURE魔镜产品,并和行政的同事商议,决定将FITURE魔镜分别摆放在公司的两个茶水间和一个专门的小型会议室。

第二天,FITURE的BD带着安装人员上门安装调试,并且给小凡介绍了如何试用,以及试用期间的运营手段。第二周开始,小凡每周四下午3点都会组织大家一起做工间操,感兴趣的同事聚集在茶水间的魔镜前面,花15分钟的时间跟着岳岳老师进行肩颈放松与背部拉伸,有效缓解了工作疲劳。上午上班前、午休时、下班后,也有部分同事通过会议室的魔镜进行单人锻炼。甚至由于想用的人太多,还需要通过公司的会议预约系统提前进行预约。

在两个月后,FITURE的BD再次和小凡交流,小凡和CEO大凡商量后,决定正式付费使用FITURE魔镜产品,作为公司给员工提供的福利之一。而且,考虑到员工排队的情况,找了另外一间大的会议室,又新增了一台FITURE魔镜。

1.2 边界

中文里系统的「边界」,有两个维度:scope 和 constraints。其中「scope」主要是通过用户故事来抽象得到的,所以梳理完用户故事之后,我们一般还需要梳理的「边界」是系统的 「contraints」,正是这些约束条件会决定系统的一些关键特性:

  • Performance Efficiency
  • Compatibility
  • Availability & Reliability
  • Security
  • Maintainability
  • Portability

由于类似于 CAP 约束的原因,一个系统只能支持我们列出的体系结构特征里面的几个。因为每个架构特性通常会成为其他架构特性的约束。例如,如果一个架构师想要提高安全性,它几乎肯定会对性能产生负面影响:应用程序必须执行更多的加解密等降低性能的活动。

一般来说,在早期最主要需要梳理的约束条件,一般是跟流量/数据相关的,比如系统承接的 rps/bps,数据一致性要求的等等,这些会决定系统设计的时候,对可靠性、可扩展性、弹性等系统特性的决定。

在我很喜欢的《Designing Data-Intensive Applications》里,它提到的应用系统主要追求的三个方面就直接没有「可用性」,而是:

  • Reliability
  • Scalability
  • Maintainability

我觉得这里的原因,主要是「可用」更多是用户纬度的一个感受(系统在运行的过程中有多少时间是可以被用户使用的)。它本身是以「可靠性」(系统在出故障的情况十分能够完成工作)和「可维护性」(系统进行定期维护和故障处理十分方便)等其他工程纬度的指标为基础的。

2. 顶层设计

经过第一步的梳理,第二步就是进行顶层设计。一个系统在最顶层基本都可以划分为:

  • 应用层(App、小程序、Web Application 等等形式)
  • 接入层(一般会有流量管理,比如 AG 的设计)
  • 拆分出来的服务(有时候用户、商品、交易等等服务会在业务较多的时候为了复用成为一个 platform service,也就是常常看到的所谓「平台」或者「中台」或者「公共服务」)
  • 数据存储/持久化层(一开始通常主从数据库加上基本的缓存就够了)

3. 核心组件设计

前面我们讲系统的定义时说过,系统是由模块组成,通过模块间的协作完成功能的。

模块之间怎么协作呢?一般通过消息或者 API 调用来进行。

所以模块的设计一般是几个方面:

  • 根据功能使用 OOD(面向对象设计)来设计模块
  • 设计模块 的数据库 schema
  • 设计模块的 API 或者消息

可以说,模块边界的划分,API 或者消息的设计、schema 的设计等等,是架构师能力的主要体现。

4. 考虑系统的瓶颈和如何扩展当前的设计

当前架构是不是有性能或者安全的方面的瓶颈?什么时候应该使用什么方法解决这些瓶颈?比如数据库会变慢,需要做主从库做读写分离?需要分库分表?需要加缓存体系?

一个好的方案,一定是对当前业务情况最适用,投入产出比最高的方案。这也往往意味着,这个方案代表的系统,多半会在一年左右大规模重构:因为一个健康的互联网业务一般一年流量就应该翻很多倍了

二、核心命题

方案需要体现对以下问题的思考:

  1. 系统的价值、构成、边界和约束条件
  2. 系统有哪些角色,关键用户路径的流程是什么,有怎样的 SLA/SLI/SLO
  3. 有什么样的假设,有什么样的依赖条件
  4. 如何保障可用性和可靠性的细节
    • a. 包括但不限于流量怎么切分
    • b. 缓存怎么设计
      • i. Application caching
      • ii. Database caching
      • iii. Object caching(KV 存储如 Reids 或 Memchache)
      • iv. …
    • c. 数据怎么放怎么取
    • d. 系统的弹性怎么保障
  5. 系统在安全性等方面的考虑
  6. 有什么外部依赖和风险

这里就不一一展开了。