你总提及的那个词,它的含义与你想表达的意思并不一样。
“建筑师”和“架构师”在英文中都是 architect,而“架构师”这个词的含义借鉴的是建筑师在建筑中的角色。
与建造建筑物相比,在软件中我们会面临大量的需求变更,使用的工具和技术也具有多样性。我们创造的东西并不是在某个时间点之后就不再变化了,甚至在发布到生产环境之后,软件还能继续演化。因此架构师必须改变那种从一开始就要设计出完美产品的想法,相反我们应该设计出一个合理框架。
其实,有一个角色可以更好地跟 IT 架构师相类比。那就是城市规划师,而不是建筑师。如果你玩过 SimCity,那么你应该很熟悉城市规划师这个角色。城市规划师的职责是优化城镇布局,使其更易于现有居民生活,同时也会考虑一些未来的因素。为了达到这个目的,他需要收集各种各样的信息。规划师影响城市演化的方法很有趣,他不会直接说“在那个地方盖一栋这样的楼”,相反他会对城市进行分区。就像在 SimCity 中一样,你可能会把城市的某一部分规划成为工业区,另外一部分规划成为居民区,然后其他人会自己决定具体要盖什么建筑物。当然这个决定会受到一定的约束,比如工厂一定要盖在工业区。城市规划师更多考虑的是人和公共设施如何从一个区域移到另一个区域,而不是具体在每个区域中发生的事情。
城市规划师就像建筑师一样,需要知道什么时候他的计划没有得到执行。尽管他会引入较少的规范,并尽量少地对发展的方向进行纠正,但是如果有人决定要在住宅区建造一个污水池,他应该能制止。
所以我们的架构师应该像城市规划师那样专注在大方向上,只在很有限的情况下参与到非常具体的细节实现中来。他们需要保证系统不但能够满足当前的需求,还能够应对将来的变化。而且他们还应该保证在这个系统上工作的开发人员要和使用这个系统的用户一样开心。听起来这是很高的标准,那么从哪里开始呢?
前面我们将架构师比作城市规划师,那么在这个比喻里面,区域的概念对应的是什么呢?它们应该是我们的服务边界,或者是一些粗粒度的服务群组。作为架构师,不应该过多关注每个区域内发生的事情,而应该多关注区域之间的事情。这意味着我们应该考虑不同的服务之间如何交互,或者说保证我们能够对整个系统的健康状态进行监控。至于多大程度地介入区域内部事务,在不同的情况下则有所不同。很多组织采用微服务是为了使团队的自治性最大化,如果你就处在这样的组织中,那么你会更多地依靠团队来做出正确的局部决定。
代码架构师
如果想确保我们创造的系统对开发人员足够友好,那么架构师需要理解他们的决定对系统会造成怎样的影响。
最低的要求是:架构师需要花时间和团队在一起工作,理想情况下他们应该一起进行编码。
对于实施结对编程的团队来说,架构师很容易花一定的时间和团队成员进行结对。
理想情况下,你应该参与普通的工作,这样才能真正理解普通的工作是什么样子。
架构师和团队真正坐在一起,这件事情再怎么强调也不过分!相比通过电话进行沟通或者只看看团队的代码,一起和团队工作的这种方式会更加有效。
至于和团队在一起工作的频率可以取决于团队的大小,关键是它必须成为日常工作的一部分。
如果你和四个团队在一起工作,那么每四周和每个团队都工作半天,可以帮助你有效地和团队进行沟通,并了解他们都在做什么。
规则对于智者来说是指导,对于愚蠢者来说是遵从。
做系统设计方面的决定通常都是在做取舍,而在微服务架构中,你要做很多取舍!当选择一个数据存储技术时,你会选择不太熟悉但能够带来更好可伸缩性的技术吗?在系统中存在两种技术栈是否可接受?那三种呢?做某些决策所需要的信息很容易获取,这些还算是容易的。但是有些决策所需要的信息难以完全获取,那又该怎么办呢?
基于要达到的目标去定义一些原则和实践对做设计来说非常有好处。接下来让我们对它们做一些讨论。
做一名架构师已经很困难了,但幸运的是,通常我们不需要定义战略目标!战略目标关心的是公司的走向以及如何才能让自己的客户满意。这些战略目标的层次一般都很高,但通常不会涉及技术这个层面,一般只在公司或者部门层面制定。
为了和更大的目标保持一致,我们会制定一些具体的规则,并称之为原则,它不是一成不变的。举个例子,如果组织的一个战略目标是缩短新功能上线的周期,那么一个可能的原则是,交付团队应该对整个软件生命周期有完全的控制权,这样他们就可以及时交付任何就绪的功能,而不受其他团队的限制。如果组织的另一个目标是在其他国家快速增长业务,你需要使用的原则可能就是,整个系统必须能够方便地部署到相应的国家,从而符合该国家对数据存储地理位置方面的要求。
我们通过相应的实践来保证原则能够得到实施,这些实践能够指导我们如何完成任务。通常这些实践是技术相关的,而且是比较底层的,所以任何一个开发人员都能够理解。这些实践包括代码规范、日志数据集中捕获或者 HTTP/REST 作为标准集成风格等。由于实践比较偏技术层面,所以其改变的频率会高于原则。
就像原则那样,有时候实践也会反映出组织内的一些限制。比如,如果你只支持 CentOS,那么相应的实践就应该考虑这个因素。
实践应该巩固原则。比如前面我们提过一个原则是开发团队应该可以对软件开发全流程有控制权,相应的实践就是所有的服务都部署在不同的 AWS 账户中,从而可以提供资源的自助管理和与其他团队的隔离。
有些东西对一些人来说是原则,对另一些人来说则可能是实践。比如,你可能会把使用 HTTP/REST 作为原则,而不是实践。这也没什么问题,关键是要有一些重要的原则来指导系统的演化,同时也要有一些细节来指导如何实现这些原则。对于一个足够小的群组,比如单个团队来说,将原则和实践进行结合是没问题的。但是在一个大型组织中,技术和工作实践可能不一样,在不同的地方需要的实践可能也不同。不过这也没关系,只要它们都能够映射到相同的原则即可。比如一个 .NET 团队可能有一套实践,一个 Java 团队有另一套实践,但背后的原则是相同的。
在优化单个服务自治性的同时,也要兼顾全局。一种能帮助我们实现平衡的方法就是,清楚地定义出一个好服务应有的属性。
能够清晰地描绘出跨服务系统的健康状态非常关键。这必须在系统级别而非单个服务级别进行考虑。简单起见,我建议确保所有的服务使用同样的方式报告健康状态及其与监控相关的数据。
你可能会选择使用推送机制,也就是说,每个服务主动把数据推送到某个集中的位置。你可以使用 Graphite 来收集指标数据,使用 Nagios 来检测健康状态,或者使用轮询系统来从各个节点收集数据,但无论你的选择是什么,都应尽量保持标准化。每个服务内的技术应该对外不透明,并且不要为了服务的具体实现而改变监控系统。日志功能和监控情况类似:也需要集中式管理。
选用少数几种明确的接口技术有助于新消费者的集成。使用一种标准方式很好,两种也不太坏,但是 20 种不同的集成技术就太糟糕了。这里说的不仅仅是关于接口的技术和协议。举个例子,如果你选用了 HTTP/REST,在 URL 中你会使用动词还是名词?你会如何处理资源的分页?你会如何处理不同版本的 API ?
一个运行异常的服务可能会毁了整个系统,而这种后果是我们无法承担的,所以,必须保证每个服务都可以应对下游服务的错误请求。没有很好处理下游错误请求的服务越多,我们的系统就会越脆弱。你可以至少让每个下游服务使用它们自己的连接池,进一步让每个服务使用一个断路器。
聚在一起,就如何做事情达成共识是一个好主意。但是,花时间保证人们按照这个共识来做事情就没那么有趣了,因为在各个服务中使用这些标准做法会成为开发人员的负担。我坚信应该使用简单的方式把事情做对。我见过的比较奏效的两种方式是,提供范例和服务代码模板。
编写文档是有用的。我很清楚这样做的价值,这也正是我写这本书的原因。但是开发人员更喜欢可以查看和运行的代码。如果你有一些很好的实践希望别人采纳,那么给出一系列的代码范例会很有帮助。这样做的一个初衷是:如果在系统中人们有比较好的代码范例可以模仿,那么他们也就不会错得很离谱。
理想情况下,你提供的优秀范例应该来自真实项目,而不是专门实现的一个完美的例子。因为如果你的范例来自真正运行的代码,那么就可以保证其中所体现的那些原则都是合理的。
如果能够让所有的开发人员很容易地遵守大部分的指导原则,那就太棒了。一种可能的方式是,当开发人员想要实现一个新服务时,所有实现核心属性的那些代码都应该是现成的。
有一点需要注意的是,创建服务代码模板不是某个中心化工具的职责,也不是指导(即使是通过代码)我们应怎样工作的架构团队的职责。应该通过合作的方式定义出这些实践,所以你的团队也需要负责更新这个模板(内部开源的方式能够很好地完成这项工作)。
如果你强制团队使用它,一定要确保它能够简化开发人员的工作,而不是使其复杂化。你还需要知道,重用代码可能引入的危险。在重用代码的驱动下,我们可能会引入服务之间的耦合。
有时候可能无法完全遵守技术愿景,比如为了发布一些紧急的特性,你可能会忽略一些约束。其实这仅仅是另一个需要做的取舍而已。我们的技术愿景有其本身的道理,所以偏离了这个愿景短期可能会带来利益,但是长期来看是要付出代价的。可以使用技术债务的概念来帮助我们理解这个取舍,就像在真实世界中欠的债务需要偿还一样,累积的技术债务也是如此。
不光走捷径会引入技术债务。有时候系统的目标会发生改变,并且与现有的实现不符,这种情况也会产生技术债务。
架构师的职责就是从更高的层次出发,理解如何做权衡。理解债务的层次及其对系统的影响非常重要。对于某些组织来说,架构师应该能够提供一些温和的指导,然后让团队自行决定如何偿还这些技术债务。而其他的组织就需要更加结构化的方式,比如维护一个债务列表,并且定期回顾。
原则和实践可以指导我们如何构建系统。那么,如果系统偏离了这些指导又会发生什么呢?有时候我们会决定针对某个规则破一次例,然后把它记录下来。
现实中的情况是多种多样的,如果你所在的组织对开发人员有非常多的限制,那么微服务可能并不适合你。
架构师的部分职责是治理。那么治理又是什么意思呢?
治理通过评估干系人的需求、当前情况及下一步的可能性来确保企业目标的达成,通过排优先级和做决策来设定方向。对于已经达成一致的方向和目标进行监督。
在 IT 的上下文中有很多事情需要治理,而架构师会承担技术治理这部分的职责。如果说,架构师的一个职责是确保有一个技术愿景,那么治理就是要确保我们构建的系统符合这个愿景,而且在需要的时候还应对愿景进行演化。
架构师会对很多事情负责。他们需要确保有一组可以指导开发的原则,并且这些原则要与组织的战略相符。他们还需要确保,以这些原则为指导衍生出来的实践不会给开发人员带来痛苦。他们需要了解新技术,需要知道在什么时候做怎样的取舍。上述这些职责已经相当多了,但是他们还需要让同事也理解这些决定和取舍,并执行下去。对了,还有前面提到的:他们还需要花时间和团队一起工作,甚至是编码,从而了解所做的决定对团队造成了怎样的影响。
需要在一定程度上相信你的团队。你没法替代他们去骑车。你会看着他们摇摇晃晃地前行,但是,如果每次你看到他们要跌倒就上去扶一把,他们永远都学不会。而且无论如何,他们真正跌倒的次数会比你想象的要少!但是,如果他们马上就要驶入车流繁忙的大马路,或者附近的鸭子池塘,你就必须站出来了。类似地,作为一名架构师,你必须要在团队驶向类似鸭子池塘这样的地方时抓紧他们。还有一点要注意的是,即使你很清楚什么是对的,然后尝试去控制团队,也可能会破坏和团队的关系,并且会使团队感觉他们没有话语权。有时候按照一个你不同意的决定走下去反而是正确的,知道什么时候可以这么做,什么时候不要这么做是很困难的,但有时也很关键。
对于一个系统技术愿景的主要负责人来说,执行愿景不仅仅等同于做技术决定,和你一起工作的那些人自然会做这些决定。对于技术领导人来说,更重要的事情是帮助你的队友成长,帮助他们理解这个愿景,并保证他们可以积极地参与到愿景的实现和调整中来。
伟大的软件来自于伟大的人。所以如果你只担心技术问题,那么恐怕你看到的问题远远不及一半。
总结一下,一个演进式架构师应该承担的职责。
确保在系统级有一个经过充分沟通的技术愿景,这个愿景应该可以帮助你满足客户和组织的需求。
理解你所做的决定对客户和同事带来的影响。
和尽量多的同事进行沟通,从而更好地对愿景进行定义、修订及执行。
确保在你的客户和组织需要的时候调整技术愿景。
在标准化和团队自治之间寻找一个正确的平衡点。
确保系统按照技术愿景的要求实现。
演进式架构师应该理解,成功要靠不断地取舍来实现。总会存在一些原因需要你改变工作的方式,但是具体做哪些改变就只能依赖于自己的经验了。而僵化地固守自己的想法无疑是最糟糕的做法。