敏捷开发“松结对编程”系列之十一:L型代码结构(团队篇之一)

来源:互联网 发布:傲梦编程 编辑:程序博客网 时间:2024/06/05 07:19

本文是“松结对编程”系列的第十一篇。(松结对编程栏目目录

上一篇中提到的技术方法都不太难,但问题是为什么很多团队做不到呢?问题在于:

高手可以每次都写出可复用的代码,从而大大地降低代码量。新手呢?总不能要求他们也都这样吧?这个,是本篇的内容。

横向分工还是纵向分工?

先看看“三”型代码结构和“川”型代码结构,形成这些代码结构的原因是分工方式的差异。

如果有三个(或三组)功能,正好有三个人,你会如何分工?

横向分工

一个人负责界面,一个人负责逻辑,一个人负责数据访问,结果就是代码形成“三型”结构。

三型分工的好处是:人员能力各有所长,安排各自负责一层,可以保证每层的计数都是最好的/可复用的。

听起来很好,但坏处也显而易见:

1. 要弄清楚各层的接口很难,很容易各层之间连接不起来。

解决这个问题的方法,就是提前做设计,约定好接口。可惜,很难找到一个人才,能提前约好接口,而做出来又不多不少的;当年的UML试图解决这个问题,而且解决得不错,唯一的问题就是UML很难学,所以真正使用的人很少。

即使学好了UML也做到了,日后代码改动的时候很少有人会去维护原来的设计文档。由于多数软件都是“改出来”的而不是“设计出来的”,所以这个问题很普遍。

2. 很容易需求镀金,就是做过了头。

这个本人深有体会。在2001年的时候参加了一个团队,这个团队的技术能力很强,我被安排做底层库(后来的复用技术就是在那里锻炼出来的),专门设计可供很多人、很长时期反复使用的代码。

后来“很多人、很长时期反复使用”倒是做到了,但是也有很多浪费,由于很少插手高层业务,我做的很多库都有多余功能,有时候甚至占一半还多。

所以后来我又从底层库里边爬出来,参与上层业务的工作,来了解他们为何需要调用我的底层库,后来才有所改善。

纵向分工

就是每个人负责一个(一组)功能,从头做到位,结果就是代码形成“川”型结构。

敏捷开发里边,比较崇尚这种方法。

好处很明显:

1. 省却了很多设计环节

这里节省的,是那些用于“沟通”的设计环节。由于各层代码自产自销,所以只要掌握了正确的方法(简单说,就是先高层后底层,参考这里),浪费很少。

但坏处也不少:

1. 对人的要求高

每个人都要掌握各个层次的技术,比较复杂。

2. 个人有个人的实现方法

尤其是新人,由于缺少对于“最佳实现方法”的共识,基本上会什么用什么,做出的东西五花八门。而且代码会绞成一团,难以拆分。

3. 重复劳动造成浪费

每个人都要做数据访问/缓存/优化/界面……很多本来可以复用的东西,都重复做了多遍。

139团队和L型代码结构

L型结构,是139团队的松结对编程的必然结果。

先剖析一下高手的代码结构。

高手的代码结构

实际上一个高手,无论是否告知其要编写底层库,几个功能下来,都会发现他积累了几个可以重复使用的东西。这种工作习惯是一旦养成,用可复用的方法还是不可复用的方法,编程的工作量相差不大。

这个时候,最好的方法把他的可复用库与大家分享,让别人必要的时候调用这些库来工作,而不是让大家以老死不相往来的方式形成“川”型代码结构。

这和“三”型代码结构相比有何差异?

差异在于,不要让高手专注于底层库的研究,而是要参与到业务功能的开发中,这可以有效地防止之前提到的需求镀金现象。确切说,只有熟悉业务功能,才能编写出适合的底层库出来。

编写了太多的业务功能,会不会影响到编写底层库呢?

火星人的代码中,只有11%的代码在与敏捷开发相关的业务中;20%代码是一些站点、部门、角色、权限这些平台业务;而超过70%位于一个与任何业务都没有关系的底层库中

所以即使完成全部业务代码,也不过增加了一少部分工作量而已,对高手做底层库影响不大;反而是更能令高手根据业务设计出合理的底层库出来。

139团队/松结对编程与L型代码结构

传统的代码共享,往往是一个人做出来之后,才通知大家有什么东西可用,请大家去学习使用。所以产生了很多额外的复用成本(乃至于一个共识是说:要让一个库可复用,要花费一次性代码成本的三倍)。

在139团队中,师傅是负责编写核心业务+底层库的人,他们在编程时会随时告知大家有新的可用的库产生,请大家必要时引用。

而徒弟们想要编写某些潜在的可复用库之前,都要先问问师傅是否已经存在了类似的东西。由于师傅的工作效率一般远远高于徒弟,基本上不等到徒弟想做什么可复用库的时候,库就已经在那里了;尤其是师傅在公司工作年限较长、已经有所积累的情况下。

最终形成的代码结构大致如下,这也是“L”型代码结构名称的由来:


左下角的一大块L型都是师傅的代码,右上角两块是徒弟们的代码。

偶然徒弟们也会为底层库贡献代码,不过一般而言机会不多。

L型代码结构的好处

1. 代码量显著降低

这个之前提到过了。

2. 质量显著提高

徒弟们编程缓慢是一个问题,不过更大的问题在于质量很差,甚至会连累师傅的进度。L型编码使得编程的过程主要是调用师傅的底层库的过程,所以质量的改善是显著的。

由于这些复用代码被反复使用,该有的问题都发生过了,质量自然就提高了;而新产生出来的代码,只是积木的组织过程,若有问题都是高层问题,一望而知。

3. 有利于团队的快速扩张

L型代码降低了对人员的要求,差不多能看懂这些接口,并能使用他们工作的人,都可以工作。

在01年的时候,我所在的团队就曾经为招聘不到懂SQL的程序员而郁闷,于是做了一个底层库“OODB”(很类似现在的LINQ/EF),免去了编写SQL的代码,大家的工作重心一下就从SQL语句转移到如何实现业务上去了。

那个团队后来有25~30个人,有大量的底层库可复用,多数业务都不需要在追究到底层实现就能解决。

L型代码结构的风险

1. 团队里必须存在一些能力很强又愿意分享的高级程序员

不过这个问题本身难度不大,至少比“我招聘了一堆能力一般又不愿意分享的程序员,该怎么办?”要好解决。

让技术带头人先做出表率,其他师傅会一点点跟进上来。如果没有人带头,或没有人跟进,这个团队面临的就不是研发管理问题了。

2. 必须进行自动化回归测试

代码复用的好处很多,但坏处是:一旦一个新应用的需要,而改动了旧有的代码,要能验证原来调用这个库的业务仍然能工作。

这个是火星人后期遇到的最主要的质量问题。由于有一些功能很少使用(比如管理员端的功能,做完后就放在那里了),当底层库变化后,这些功能是否还能运行,就需要进行及时验证。

3. 大型团队的管理困难

在大型团队中,L不是一个师傅写成的,而是由多个师傅级别的程序员共同编写的,在这个时候需要一定的分工管理,每个人侧重编写自己擅长的部分,每次编写不擅长的部分时,都先向别人咨询或乃至于把工作推送到别人那里。

这需要相当好的沟通管理,以至于当时我们做了一个内部网站来管理底层库。

不过比起来每个组一堆独立的代码,还是要好管理地多。确切说当每个组乃至每个人一堆独立代码的时候,人们并不是觉得“更好管理”,而是彻底放弃了管理,眼不见心不烦,等问题发生了再说。

4. 知识传递

之前提到过师傅如何向徒弟传递知识,这里不多说了。

师傅要抓住一切机会,让徒弟们也尝试去理解如何把软件做好,有可能是没事读读可复用代码(与“没事读读”相比,我更建议“有事的时候读读”),有可能是让他们尝试写一些可复用代码但师傅加以指导。

但不要不加指导和审核地让徒弟们贡献代码,新手发明轮子和制造Bug的速度,远远超过制作可复用代码的速度。

总之比之大家各顾各的,L型代码结构更适合知识传递。