一个架构师的真正职责
“你总提及的那个词,它的含义与你想表达的意思并不一样。”——Inigo Montoya,电影《公主新娘》中的人物
架构师的一个重要职责是,确保团队有共同的技术愿景,以帮助我们向客户交付他们想要的系统。
在某些场景下,架构师只需要和一个团队一起工作,这时他们等同于技术引领者。在其他情况下,他们要对整个项目的技术愿景负责,通常需要协调多个团队之间,甚至是整个组织内的工作。
不管处于哪个层次,架构师这个角色都很微妙。在一般的组织中,非常出色的开发人员才能成为架构师,但通常会比其他角色招致更多的批评。
相比其他角色而言,架构师对多个方面都有更加直接的影响,比如所构建系统的质量、同事的工作条件、组织应对变化的能力等。这个角色也很难做好,原因何在呢?
很多时候人们似乎忘了,我们的行业还很年轻。我们编写的程序在计算机上运行,而计算机从出现到现在也只有 70 年左右而已,因此我们需要在现存的行业中不断地寻找,帮助别人理解我们到底是做什么的。
我们不是医生或者医学工程师,也不是水管工或者电工。我们处于这些行业的中间地带,因此社会很难理解我们,我们也不清楚自己到底处于什么位置。
所以我们尝试借鉴其他的行业。我们把自己称作软件“工程师”或者“建筑师”1,但其实我们不是,对吧?
建筑师和工程师所具备的精确性和纪律性是遥不可及的,而且他们在社会中的重要性也很容易理解。
我的一个朋友在成为认证建筑师的前一天说:“如果明天我在酒吧对于如何盖房子给了你错误的建议,那么我要为此负责。从法律的角度来说,因为我是一个认证建筑师,所以做错了很可能会被起诉。”
他们在社会中有非常重要的作用,因此需要经过专门认证才能工作。比如,在英国你至少需要学习七年才能成为一名建筑师。这些职业在几千年前就存在了,而我们呢?相差甚远。
这也就是为什么我觉得很多形式的 IT 证书都没价值,因为我们对什么是好的知之甚少。
有些人想要得到社会的认可,所以借鉴了这些已经被大众认知的行业中的名词,但这样可能会造成两个问题。
首先,这么做的前提是我们要清楚自己应该干什么,而多数情况下事实并非如此。并不是说建筑和桥梁就一定不会倒塌,而是它们倒塌的次数要比我们程序崩溃的次数少得多,所以跟工程师相类比是不公平的。
其次,经过一些粗略的观察就会发现这种类比是站不住脚的。因为如果桥梁建筑和编程类似的话,那么建到一半的时候你可能会发现对岸比预想的要远 50 米,而且其材质是花岗岩而不是泥土,更糟糕的是我们最终想要的是一座公路桥而不是步行桥。
软件并没有类似这种真正的工程师和建筑师在物理规则方面的约束,事实上,我们要创造的东西从设计上来说就是要足够灵活,有很好的适应性,并且能够根据用户的需求进行演化。
也许“建筑师”这个术语是很有问题的。建筑师的工作是做好详细的计划,然后让别人去理解和执行。
进行这项工作需要对艺术性和工程性进行权衡,并且对整体进行监督,而其他所有的视角都要屈从于建筑师的视角,当然有时候他们也会考虑结构工程师基于物理规则的一些建议。
在我们的行业中,这种建筑师的视角会导致一些非常糟糕的实践。人们试图通过大量的图表和文档创建出一个完美的方案,而忽略了很多基础性的未知因素。
使用这种方式会导致人们很难真正理解实现起来的难度,甚至不知道这个设计到底能否奏效,想要对系统了解更多之后再对设计进行修改就更不可能了。
当我们把自己和工程师或者建筑师做比较时,很有可能会做出错误的决定。不幸的是,架构师这个词已经被大众接受了,所以现在我们能够做的事情就是在上下文中去重新定义这个词的含义。
本文节选自《微服务设计》
架构师的演化视角
与建造建筑物相比,在软件中我们会面临大量的需求变更,使用的工具和技术也具有多样性。
我们创造的东西并不是在某个时间点之后就不再变化了,甚至在发布到生产环境之后,软件还能继续演化。
对于我们创造的大多数产品来说,交付到客户手里之后,还是要响应客户的变更需求,而不是简单地交给客户一个一成不变的软件包。
因此架构师必须改变那种从一开始就要设计出完美产品的想法,相反我们应该设计出一个合理的框架,在这个框架下可以慢慢演化出正确的系统,并且一旦我们学到了更多知识,应该可以很容易地应用到系统中。
尽管截止到目前,本章都在警告你不要跟其他行业做过多的比较,但是我发现,有一个角色可以更好地跟 IT 架构师相类比。
这个想法是 Erik Doernenburg 告诉我的,他认为更好的类比是城市规划师,而不是建筑师。如果你玩过 SimCity,那么你应该很熟悉城市规划师这个角色。
城市规划师的职责是优化城镇布局,使其更易于现有居民生活,同时也会考虑一些未来的因素。为了达到这个目的,他需要收集各种各样的信息。
规划师影响城市演化的方法很有趣,他不会直接说“在那个地方盖一栋这样的楼”,相反他会对城市进行分区。
就像在 SimCity 中一样,你可能会把城市的某一部分规划成为工业区,另外一部分规划成为居民区,然后其他人会自己决定具体要盖什么建筑物。当然这个决定会受到一定的约束,比如工厂一定要盖在工业区。
城市规划师更多考虑的是人和公共设施如何从一个区域移到另一个区域,而不是具体在每个区域中发生的事情。
很多人把城市比作生物,因为城市会时不时地发生变化。当居民对城市的使用方式有所变化,或者受到外力的影响时,城市就会相应地演化。城市规划师应该尽量去预期可能发生的变化,但是也需要明白一个事实:尝试直接对各个方面进行控制往往不会奏效。
上面描述的城镇和软件的对应关系应该是很明显的。当用户对软件提出变更需求时,我们需要对其进行响应并做出相应的改变。
未来的变化很难预见,所以与其对所有变化的可能性进行预测,不如做一个允许变化的计划。为此,应该避免对所有事情做出过于详尽的设计。城市这个系统应该让生活在其中的住户感到开心。
有一件经常被人们忽略的事情是:系统的使用者不仅仅是终端用户,还有工作在其上的开发人员和运维人员,他们也对系统的需求变更负责。
借鉴 Frank Buschmann 的一个说法:架构师的职责之一就是保证该系统适合开发人员在其上工作。
城市规划师就像建筑师一样,需要知道什么时候他的计划没有得到执行。尽管他会引入较少的规范,并尽量少地对发展的方向进行纠正,但是如果有人决定要在住宅区建造一个污水池,他应该能制止。
所以我们的架构师应该像城市规划师那样专注在大方向上,只在很有限的情况下参与到非常具体的细节实现中来。他们需要保证系统不但能够满足当前的需求,还能够应对将来的变化。
而且他们还应该保证在这个系统上工作的开发人员要和使用这个系统的用户一样开心。听起来这是很高的标准,那么从哪里开始呢?
分区
前面我们将架构师比作城市规划师,那么在这个比喻里面,区域的概念对应的是什么呢?它们应该是我们的服务边界,或者是一些粗粒度的服务群组。
作为架构师,不应该过多关注每个区域内发生的事情,而应该多关注区域之间的事情。这意味着我们应该考虑不同的服务之间如何交互,或者说保证我们能够对整个系统的健康状态进行监控。
至于多大程度地介入区域内部事务,在不同的情况下则有所不同。很多组织采用微服务是为了使团队的自治性最大化,第 10 章会对这个话题做更多讨论。如果你就处在这样的组织中,那么你会更多地依靠团队来做出正确的局部决定。
但是在区域之间,或者说传统架构图中的框图之间,我们需要非常小心,因为在这些地方犯的错误会很难纠正。
每一个服务内部可以允许团队自己选择不同的技术栈或者数据存储技术,当然其他的问题也需要考虑。
但是事实上也不会无限制地允许团队选择任意技术栈,比如如果需要支持 10 种不同的技术栈的话,可能会在招聘上遇到困难,或者很难在不同团队之间交换人员。
类似地,如果每个团队自己选择完全不同的存储技术,可能你会发现自己对它们都不够熟悉。
举个例子,Netflix 在 Cassandra 这种存储技术上有非常成熟的使用规范,并认为相比对特定的任务使用最合适的技术而言,围绕 Cassandra 来构建相关的工具和培养专家更重要。
Netflix 是一个很极端的例子,他们认为可伸缩性是最重要的因素,但是通过这个例子你可以有自己的理解。
然而,服务之间的事情可能会变得很糟糕。如果一个服务决定通过 HTTP 暴露 REST 接口,另一个用的是 protocol buffers,第三个用的是 Java RMI,那么作为一个服务的消费者就需要支持各种形式的交互,这对于消费者来说简直就是噩梦。
这也就是为什么我强调我们应该“担心服务之间的交互,而不需要过于关注各个服务内部发生的事情”。
代码架构师如果想确保我们创造的系统对开发人员足够友好,那么架构师需要理解他们的决定对系统会造成怎样的影响。最低的要求是:架构师需要花时间和团队在一起工作,理想情况下他们应该一起进行编码。对于实施结对编程的团队来说,架构师很容易花一定的时间和团队成员进行结对。理想情况下,你应该参与普通的工作,这样才能真正理解普通的工作是什么样子。架构师和团队真正坐在一起,这件事情再怎么强调也不过分!相比通过电话进行沟通或者只看看团队的代码,一起和团队工作的这种方式会更加有效。至于和团队在一起工作的频率可以取决于团队的大小,关键是它必须成为日常工作的一部分。如果你和四个团队在一起工作,那么每四周和每个团队都工作半天,可以帮助你有效地和团队进行沟通,并了解他们都在做什么。
一个原则性的方法
“规则对于智者来说是指导,对于愚蠢者来说是遵从。”——一般认为出自 Douglas Bader
做系统设计方面的决定通常都是在做取舍,而在微服务架构中,你要做很多取舍!
当选择一个数据存储技术时,你会选择不太熟悉但能够带来更好可伸缩性的技术吗?在系统中存在两种技术栈是否可接受?那三种呢?
做某些决策所需要的信息很容易获取,这些还算是容易的。但是有些决策所需要的信息难以完全获取,那又该怎么办呢?
基于要达到的目标去定义一些原则和实践对做设计来说非常有好处。接下来让我们对它们做一些讨论。
1. 战略目标
做一名架构师已经很困难了,但幸运的是,通常我们不需要定义战略目标!战略目标关心的是公司的走向以及如何才能让自己的客户满意。
这些战略目标的层次一般都很高,但通常不会涉及技术这个层面,一般只在公司或者部门层面制定。这些目标可以是“开拓东南亚的新市场”或者“让用户尽量使用自助服务”。因为这些都是你的组织前进的方向,所以需要确保技术层面的选择能够与之一致。
如果你是制定公司技术愿景的人,那么你可能需要花费更多的时间和组织内非技术的部分(通常他们被叫作业务部门)进行交互。那么业务部门的愿景是什么?它又会如何发生改变呢?
2. 原则
为了和更大的目标保持一致,我们会制定一些具体的规则,并称之为原则,它不是一成不变的。
举个例子,如果组织的一个战略目标是缩短新功能上线的周期,那么一个可能的原则是,交付团队应该对整个软件生命周期有完全的控制权,这样他们就可以及时交付任何就绪的功能,而不受其他团队的限制。
如果组织的另一个目标是在其他国家快速增长业务,你需要使用的原则可能就是,整个系统必须能够方便地部署到相应的国家,从而符合该国家对数据存储地理位置方面的要求。
很有可能这些原则并不适合你的组织。一般来讲,原则最好不要超过 10 个,或者能够写在一张海报上,不然大家会很难记住。而且原则越多,它们发生重叠和冲突的可能性就越大。
Heroku 的 12 Factors 就是一组能够帮助你在 Heroku 平台上创建应用的设计原则,当然它们在其他的上下文中可能也有用。其中,有些原则实际上是为了让你的应用程序可以适应 Heroku 这个平台而引入的约束。
约束是很难(或者说不可能)改变的,但原则也是我们自己决定的。你应该显式地指出哪些是原则,哪些是约束,这样用户就会很清楚哪些是不能变的。从个人角度来讲,我认为把原则和约束放在同一个列表中是有好处的,这样我们就可以不时地回顾一下这些约束是否真的不可改变。
3. 实践
我们通过相应的实践来保证原则能够得到实施,这些实践能够指导我们如何完成任务。
通常这些实践是技术相关的,而且是比较底层的,所以任何一个开发人员都能够理解。这些实践包括代码规范、日志数据集中捕获或者 HTTP/REST 作为标准集成风格等。由于实践比较偏技术层面,所以其改变的频率会高于原则。
就像原则那样,有时候实践也会反映出组织内的一些限制。比如,如果你只支持 CentOS,那么相应的实践就应该考虑这个因素。
实践应该巩固原则。比如前面我们提过一个原则是开发团队应该可以对软件开发全流程有控制权,相应的实践就是所有的服务都部署在不同的 AWS 账户中,从而可以提供资源的自助管理和与其他团队的隔离。
4. 将原则和实践相结合
有些东西对一些人来说是原则,对另一些人来说则可能是实践。比如,你可能会把使用 HTTP/REST 作为原则,而不是实践。
这也没什么问题,关键是要有一些重要的原则来指导系统的演化,同时也要有一些细节来指导如何实现这些原则。
对于一个足够小的群组,比如单个团队来说,将原则和实践进行结合是没问题的。但是在一个大型组织中,技术和工作实践可能不一样,在不同的地方需要的实践可能也不同。
不过这也没关系,只要它们都能够映射到相同的原则即可。比如一个 .NET 团队可能有一套实践,一个 Java 团队有另一套实践,但背后的原则是相同的。
5. 真实世界的例子
我的同事 Evan Bottcher 帮一个客户画出了如图 1 所示的图表。该图很清楚地显示了目标、原则和实践之间的相互影响。
几年间,实践改动得很频繁,而原则基本上没怎么变。可以把这样一个图表打印出来并共享给相关人员,其中每个条目都很简单,所以开发人员应该很容易记住它们。
尽管每条实践背后还有很多细节,但仅仅能把它们总结表述出来也是非常有用的。
图 1:原则和实践的真实例子
上面提到的一些项可以使用文档来支撑,但大多数情况下我喜欢给出一些示例代码供人阅读、研究和运行,从而传递上面涉及的那些信息。更好的方式是,创造一些工具来保证我们所做事情的正确性。后面马上就会对这个话题做深入的讨论。
要求的标准
当你浏览这些实践,并思考你需要做的取舍时,需要注意一个很重要的因素:系统允许多少可变性。
我们需要识别出各个服务需要遵守的通用规则,一种方法是,给出一个好服务的例子来阐释好服务的特点。在系统中什么是好服务“公民”呢?
它需要有什么样的能力才能保证整个系统是可控的,并且一个有问题的服务不会导致整个系统瘫痪?
这些问题很难回答,因为就像人一样,在某种上下文中是一个好公民不代表在其他上下文中也是,但我们还是可以观察到各个服务中一些通用的优秀实践。一些关键领域有太多的变化方向,而这可能会导致很多问题。
就像 Netflix 的 Ben Christensen 说的那样,当我们在考虑一个更大的全景图时,“系统应该由很多小的但有自治生命周期的组件构成,而且这些组件之间有着紧密的关联”。
所以在优化单个服务自治性的同时,也要兼顾全局。一种能帮助我们实现平衡的方法就是,清楚地定义出一个好服务应有的属性。
1. 监控
能够清晰地描绘出跨服务系统的健康状态非常关键。这必须在系统级别而非单个服务级别进行考虑。
往往在需要诊断一个跨服务的问题或者想要了解更大的趋势时,你才需要知道每个服务的健康状态。
简单起见,我建议确保所有的服务使用同样的方式报告健康状态及其与监控相关的数据。
你可能会选择使用推送机制,也就是说,每个服务主动把数据推送到某个集中的位置。(在作者所著的《微服务设计》第八章讲到)
你可以使用 Graphite 来收集指标数据,使用 Nagios 来检测健康状态,或者使用轮询系统来从各个节点收集数据。
但无论你的选择是什么,都应尽量保持标准化。每个服务内的技术应该对外不透明,并且不要为了服务的具体实现而改变监控系统。日志功能和监控情况类似:也需要集中式管理。
2. 接口
选用少数几种明确的接口技术有助于新消费者的集成。使用一种标准方式很好,两种也不太坏,但是 20 种不同的集成技术就太糟糕了。这里说的不仅仅是关于接口的技术和协议。
举个例子,如果你选用了 HTTP/REST,在 URL 中你会使用动词还是名词?你会如何处理资源的分页?你会如何处理不同版本的 API ?
3. 架构安全性
一个运行异常的服务可能会毁了整个系统,而这种后果是我们无法承担的,所以,必须保证每个服务都可以应对下游服务的错误请求。没有很好处理下游错误请求的服务越多,我们的系统就会越脆弱。
你可以至少让每个下游服务使用它们自己的连接池,进一步让每个服务使用一个断路器。在第 11 章中讨论规模化微服务时,会就这个话题做更深入的讨论。
返回码也应该遵守一定的规则。如果你的断路器依赖于 HTTP 返回码,并且一个服务决定使用 2XX 作为错误码,或者把 4XX 和 5XX 混用,那么这种安全措施就没什么意义了。
即使你使用的不是 HTTP,也应该注意类似的问题。对以下几种请求做不同的处理可以帮助系统及时失败,并且也很容易追溯问题:
(1)正常并且被正确处理的请求;
(2)错误请求,并且服务识别出了它是错误的,但什么也没做;
(3)被访问的服务宕机了,所以无法判断请求是否正常。如果我们的服务没有很好地遵守这些规则,那么整个系统就会更加脆弱。
4. 代码治理
聚在一起,就如何做事情达成共识是一个好主意。但是,花时间保证人们按照这个共识来做事情就没那么有趣了,因为在各个服务中使用这些标准做法会成为开发人员的负担。
我坚信应该使用简单的方式把事情做对。我见过的比较奏效的两种方式是,提供范例和服务代码模板。
5. 范例
编写文档是有用的。我很清楚这样做的价值,这也正是我写这本书的原因。但是开发人员更喜欢可以查看和运行的代码。
如果你有一些很好的实践希望别人采纳,那么给出一系列的代码范例会很有帮助。这样做的一个初衷是:如果在系统中人们有比较好的代码范例可以模仿,那么他们也就不会错得很离谱。
理想情况下,你提供的优秀范例应该来自真实项目,而不是专门实现的一个完美的例子。因为如果你的范例来自真正运行的代码,那么就可以保证其中所体现的那些原则都是合理的。
裁剪服务代码模板
如果能够让所有的开发人员很容易地遵守大部分的指导原则,那就太棒了。一种可能的方式是,当开发人员想要实现一个新服务时,所有实现核心属性的那些代码都应该是现成的。
Dropwizard 和 Karyon 是两个基于 JVM 的开源微容器。
它们的运行模式相似,会自动下载一系列第三方库,这些库可以提供一些特性,比如健康检查、HTTP 服务、提供指标数据接口等。这样你就有了一个可以从命令行启动的嵌入式 servlet 容器。
这是一个很好的开始,但是你可以做得更多。在实际工作中,你可以使用 Dropwizard 和 Karyon 作为基础,然后根据自己的上下文加入更多的定制化特性。
举个例子,如果你想要断路器的规范化使用,那么就可以将 Hystrix 这个库集成进来。
或者,你想要把所有的指标数据都发送到中心 Graphite 服务器,那么就可以使用像Dropwizard’s Metrics 这样的开源库,只需要在此基础上做一些配置,响应时间和错误率等信息就会自动被推送到某个已知的服务器上。
针对自己的开发实践裁剪出一个服务代码模板,不但可以提高开发速度,还可以保证服务的质量。
当然,如果你的组织使用多种不同的技术栈,那么针对每种技术栈都需要这样一个服务代码模板。你也可以把它当作一种在团队中巧妙地限制语言选择的方式。
如果只存在基于 Java 的服务代码模板,那么选用其他技术栈就意味着开发人员需要自己做很多额外的工作。Netflix 非常在意服务的容错性,因为它们不希望一个服务停止工作造成整个系统都无法正常工作。
Netflix 提供了一个基于 JVM 的库来处理这些问题。任何一个新技术栈的引入都意味着要把这部分工作重新做一遍。相对于做这些事情的代价,Netflix 更关心的是,开发这些库时可能会引入的错误。
如果某个新实现的服务的容错处理机制出错,其对系统带来严重影响的风险也会增加。Netflix 使用挎斗(sidebar)服务来降低这种风险。挎斗服务会和 JVM 进行本地通信,而为了完成这种通信,该 JVM 需要使用某些特定的第三方库。
有一点需要注意的是,创建服务代码模板不是某个中心化工具的职责,也不是指导(即使是通过代码)我们应怎样工作的架构团队的职责。应该通过合作的方式定义出这些实践,所以你的团队也需要负责更新这个模板(内部开源的方式能够很好地完成这项工作)。
我也见过一个团队的士气和生产力是如何被强制使用的框架给毁掉的。基于代码重用的目的,越来越多的功能被加到一个中心化的框架中,直至把这个框架变成一个不堪重负的怪兽。
如果你决定要使用一个裁剪的服务代码模板,一定要想清楚它的职责是什么。理想情况下,应该可以选择是否使用服务代码模板,但是如果你强制团队使用它,一定要确保它能够简化开发人员的工作,而不是使其复杂化。
你还需要知道,重用代码可能引入的危险。在重用代码的驱动下,我们可能会引入服务之间的耦合。有一个我接触过的组织非常担心这个问题,所以他们会手动把服务代码模板复制到各个服务中。
这样做的问题是,如果核心服务代码模板升级了,那么需要花很长时间把这些升级应用到整个系统中。但相对于耦合的危险而言,这个问题倒没那么严重。
还有一些我接触过的团队,把服务代码模板简单地做成了一个共享的库依赖,这时他们就要非常小心地防止对 DRY(Don’t Repeat Yourself,避免重复代码)的追求导致系统过度耦合!这是一个很微妙的话题,所以第 4 章会做更深入的讨论。
技术债务
有时候可能无法完全遵守技术愿景,比如为了发布一些紧急的特性,你可能会忽略一些约束。
其实这仅仅是另一个需要做的取舍而已。我们的技术愿景有其本身的道理,所以偏离了这个愿景短期可能会带来利益,但是长期来看是要付出代价的。
可以使用技术债务的概念来帮助我们理解这个取舍,就像在真实世界中欠的债务需要偿还一样,累积的技术债务也是如此。
不光走捷径会引入技术债务。有时候系统的目标会发生改变,并且与现有的实现不符,这种情况也会产生技术债务。
架构师的职责就是从更高的层次出发,理解如何做权衡。理解债务的层次及其对系统的影响非常重要。
对于某些组织来说,架构师应该能够提供一些温和的指导,然后让团队自行决定如何偿还这些技术债务。而其他的组织就需要更加结构化的方式,比如维护一个债务列表,并且定期回顾。
例外管理
原则和实践可以指导我们如何构建系统。那么,如果系统偏离了这些指导又会发生什么呢?有时候我们会决定针对某个规则破一次例,然后把它记录下来。
如果这样的例外出现了很多次,就可以通过修改原则和实践的方式把我们的理解固化下来。
举个例子,可能我们有一个实践论述应该总是使用 MySQL 做数据存储,但是后来有足够的证明表明在海量存储的场景下应使用 Cassandra,这时就可以对实践进行修改:“在大多数场景下使用 MySQL 做存储,如果是数据快速增长的场景,可以使用 Cassandra。”
在这里我觉得有必要重申一下:每个组织都是不同的。我曾经合作过的某些公司有高度自治的团队,他们也得到公司足够的信任。对于这种情况,通常原则都是很轻量级的(例外管理可能会完全消失,或者大大减少)。
有些组织结构化较强,开发人员拥有较小的自由度。这种情况下,通过例外管理来保证规则的合理性就非常重要了。
现实中的情况是多种多样的,但我个人非常支持使用拥有更好自治性的微服务团队,他们有更大的自由度来解决问题。如果你所在的组织对开发人员有非常多的限制,那么微服务可能并不适合你。
集中治理和领导
架构师的部分职责是治理。那么治理又是什么意思呢? COBIT(Control Objectives for Information and Related Technology,信息和相关技术的控制目标)给出了一个很好的定义:
治理通过评估干系人的需求、当前情况及下一步的可能性来确保企业目标的达成,通过排优先级和做决策来设定方向。对于已经达成一致的方向和目标进行监督。——COBIT 5
在 IT 的上下文中有很多事情需要治理,而架构师会承担技术治理这部分的职责。
如果说,架构师的一个职责是确保有一个技术愿景,那么治理就是要确保我们构建的系统符合这个愿景,而且在需要的时候还应对愿景进行演化。
架构师会对很多事情负责。他们需要确保有一组可以指导开发的原则,并且这些原则要与组织的战略相符。
他们还需要确保,以这些原则为指导衍生出来的实践不会给开发人员带来痛苦。他们需要了解新技术,需要知道在什么时候做怎样的取舍。
上述这些职责已经相当多了,但是他们还需要让同事也理解这些决定和取舍,并执行下去。
对了,还有前面提到的:他们还需要花时间和团队一起工作,甚至是编码,从而了解所做的决定对团队造成了怎样的影响。
要求很高,是吗?没错。但是我坚定地认为他们不应该独自做这些事情,可以由一个治理小组来做这个工作,并确定愿景。
一般来讲,治理是一个小组活动。它可以是与一个足够小的团队进行非正式聊天,也可以是在比较大的范围内,与一个有着正式成员的小组进行结构化例会。
在这些会议上,可以讨论前面提到的那些原则,有必要的话也可以对其进行修改。这个小组应该由技术专家领导,并且要有一线人员的参与。这个小组也应该负责跟踪和管理技术风险。
我很喜欢的一种模式是,由架构师领导这个小组,但是每个交付团队都有人参加。架构师负责确保该组织的正常运作,整个小组都要对治理负责。
这样职责就得到了分担,并且保证有来自高层的支持。这也可以保证信息从开发团队顺畅地流入这个小组,从而保证小组做出更合理的决定。
有时候架构师可能不认同小组做的决定,这时应该怎么办?我曾经面对过这样的场景,我认为这是架构师需要面对的最富有挑战性的场景之一。
事实上,大多数情况下我会认同小组的决定。我曾经尝试说服大家,但事实证明这很难做到。一个小组通常会比单个人更加聪明,而且我也不止一次被证明是错误的!
如果你给一个小组权力去做决定,但在最后又忽略了这个决定,那这个小组就毫无意义可言了。有时候我也会对小组施加影响。那么我为什么这么做,我会在什么时候做,又会怎么说呢?
类比一下教小孩儿骑自行车的过程。你没法替代他们去骑车。你会看着他们摇摇晃晃地前行,但是,如果每次你看到他们要跌倒就上去扶一把,他们永远都学不会。
而且无论如何,他们真正跌倒的次数会比你想象的要少!但是,如果他们马上就要驶入车流繁忙的大马路,或者附近的鸭子池塘,你就必须站出来了。类似地,作为一名架构师,你必须要在团队驶向类似鸭子池塘这样的地方时抓紧他们。
还有一点要注意的是,即使你很清楚什么是对的,然后尝试去控制团队,也可能会破坏和团队的关系,并且会使团队感觉他们没有话语权。
有时候按照一个你不同意的决定走下去反而是正确的,知道什么时候可以这么做,什么时候不要这么做是很困难的,但有时也很关键。
建设团队
对于一个系统技术愿景的主要负责人来说,执行愿景不仅仅等同于做技术决定,和你一起工作的那些人自然会做这些决定。
对于技术领导人来说,更重要的事情是帮助你的队友成长,帮助他们理解这个愿景,并保证他们可以积极地参与到愿景的实现和调整中来。
帮助别人成长的形式有很多种,其中大部分都超出了本书的范围。微服务架构本身能够提供一种很好的形式。
在单块系统中,人们为某些事情负责的机会非常有限,而在微服务架构中存在多个自治的代码库,每个代码库都有着自己独立的生命周期,这就给更多人提供了对单个服务负责的机会。
而当这些人在单个服务上面得到足够锻炼之后,就可以给他们更多的责任,从而帮助他们逐步达成自己的职业目标,同时通过分担职责也可以防止某一个人的负担过重。
我坚定地相信,伟大的软件来自于伟大的人。所以如果你只担心技术问题,那么恐怕你看到的问题远远不及一半。
小结
总结一下本章,下面是我认为的一个演进式架构师应该承担的职责。
- 愿景
- 确保在系统级有一个经过充分沟通的技术愿景,这个愿景应该可以帮助你满足客户和组织的需求。
- 同理心
- 理解你所做的决定对客户和同事带来的影响。
- 合作
- 和尽量多的同事进行沟通,从而更好地对愿景进行定义、修订及执行。
- 适应性
- 确保在你的客户和组织需要的时候调整技术愿景。
- 自治性
- 在标准化和团队自治之间寻找一个正确的平衡点。
- 治理
- 确保系统按照技术愿景的要求实现。
演进式架构师应该理解,成功要靠不断地取舍来实现。总会存在一些原因需要你改变工作的方式,但是具体做哪些改变就只能依赖于自己的经验了。而僵化地固守自己的想法无疑是最糟糕的做法。
虽然本章的大部分建议对任何一个系统架构师来说都适用,但是在微服务系统中,架构师需要做更多的决定,因此,能更好地平衡这些取舍是非常关键的。