背景
不少同事,包括我自己关于长期的程序设计和隔三差五的设计评审(Program Design Review,下文简称PDR),总有这样的疑问:
- 政治正确的程序设计评审究竟有没有达到期望的实际效果?
- 如何快速理解别人的程序设计,该怎么去评审,哪些东西不需要评审?
- 开发的功能有大有小,有难有易,我应该做什么设计去表达我的想法?是否每次迭代都需要评审?
这些问题虽然没有调研过,但我相信绝大部分人都有过这样的困惑。在实际工作中,有大部分团队都会做程序设计,但只有其中一部分团队会做设计评审,而只有极少一部分团队会坚持一直评审。因为设计评审往往跟开发人员希望着重的任务——设计和开发,在时间上有所冲突,评审必然会减少开发的时间,而且过程往往是难受的,因为需要给别人介绍自己的工作并取得他人的理解,以及接受他人的批判。
所以抛开政治要求这一点,我们是否真的需要设计评审,以及如何做设计评审呢? 为什么要做程序设计评审?
为什么要做程序设计评审
私以为除了用来排查前期错误,指导开发之外,PDR还有一些关于社会学的作用,一种长期行为和团队文化,主要体现在以下几个方面:
良性的开发压力
当我们在紧张的编码,开发周期较短,交付压力较大时,往往可能拿到需求之后直接就在脑海里建模、分好类,然后就动手开始编码了。但是,在此基础上,当我们负责的功能需要跟其他人负责的模块交互的时候,或者是功能较为复杂,有多个人维护时,我们的编码很可能会影响到已有的功能,我们理想获得的接口参数很可能是别人给不到或者很难给到的,当代码编写完之后再跟别人对接口亦或是讲解时,才发现跟现实中的差距,此时很可能需要进行大量的返工。所以,在编码之前先进行程序设计评审,可以跟团队成员或者协作方保持概念上的一致性,确保自己的目标方向是不会偏差,是可以运行的,不至于浪费大量的时间在错误的方向上。“尽快失败”大概就是如此,永远不要闭门造车。
保证程序概念完整性
一个实务中的系统往往是由多个组件,多个容器共同组成的,同时,也很可能需要跟多个系统进行交互。除了架构师之外,没有人能在一开始就知道整个系统的运行关系,而随着项目的逐渐演绎和发展,系统之间的关系只会越来越复杂。
显而易见的,没有人能够独立完成一整个项目,当某个团队成员吭哧吭哧进行编码之后,假如没有输出任何文档,也没有将他的构思跟别人讲解过,如果他一直在工位上还好,但如果某一天他离开了岗位,这位离职同事负责的代码就需要由其它同事来进行维护和开发,那么可以预见这位新同事将会非常难受,他不知道什么时候是需要其他人配合的,不知道这部分代码的作用是什么,不知道从哪里入手阅读。最糟糕的情况下,他可能需要花上好几周甚至好几个月的时间通读所有代码,然后到最后发现,原来他只需要修改寥寥几行代码就达到目的。所以保持PDR这个习惯,能让团队其他人时刻知道你在做什么,知道系统又加入了什么新的模块或者功能,知道这个模块跟其他地方是怎么交互的,哪些地方会影响到哪些不会,当别人接手你的项目的时候可以很快上手,他只需要阅读特定模块的代码即可。
永远不要让团队成员孤立的编码,公司也不应该培养不可或缺的人,这对于团队是及其危险的。
知识传播和团队共识
在团队中,个人的技术能力很好还远远不够,如果其他团队成员知识储备不够,团队也无法发挥其全部的实力。
假设一个人了解诸如《整洁代码》之类的入门书籍,还介绍了《设计模式》,推荐了《领域驱动设计》等,同时希望团队成员能理解产品的业务逻辑,周期性地进行技术分享。所有这些努力都很好。但是几个个月过去了,似乎团队成员对命名规范都建立了概念,但是该怎么命名这件事上,大家并未形成共识。不少同学已经了解了一些设计模式,但是有人过度运用设计模式,搞的代码臃肿不堪,有人则只知道单例,但为什么用,什么时候用并不了解。团队成员对什么是实体对象,什么是值对象争的不可开交,没有人说得清楚聚合是什么,应该在什么场景下适用。
所以真正缺乏的,是一个具体的业务场景。抽象的概念如果不落到具体的事情上,就很难形成共识。欧美国家的法律采用的是判例法,这是法律层面形成共识的一种非常好的方法。PDR其实也是形成判例的好的时机:比如哪一类设计是合理的,哪一类设计是不合理的。通过针对具体的问题进行分析,团队就会逐渐形成设计共识,在过程中,对这些共识不那么熟悉的团队成员也可以慢慢融入。当然在此过程中,最好有一个比较权威的专家,不然很可能各个成员讨论出来的结果并不是一个正确的结论。
当然更好的是,事后有人能将这些业务问题和理解用文笔写出来,供团队成员反复阅读和修正,将对团队是非常有利的事。
当然,PDR也能进行逻辑检验
大部分人都觉得这一点是PDR最重要的作用,但我个人反而觉得不应该给予太高的期望。程序设计评审 = 程序设计 + 评审。也就是说,PDR是先有程序设计,再基于程序设计做评审。
单论程序设计,程序设计更多是用于指导设计者接下来的代码编写,往往需要足够多且必要的细节,例如参数的类型,和对象之间的调用关系、时序等,设计者才能够从设计中发现思路的可行性和缺陷。
而评审重点是在于给评审的人知道你要做什么,你为什么这么做。在PDR过程中给团队成员展示过多细节时,别人很可能不理解你在做什么,即使理解了,可能也无法发现你设计中的缺陷,因为其他人(除了产品经理)对于你的需求上下文是缺失的。
在实际项目中,往往需要先给别人展示用例,让别人理解你的需求上下文,从业务层面出发,展示业务模块之间的调用逻辑。进一步的,才是放大逻辑中的某一部分,讲解其中的细节。但很多情况下,讲解细节需要耗费大量的时间成本,而且设计人员在充分理解需求的情况下,也需要额外花费时间去备注那些看起来非常容易想到的细节,以应付评审人可能存在的对于表达形式的不满。
在实务中,PDR的设计细节经常会被弱化,评审中更多的是从业务层次了解领域的划分和领域之间的交互关系,评审比代码逻辑更高层次的逻辑。因此,PDR往往只能做到一种大概的逻辑检验,而不能做到充分的逻辑检验。
如何做程序设计评审
前面讲的都是为什么需要做程序设计,以及实务中程序设计存在的一些客观问题,但具体应该怎么做程序设计呢,根据个人经验,大概可以分成以下几点:
用恰当的表现形式
首先,可以参照C4模型,先了解自己修改变动的部分,在项目中是什么定位,究竟是系统层面的变动,还是容器层面,亦或是模块层面;其次,画出对应层次的C4图,用于分析此次修改涉及的部分的上下游,和改动部分的作用;
其次,可以通过产品原型图,交互设计图的展示+口述等方式让别人快速知道需求,也可以采用用例图或者泳道图的方式,让别人快速理解业务用例。对于没办法通过ui展示的需求,例如一些算法的重构,或者数据结构的变更,则可以通过一些简单的文字描述让别人快速了解上下文。
对于评审人员而言,追求更好的表现形式并没有错,但是在设计人员提供了不那么完美的图表的情况下,经过简单的口述能够理解需求,则建议放过细节,让评审能够顺利进行。
合适的评审人员
如果涉及接口和/或返回参数的修改,则需要拉上上下游相关部分的开发人员一起参与设计评审;如果仅仅涉及算法的重构,输入输出并没有发生变化,那只与共同开发该部分的人员一起进行PDR即可。对于一些新的概念和理论的引入,那一个资深的评审人员则很可能是必要的。
评审的程度
程序设计是用于指导开发的,必须具备足够的细节;而评审是用来让别人评价你的设计思路,必须结合业务,具有一定的抽象,抽象和细节往往不能融合在一张图中,常常是具有矛盾的,因此在设计评审的时候,大部分情况下需要有自顶而下的不同抽象程度的图表展示,具体在PDR中,给予评审的图表需要细化到什么程度,这里有一个个人的经验,如果需求有了小的变化,评审时的图表仍然能够实现而不需要做什么改动,那就足够了。如果小的需求变化带来大量基础代码的破坏,那么设计就需要改进。
设计可以分为两层:战略和战术。给别人评审的应该是战略,战略级别的设计不应该具体说明程序的参数,字段,以及对象之间的交互精确顺序的细节,那应该留到战术设计阶段,应该是设计者自己在编码阶段再展开的东西。我们应该要有这样的认识,几乎不可能在PDR环节考虑到所有code细节。好的设计应该是正确的,而不是精准的,他描述的一切必须是正确的,但不应该涉及不确定或者可能会发生变化的细节。
同时在PDR之前,建议给PDR做一个期限,这样的时间限制可以防止人们陷入无休止的理论争辩中,保证团队工作的顺利进行。我们应该认识到一点:没有最好的方案,只有更合适的方案。设定期限可以让我们在为难的时候果断作出决策,让后续工作顺利进行。 关于评审的基础条件 频繁评审 每次版本的迭代都应该进行PDR,现在大部分敏捷团队的开发都是双周迭代或者的月迭代,这样可以保证每次的代码改动量小,越少的改动可以更清晰的了解变动范围,更容易理解需求,出现逻辑问题也更容易发现。如果好几个版本才评审一次,就会堆积一大堆变动,一次评审十个模块,几乎不可能达到什么有价值的PDR效果。
快速响应
多次频繁的评审,才能保证快速的响应,评审不一定需要多么正式,小范围的改动只需要通知到相关方即可,确保至少有人知道你在做什么,同时能对你的方案作出反馈。
其它条件
其次,建议采取代码轮换制,让每个成员可以接触到不同部分的代码,也允许他们对别人的代码进行重构,可以提升团队的整体知识和技能,了解别人采用的技术和业务,当你在改别人的代码的时候,肯定会先理解对方的代码,然后咨询相应的开发人员,这样你就能深入问题领域。在当评审员的时候,也能更快了解别人的需求上下文。试想一下,一个刚加入团队、对项目还不了解的新成员,和一个长期跟你合作开发的老成员,谁能够提供更加有效的评审建议呢?
最后
千万不要用PDR进行绩效考核,一方面可能会造成评审人过于苛刻,他可能会以挑出毛病的数量作为自己绩效的加分项,而被评审人也可能会因为过于苛刻的评审条件而对PDR造成恐惧和厌倦。我们应该更多关注PDR的人文和社会属性,同时,是让设计指导开发,而不是控制开发。