成功微服务实施的组织演进
在 成功微服务实施的技术演进里我们介绍了案例中微服务架构演进的技术背景,本文介绍一下这期间发生的组织演进。可以说,一个合适的组织结构是驱动微服务架构成功落地的必要能力。
在我们如何衡量微服务实施的成功里面,我们介绍到系统的规模会因为维护成本达到极限。这个维护成本中最主要的一个部分就是人员成本和管理成本。而在这个案例里,我们可以看到两个特征:管理层的缩减和生产力的提升。
微服务开发团队的演化过程
在最开始的时候,我们的产品分为两类团队,如下图所示:
microservice-team.png一类是维护现有产品的团队,我们称之为“BAU (Business As Usual)团队”。这样一个团队用来修复 Bug、清理技术债、并对生产需求快速响应,有时候也做一些小于一个迭代(2周)的需求。可以说是一些重要又紧急的事情。在代码库上负责对代码主干和hotfix(快速修复)分支进行更改。
另一类团队是功能团队,又称特性团队。这样的团队有多个,都是按照不同的新特性和新需求组建的团队。团队大小根据需求的规模和项目的周期决定。每个团队都有一个特性分支,这个特性分支采用单主干开发。在开发的过程中会每天把master 分支合并到自己的分支上,以降低未来合并的痛苦。
待特性开发团队完成了一个项目或者一个特性的开发后,代码合并到主干,开始进行1~3个月的维护期,这个期间特性团队解散并入BAU团队。而之前 BAU 团队的成员开始准备成立新的特性开发团队了。
由于代码是“全民所有制”,每个人都会对所有的代码质量负责,而不是自己负责的那一小块。而且每个团队在 BAU 项目上工作的时候,可以学习到完整的业务知识和开发实践。因此 BAU 团队也适合培养刚加入团队的新人。
在这样不断的轮换过程中,每个人都学习到了整个代码库的业务知识,也参与了新特性的开发。
微服务团队就来自于这样一个特性团队:我们需要为新的微服务新建一个代码库。也需要在原先的代码库上通过创建新的分支来进行修改,把微服务集成到老的系统上去。当微服务部署好之后,新的分支就会被合并到主干,部署后和微服务集成。
后来,随着需要微服务化改造的系统越来越多,会慢慢演变成下图的样子:
多个微服务的团队从宏观上来看,一个企业为了满足各个方面的信息化需求,一定会有很多不同的应用系统。比如财务、人员管理、产品管理、工作流程等。等发展到了一定阶段一定会需要通过技术手段将不同的系统实现数据共享。我们会采用系统集成技术来集成不同的系统,把所有的系统都整合到一起。这里就涉及到了两个问题:
一个是“�Single source of truth”,也就是单一事实来源。我们希望在多系统集成的情况下,某一种数据,例如客户信息、价格,等都有单一的事实来源。否则在不同子系统之间出现数据不一致的情况。
另外一个就是之前提到的 Design For Failure,在业务正在运行的期间,应用系统的改造不能使当前业务崩溃。因此,我们的任何一个决策都要保持现有业务运行的稳定,一方面是人员组织,另一方面是系统架构。
图里三个颜色表示三个业务系统,三个业务系统最开始只有 Team A 是做微服务的,它只做一个应用的一小部分,比如 APP-1 的其中一个微服务。而其它的团队还在维护各自的单体应用。他们把所有应用业务切分成不同的微服务并集成,花了三到五年的时间。他们的团队所面对的维护工作量看起更大的了,因为他们需要关注的点更多了,但是它的团队没有增加反而减少了。某些团队被拆散,和其他的团队整合。或者开发了新的业务部门。
之前在这个公司里面一共有120个开发人员在维护这些系统,包括我们这边和客户那边的,到现在只剩80个人了。过去四年到五年有将近 30% 的人离职去搞比特币或者区块链创业了,当然还有人补充进来。
然而他们的系统并没有因为要维护这么多模块垮掉,而是这么多人已经足够多了。一开始我们是有运维团队的,第一个微服务团队和这个团队是一起工作的。到后面它又不再去到每一个团队工作了,而是形成一个运维模式,这个团队就是之前文章提到过的“熊猫团队”(PandA,Platform AND Architecture 平台和架构团队)。
微服务的团队大小的原则
多大的微服务团队是合适的?下面是我们微服务团队的照片,亚马逊提出两个披萨饼的团队。我们也采用过两个必胜客披萨的团队,但我们发现两个披萨的团队不符合实际。是因为你所碰到微服务的粒度是不一样大的。
因此,我们组建了“两个桌子间”的团队,如下图所示:
两张桌子间的微服务团队团队的规模决定了两件事:沟通的成本和微服务的大小
这两个条件一个决定了团队规模的上限,一个该决定了团队规模的上限。所谓“两个披萨的团队”事实上约束了团队的成本,同样也约束了微服务的规模。如果团队面对的代码库觉得力不从心,你就得缩减一下微服务的规模直到团队能够独立维护这个微服务。如果很多人都空闲,你可以让团队承担多一点代码。
这张照片是我们的一个微服务团队大概的规模:两个桌子背对背的空间,最大不超过16个人。
这样的一个空间形成了一个天然的场地:显示器是天然的屏障,你需要转过身来面对大家而不是坐在显示器背后。这样人和人之间不存在阻碍,也没有了秘密。这恰恰是一个团队理想的开会场所,我们在这里开站立会议,并且在一头设置了物理的看板墙,这样团队可以对当前的工作一目了然。
我们决定微服务团队的大小有三个原则:
-
团队的成员相互之间可以随时沟通:两个桌子之间的空地就是我们的会议室,有事随时沟通,同时也不会被隔壁桌子打扰。
-
不增加额外的管理成本:无需增加管理团队来管理微服务团队,微服务团队的工作责任边界完全自治。
-
不需要加班即可完成计划的任务:表明当前的工作量对于团队成员来说是合适的。
如果大于这个尺寸,证明你的微服务团队过大,需要进一步拆分。遇之相对应的是你的微服务的开发维护工作量过大,也需要进一步拆分。团队的最好的大小是和微服务的工作量是一致的。
如果小于这个尺寸,会因为微服务拆分的过小反而增加管理成本。你会发现有很多的团队需要协调,不得不增加协调人员来协调各微服务之间的工作,这就是额外的微服务团队管理成本。
当然,你可以拥有“两辆轿车”的团队或者“一个大圆桌团队:团队所有人出去吃饭刚好可以坐下两辆轿车,或者可以坐下一个包厢的圆桌。主要还是为了降低团队沟通和决策的成本,增加团队凝聚力。
从工作量的角度来看,每天的工作量要达到75%以上的时间利用率。也就是说,如果是“朝九晚六”(9:00-18:00)的工作方式,除去午休的一个小时。全天有8个小时的工作时间,起码要保证至少 6 个小时是在微服务的工作上。可以有2个小时左右的时间处理私人和组织的事务。如果微服务团队内部的工作时间小于这个比例,那么就证明组织之间存在额外的沟通成本,这些沟通就是需要被拆分出来的依赖,或者被下放的责任。
微服务团队中的角色分工
作为一个微服务团队组织是什么样的呢?我们的微服务团队是一个全功能的敏捷团队。这样的一个团队除了满足以上的团队大小外,还需要满足“全功能”和“敏捷”两个条件。
首先,我们是一个全功能的团队,也就意味着我们的团队可以处理整个团队端到端的所有任务,而无需依赖其它团队。这就保证了团队的自治。
其次,我们是一个敏捷团队,采用敏捷方法论和实践指导微服务的实践。
我们的角色分工是这样的:
微服务团队是一个全功能团队-
一名微服务的负责人。这样的团队我们又叫项目经理(PM),又叫MS-MASTER,它是一个复合的角色,不光是经理还是架构师是技术角色。帮我们隔离外部的干扰,例如会议、沟通等……以确保团队可以独立的工作。
-
一名业务分析师(BA),而发现需要这么一个角色的过程是经历过惨痛教训的:如果你的团队没有人十分熟悉业务流程和组织结构,划分出来的微服务就会和别的团队有重复。这就违反了单一事实来源的原则,而提前的分析可以避免这一点。而团队内部大部分是开发工程师,两个到14个不等。当然,这样的一名业务分析师可以多个团队共享。不过刚开始的时候,建议一个微服务团队有一个专门的业务分析师和领域专家共同合作。
-
一名质量分析师(QA),我们的 QA 不仅仅是做测试的,我们的 QA 还要理解业务,而 QA 是做全流程的质量保障。我们的测试流程是开发工程师写的自动化测试。注意,由于微服务的抛弃成本很低,我们并没有很高的单元测试覆盖率,但是我们要确保对应的端到端测试和集成测试都是大部分被覆盖的。另外我们需要运维工程师来帮我们设计持续部署和在线微服务的监控。此外,由于QA熟悉业务,某种程度上可以替代 BA 的职责。
-
一名运维工程师(Ops),帮我们构建基础设施平台并做好配置,以便我们快速部署微服务。这样当需要运维支持的时候,我们就不需要依赖运维团队了。这样一个角色可以是多个团队共有的,它可以在多个团队中寻找一些模式来构建微服务平台或者工具。
-
一名技术负责人(Tech Lead),主要负责架构和技术选型,指导其它开发者的开发,某种程度上是可以作为 Ops 。
-
若干个开发者(Dev),完成微服务的开发。需要注意的是,这样一个团队包括前端工程师和后端工程师,而不仅仅是前端工程师。
此外,微服务团队的划分容易出现两个误区:一个是根据系统模块划分团队,另一个是团队只负责某一个微服务。
-
前端团队和后端团队:有些情况下,我们会根据技能或者技术栈来区分两类团队。这样的有一个明显的陷阱:两个团队只对微服务的一部分负责。这样的前后端依赖如果没有管理的很好则会出现阻塞。一种解决办法是采用消费者驱动的契约测试来建立前后端之间的开发规范。另外一种办法则是通过全功能团队来消除这种隔阂。微服务团队的 PM、QA 和 BA 共同监督前后端的集成。这时候,前端和后端都要看做统一的微服务,只是集成到不同的网关而已。
-
按微服务划分团队:另外一个很危险的事情是一个微服务一个团队,这样划分团队的结果会变成更加隔离小团队。每个小团队只关注自己的微服务,而不管的整个业务的场景集成。这时候就需要更多的管理手段来介入,反而增加了更多的管理层使整个组织膨胀。此外,这样会给人一种错觉,我们都是独立发布独立部署的。然而开发需求、特别是集成很多微服务的需求则是需要详细安排开发计划的,这样不考虑业务场景的并行开发只会导致更多的阻塞和延迟,使得端到端的测试成本不断提高,阻碍整个架构灵活的变动。一种错误的技术解决方案是采用多个在线的微服务版本来保证兼容性。但带来的只会是过渡方案的妥协和资源的浪费:为了避免兼容性带来的问题,会在线留存多个版本,谁都不能轻易下线之前的版本。
因此,一个团队能够独立的完成端到端的开发和部署才是微服务团队的黄金原则。
微服务团队的工作规范和节奏
树立起微服务的工作规范是很重要的,它能形成文化和模式,替代管理人员将微服务的经验快速扩张。所以微服务的工作规范是需要最早开始确立,并不断在实践中完善的。
当我们刚开始做微服务的时候,并不知道哪一条微服务路径是更好的。尽管有各种各样的方法论,但在实际过程中还会出现这样那样的问题。所以我们先做一到两个试点,然后去总结出一个模式出来,但是一定要注意不要把它形成一个公共代码库,否则又变成了新的耦合。
此外,要采用自动化的方式做微服务端到端的部署。最好是除了代码提交和最后灰度发布,中间的所有环节都是自动化的。包括静态扫描、单元测试、构建、制品管理、部署、部署后功能性测试和部署后非功能性测试。要在每个代码库中做到一定的质量规范,以确保每一个微服务上线质量都是有所保障的。
这样就可以通过自动化落地一个制度,避免人工执行中造成的疏漏和变形。我们是通过“流水线即代码”技术,把交付规范变成了一系列自动化的手段。而且采用了 git hook 的技术,在代码提交前就做自动化测试,避免没有经过测试的代码提交到代码库上。
在微服务的开发过程中,容易形成“隐性知识”,即只有少部分人知道的知识。
一个有效的方法是结对编程,但当你碰到项目时间截止、预算截止又加不了人的时候,能够砍掉第一个敏捷实践就是结对编程。但是把眼光放长远看,你会发现结对编程是利用的是短板原理。在你的团队你跟别人面对面工作,如果你一个人工作,你的工作能力不足你是很难感受到的。而和别人一结对,你的工作能力不足你就有了很清晰的认识。这可以让团队成员向高水平的成员学习,不断提高团队的短板。而交付代码的结果永远是水平较高的那个人的。
而不采用结对编程的团队一般就是末位淘汰制。这个很容易理解,但实际上这种制度只会浪费大家的时间。因为在这样的组织里遵循马太效应,强者愈强,弱者愈弱,这不利于团队的发展,特别是需要复制的微服务团队。
另外需要说明的一点就是结对编程是非常辛苦但能够提升效率的方式,因为你在写代码的时候,始终有一个人盯着你,你没有时间开小差,你所有时间都在思考、设计。如果你没有这样做的话就是对结对伙伴的不尊重,所以从另外一种角度来看,结对编程实际上是一种监督制度,让对方监督来克服自己的惰性。工作的高效率就是这么形成的。
单单有结对编程这一点是不够的,还要做微服务团队之间的交换结对(Switch Pair)。
我们经常会出现一个问题,那就是我们团队有些人水平高,有些人水平低。水平高的人开发一些功能然后离职了,留下一个坑。但是这个风险往往是我们忽视的,我们做交接的时候往往交出去没有接起来,然后又变成另外一个坑。而结对编程是避免坑的有效的手段,但是一定要注意定期交换结对的伙伴。
为什么呢?持续交付里面有一个很重要的原则叫做尽早并频繁的做一些让你感到痛苦的事情。如果一个团队成员离职交接很痛苦,那每一天做一次交接。这就是结对编程和交换结对伙伴所做的事,因为每一次你做交换结对的的时候都进行了增量的交接,所以交接压力非常小。但是如果某个人做了半年的系统需要交接,这个压力则是非常大的,因为知识量很多。
从这个角度看,结对编程也是一种组织层面 Design for Failure:任何人的离开都不会对团队的交付产出有大的影响。
另外一个很重要的环节就是回顾会议。回顾会议非常重要,团队要学会自我改进。特别是微服务团队刚组建的时候,一定要养成复盘的习惯,否则很多问题就会积累,拖累整个微服务团队的工作节奏。这样,我们就可以从一个周期中认识到问题,并且在下一个周期中落实改进。采用这种循环的方式不断提升团队的工作表现。
此外,你需要给团队充分的授权,如果你不信任你的团队,你的团队也会用不信任的方法对待你。最重要的表现是各种“评审”和“审批”,大家的注意力都在流程上,而不在最终的结果上。最后的结局就是人浮于事,大家都在“做事情”但都没“把事情做完”。
演进中的组织
在 Netflix 的微服务经验中,Netflix 的工程师 R. Meshenberg 提出。微服务的落地需要各方面的配合和统一。这就意味着组织结构需要变化,这些变化的落地是困难的,而且这不是技术能够解决的问题。如果我们有一个等级森严,权限隔离的制度,组织的创造性和生产力则会被权力所削弱。因为很多人都希望确定性,避免不确定性。久而久之,就会使一个系统变得很脆弱,而花更大的代价来维护系统的脆弱性。而不是构建一个反脆弱性的系统,使组织更加有弹性,可以面对任何外在环境的变更。
你需要你的组织能够不断自我演化能够面对各种挑战。而组织结构的变化是往往是微服务落地困难中容易被忽视的一环成功的微服务的组织都是可以自我演进的,它会自我调整并孕育出新的技术。最好的例子也是 Netflix,在他们开始决定做微服务转型的时候,微服务,甚至是 DevOps 的概念还没有出现。然而,Netflix 的自动化和工程师文化,帮助他们成功的进行了技术转型而成为微服务应用中的楷模。
然而在组织和技术的相互演进中,我们也走过了很多弯路。我也发现,越来越多应用微服务的团队也会犯我们曾经犯过的错误,下一篇我们就来谈谈《微服务演进中的经验和反思》。