1. 马斯克440多亿美元收购 Tweet
2022年10月26日,马斯克带着厨房水槽走进推特位于旧金山的总部大楼;10月27日,马斯克完成收购推特,并解雇了推特三名高管:首席执行官、首席财务官及法律事务和安全主管,并在此后的1个月内裁掉包含合同工在内的近75%员工。
2023年4月,马斯克在Twitter Space上接受BBC现场直播采访时表示,Twitter目前约有1500名员工,相比10月接管前的“不到8000名员工”相比有大幅下降。同时,公司已基本实现收支平衡,Twitter目前的用户数量已创下历史新高。
2. Brooks 《人月神话》这些研究表明,效率高和效率低的实施者之间个体差异非常巨大,经常能够达到数量级的水平 —— Sackman,Erikson,Grant(https://dl.acm.org/doi/10.1145/362851.362858)

软件经理很早就认识到优秀程序员和较差程序员之间生产率的差异,但实际测量出的差异还是令我们所有的人感到吃惊。在他们的一个研究中,Sackman,Erikson和Grant 曾对一组具有经验的程序人员进行测量。在该小组中,最好的和最差的表现在生产率上平均为10:1,在编程速度和空间上具有5:1的惊人差异!
我经常重复这样的一个观点,需要协作沟通的人员数量影响着开发成本,因为成本的主要组成部分是相互的沟通和交流,以及更正沟通不当所引起的不良结果(系统调试)。这一点,也暗示系统应该由尽可能少的人员来开发。实际上,绝大多数大型编程系统的经验显示出,一拥而上的开发方法时高成本的、速度缓慢的、低效的,开发出的是无法在概念上进行集成的产品。
3. 一个案例由于很多时候不会有2个差异大的团队或个人,会同时在实际业务交付场景中开发同样的业务功能,所以很难直观的统计出不同团队或个人编程效率的差异。虽在大部分时候能感受到2者之间的差异,但很难去量化。而对于某一个系统或功能的重构,由于优秀的程序员会将此工作融于平时的工作中,所以并不好量化平时的工作。而对于比较正式的重构项目,由于参与程序员的编程水平跟原来老版本开发的程序员的编程水平不会有太大的差异(人员流动,其他项目交付等),亦或投入的程序员并不是全部时间(交付新需求一般总认为比重构优先级高),等等这些因素又加大了不同程序员之间编程效率量化对比的难度。
下面是某同学总结一个相对比较完整的案例,从总结描述看,项目是一个正规的交付项目,实际交付的软件产品也真实的运行于线上,一方面可以排除仅仅为了实验,另一方面也可以对比从需要开发到线上稳定运行的全流程。同时,同学本人又是对比一方,只有一人参加,对项目足够的熟悉,项目不大,能好好的统计对比数据。在此,感谢danteliujie同学(https://blog.csdn.net/danteliujie/article/details/52296746)。
不同程序员生产力的11倍差别
【基本情况】
一个需求最先由Boss完成需求和设计并在7月份发给印度合作公司以项目外包形式发包,约定在9月底完工,我没有参与。印度方面投入了两个工程师和一个兼职的PM。但是在9月份的时候我们发现我们还需要兼容一个Android客户端,而原先设计的架构无法兼容。Boss要求我从新开发一套来针对Android的实现,而功能性需求是一模一样的,时间上越快越好。本人从9月7号到9月25号三周15个工作日(加周末约20Manday),完成从设计,环境搭建,文档,代码,测试的各个环节。在进入UAT阶段后,Server只修改了一行代码。Android客户端由要由以色列同事构建整个Image才能发布,所以使用了Hybrid的形式将尽可能多的功能放到(HTML/WebView上),从测试开始到UAT只修改了三行代码,而且是用来增强健壮性。值得一提的是印度公司解决方案在9月底提交后UAT阶段不停出现严重Bug无法使用,经过不断Fix,到11月初才完成UAT,项目总共历时4个月。
【项目实现比较】
【工作量】
印度公司:使用Strus 1, Hibernate;到UAT结束,两名程序员一共用了4个月。
作者:使用Spring Boot / MVC / Data JPA;一人用了15个工作日,加上周末加班有20个Man Day。
对比:考虑到加班因素,此项目中不同程序员的的生产力可以有11倍的差别。
印度:2224 = 176
作者:ManDay Rate = 15 : 176=1:11
-----------
【代码量(行)】
印度版本: 7385
作者:3968
对比:两个项目的总代码行对比,实现完全相同的功能,印度公司多写了86%的代码。
7385/3968100%= 186%
-----------
【进一步分析】
· (加班)由于本人在那几个周里每周工作了差不多120个小时,相当于3倍的正常工作量。去掉加班因素(15 ManDay 3 = 45)后生产力的差别约为1:4。
ManDay 45 : 176 = 1 : 4
· (框架使用)去除DAO、Form后,印度公司还是多出33%的代码,但是这以经可以归在代码风格,每行长度的误差里了。使用Strus1+Hibernate框架相比Spring Boot(MVC/Data JPA)还要多写40%的代码 (186%/133%)。Form Bean多为生成,所以推算使用新的框架可以减少30%左右的工作量(编码和Bug Fix)。
去除框架不同所至的代码量差别因素后,生产力的差别约为1:3
45 × 1.30 :176 = 1 : 3
· (日产代码)虽然总的效率差别达到了11倍之多,但是我们之间的每日代码产量差别不到3倍,去掉加班因素,我们的日代码产量几乎是一样的。
7385/(2×22×4)176 = 83 Line/ManDay
3968/45(折算加班) = 88 Line/ManDay
83 :88 = 1 :1.06 (约等于1)
【总结】
1. 假设使用同样框架下1:3的效率差异的分析(上面第二条,但实际及时使用同样框架,也可能写出差异巨大的代码)
a. 没有双人协作的沟通成本;
b. 压力下对时间与注意力更高效的管理;
c. 设计与编码经验的差别;
d. 责任心,态度,或者是能力(不具备同样的意识和水平);
2. 总体结论:
a. 此项目中不同程序员的的生产力有11倍的差别;
b. 有效的加班最多可将效率提升三倍;
c. 使用合理的框架可以减少30%左右的工作量;
d. 态度决定了25%的效率差;
e. 设计,经验,责任心等因素决定了3倍的效率差别;
f. 去掉加班因素,不同效率的程序员每日代码产量几乎是一样的;
g. 注意加班因素可产生最高3倍提升,e项也可以!
表1 软件研发10倍效率差异的案例
4. 数十倍差异背后的原因上面案例总结了一些开发同样需求的软件产品,一个全职开发者对比一个团队多人交付同样需求的软件产品的开发效率,相差近11倍的原因。包括,沟通,Brooks也重点提到了这点;框架复用,一个好的框架不仅能降低代码量,还能很好的降低后期维护成本;态度,也包含了背后经验和能力,决定了你是在建造“大教堂”,还只是在“搬砖”。
一个交付给客户的软件产品,按照其生命周期,从客户提出需求,到最后部署到线上运行并实现客户价值,中间大致会经历,需求分析,架构设计,开发,测试,部署&运行,运维&升级,这5个阶段。
图1 DevOps流程
当前软件产品的开发交付都是团队方式运作,在端到端交付流程中有明确的职责分工,对于需求、架构设计、代码开发等也可能涉及多人协作,各自负责不同的部分,彼此协作完成最终的软件产品的交付,如下图所示(在后2个阶段也有可能涉及多人协作,图中暂未展示)。
图2 软件研发流程关键阶段
从横向看,软件产品的全流程可以分解为不同的阶段,每个阶段由不同的角色负责;从纵向看,每个阶段由不同的单元组成,比如,需求可以按照来源分解为不同场景,设计过程可以由多个架构师共同完成,开发和测试可以按照模块或需求分配到不同人员。
上图2只是一个简化的示意图,实际的软件研发项目交付中,不同阶段以及不同单元之间并不完全独立,上下游,以及非上下游之间都需要彼此的协作。比如,设计需要充分的理解需求才可能做出架构设计,而开发人员也只有理解设计的软件架构和需要交付的需求内容,才可能最终交付出满足需求要求的代码;而SRE在运维过程中,出了要了解客户场景,也需要学习上游交付的软件产品及相关操作方法和运维手段。所以,阶段与阶段之间,阶段与单元之间,单元与单元之间,都是非单向的时序关系和非 1:1 的对应关系。图3以粗粒度的方式展示了软件研发流程不同阶段之间的关系。
图3 软件研发流程不同阶段间的关系
绿色线条是正常的需求流动过程,从客户需求到最终交付的满足客户需求的软件产品,并线上部署运行,为客户提供按照需求要求的服务。但是由于每个阶段在信息传递过程中存在信息丢失、错误等,下一个节点需要反向check传递的信息是否由偏差,而两个阶段之间的距离越远,信息产生丢失或错误的概率越大,反向check的成本也越高。这也是为什么越是到软件交付的后期发现需求偏差或BUG,修复此问题需要花费成本越高的原因。
结合上面的案例以及软件交付流程图,我们来进一步定性的分析10倍差异的原因。
4.1. 软件研发3个关键阶段的时间分布首先看下一个软件产品开发周期的时间分布,由于部署&运行&运维&升级等软件生命周期后期,与软件产品的研发交付相对独立,并且周期长短跟客户的产品服务策略相关,在此不放在讨论范围内。参考下面Brooks关于设计、开发、测试的时间比,差不多是 4:5:3,如果单纯只是考虑代码编写,时间会少于20%,一般在10%~20%之间的样子,调试和测试时间占比会远超代码编写本身。
Brooks在《人月神话》中总结的时间分布:
对于软件的进度安排,作者以自己多年的管理经验总结出如下法则:
· 1/3 计划
· 1/6 编码
· 1/4 构件测试和早期系统测试
· 1/4 系统测试,所有的构件已完成
计划,可以理解为对需求的理解和设计,对应到上图中的“设计”,时间占比 4/12;编码和早期测试(UT或IT),可以理解程序员在开发过程中需要完成的事情,对应到上图中“开发”,时间占比 5/12;系统测试,面向客户需求的验证和验收,对应上图中“测试”,时间占比 3/12。
设计:开发:测试 = 4:5:3
Brooks总结的研发关键阶段的时间分布,偏向于类似OS/360这样的大型软件系统的,瀑布式的开发流程。
表2 软件研发阶段的时间分布
4.2. 软件产品复杂性的背后逻辑软件遵循熵的定律,跟其它所有东西一样。持续的变更会导致软件腐烂,腐蚀掉对原始设计的完整性概念。软件的腐烂是不可避免的,但程序员在开发软件时没有考虑完整性,将会使软件腐烂的如此之快,以至于软件在还没有完成之前就已经毫无价值了。软件完整性上的熵变可能是软件项目失败最常见的原因。(第二大常见失败原因是做出的不是客户想要的东西)。软件腐烂使开发进度呈指数级速度放缓,大量的软件在失败之前都是面对着突增的时间要求和资金预算 —— 《鲜为人知的编程真相》
规模上,软件实体可能比任何由人类创造的其他实体更复杂,因为没有任何两个软件部分是相同的。同时,软件的复杂度是软件无法规避的内在属性之一,如果试图去抽调复杂度的软件实体描述,也常常会去掉软件的一些本质属性,所以无法通过类似数学家或物理学家那样去,通过简化的模型来验证这些特征 —— 《没有银弹》
不同团队实现同样业务功能的2个软件产品,其复杂度可能存在巨大的差异,正是这些巨大的差异才导致了2个软件产品端到端巨大效率的不同。既然“复杂度”如此重要,那么,在软件产品范畴内,复杂度”是什么?
复杂度从字面理解就是事物复杂的程度。在复杂度前面一般都会增加系列定语来限定其描述的对象和范围,比如,算法复杂度,空间复杂度,时间复杂度等。而软件产品的复杂度特指,软件产品对与其相关各类角色的理解成本。定义中有几个关键概念,第一个是核心主角“软件产品”;第二个是软件产的使用者“各类角色”;第三个是里面的“理解成本”。
图4 软件产品与不同角色间的关系
同样的一个软件产品,在面对不同角色时,有不同的理解成本,也就是说,有不同的复杂度。
对于客户来说,其关心的是软件产品是否可以稳定、可靠的满足其业务需求,带来价值。所以,客户业务感受的复杂度更多的体现在界面是否美观,操作是否方便,响应是否迅速,使用过程体验是否流畅等。有可能,后端服务是技术大牛完成的,架构好、性能好、代码美,但用户UI界面丑陋,响应慢,一个简单功能需要无数个步骤,用户可能认为这个软件产品就是个复杂的“垃圾”。
而对于开发人员来说,更多关心的是,在原来软件产品的代码上进行增量开发时,对原来代码的理解成本,对原有代码的修改,新需求需要新增的代码量,如何快速与老代码集成,能否方便测试等。当然,对软件产品来说,这是其从无到有,从有到大的出生和长大的过程,也是复杂度产生的源头,从程序员敲出第一行代码,到最终完成所有需求功能开发的过程中,软件产品的复杂度会急速的上升,这就是下面会重点说到的复杂度放大的过程。
对于测试和SRE也有对复杂度的不同评价维度,这里就不详述。由于软件产品的开发过程是复杂度诞生的源头,接下来会聚焦到软件的开发过程。
在这之前,先了解下代码复杂度。代码实现的过程逻辑,类似一颗从main()树根生长的大树,沿着不同的代码路径向上生长,在每个节点(函数)中,有不同的逻辑判断,根据不同的条件流向不同的子节点(函数),所以,从main()树根函数到所有叶子函数的路径,及路径的选择逻辑,组成了完整的代码逻辑,这些逻辑的副产物就是有价值的数据(这些数据对应的就是业务需求)。所以,代码的复杂度就是所有的这些路径和路径判断逻辑的总和,这也是圈复杂度的定义。圈复杂度最初的目的是用来识别“难以测试和维护的软件模块”,它能算出最少的全覆盖的测试用例量,但不能测出一个让人满意的“理解难度”。所以,圈复杂度低的不一定好,圈复杂度高的一定不好。
圈复杂度
代码状况
可测性
维护成本
1~10
清晰
高
低
10~20
复杂
中
中
20~30
非常复杂
低
高
>30
高阅读成本
非常低
非常高
表3 函数圈复杂度建议
4.2.1. 需求本身复杂度在编码中会被指数级放大对于某一个具体需求的软件产品实现,从编程技术上看,有多种实现路径,不同路径之间会产生巨大的差异。在表1 案例中,作者总结了使用Java Spring框架和不用框架之间会带来近2倍的代码量差异,如果考虑后续的测试,BUG修复,后期运维等阶段的工作量增加,总体增加的工作量会远超 2倍。另外,如果某些场景下,选择更加合适的编程语言,比如Python或Golang,利用更加成熟和抽象层次更高的框架或软件库,从而带来更少的代码量,更加简洁的代码,端到端更高的效率提升!
【通用算法vs定制算法】
即使在使用完全相同的编程语言和框架,不同的程序员也几乎不会写出完全的一样的代码实现,甚至很多时候,不同技术背景和经验的程序员,针对同样需求,会写出巨大差异的代码实现。资深、有经验的程序员,会写出相比原始需求更加通用和抽象的代码实现逻辑,比如,用户希望针对商品类型是1~100的数据进行排序,程序员在具体实现是可能偏向于直接实现一个类似“冒泡排序”或“二分排序”的通用算法,而不是仅仅针对1~100数值排序的代码逻辑。
但是,对于类似通用的算法或场景的实现,代码本身覆盖的场景是超出原始需求的要求,从而也带来了代码本身复杂度的增加(这边可能不一定严谨,因为有些时候,通用算法不见得比定制化算法的复杂度高)。在这个例子中,对于算法本身的封装,即方便测试,也方便后期场景中的复用,是一个良性的实现。但不可否则,从需求实现角度看,已经超出了原来的需求范围。类似情况,如果开发测试对于算法测试覆盖不充分,留有BUG,由于系统测试主要是面向需求的黑盒测试,扩大的范围很难黑盒测试角度进行覆盖,从而将此BUG一直留到了软件产品的运行阶段。后期如果由于各自原因触发到了本不应该在此需求范围内的BUG,需要付出非常高昂的定位成本。
【软件产品复杂度(分支路径)】
如果我们详细的去分析我们代码实现的每一条路径,这些路径组合起来可以实现的功能会远远超过需求本身需要实现的功能。对于一个稍大规模的软件产品,从main函数到不同分支端,路径数量是惊人的。但实际用于业务处理逻辑所涉及的分支路径只是里面的一部分,在一个已经交付给客户的软件产品中,实际业务运行所覆盖的分支就更少了。
一方面,可能是从人类对需求描述的高级语言,映射到低级的编程语言编译生成的计算机可以理解和处理的实现之间并不是一一映射的关系。如果反向从软件产品实现过程再次映射到人类可理解的描述上,其复杂度也远超客户提出的需求本身。以在线购物的“购物车”为例,从非技术人员角度看,“购物车”就是类似超市里面购物车的功能,推车--物品放购物车--结算,但是在软件实现“购物车”功能时,除了在用户界面,比如手机APP上展示类似购物车LOGO,并提供使用外,其他层次的实现架构、逻辑、名词等完全体现不出购物,比如数据库,JS,JAVA,Redis等等。也就是说,试图用低级的抽象去描述高级抽象,必然会带来复杂度的增长,两种抽象层次差距越大,复杂度增加越多(指数级)。
另一方面,在计算机体系中,任何软件产品都需要实现基本的非业务类需求(业务类需求特指用户可感知的需求,非业务类需求特指用户不感知的需求),比如,可靠性,安全性,可运维性等。围绕这些非业务类需求的代码和工作量在很多商业交付的软件产品中会超过业务类需求,并且在软件线上运行的后生命周期中占据运维的大量工作。以电商领域为例,为了支撑在线服务的高可用性,以及超大规模的实时并发交易能力,在首猜、导购、交易、支付等业务类需求以外,背后有大量支撑性中间系统或中间件,比如监控系统或平台。同时,为了应对类似双11这样的突发性、超大峰值的交易模型,系统必须具备动态、横向的弹性扩缩容能力,同时,也要具备熔断、限流等防止系统雪崩的能力。很多时候,还会涉及全链路模拟、压测,业务全链路追踪等非业务的相关需求。所以,从一个大型的软件产品角度看,为了能很好的支撑用户的业务类需求外,需要存在大量的非业务类功能,这些功能的存在,大大增加了整个软件产品的复杂性。
最后,很多时候,要交付的软件产品并不是从头开始的全新系统,而是在已有软件产品基础上进行增量开发,对原有系统理解的程度,会影响新增软件功能的复杂度。在老系统上开发新需求,程序员都有这种感觉:宁愿重新写一遍,也不想看和改原来的老东西。产生这样的想法和行为,是因为,要想修改原来的代码,首先要理解原来代码实现逻辑和具体实现过程,这个“范围”可大可小,也跟原来代码本身质量高低有关。如果原来是“面条型”代码,涉及修改多条面条代码相关联的核心数据结构,修改原来代码本身产生的工作量,就要超过新需求开发工作量,再算上测试验证工作量,累积开销可能会惊掉你下巴。当然还有可能来自其他方面的开销,如《仅 1 行代码,我们改了 6 天!
》。所以,很多时候程序员更希望针对新需求完全重新开发代码,而不是修改原来代码。但是,不论如何,除非这个软件开发团队和个人,在交付新需求的同时,及时对老代码进行重构和优化,否则,每当新需求代码提交到原来系统后,原来系统的复杂度会急速增加,其复杂度增加是乘积、甚至指数的关系,软件同样遵循熵的定律。
不同编程语言,不同编程框架,不同编程技术等会带来软件产品复杂度和工作量的巨大差异,但不论是什么技术,最终还是需要通过人(PD、架构师、程序员等)去使用,实施落地,最终交付出满足客户需求的软件产品。
图5 软件产品中角色及之间关系
如上图4 所示,从客户提出需求到最终交付完成软件产品的过程中,涉及多个不同阶段,多种不同角色,并通过依赖关系和沟通关系形成一张非常复杂的网络(为了简化描述,软件产品交付后周期的部署、运维等没有体现)。
【需求】
如果以需求作为关键核心,从客户提出需求到完成满足需求功能的软件产品,会沿着如图2 的不同阶段的管道向下流动,在图4中以绿色线条表示的方向,不同角色之间会通过一些关键的交付件传递关于需求的信息,比如,需求文档,架构文档,软件产品交付件,用户手册,部署文档等。由于需求流动,以及不同阶段、不同角色的处理,针对原始需求本身,一定会出现遗漏、变形、片面,甚至错误的问题。
之所以出现此情况,一方面是类似《没有银弹》一文中,Brooks博士提出的软件开发的根本困难 ——“抽象软件产品的概念结构”,针对需求的形式化描述,并没有一个类似于建筑领域的空间几何的模型系统,可以做到,在一系列图纸上即抽象,又可以完整、无歧义的描述一座摩天大楼。也就是,软件系统固有特征中的不可见性(复杂性、一致性、可变性、不可见性)。单纯的通过文档或UML图形来描述需求或架构,并向下游传递以支撑软件产品的开发,注定会偏离需求本身,从而更多的掺杂非原始需求本身的功能实现,增加软件产品本身的复杂性。
另一方面,同一角色的不同个体之间存在巨大差异。以客户为例,一部分客户可以非常清楚的描述自己需要什么,要达到什么标准;而另外一部分客户的描写可能会相当的模糊,甚至客户自己都不太清楚应该达到什么标准,套用乔布斯的话:“用户需要被引导”。所以,参加同一次客户交流会议的两个PD,按照各自不同的理解,完全可能输出差异较大的需求文档。同样的情况也会出现在其他角色中,尤其是连接需求和代码之间的架构师角色,优秀的软件架构师与拙劣的软件架构师,所指导交付出的软件产品,其开发、测试、运维及后期迭代升级过程中,所产生的效率差异非常巨大。这也是为什么Brooks博士认为,解决“抽象软件产品的概念结构”的软件根本困难,最终一定是依赖优秀的设计人员(优秀的架构师)。所以,根据28原则,20%优秀架构师,80%一般架构师(从我接触的中国TOP级的软件公司和所谓的牛逼的架构师看,可能还达不到这个比例),就会有80%的软件产品,因为各种角色的人为原因(需求理解有限性,角色自身的历史背景和经验,角色本身能力等),导致软件复杂度增加。
最后,重要并容易被忽略的一个方面 ——“故意为之”。人性不是这里讨论的重点,但大部分的软件产品都是围绕商业逻辑展开,除了满足客户需求的功能外,还会故意加入其他方面的一些功能,甚至故意把一些简单的功能复杂化,增加理解的成本。或许,License就是一个典型的案例,通过不同License去控制规格、功能、甚至性能等;而出于防止代码反编译的各种代码扰乱技术,目的也是增加复杂度。同样,如果软件开发外包的工作量是以代码量来计算,外包公司一定会要求下面的程序员(大概率程序员自己会这么要求自己),“实现同样需求功能,能通过复杂方法实现的,千万不要通过简单方法;能写10K代码,一定不要写5K”,类似软件工程实践中的“抽象、封装、复用”等开发优秀代码,降低代码量的思想,是不受推荐的。听起来有点讽刺的一幕,恰恰是2006年我刚入职华为,以及2016年我从华为杭州研究所回到南京研究所负责部分印度团队业务时,所看到2个真实案例。或许,类似讽刺的一幕还正在很多公司真实的发生着。
【沟通】
当前软件产品已非1人就可以完成交付,几乎所有的商业软件产品都是团队合作来共同完成的,也如上图描述的各种角色。为了实现多人协同,需要彼此之间的沟通。沟通的形式、质量、效果等,会给整个软件产品的设计、开发、测试等带来有益和有害的影响,最终会体现到软件产品交付各个阶段的效率和产品质量上。在解释沟通对软件产品复杂度影响之前,先明确“沟通”在此的范围,此处的“沟通”,除了上图4中不同角色之间的沟通交流外,还包括上下级之间的方案汇报、争议决策等,也包括不同部门或不同角色不同人员的平级之间的方案交流或PK。
沟通在软件产品交付的整个生命周期的重要性怎么说不为过。在1986年Brooks博士的《人月神话》中一直强调,无论是什么职业什么身份的人,都要进行有效的沟通,来确保概念的完整性。
· 软件开发本质上是一项系统工作——错综复杂关系下的一种实践——沟通交流的工作量非常大,它会很快消耗任务分解所洁身下来的个人时间。 (第2章 The Mythical Man-Month)
· 尽早交流和持续沟通能使结构师有较好的成本意识,以及使开发人员获得对设计的信心,并且不会混淆各自的责任分工。(第5章 The Second-System Effect)
· 只有一小部分管理人员的时间——可能只有 20%——用来从自己头脑外部获取信息。其他的工作是沟通:倾听、报告、讲授、规劝、讨论、鼓励。(第10章 The Documentary Hypothesis)
· 项目的关键问题是沟通,个性化的工具是妨碍——而不是促进沟通。(第12章 Sharp Tools)
· 作者也对沟通交流给出了自己的看法(第7章 Why Did the Tower of Babel Fail?),里面说到,团队应该以尽可能多的方式进行相互之间的交流:非正式、常规项目会议,会上进行简要的技术陈述、共享的正式项目工作手册以及电子邮件。在里面,他给出了使用规格说明书、周例会和年度大会、电话日志等方式来进行平时工作时的沟通依据,通过采取这些方式来达到理解的概念的一致性和完整性。
在2001年发布的、影响至今的《敏捷软件开发宣言》,更是将“沟通”放到了及其重要的位置,要求融入到软件交付过程的每个时刻。
个体和交互 胜过 过程和工具
可以工作的软件 胜过 面面俱到的文档
客户合作 胜过 合同谈判
响应变化 胜过 遵循计划
· 原则一:我们最优先要做的是通过尽早的、持续的交付有价值的软件来使客户满意
· 原则二:即使到了开发的后期,也欢迎改变需求。敏捷过程利用变化来为客户创造竞争优势
· 原则三:经常性地交付可工作的软件,交付的间隔可以从几个星期到几个月,交付的时间间隔越短越好
· 原则四:在整个项目开发期间,业务人员和开发人员必须天天都在一起工作
· 原则五:围绕被激励起来的个体来构建项目。给他们提供所需的环境和支持,并且信任他们能够完成工作
· 原则六:在团队内部,最具有效果并且富有效率的传递信息的方法,就是面对面的交谈
· 原则七:工作的软件是首要的进度标准
· 原则八:敏捷过程提倡可持续的开发速度。责任人、开发者和用户应该能够保持一个长期的、恒定的开发速度
· 原则九:不断地关注优秀的技能和好的设计会增强敏捷能力
· 原则十:简单(尽最大可能减少不必要的工作)是一门艺术
· 原则十一:最好的架构、需求和设计出自于自组织的团队
· 原则十二:每隔一段时间,团队会在如何才能更有效地工作方面进行反省,然后相应地对自己的行为进行调整
所以,“软件开发本质上是一项系统工作——错综复杂关系下的一种实践——沟通交流的工作量非常大”,类似团队方式的研发交付体系,只有沟通才能处理好如此错综复杂的关系,也只有沟通才能解决上一节中提出的各种需求传递过程中问题。但是,如果没有处理好“沟通”本身,反而会带来一些列问题,增加软件产品的复杂度。
如所有公司都无法逃避的下级与上级之间的沟通(或汇报),注意,这个里面的上级不一定是行政级别方面的上级,可能是某大型软件系统的某子系统的架构与系统总架构师之间的沟通,也可能是程序员与架构师之间的沟通(注意,这里架构师对程序员的软件实现架构方案有否决权),又可能是某团队leader与团队同学之间的沟通,甚至可能是PD与需求实现的程序员之间的沟通。总之,下级和上级之间需要具有决策关系,也就是说上级对下级的方案和实现具有否决权。当存在类似关系的群体之间进行沟通,并产生冲突,很多时候都会出现实现方案的巨大妥协,甚至出现“挂羊头,卖狗肉”的情况。
我亲身经历过多次给领导汇报方案与代码实现方案完全不同的情况。给领导汇报之前,下面同学很多时候会针对汇报本身做足功课,领导的层级越高,花费在类似功课上的时间越多,前期准备越充分。善于汇报的同学,会在汇报前,通过各种方式了解领导的喜好。即使在很多有经验程序员(或架构师)看起来实现方案,已经非常明确方案的情况下,大家也会准备好几种所谓的备选方案,然后经过“一系列对比”,最终确认方案X是最合适的。但最终在代码中真正实现的,却是里面的方案Y'(汇报方案Y的变体,一般肯定不会是方案Y),甚至是汇报材料中没有汇报的方案M。因为如果拿方案M去汇报,不仅肯定不会汇报通过,还很有可能被上级臭骂一顿或留下不好的印象。但在现有的代码架构下,方案X根本就不可能落地实现,因为现有代码架构已经不是领导(或架构师)心目中的架构了,自然方案X也不可能在现有代码中落地实现。但是,为了维护领导心目中的美好的理想化,只能用完美的方案X去配合这种理想化,其实方案X也只是汇报用的。下面一线软件产品交付的同学(编码的程序员)为了能让需要正常落地,代码中真正实现的是方案M,但也必须对外穿着方案X的皮衣。我们这些具有智慧的程序员通过自己的骚操作,开发出了穿着美丽外衣的骚代码,承载着用户诗和远方的美好需求。
对于有些没有从一线软件产品交付干起并成长起来的中高层领导(尤其是架构师),比如,市场出生的,硬件出生的(硬件与软件的产品交付存在很大的不同点),产品交付出生等的。总的来说,很多听起来不可思议的操作和实现,却是非个例般存在于不同公司、不同研发团队中。说白了,这些没有办法的办法,也仅仅是做实际编码的一线程序员们,希望能安心的把业务需求按时交付掉。所以,越是能充分了解真正代码实现情况,能尊重客观现实,能与编码人员站在一个平面去思考方案和架构的leader和架构师,才是好领导、好架构师。
上面方案X和方案M的例子,看似极端,但却是时刻、真实的发生在我们身边,越是很多人心目中的头部公司(这方面我应该还是有发言权的),类似情况越是严重(小公司反而好点,有可能是没有大公司那么正式或复杂的流程体系)。在X和M“理想”方案间(这里的理想也只是某些所谓专家、权威或领导自己认为的理想方案,实际并不一定是,他们自身对代码实现的现状都不了解,谈何理想方案),其实还存在各种折中、权衡的变体,比如,X',X''等,所以,才会出现各种“转换层”、“中间层”、“垫层”(非正常的层次)。这些代码对于需求或软件架构(面向未来)并没有带来实际的价值,反而增加了软件的复杂度,长此以往,在出现超越现有架构的大需求时,软件将腐化到无法扩展的地步(消耗掉巨大研发成本,或影响业务致无法正常提供有竞争力的服务)。
除了上下级,平行部门或角色之间不合理的沟通,也可能导致包括软件产品交付在内的很多事情的复杂化。不同部门之间常见变现出来的形式就是“卷”,为了各自的利益抢活干,各自为政,重复造轮子;也可能对于一个本来很内聚的功能,完全可以在一个部门闭环掉的工作,却硬是被拆解到了两个甚至几个不同的部门中,降低了系统概念的一致性,增加了子系统或模块间的接口,也增大了系统集成的难度和工作量。这样的例子,在我近20年的职业生涯中,在不同的大公司看到了太多太多,之所以频繁出现此类情况,或许“康威定律”可以给出答案。
【组织】
康威定律可谓软件架构设计中的第一定律,起初只是在杂志上的发表,后经过《人月神话》这本软件界圣经的引用,并命名为康威定律(Conway’s law),因此得以推广。
康威定律,马尔文·康威1967提出:“设计系统的架构受制于产生这些设计的组织的沟通结构( organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.)”。通俗的来讲,产品必然是其(人员)组织沟通结构的缩影。
在原文中康威定律可总结为四个定律:
· 第一定律 组织沟通方式会通过系统设计表达出来。
· 第二定律 时间再多一件事情也不可能做的完美,但总有时间做完一件事情。
· 第三定律 线型系统和线型组织架构间有潜在的异质同态特性。
· 第四定律 大的系统组织总是比小系统更倾向于分解。
图6 组织长大的过程
很多时候,我们把公司也比作一个生命体,这个生命体也是遵循着从小到大的成长过程,而对于围绕公司业务的软件产品,随着公司的成长,需求量、规模会逐步增加,其复杂度也会逐步累积,为了能合理处理复杂性,需要对系统进行分解,由此形成了上述康威的第四条定律。当原先的一个组织分解为多个更小的组织去分别负责软件系统中的某一个或多个子系统后,原来的组内沟通会逐步的演变为组间沟通,沟通方式的变化又会反向的影响子系统之间的界面和设计,出现类似模块A的功能是应该在团队X完成,还是应该在团队Y完成的情况。当无法协调好类似情况时,在软件实现层面可能就会出现overlap,甚至更大粒度的重复造轮子。
随着组织的成型,组织将会对软件系统的设计产生影响,一个功能是由团队X还是Y做,除了架构合理性外,还受到组织结构的影响,这就是大家常说的“屁股决定脑袋”,也正是康威的第一条定律所表达的含义。
所以,当一个软件产品的交付不再是一个单独的个体完成的时候,就会涉及到组织和沟通,不良组织和沟通方式会极大的提升软件产品的复杂度,降低整体的生成效率;反正,好的组织和沟通方式会带来好的软件架构,降低复杂度,极大的提升生成效率。
4.3. 软件研发效率巨大差异的定性分析上节围绕业务需求实现过程中的“软件技术”和“人”,简单的说明为什么软件产品会如此的复杂,为什么简单的用户需求在最终转换为软件产品后会变的如此复杂?
图7 抽象层次及沟通程度对软件研发整体的影响
对照图7,我们来稍微总结下前面提到背后的一些逻辑,然后定性的分析下上面的案例中端到端如此巨大效率差异的原因。
上图7有2个正交的维度,概念抽象的层次和沟通程度。概念抽象的层次及涵盖了软件技术,包括编程语言,可复用的框架、组件等。也涵盖了架构师或程序员在实际编码过程中对于各种的概念的抽象和实现程度。而沟通程度除了不同角色和人员之间的关联程度外,还受到组织制度和管理方式的影响。下表稍微总结下对这两个维度影响的领域及对应领域在维度的影响面和影响程度的比重(用1~10表示,1表示影响最小,10表示影响最大)。当然,影响两个维度的涉及领域,不一定全面,可以根据各自情况扩展,程度比重也比较有主观性,不同团队,不同项目类型,影响的程度可能会有较大差异,这里面仅是从我个人的主观出发,给出一些比重数值。
分类
涉及的领域
影响面
程度比重(1~10)【1,2】
概念抽象
编程语言
抽象粒度,思维方式
6
开发框架、组件库
可复用单元粒度
8
设计方法、设计模式
抽象理念、方法、成熟度
10
架构师(或程序员)
经验、思维方式
10
项目流程、项目计划
时间进度、资源保障
3
研发组织导向
政策牵引,潜移默化
5
沟通程度
研发组织设置
康威定律
7
团队及角色间的关系
卷 or 协同
7
阶段交付件质量
上下游角色对需求的理解度和成本
8
软件开发方法
瀑布,敏捷
10
【1】1~10,对于软件项目交付效率影响的程度。1表示影响最小,10表示影响最大。以“编程语言”为例,1表示采用哪种主流的编程语言,对于项目的端到端交付效率影响极小,C、PYTHON、JAVA、GO、RUBY 用其中的任何语言开发项目都不会影响项目交付进度和计划(对一个面向客户交付的项目,几乎不可能存在);10表示此项目只有某种类型的编程语言最为合适。
【2】影响程度比重:低:1~4;中:5~7;高:8~10。
表4 对抽象概念和沟通程度的影响领域及比重
接下来,我们来定性的说明上述涉及的领域对于软件研发效率影响的程度,这边我们无法给出具体的数值,因为这涉及下一节讨论的“是否可以定量”的问题,这边暂时给出一个我从多年的实践经验中总结的对比关系,以及大概的倍数关系。这边更多是想表达的是为什么会有这样的结果,而不是这样的结果是多少!
当然,从最终分析的结果推导出最优与最差的软件研发团队存在至少10倍的端到端研发效率差异,应该是显而易见的。
在《软件开发之道》文章中,我总结“抽象之于软件,其重要性类似,符号之于数学”。在《人月神话》一书中,Brooks博士反复强调“概念的完整性”,也是在强调概念(抽象)在研发组织和研发过程中,对所有参与的角色应该要有一致的理解。其实人类的自然语言是牛的概念抽象,告诉幼儿园的小朋友“苹果”,他们立刻就知道是那是一种水果,可以吃,甜的等等,不需要再去说一堆话,比如“有个东西,可以吃,甜的,咬下去有很多水分,有各种品种,表皮颜色也各不相同,红色、绿色、黄色颜色都有 ......”。如果每次,对每个人都用类似方式进行交流,不仅沟通及其低效,而且不同人对类似冗长的描述的理解也有可能千差万别,最终无法有效的共同完成一件事情。
【什么是概念】
从字面意思看,概指的是在一定的范围内,如大概、概况、概莫能外;念指思维,如杂念、理念。因此,概念的字面意思可理解为“大概的思想认识”。参照百科,概念一词在哲学(逻辑学)上的定义为:是对事物本质属性的概括。是人类在认识过程中,从感性认识上升到理性认识,把所感知的事物的共同本质特点抽象出来,加以概括所形成的一种自我认知的表达(通常采用文字表达)。
心理学上认为,概念是人脑对客观事物本质的反映,并以词来标示和记载的。概念是思维活动的结果和产物,同时又是思维活动借以进行的单元。
概念有“内涵”与“外延”两个属性:内涵指概念所反映的事物的本质属性的总和;外延指适合于某一概念的一切对象,即概念的适用范围。
内涵和外延具有反比的关系,即,概念的内涵越多其外延越小,反之,内涵越少外延越大。当谈及某个概念时,区分其内涵和外延是非常重要的。例如先秦著名诡辩家公孙龙的“白马非马”问题,其实就是混淆了内涵与外延。白马和马作为两个概念,从内涵来说,当然是不同的,因此白马≠马,但是从外延来说,白马的外延属于马的外延的子集,因此白马当然是马了。
另外,根据外延的大小,概念之间会有层级关系,高层级的概念其外延大于低层级的概念。根据概念形成的过程(即对事物进行对比、反思、抽象的思维过程),越高层级的概念意味着其抽象程度越高,具象化程度越低。如中国人、人类、动物、生物这几个概念,其层级越来越高,越来越抽象,外延也越来越大。
【概念的重要性】
概念是人类思维体系中最基本的构筑单位,换句话说,我们所有的理性认知、知识体系是建立在形形色色的概念之上的,可见概念何其重要。下面从三个方面进一步说明。
· 理性认识 理性认识有三种形式,即概念、判断、推理。其中概念是最基本的,相当于公理在欧氏几何中的地位。判断是指在概念的基础上对事物的各种关系进行区分、识别;推理是指由一个已知的判断推出下一个判断。由此可见,没有清晰的概念,判断与推理无法进行,理性认识便沦为空谈。
· 逻辑思维 逻辑思维有时也被称作概念思维,是指将思维内容联结、组织在一起的方式或形式。而思维是以概念、范畴为工具去反映认识对象的。可见,如果没有清晰的概念,便无法进行有效的逻辑思维,那么人对世界的认知也就只能停留在初级的感性认识阶段了。
· 概念技能 美国著名的管理学学者罗伯特.卡茨,曾经提出管理的三大技能,其中概念技能被认为是高阶管理者最重要的技能(另外两个是技术技能和人际技能)。所谓概念技能是指,一种洞察既定环境复杂程度和减少这种复杂性的能力。指能够统观全局、面对复杂多变的环境,进行分析、判断、抽象和概括并认清主要矛盾,抓住问题实质,形成正确概念,从而做出正确决策的能力,也就是洞察组织与环境要素间相互影响和作用关系的能力。可见搞清楚概念也是职场升迁的必备技能。
【概念完整性】
计算机科学巨匠Frederick P. Brooks在他的经典著作《人月神话》(第4章)和《设计本原》(第6章)两本书中,都强调了【概念完整性】对软件系统的重要性。
在《人月神话》中作者并未给出概念完整性的定义,只是借用“欧洲的教堂建筑风格能够在经历几代人的建设中始终保持风格统一”来隐喻或让读者意会什么是概念完整性。在《设计原本》中,谈及概念完整性时,作者提到了一堆近义词:内聚(coherence)、一致性(consistency)、风格统一(uniformity of style)、组件原则的正交性(orthogonality)、妥当性(propriety)、通用性(generality)等。为了更好地理解什么是概念完整性,我们不妨再类比两个类似的概念。
· 类比1:数据库完整性,指数据库中数据在逻辑上的一致性、正确性、有效性和相容性。数据库完整性由各种各样的完整性约束来保证,因此可以说数据库完整性设计就是数据库完整性约束的设计。
· 类比2:信息完整性,是信息安全的三要素之一(另两个是:保密性和可用性),是指保证信息从真实的发信者传送到真实的收信者手中,传送过程中没有被非法用户添加、删除、替换等。
综上所述,我个人理解,所谓概念完整性,是指在设计时保持统一的风格和理念,对设计中涉及到的所有概念有完整且一致的解释,并能确保团队所有成员对所有概念都有着相同的理解。
当我们谈论某事物的概念完整性时,其实是在说,在概念上这个东西要保持完整。例如,当设计一个软件系统时,我们说要保持概念完整性,其实就是在说,系统的设计方案要保持使用统一的一套概念术语来描述,设计风格要统一,设计方案在团队成员间传阅时,要让所有人理解一致。
所以,在软件研发过程中,从客户需求到软件产品实现的全部过程,利用抽象建立一套整个团队共同理解的概念,是保证整个研发流程高效的第一步,也只有做到并做好这一步,才有可能实现高效。
4.3.1.1. 影响概念抽象的各个领域及之间的关系图8 影响概念抽象的各个领域及关系
上图8展示了影响软件产品概念抽象的各个领域之间的关系,从图中可以看出架构师处于最为核心的位置,因为整个产品的概念抽象需要通过这个角色实现,这里需要的注意的是,架构师在这边是一个角色的概念,实际的项目运作过程中,即可以是专门团队中的专职人员承担架构师的角色,也可以是资深程序员兼任此角色(我们更推荐类似的方式,不仅完成软件产品的概念抽象和设计,还承担框架代码或核心代码的编写)。从某种程度上说,一个软件产品的架构师(或架构师们)决定了产品的概念、架构、甚至是核心代码,这些会对软件研发效率产生极大的影响,这也是《人月神话》中的“外科手术室”团队的研发阵型的主治医师的角色,更是军中名将,其影响度10。
当然,再牛的架构师,也不可能一个把所有事情做完,就像历史几千年无数战争的无名小卒,历史或许没有给他们留下一个镜头,便消失在战争的硝烟中,但不要忘记,却是他们这个群体支撑了战争的胜利或历史朝代的变迁,支撑了名垂青史的历代名将,他们也应该被历史铭记。而之所以一个个个体能聚集在一起,需要的是目标,是文化,是导向,并同纪律和规范,实现每个人像无数齿轮一样精密而又丝滑的咬合在一起,最终爆发出无穷的思路和力量。而这个目标、文化、导向,规律、规范的载体就是组织。对于软件产品交付效率,组织在整个过程中,会起到及其关键的作用,它会通过政策制度,价值导向等方式间接的产生,也会通过考核标准,奖励惩罚等方式直接的产生。但不管怎么说,所有这些交付阵型,角色分工都需要通过组织来实施,团队内部程序员的做事方式,价值观等也受到组织文化的影响,所以,研发组织会极大的影响软件概念抽象是否可以落地,是否可以高效落地,如何落地,以及落地效率如何,也是其他领域有效实施的关键条件。
而对与软件产品研发直接相关的,针对概念抽象实现的三个不同层次的实现工具,“设计模式”、“框架&库”、以及“编程语言”,像图中示意的那样,越往上抽象程度越高,对于架构师或程序员的技能和经验要求越高,对外呈现的颗粒度也越大。以“设计模式”为例,所谓设计模式,就是针对软件开发中经常遇到的一些设计问题,根据基本的设计原则,总结出来的一套实用的解决方案或者设计思路。其可以针对某一类应用场景,直接给出标准、有效、高质量的方案。通过简洁、无歧义的名字,解决一类具体问题,其魅力类似前面“苹果”这个概念对于幼儿园小朋友的效果,最大程度保持不同角色和人员间概念的完整性,这也是为什么在影响度给出10的原因。而对于这三种概念抽象工具重要性的探讨,可以参考鄙人的文章《软件开发之道》。
最后,针对图8 最底下的“项目流程和计划”这个领域,对于软件产品研发效率的影响程度相对其他几个领域来说是比较低的,因为影响软件研发效率的核心因素还是来自“人”,再完备的项目流程和计划,如果没有优秀的架构师和程序员,就无法带领优秀的软件概念一致性,无法带来优雅的软件架构,无法利用好“抽象、封装、复用”这几把利器,会将简单的事情复杂化,最终,出现看似前期项目流程和计划都执行的很好,但后期却是BUG无法收敛、新增需求无法落地(或落地时间不可控)。所以,一个好的项目流程和计划,以及充足的资源供给,比如研发过程中的各种硬件资源、系统、工具等,能很好的保障软件产品的高效交付;而不合理的时间进度,交付过程中的研发资源缺乏,会导致很多研发动作无法及时开展,积累债务会不断的遗留到下游,时间越长,后期还债的成本也就越高,从而在全流程降低了软件研发的整体效率。
4.3.1.2. 研发效率影响的定性分析前面简单总结了影响“概念抽象”的6个关键领域,其中影响最大的两个领域就是“架构师”和“设计模式和方法”。如果我们拿一个军队来做对比,“架构师”就是军中统帅,而“设计模式和方法”就是兵法。“兵熊熊一个,将熊熊一窝”,只有优秀架构师,才能带来一个优秀的概念抽象的软件产品,才能善用设计模式和方法,站在前人的肩膀上,带来整个软件交付过程少走甚至不走弯路,达到“不战而屈人之兵”,交付高内聚、低耦合、易扩展、零缺陷的软件产品,“一次性把事情做对”。
从组织层面,围绕“架构师”和“设计模式和方法”这两个领域还可以继续深入探讨。比如,“架构师”在组织处于什么角色?对于一个交付的项目,里面有很多角色,如项目经理、架构师(或DE)、程序员、配置管理员、测试人员等等;而对于一个实体团队,也存在不同的角色,如部门经理、团队Leader(如华为的PL)。公司行政实体组织和项目交付的虚拟组织之间一般构成类似下图9 的矩形阵型。
图9 软件项目交付阵型
对于一个项目的中关键角色,项目经理、架构师和程序员,以及实体组织团队Leader,这些角色之间是什么关系,应该采用什么关系最为高效?针对4个不同角色,看一下几种角色各自不同的工作职责和相关权力:
· 项目经理:项目一把手,整体负责项目管理工作,制订交付计划和过程,对质量负责。是否具有对项目成员的考核和激励的权力,不同公司有差异,这是后面需要探讨的一个问题。
· 团队Leader:实体组织团队负责人,负责团队成员的选、育、用、留,具有对团队成员的考核和激励的权力。
· 架构师:负责软件产品概念抽象和架构设计。
· 程序员:软件产品代码编写和开发者测试(是否包含此项,不同组织有差异,但当前绝大部分公司的做法是包含此项)。
现在回答一下关于“项目经理是否对项目成员具有考核和激励权力”的问题,因为这个问题直接关系到项目中的架构师和程序员对于项目投入的专注度。虽然说,程序员是为了兴趣和理想在开发软件系统,在“建造大教堂”,但生活除了精神激励,首先需要的是物资保障,毕竟诗和远方也是需要金钱来支撑的,所以,考核和激励在任何时候都具有非常重要的牵引作用。
从公司管理层面看,团队人员归属实体组织,关于团队里面成员的考核和激励也自然是在实体组织中进行,这也是大部分组织的运行模式,所以作为团队的Leader,也自然具有此种权力。但是,如果从(软件)公司经验的层面看,核心是(软件)产品的研发和售卖,获取利润是企业存在的根本。而所有的团队成员一定是围绕某个或某几个产品进行工作,处于不同的岗位,承担不同的角色,完成不同的任务,负责产品交付的项目经理,对于项目中的成员的工作内容和产出应该最为了解,也最能做出客观评价,所以,从实际日常工作内容看,项目经理应该对相关成员的工作内容和产出进行考核,并给予恰当激励。到此我们发现,到底谁应该给某个团队成员进行考核和激励这个事情上产生了问题。
架构师和程序员这两个角色,一直是软件产品交付中相爱相恨的主角,架构师在完整的理解需求后,完成软件产品完整概念和架构的设计,(通过文档、UML或其他各种交付件)传递给程序员完成代码编写和功能测试,但真如前面所说,软件领域并没有类似建筑领域的符号系统或CAD软件,对建筑进行1:1抽象,并无歧义的传递给后面的施工队。所以,概念和架构从架构师大脑传递到程序员大脑过程中,就开始丢失很多信息,甚至概念的自身含义都无法准确传递(类似情况非常普遍的存在)。但软件产品无法按时完成交付,或者交付过程的压力超出预期时,这两个角色之间就会爆发激烈的矛盾。
所以,如何处理好这些不同角色之间的问题和矛盾,是保证架构师作用发挥,及设计模式和方法落地的关键,这也是项目和组织对效率影响的关键所在。
不同角色之间什么样的关系最为高效?
为了解决上述各种角色之间的问题和矛盾,最理想的方式就是“角色合一”。如果这个人既是Leader,也是项目经理,还是架构师和程序员,具有全栈技术的全能型选手。其实也就是说,这项目就这么一个人,上面案例正是如此。所以,项目最终的交付效率决定于此人对上面三种能力和工具(设计模式”、“框架&库”、以及“编程语言”,也就是图8那个三角形的三层)的掌握水平。
但毕竟在实际公司运作中,完全只需要一个人就能搞定的项目毕竟很少,绝大部分时候还是需要多人的团队协助完成,所以,可以尝试不要合并的那么彻底,比如,为了避免考核和激励权力的问题,将团队Leader和项目经理角色合一,这也正是华为PL这一层组织设立的目的。但正如图9所示,如果项目在大一点,需要跨越多个实体团队,如项目1,一个项目只会有一个项目经理,可以来自团队A1、A3、B1、或B3的团队Leader,但还是会存在项目中不是本团队成员的情况,一样会出现上面提到的问题。所以,出现了在很多公司应用的PM提建议或360度考评等手段,但是从我观察到的实际情况看,还是谁掌握最终排名的权力,大家会听谁的。所以,当前类似简单考核和激励的手段和方法,无法应对软件产品交付这样复杂的情况,尤其是那种短周期、敏捷类型的项目,需要一种新的方式,这个后面章节会详细展开。
而对于架构师和程序员之间的关系,在《人月神话》中提到了“外科手术室”类型的解决方案,此团队成员全部围绕结构师(我理解,应该就是现在的软件架构师)展开工作,以此来保证概念的完整性。在此基础上,还需要进一步结合我多年的工作,进一步延伸。如果像高效达到全局的概念完整性,并在完成落地,架构师既需要完成概念的定义,讲解,跟程序员不断的Check,还需要完成框架代码、核心代码的开发,所以,此处的架构师有时是一个,有时是一个群体,而这个群体是整个软件产品交付中最为核心的群体,是精英中的精英。
图10 软件产品代码构成
所以,如上图10 所示,通过粉色包围的架构师群体(项目中人数占比10%左右)完成软件产品中最为核心的几件事情,包括:
· 从需求到概念抽象
· 从需求到软件架构
· 定义对象、术语、规范
· 框架选型、模块边界、三方能力
· 代码可测试性,可观测性,可运维性,可靠性 ......
· 产品各项指标,竞争力,SLA
关键,这个架构师群体要负责完成一个软件产品中最为核心的框架代码和关键代码的开发,而这些正是能够保持概念完整性和设计的软件架构可以有效落地的保障。
俗话说,世上最难的有两件事情,一是让别人把钱放进你的口袋里;二是把你的想法放进别人的脑子里。所以,这个群体在知识积累,软件工程能力,开发经验,以及对上面三种能力和工具的理解和应用上,都应该处于同一个层次,以确保处于同一起跑线,思维方式处于同一纬度,最大可能保障产品概念的快速对齐。同时,这个组织方式,对后面需要提到的沟通方式也会产生巨大的影响。
总结我见过的成功和失败软件产品的关键,在一个软件产品中能否有几个有丰富的交付经验,有深厚的软件工程积累,有精湛的编程水平的架构师,并且这些架构师承担最为核心的框架和关键代码的开发职责。因为只有这样,才有可能最大可能保障软件产品概念的完整性,以及概念完整性没有歧义的落地到代码实现中。千兵易得,一将难求啊。
所以,软件产品交付中,要想达到高效。首先,从公司架构的实体组织到项目交付中动态的虚拟组织,角色尽量合一,这对关键人员的能力提出了很高的要求,但一旦找到了这样的人选,会带来效率的极大提升。
其次,要围绕工作的核心目标去确定关系中的主次。软件产品交付的关键目标就是“满足用户需求,有竞争力,高质量的软件产品”,而能完成此目标一定是写代码的程序员,其他包括项目管理,架构设计,测试验证,还有其他类似QA这样那样的角色的工作,虽然可以一定程度上为目标的达成提供支持,但都并不能完成客户需求到代码的转换,而很多组织低效的主要原因也真是源自于此,所以在软件产品交付的复杂关系中,谁主谁次,一目了然了。
图11 软件产品研发令人遗憾的现状
最后,专制,上下齐心,令行禁止,一切行动听指挥。软件产品是纯粹的人类思维活动的产物,不同人员对同一产品和需求在大脑中形成结果差距极大,更不会出现类似搬砖头那样的,多一个人就多一份力量的效果。反而,在软件开发过程中过分民主,很有可能导致软件产品的分崩离析,最终,彼此之间无法协同对外提供服务。所以,要想获得极高的效率,整个交付团队就需要以少数的几个人为核心,在没有完全理解这些人设计的概念之前,要坚定执行。这个说起来容易,做起来难啊。首先,这几个人需要具备这个能力,尤其是架构师,否则,会造成灾难性结果;其次,组织在文化、导向、考核、激励等多个方面要给予牵引和保障;最后,这些核心人员真的可以做到以德服人,以能力服人,以结果服人。
· 没有任何借口 --- 美国西点军校最重要的行为准则
· 没有坚决的服从,就打不了胜仗 --- 中华人民共和国国防部
· 只有一切行动听指挥,才能步调一致打胜仗 --- 中国人民解放军在长期的革命战争实践中形成的优良传统
· 将听吾计,用之必胜,留之;将不听吾计,用之必败,去之。计利以听,乃为之势,以佐其外。势者,因利而制权也。 --- 《孙子兵法》
服从是军人的天职,项目交付中,一样需要“服从”。但这里的“服从”不是不动脑子的服从,让我干啥就干啥,而是一个方案在决策以后,空杯心态后的坚决执行,这恰恰是现在程序员最为缺乏的基本素质。
4.3.2. 沟通程度对研发效率的影响前面反复强调了,软件行业与建筑行业有很多相似的地方,但与之不同的是,软件行业没有一种符号系统或概念系统,能准确、无歧义的实现从业务需求到代码实现的各个不同阶段的传递,所以,在图2的各个不同阶段之间需要大量的沟通,而沟通的顺畅度和沟通程度,直接影响了研发效率和交付的代码实现与真实业务需求之间的差异度。后面我们还会结合组织、人性和各种敏捷方法进一步分析,待这些主题讨论完成后,再做深入分析。
4.4. 优秀团队与普通团队之间差距有多大?《明朝哪些事儿》中将军队分成四个等级。第四等级:乌合之众,散兵游勇,无组织,无纪律;第三等级:结构完整,军容整齐,无斗志;第二等级:士气高涨,装备经精良,有冲劲;第一等级:统一指挥,士气高涨,装备精良,万人如一。
第四等的军队是乌合之众,他们没有军纪,四处抢劫,没有纪律。这样的军队只要受到有组织的军队的打击,就会一哄而散,他们绝对算不上强大。
第三等的军队有着完整的组织结构,他们军容整齐,步伐一致,但斗志不高,士气不盛。他们虽然比第四等要强,但只要遇到更有战斗力的敌人,也必然会被打败。他们也算不上强大。
第二等的军队不但有统一的指挥系统,装备精良,而且士气高涨,在行军途中经常会喊出两句“杀敌报国”的口号,士兵们都急于表现自己的英勇。这一档次的军队有气势、有冲劲。他们不畏惧任何敌人,可以称得上是强大的军队,但很遗憾的是,他们也不是最强大的。与最强大的军队相比,他们还缺少一种素质。
这种素质就是沉默,最强大的军队是一支沉默的军队。
这种沉默并不是指军队里的人都是哑巴,或者不说话。
所谓的沉默应该是这样的一种情景:
指挥官站在高地上对他的十五万大军训话,这十五万军队漫山遍野,黑压压的占满了山谷、平地。
他们不同相貌、不同民族、不同地方、不同习好,却挤在同一片地方,听着同一个声音,看着同一个方向,鸦雀无声。
这才是所谓沉默的真意,这才是军队最重要的素质。
软件研发团队从优秀到普通,我们也可以大致分为四等:
第一等,优秀的团队,作为管理者(项目经理&团队Leader)具有明确的使命感,目标感,具有丰富的管理经验和技能,有一线软件架构设计和开发经验,有在复杂环境下成功交付的经历。团队人员的能力模型清晰,既有具备上述三种能力和工具的人员梯度,也有事前平等讨论,事中坚定执行,事后奖罚分明的组织纪律和对纪律的敬畏之心,并在实际的软件产品交付过程中能做到,力出一孔,随时可以集中优势兵力完成突发需求的高质量交付。很好完成业务需求到代码架构的设计和落地实现,并在需求变化过程中,不断的进行架构优化和守护。
第二等,管理者能力强,团队管理,需求管理,项目管理都有条有理,架构师具有从需求到软件架构的设计能力,但缺乏丰富的软件工程经验和代码开发能力,导致无法将优雅的架构落地,但在后续需求不断变化过程中,有意识的进行架构守护。
第三等,管理者具有较强的人员管理能力,能组织对业务需求的跟踪和评审,需求的开发分发给一些列团队成员,大家按时交付需求,出现问题,能尽心尽责的处理问题。
第四等,需求管理混乱,组织纪律涣散,研发过程没有章法,内部成员相互看不惯,各自为政,甚至互卷;无法完成的任务总能找出很多理由,关键时候难以调动资源(当然理由肯定很多)。
如果从软件产品全生命周期看,等级一到四之间的效率差距,每个之间至少2倍的差距,粗算下来,一到四之间的差距达到16倍以上。
等级
编码能力
需求管理
责任心
架构及工程能力
文化&纪律
第四等
第三等
第二等
第一等
4.5. 研发效率的因素
结合上述的分析,影响软件产品整体研发效率的可能因素,包括,团队规模,产品复杂度,技术积累,编码和集成能力,架构和工程能力,团队管理成熟度,项目管理成熟度,需求管理成熟度,团队文化,组织纪律。涵盖项目、组织、人员、技术 4个不同的领域。
图12 影响研发效率的多种因素
一个中型或大型的软件产品,其端到端的受到很多因素的影响,他们根据某种关系,相互之间共同作用,相互影响,从而导致很难去精确的对比两个不同的研发团队的效率,没有度量就没有管理,更别说持续改进,所以,无论从哪个角度出发,针对软件研发团队的一套标准的度量系统都非常必要。虽然这件事情很难,但不代表不能,至少针对某个研发团队还是可以的,当然,这是我们未来需要进一步探讨的事情。
5. 总结“重大战略成果的取得离不开英雄,伟大抗疫精神的弘扬更离不开英雄,这是一个呼唤英雄、造就英雄、尊重英雄的时代”。
软件行业也需要英雄,需要有动手能力强的架构师,需要有架构能力的程序员,需要懂软件工程的管理者,更需要懂技术和管理的项目经理。他们熟读“兵书”,经验丰富,经历过“焦油坑”的洗礼,能带兵打仗,能放低姿态,团结兄弟团队,并始终把交付高质量满足客户需求的软件产品作为每个项目的交付目标。
越多这样的英雄,这样的大牛,我们的软件研发效率才能越高,才能将硬件摩尔定律的价值真正的带给客户,为业务增值。