4.9 协调完成完整功能
4.9.1 背景
4.1节在介绍软件交付的第1个策略时,讲到软件架构要细粒度、低耦合、可复用。有了好的架构,在实现某个用户故事时,可能只需要修改一个微服务的代码即可。然而,不论架构多么好,总会遇到需要为一个用户故事修改多个微服务的代码的情况。
4.2节在介绍软件交付的第2个策略时,讲到每个用户故事的颗粒度要小,并且每次发布的用户故事数量要少。这样一来,可能每个用户故事只需要修改一个微服务的代码即可,也可能每个微服务都可以单独发布,而无须连带进行其他微服务的发布。然而,不论用户故事颗粒度多么小,也不论每次发布的用户故事数量多么少,总会遇到需要为一个用户故事修改多个微服务的代码的情况,也总会遇到一次发布包含对多个微服务的改动的情况。
事实上,正是从单体应用到微服务化这个趋势,使得我们需要越来越关注如何实现和交付跨代码库的改动。当这种情况出现时,就需要进行一定的协调管理——可能是跨多个代码库的协调,也可能是跨多个开发团队的协调,甚至是与外部系统、第三方之间的协调。下面我们来进一步分析。
4.9.2 开发全过程的协调
对于牵涉到多个代码库、多个开发团队的软件开发全过程的协调管理,从瀑布模型时代就在进行探索。瀑布模型本身就是用于整体系统从需求到发布的过程,当然它不够好。在敏捷管理实践中,目前业界有几个重要的多团队敏捷实践,即SoS(Scrum of Scrum)、SAFe(Scaled Agile Framework)、LeSS(Large Scale Scrum)、DAD(Disciplined Agile Development)。而在精益方面,精益看板墙的一些复杂形式就是用来协调多个开发团队之间的协作服务的。
4.9.3 交付过程的协调
当聚焦于软件交付过程时,也有一些具体问题需要处理。这是本书特别关注的地方。
当一个特性包含对多个微服务的改动时,能否在特性对应的改动还在特性分支上、还没有被提交到各代码库的集成发布分支时,就对该特性整体进行一些测试?答案是肯定的,但是需要动态创建或分配一个测试环境,专门用于测试这个跨多个微服务的特性。随后把每个微服务的相应特性分支上的代码版本部署上去,或者支持将各开发人员的本地开发环境加入这个测试环境中。
当一个特性包含对多个微服务的改动时,将该特性改动提交到集成发布分支,如何能够保证各代码库中的相应特性分支都合入了集成发布分支?当(打算)把集成发布分支上的代码部署到测试环境中进行测试时,能否自动计算出它包含了各个微服务上的哪些特性?进而,其中那些涉及多个微服务的特性,是否已经被完整包含了,而不是只包含该特性在一部分微服务上的改动?
当一个特性包含多个微服务甚至跨开发团队时,应该如何规划它的集成、测试和发布?如何协调相关的各个微服务甚至各个开发团队的集成、测试、发布的节奏?整体跑版本火车似乎是一种方法,有没有更好的方法?
当一次部署特别是一次向生产环境中的部署包含多个微服务时,该如何编排它们之间的顺序,进行适当的串行和并行?如何自动按照这样的编排部署?此外,无论怎样编排,总是会存在在短暂的时间内,一个微服务的新版本的实例需要和另一个微服务的旧版本的实例一起运行的情况,同一个微服务也会有新旧版本的实例同时运行。此时,如何避免出现问题?如何保证服务的连续性?
当生产环境中出现故障,需要紧急回退最近的部署时,是只将某个微服务回退到原先的版本,还是需要回退一组微服务?同时还要考虑回退顺序的编排,以及在回退过程中不要因为新旧版本并存而出问题。
以上讨论的都是跨微服务的源代码修改的问题。除了源代码,数据库表结构、数据库中的数据也可能需要随着源代码一起修改,共同实现某个特性,共同实现软件系统的演进。类似地,对环境及其配置也有可能需要做相应的修改。所以在讨论上面的问题时,也要同时考虑涉及数据库、环境、配置修改的情况。