开发程序时,经常会碰到如下场景:
- 为了赶项目进度,单元测试代码来不及写了,打算之后再补
- 随着需求的变化,原有的架构设计已经不能很好的满足新的需求,但是又不想对架构做改动,于是就绕开架构设计增加了很多代码
- 一个旧的系统,没有文档没有注释,技术老旧,难以维护。
这些问题,如果没有及时修正,就会导致代码臃肿、下图效率低下,难以维护,也难以增加新的功能。
有一个很形象的名称叫做“技术债务”,用来形容上面这些架构或代码上的质量问。
什么是技术债务
软件开发时会遵循项目管理金三角规律。
轻率/有意的债务
这个象限,反映的是团队因为成本、时间的原因,故意走捷径没有设计、不遵守好的开发实践,对于债务没有后继的改进计划的情况。
比如不做设计直接编码,后期也没有打算重构代码,或者是团队成员以新手程序员为主,没有足够的资深程序员指导和审查代码。
这样产生的债务,短期可能还好,但是因为技术债务会一直积累,会导致利息越来越多,最终带来的负面效果会越来越大。
谨慎/有意的债务
这个象限,则反映的是团队清楚知道技术债务的收益和后果,并且也制定了后继的计划去完善架构和提升代码质量的情况。
比如说为了尽快发布产品,先采用“快猛糙”的方式开发,后继再对代码进行重构
这样产生的债务,因为能及时偿还,所以既可以短期有一定时间上的收益,长期也不会造成负面影响。
轻率 / 无意的债务
这个象限,反映了团队不知道技术债务,也不知道后继要偿还技术债务的情况。
比如说一些开发团队对于什么是架构设计,什么是好的开发实践一无所知,代码一团糟。
这样产生的债务是最危险的,因为既没得到技术债务的收益,还要偿还其产生的利息。
谨慎 / 无意的债务
这个象限反映了团队其实很重视架构设计和技术债务,但是因为业务的变化,或者其他客观因素的原因,造成技术债务的产生。
比如最初设计的时候,无法准确预测后面业务的发展,随着业务的发展,设计无法满足好新的需求。
这样产生的债务难以避免,但是如果能够及时对架构升级、重构,就能保证不会造成严重的影响。
以上就是软件项目中的四种技术债务,每一种技术债务产生的原因都不尽相同,对其处理的策略不同,也会造成不同的影响。
如何管理技术债务
既然技术债务有收益也有利息,那么我们怎样才能保证软件项目中的收益大于支付的利息呢p>
下图形象的描述了设计、开发速度和时间的关系。没有设计直接写代码,从短期看确实是节约时间的,但是跨过一个临界点之后,开发速度就会急剧下降

技术债务的收益和利息也是类似的道理,最初的时候,利息低收益高,欠一些技术债务是会节约时间的,但是超过一个临界点后,利息高收益低,就会大大降低开发效率。
所以最好能够让技术债务控制在临界点之下,这就要求我们能充分了解目前项目中的债务情况,然后才能制定相应的策略,从而达到控制债务的目的
识别技术债务
第一个是需要识别出技术债务,只有发现系统中的技术债务,才能去找合适的方案解决它。
可以通过很多指标来发现软件项目存在的技术债务,比如说:
- 开发速度降低:通常项目正常情况下,在相同的时间间隔下,完成的任务是接近的。尤其是使用敏捷开发的团队,每个任务会评估故事分数,每个sprint能完成的故事分数是接近的。但是如果单位时间内能完成的任务数明显下降,那很可能是技术债务太多导致的
- 单元测试代码覆盖率低:现在大部分语言都有单元测试覆盖率的检测工具,通过工具可以很容易知道当前项目单元测试覆盖率如何,如果覆盖率太低或者下降厉害,就说明存在技术债务了
- 代码规范检测的错误率高:现在主流的语言也有各种规范和错误检查工具,也叫做lint工具。通过各种lint工具,可以有效的发现代码中潜在的错误和不规范之处,如果错误率高,则说明代码质量不够好
- bug数量越来越多:正常情况下,如果没有新功能开发,bug数量只会越来越少。但是如果bug数量下降很慢,甚至有增多的迹象,则说明代码质量或者架构可能存在比较大的问题。
除了上面这些指标,其实你还能找到一些其他指标,比如你用的语言或者框架的版本是不是太老,早已无人更新维护了;比如开发人员总是需要加班加点才能赶上进度,如果架构良好、代码质量良好,这些加班本是可以避免的。
如何解决技术债务
有三种策略
重写:推翻重来,一次还请
将老系统推翻重写是很多程序员最热衷干的事情之一了。重写系统是一种优缺点都很明显的策略,这有点像你试图把债务一次性还清。
优点是你可以针对当前的需求和业务发展特点,重新进行良好的设计,精简掉不需要的功能和代码。缺点就是重写通常工作量很大,在新系统还没完成之前,同时还要对旧系统维护增加新功能,压力会非常大;另外新写的系统,重新稳定下来也需要一段时间。
维持:修修补补,只还利息
维持现状,只对严重问题修修补补,这其实是常见的一种策略,就跟还债的时候只还利息一样。
修修补补相对成本低,不用投入太大精力,如果项目不需要新增功能,只需要维护还好,如果项目还持续要新增功能,越到后面,维护的成本就越高了。
重构:新旧交替,分期付款
重构相对是一种比较折中的策略,就跟我们采用分期付款的方式偿还贷款一样。
每次只是改进系统其中一部分功能,在不改变功能的情况下,只对内部结构和代码进行重新整理,不断调整优化系统的结构,最终完全偿还技术债务。这种方式优点很多,例如不会导致系统不稳定,对业务影响很小。缺点就是整个过程耗时相对更久。
重构的要领:
- 第一:你要先写一部分自动化测试代码,保证重构后这些测试代码能帮助你检测出来问题
- 第二:在重构模块的时候,老的代码先保留,写新的代码,然后指向新代码,或者用特定开关控制新旧代码的指向(这样上线后可以自己先测试,有问题也可以及时关闭),然后让自动化测试通过,再部署测试,新代码没问题了,删除旧代码
怎么选
这三种策略并没有绝对好坏,需要根据当前项目场景灵活选择。有个简单原则可以帮助你选择,那就是看哪一种策略投入产出比更好。
无论选择哪种策略,都是要有投入的,也就是要有人、要花时间,而人和时间就是成本;同样,对于选择的策略,也是有收益的,比如带来开发效率的提升,节约了人和时间,这就是益。
如果收益高于投入,那这事可以考虑做,否则就要慎重考虑。
对一个生命周期不会太久,或者没有什么新功能开发的系统,花大力气去重构、重写是不合算的,不如维持现状。
而如果有新技术新产品出现,可以以极低的成本替代原有系统,这样重写就是个好方案。
通常,如果你纠结于不知道该选择哪一种策略时,那就选择重构的策略,因为这是相对最稳妥有效的。
实施策略
当你选择好用哪种策略处理技术债务之后,就可以实施你的策略了。不同测策略实施方式不同:
- 对于重写策略,要当做一个正式的项目来立项,按照项目流程推进。
- 对于重构策略,要把整个重构任务拆分成一个个小任务,放到项目计划中,创建成ticket,放到任务跟踪系统中跟踪起来
- 对于维持策略,也要把需要做的修补工作作为任务,放到计划中,放到任务跟踪系统中
实施策略的关键就在于要落实成开发任务,做为项目计划的一部分。
预防才是最好的方法
前面说的方法策略,都是针对已经存在的技术债务而言的。其实最好的方法是预防技术债务的产生。像下面这些方法,都是行之有效的预防策略:
- 预先投资:好的架构设计、高质量代码就像一种技术投资,能有效的减少技术债务的发生
- 及时还债:有些时候项目中,因为进度时间紧等客观原因,导致不得不走捷径,那么就应该把欠下的技术债务记下来,放到任务跟踪系统中,安排在后继的开发任务中,及时还债及时解决,就可以避免技术债务越来越多。
如果团队能提高对技术债务的认识,防患于未然,就能让技术债务保持在一个合理的水平,不会影响到开发效率。
总结
技术债务,就是软件项目中架构质量和代码质量的透支。
技术债务,也并不都是坏事,如果合理利用,就可以在短期内缩短时间,但是后期如果不偿还技术债务,也会对项目及个人造成不好的后果。
技术债务产生的原因有四个方面:轻率 / 有意的债务、谨慎 / 有意的债务、轻率 / 无意的债务和谨慎 / 无意的债务。
可以分三个步骤来管理技术债务:识别技术债务、选择处理策略和实施策略。处理策略有三种:推翻重写、修修补补和重构。
对于技术债务,是继续修修补补凑合着用,还是推翻重来取决于哪一种策略的投入产出比更好,如果推翻重来代价太大,那么就应该谨慎考虑,不如先修修补补或者局部重构;
如果修修补补难以维持,就要考虑重写或者重构。
对于技术债务,还是要在日常开发中有好的意识,不走捷径,防患未然,预防技术债务的发生。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!