一个苹果放在桌子上不理它,它会慢慢地变坏。代码也跟苹果一样,会发生代码腐烂。坏的代码就跟坏的苹果一样,会更容易发生腐烂、腐烂得更快。工作时间久了,关注的角度从个人变成了团队整体。我就会想:代码腐烂是否真的不可避免?有什么办法能够避免代码腐烂呢?
代码腐烂可以避免吗?
对于这个问题,我想了挺久,后面发现答案是:代码腐烂不可避免,只不过是时间问题。 虽然很沮丧,但是却认清了事物的本质,走上了一条正确的道路。这比起不愿意接受,然后制定错误的决定来得更好。
我给出代码腐烂不可避免的结论,其实是在思考了许多之后才做出的结论。代码质量高低取决于许多因素,包括但不限于:需求紧急程度、需求变化程度、团队成员技术能力、团队幸福感等等。这些因素都会从不同方面影响到代码质量,从而造成代码持续腐烂。
如果一个需求特别紧急,这时候我们不会考虑使用多么高深的代码结构去实现,肯定是短平快直接开干。毕竟对于现在来说,时间才是我们真正的敌人。这时候的代码质量肯定没有那么高,考虑得也没有那么全面,这时候代码腐烂的进度条又快速往前跑了一步。
需求变化程度也会影响代码腐烂的程度。如果需求来来回回变化特别大,那么我们很难设计一个统一的架构去适应需求。这时候就会出现分叉,分叉变得多了,代码结构就不好理解了。代码腐烂就自然而然发生了。
团队成员技术能力也是一个很重要的点。很多时候我们希望大家能用更好的代码结构,例如设计模式,例如用封装的思路来写代码。但是团队成员的能力是有区别的,有些人对代码能力强一点,对代码有追求,会做得很好。但是有些人能力就是差一些,很难写出这么好的代码。
简单地说,希望通过某些流程规范去完全避免代码腐烂,那是不可能的。注意,我这里说的是「完全避免」是不可能的。无论你做得多好,你的系统可能两三年后就需要做一次重构,这太正常了。但我们可以通过一些流程规范,去减缓这种代码腐烂的发生。
弄清楚我们的目标是完全消灭代码腐烂,还是减缓代码腐烂,这非常重要。只有制定了正确的目标,我们才不会做出错误的决策,我们制定具体行动的时候才会更有信心。
如何减缓代码腐烂?
减缓代码腐烂,其实有好多种办法。但最常见、收益最高、最好落地的两个措施,我认为是:技术方案评审、CodeReview。
编写技术方案,简单地说就是在你开发之前先想好技术方案。整个需求是怎么样的,你想如何去实现这个需求?表结构你要怎么调整?数据流从前到后的流动是怎样的?你要做哪一些改动?而技术方案评审,则是拉上熟悉这块业务的同学,让他们一起看看你的技术方案。看看这种实现方案是否有问题,是否有更好的实现方式?
通过技术方案评审,我们基本上可以避免出现大的需求问题,并且能确保需求改动能符合原有的系统设计。即使不得已选择了另外一个方式,出现了设计分叉,那大家也都知道这个事情的背景,更有利于后续解决问题。
CodeReview 则是对于技术方案的最终核对。很多时候技术方案写的是 A,但是代码写着写着就变成了 B。CodeReview 的出现就可以避免这个问题。当然 CodeReview 还有很多其他好处,例如:提高代码质量等等。
总结
代码腐烂是不可避免的,几乎所有系统都在发生不同程度的代码腐烂,大多数系统在两三年后就要做一次重构。我们能做的只是减缓代码腐烂的速度,让系统能够撑得更久。而减缓代码腐烂的方法,技术方案评审和 CodeReview 是最基本的、最好用的两个方法。
在周志明最新的书籍《凤凰架构:构建可靠的大型分布式系统》里,他也说到:
架构腐化与生物的衰老过程很像,原因都来自于随时间发生的微妙变化,如果你曾经参与过多个项目或产品的研发,应该能对以下场景有所共鸣:在项目开始的时候,团队会花很多时间去决策该选择什么技术体系、哪种架构、怎样的平台框架,甚至具体到开发、测试和持续集成工具。此时就像小孩子在选择自己钟爱的玩具,笔者相信无论决策的结果如何,团队都会欣然选择他们所想选择的,并且坚信他们的选择是正确的。
老人的退出、新人的加入使得团队总是需要理解旧代码同时完成新功能的成员,技术专家偶尔来评审一下或救一救火,充其量只能算临时抱佛脚;另一方面是代码会逐渐失控,时间长了一定会有某些并不适合放进最初设计中的需求出现,工期紧、任务重、业务复杂、代码不熟悉等都会成为欠下一笔技术债的妥协理由,原则底线每一次被细微地突破,都可能被破窗效应撕裂放大成触目惊心的血痕,最终累积到每个新人到来就马上能嗅出老朽腐臭味道的程度。
架构腐化与生物体衰老一样,是不可避免的。老人退出、信任加入、工期紧、任务重等等原因,都是不断欠下的技术债,我们无法避免。而对于代码腐烂,演进式设计或许是一个可解决的方案。简单地说:演进式设计是不追求完美,而是追求满足一定「保质期」内的合适,让合适的架构在合理的生命周期中发挥价值。
演进式设计是ThoughtWorks提出的架构方法,无论是代际的演进还是渐进的演进,都带有不少争议,它不仅是建造的学问,也是破坏的学问。Neal Ford在Building EvolutionaryArchitectures:Support Constant Change一书中比较详细地阐述了演进式架构的思想,获得不少关注,却不见得其中所有观点都能得到广泛认可。如果你是管理者,大概很难接受正是那些正常工作的系统带来了研发效率的下降的观点;如果你是程序员,估计不一定能接受代码复用性越高、可用性越低这样与之前认知相悖的结论。
当我们思考清楚代码腐烂这件事情之后,或许我们就能更客观、更平和地接受系统里那些烂代码。因为我们知道代码腐烂是一个自然法则,是不可避免的一件事情。我们能做的是尽量减缓腐烂的速度,让系统在合理的生命周期里发挥它的价值。