陈惠超的博客Github

作为程序员,你真的了解技术债务吗?

2020-03-12#技术

💡
最近在学习极客时间专栏《软件工程之美》,收获了不少知识。本文的内容是该专栏的学习笔记。
对于很多程序员来说,或多或少都听说过技术债务,但要具体说什么是技术债务,却有说不清楚。就好比我自己一样,在这之前,也听到,看到过技术债务这个概念。对于它的理解也就局限于字面意思,欠下技术方面的债务。除此之外,对于技术债务到底是什么?怎么产生的?该如何解决?却一无所知
今天这篇文章就来好好学一学技术债务。
什么是技术债务?
根据软件项目管理金三角的关系图(如下),质量之所以放在了最中间,是因为对于一个软件而言,质量往往是平衡了这三个因素后结果的体现。
软件项目金三角
这个质量不仅仅指的是软件的质量,同时还有项目的架构质量和代码质量
所谓技术债务指就是软件项目中对架构质量和代码质量的透支。
比如下面的情况,大家肯定都不陌生:
为了赶项目进度,导致开发的时候不得不写一些质量差的代码来追求速度;
为了赶项目进度,单元测试就来不及写;
随着需求的变化,原有的架构不能很好满足需求。但是又因为种种原因没法对架构做改动,只能在原有架构的基础上,通过各种hack来的实现;
一个旧的系统、没有文档也没有注释,技术老旧难以维护。
上面列举的几种情况都是属于欠下了技术债务。技术债务如果不解决的话,会累积越来越多,最后导致系统效率低下,代码臃肿难以维护,也难以增加新功能。
技术债务之所以称为债务,是因为跟金融债务很类似。技术债务也存在着利息。同时,并不是所有的债务带来的影响和价值都是不好,恶性的。
技术债务是有利息的
当你向银行借钱背下债务时,你是需要向银行支付利息的。同样的,如果你欠下了技术债务,你也需要支付相应的利息。
技术债务的“利息”体现在:当后面需要对软件进行修改时,需要额外的时间成本
一个项目在刚开始的时候,由于架构良好代码整洁,添加一个新功能只要4天。随着项目的不断维护,有时候因为迭代时间紧、团队人员水平参差不齐、团队没有代码规范、没有 Code Review 机制等因素的影响,导致了项目的代码质量越来越差而产生了技术债务。这时候如果再开发一个同样复杂的功能就不止4天的时间。这多出来的时间就是技术债务所产生的利息
这多出来的时间是怎么多出来的呢?因为你在开发新功能之前,还需要去梳理现在臃肿的代码,以找到合适的位置添加代码;修改代码后还可能导致原有系统不稳定,需要额外的时间去做 Bugfix。
这就是欠下技术债务后所导致的软件项目成本增加。但是是不是意味着在项目中,欠下的技术债务余越少也好呢?
技术债务也有好的一方面
并不是在所有的项目中,欠下的技术债务越少越好。
这里同样要以金融债务作为类比。
就是金融债务一样,债务也有好与不好的区分。比如你贷款买了豪车,一方面要支付利息,一方面车还要贬值。这时候债务就是坏的。如果你的债务是用于买入资产如房子,而房子在未来具有升值的空间,那么这个债务就是好的。
同样的道理,当你欠下技术债务的时候,却能因此而得到更大的收益时,那么此时的技术债务就是良性的。
良性的技术债务主要是从时间角度考虑。
在一些软件项目中,会刻意欠下一些技术债务,短期提升软件开发速度,快速上线,抢占市场的先机。
或者是一些给客户演示的原型项目,主要的目的是快速开发,演示给客户看,而不是实现完整的功能。毕竟有可能原型项目开发完之后,项目没有谈好,就没有下文了。
在上面列举的这两种情况,都是在项目有其他更高优先级的目标时,而故意欠下技术债务,提高开发速度。
但是这并不意味着可以无限制的欠下技术债务。因为借债越多,利息越大。当受益抵不过利息时,就会陷入恶性循环,导致开发效率低下,进度难以保障,最终可能导致整个项目的失败。
技术债务产生的原因
《重构》一书中将技术债务分为两个维度:
1.
轻率(reckless) 还是谨慎(prudent)
2.
有意(deliberate)还是无意(inadvertent)
两个维度形成的四个象限:
轻率 / 有意
该象限属于团队因为成本、时间等原因,故意走捷径没有设计、不遵守好的开发实践。对于债务没有后续的改进计划。
常见的情况是:没有开发设计直接开发;后期也没有重构打算。或者是团队以新手程序员为主,没有足够资深的程序员指导和 Code Review。
谨慎 / 有意
该象限反映团队清楚知道技术债务的收益和后果,并且也制定了后续的计划去完善架构和提升代码质量的情况。
常见的情况是:如为了尽快发布产品,忽略掉部分代码质量,后续再对代码进行重构。
轻率 / 无意
该象限反映团队既不知道技术债务,也不知道后续要偿还技术债务的情况。
常见的情况是:团队对什么是架构设计,什么是好的开发实践一无所知,代码一团糟。但愿大家永远都碰不到这样的代码。在这种债务技术上进行开发和维护简直比吃xxx还难受。
谨慎 / 无意
该象限反映团队其实很重视架构设计和技术债务,但因为业务的变化,或者其他客观的原因,造成技术债务的产生。
常见的情况是:最初的开发设计,随着业务的发展,已经无法满足新的需求。这样的情况技术债务难以避免。
其实很多技术团队遇到更多的还是这种象限的问题。毕竟并不是每个团队都有一个牛逼的架构师,能从一开始就设计了一个具有良好拓展性的架构。系统的架构往往是在需求不断增加和变更的过程中,慢慢不适合了。
如何解决技术债务
解决技术债务也有三种策略:
1、重写:推翻重来,一次还清
重写是优缺点都特别明显的一个方案。
优点是可以根据当前需求和业务,重写进行良好设计,精简掉不需要的功能和代码。
缺点是重写通常工作量大,在新系统没有完成之前,同时还要对旧系统维护增加新的功能。
2、维持:修修补补,只还利息
维持现状,只对严重问题修修补补。这是比较常见的策略。
修修补补相对成本较低,不同投入太大精力。但是如果项目有新功能增加的话,越到后面,修修补补的成本会越来越高。
3、重构:新旧交替,分期付款
重构是折中的策略。每次只改系统其中的一部分,在不改变功能的情况下,只对内部结构和代码进行重新调整,不断调整优化系统的结构,最终完全偿还技术债务。
优点是:不会导致系统不稳定;对业务影响小。
缺点是整个过程耗时相对较久。
那么这三种策略该如何选择呢?有一个标准就是考虑在你所在项目的情况下,哪一种策略的投入产出比最高。因为不管哪种策略,都需要投入时间和人力成本,只有投入产出比最高的才符合利益。
实施策略
重写。要把重写当做一个正式的项目来立项,按照项目流程推进;
重构。把重构任务拆分成一个个小的任务,放到任务跟踪系统跟踪起来;
维持。也要把修修补补的工作作为任务,放到任务跟踪系统。
预防才是最好的方法
预先投资:好的架构设计、高质量的代码就像一种技术投资,能有效减少技术债务的发生;
不走捷径:大部分技术债务都是因为走捷径。如果日常能做好 Code Review,单元测试等,都可以帮助预防。
及时还债:若因为项目进度等客观原因导致不得不欠下技术债务,必须在后续的开发任务中,将解决债务作为任务,安排进开发任务中,及时解决。
看到这里,是不是对于技术债务有了更加不一样的认识呢?希望大家都能“无债一身轻”。