一、俯瞰软件工程
我们常常把软件工程和建筑工程作对比,两者确实有很多相似的地方,但是对于如下两点,差异却很大:
- 不确定性。软件工程有很多人参与,但是没有任何两个人的工作是重复的,即便对于某个人,昨天和今天的工作也是不一样的,没有人会写一模一样的代码,软件工程从事的是创造性的工作,创造意为着试错。大部分软件工程涉及的人力、时间、业务的变数都很多,导致软件工程有非常大的不确定性。
- 快速变化。建筑工程在完成以后就结束了,基本上很少会有变更。但是软件工程,产出只是开始,只要软件还在服务客户,程序员的工作就不会停止,以便形成更好的市场竞争力。
由于上述两点,软件工程和建筑工程基本不具备可对比性。
站在管理的角度去看软件工程,实际上管理学谈的是确定性,管理学本身的目的之一就是要抑制不确定性,产生确定性。比如,开发排期、时间成本是否确定;人力成本、研发成本以及后期运维成本是否可以确定。管理想要确定性,而软件工程又是不确定的,这里存在矛盾点。所以软件工程的目标是在大量不确定性中找到确定性。
软件工程并不是一个项目,而是无数个项目,每个项目只是软件工程里的一个里程碑。光靠把控程序员的水平,依赖他们自觉保障工程质量,是远远不够的。它需要架构师的角色,掌控整个工程全局,来规划和引导整个系统地演变过程。
架构师的职责,并不单单是对软件系统进行边界划分和模块规格的定义,从根本目标上来说,架构师要对软件工程的执行结果负责,包括:按时按质进行软件的迭代和发布、敏捷地响应需求变更、防范软件质量风险、降低迭代维护成本。
架构师要做的事情并不是那么纯技术:
- 解读用户需求。如何对需求演进进行预判?无关技术,关键是心态,心里得装着用户。除了需要“在心里对需求反复推敲”的严谨态度外,对用户反馈的尊重之心也至关重要。
- 参与产品设计。产品边界的确立过程虽然是产品经理主导,但是架构师理应深度参与其中。原因在于,产品功能的开放性设计不是一个纯粹的用户需求问题,它通常设计技术方案的探讨。因此,产品边界的确立不是一个纯需求,也不是一个纯技术,而是两者合二为一的过程。
- 确立团队分工与协同。包括团队的目标共识,做事方式的默契,各类规范的制定。
- 软件的质量管理。包括软件的版本发布,质量保障过程体系等。
如果明确,架构师的职责,是“对软件工程执行结果负责”,就能够明白项目设计时,需要关注哪些问题。
二、团队共识管理
2.1 什么是团队共识
分很多层次:
- 团队是不是有共同的目标。
- 团队是不是有共同的行事准则
- 对产品的要与不要,以及为什么要或者不要,是否已达成一致
- 对执行路径有没哟共同的认知
- 有没有团队默契,是否日常沟通交流很多地方不必赘述,沟通上一点即透
团队靠共识上下同心。
2.2 如何达成共识
越“聪明”的团队负责人,往往越容易忽视达成共识的难度。他们通常会召开会议,然后把自己的想法说给大家听。半个小时后,兄弟们迷茫地回去了。
在团队还小的时候,这种简单的共识的方式很可能是可以奏效的,尤其是当团队负责人还能够一一去检查每个人的工作内容时,所有的理解偏差都能得到比较及时的纠正。
让更多的人参与到决策形成的过程现场,是更好的共识达成方式。通过同步足够充分的信息,通过共创而非传达决策的方式让结论自然产生。这个共创过程不必团队所有人都参与,但要确保所有影响落地的关键角色都在,并确保参与这个过程的人都能够产生思想的碰撞,而非做个吃瓜群众。
2.3 契约与共识效率
目标与执行路径达成了共识,这还不够。我们还需要把共识表达出来,形成文字。
为什么这很重要?
因为共识之所以为共识,是因为它不是空中楼阁,不是口号,而是指导我们做战略选择的依据,指导我们平时行为的依据。
所以,共识就是团队协作的契约。契约的表达越是精确而无歧义,团队协作中主观能动性就越高,执行效率也就越高。
对于架构过程同样如此。
架构过程实际上是团队共识形成与确认的过程。架构设计需要回答两个基本的问题:
- 系统要做成什么样?
- 怎么做?
架构设计为什么叫架构设计,是因为架构师的工作中,除了架构,还有设计。设计其实谈的就是“系统要做成什么样”。
设计高于架构。
设计强调规格,架构强调实现。规格设计时架构过程的最高共识。所以,规格高于实现。我们用架构的全局性和系统性思维去做设计。
一些架构师乐衷于画架构图,把它当作是架构师最重要的工作内容。但架构图在共识的表达上并不太好。因为共识是需要精确的、无歧义的。而架构图显然并不精确。
对于一个工程团队来说,没有精确的共识很可怕。它可能导致不同模块的工作牛头不对马嘴,完全无法连接起来,但是这个风险没有被暴露,直到最后一刻里程碑时间要到了,要出版本了,大家才匆匆忙忙联调,临时解决因为架构不到位产生的 “锅”。这时候人们的动作通常会走形。追求的不再是架构设计的好坏,而是打补丁,怎么把里程碑的目标实现了,别影响了团队绩效。
我们作个类比,这种不精确的架构,就好比建筑工程中,设计师画了一个效果图,没有任何尺寸和关键细节的确认,然后大家就分头开工了。最后放在一起拼接(联调),发现彼此完全没法对上,只能临时修修改改,拼接得上就谢天谢地了。是不是能够和当初效果图匹配?让老天爷决定吧。
更精确描述架构的方法是定义每个模块的接口。接口可以用代码表达,这种表达是精确的、无歧义的。架构图则只是辅助模块接口,用于说明模块接口之间的关联。
尊重契约,尊重共识精确的、无歧义的表达,非常非常重要。
绝大部分哪怕是非常优秀的架构师,在系统设计(也叫概要设计)阶段通常也只会形成系统的概貌,把子系统的划分谈清楚,把子系统的接口规格谈清楚。
但实际上概要设计阶段最好的状态并不是只有设计文档。
为了降低风险,系统设计阶段也应该有代码产出。这样做有两个方面的目的。其一,系统的初始框架代码。也就是说,系统的大体架子已经搭建起来了。其二,原型性的代码来验证。一些核心子系统在这个阶段提供了 mock 的系统。
这样做的好处是,一上来我们就关注了全局系统性风险的消除,并且给了每个子系统或模块的负责人一个更具象且确定性的认知。
代码即文档。代码是理解一致性更强的文档。