送给研发同学的一封技术债务催收函(附:偿还指南)

你是否收到过以下消息:

  • 接连不断地收到消息得知:项目单测覆盖率不达标、服务框架老旧、服务鉴权要开启、存储组件需平迁、kms待升级、tcc更新版本、SQL注入漏洞、慢查询语句待治理。。。

  • 为了赶项目进度,导致开发的时候不得不写一些质量差的代码来追求速度,单元测试就来不及写;

  • 随着需求的变化,原有的架构不能很好满足需求。但是又因为种种原因没法对架构做改动,只能在原有架构的基础上,通过各种高耦合、低内聚代码来实现;

  • 一个旧的系统、没有文档也没有注释,自行挖掘逻辑、技术老旧难以维护。

上面列举的几种情况都是属于欠下了技术债务。技术债务如果不解决的话,会累积越来越多,最后导致系统效率低下,代码臃肿难以维护,也难以增加新功能。

让我们看看应该怎么做最好。

什么是技术债务?

根据软件项目管理金三角的关系图(如下),质量之所以放在了最中间,是因为对于一个软件而言,质量往往是平衡了这三个因素后结果的体现。

 这个质量不仅仅指的是软件的质量,同时还有项目的架构质量和代码质量。所谓技术债务指就是软件项目中对架构质量和代码质量的透支。

技术债务产生原因

《重构》一书中将技术债务分为两个维度:

1.轻率(reckless) 还是谨慎(prudent)

2.有意(deliberate)还是无意(inadvertent)

  • 轻率 / 有意

    • 团队因为成本、时间等原因,故意走捷径没有设计、不遵守好的开发实践。对于债务没有后续的改进计划。

    • 常见的情况是:没有开发设计直接开发;后期也没有重构打算。或者是团队以新手程序员为主,没有足够资深的程序员指导和 Code Review。

  • 谨慎 / 有意

    • 团队清楚知道技术债务的收益和后果,并且也制定了后续的计划去完善架构和提升代码质量的情况。

    • 常见的情况是:如为了尽快发布产品,忽略掉部分代码质量,后续再对代码进行重构。

  • 轻率 / 无意

    • 该象限反映团队既不知道技术债务,也不知道后续要偿还技术债务的情况。

    • 常见的情况是:团队对什么是架构设计,什么是好的开发实践一无所知,代码一团糟。但愿大家永远都碰不到这样的代码。在这种债务技术上进行开发和维护简直比吃xxx还难受。

  • 谨慎 / 无意

    • 团队其实很重视架构设计和技术债务,但因为业务的变化,或者其他客观的原因,造成技术债务的产生。

    • 常见的情况是:最初的开发设计,随着业务的发展,已经无法满足新的需求。这样的情况技术债务难以避免。

技术债务好与不好

技术债务之所以称为债务,是因为跟金融债务很类似。技术债务也存在着利息。同时,并不是所有的债务带来的影响和价值都是不好,恶性的。

是一种经济选择

正如,“有了借来的钱,你可以更快地做一些事情,但是直到你还清这笔钱,你都需要支付利息。借钱是个好主意,将软件推向市场以获得一些经验也是个好主意,但是当然,当你获取了相关信息之后,需要通过获得的经验来重构程序,以偿还债务。”

技术债务的概念让人们真正从经济上考虑这个问题。根据最佳决策时机原则,每个决策都有其最佳经济时机。最佳经济时机的衡量需要综合考虑成本与收益。

上述问题的核心,在于重构的成本,以及因为此模块而背负债务的利息。利息与维护和更新的频度有关,与单次的维护成本有关。

是一种不可避免的情况

  • 软件的真正成本是时间

所有软件都是为了解决问题而设计的,今天解决一个问题比明天解决它更有价值。因此,在任何工程项目中,尽快完成都至关重要。快速而不完美的代码,具有最多技术债务的代码,实现了这一点。如果在每一行代码都完美无缺之前拒绝发布软件,你的产品可能永远不会交付,你的公司会很快接近尾声。

  • 不存在完美的产品

我们是在未知的不确定性世界中构建软件。软件的客户对他们需要产品中的哪些功能只有一个粗略的想法,并在软件构建过程中逐渐了解更多的信息,尤其是在向用户发布早期版本之后。“我们做出了很好的决定,但直到现在我们才明白我们应该如何构建它”,对于产品和架构,只有产品发布之后才会获得足够多的信息,以便更好的指导构建。

所以我们不可能也不需要一开始就把它设计得最好,我们无法避免技术债务。债务比喻提醒我们可以针对设计缺陷做出选择,快速交付获得的收益足够大,并且利息支付足够小,或者债务位于代码库中很少涉及的部分,那么债务可能不值得尽快的偿还。

当你在编程时,你是在学习。通常情况下,在了解最佳设计方法应该是什么之前,甚至可能需要对项目进行超过一年的编程尝试。技术债务是不可避免的,所以是可以预料的。随着项目的进行,即使是最好的团队也会有债务需要处理,更有理性而非鲁莽的,用清晰但不完美的代码背负它。

是一种有意为之的选择

  • 这里同样要以金融债务作为类比。

就是金融债务一样,债务也有好与不好的区分。比如你贷款买了豪车,一方面要支付利息,一方面车还要贬值。这时候债务就是坏的。如果你的债务是用于买入资产如房子,而房子在未来具有升值的空间,那么这个债务就是好的。

同样的道理,当你欠下技术债务的时候,却能因此而得到更大的收益时,那么此时的技术债务就是良性的。

  • 良性的技术债务主要是从时间角度考虑。

在一些软件项目中,会刻意欠下一些技术债务,短期提升软件开发速度,快速上线,抢占市场的先机。

或者是一些给客户演示的原型项目,主要的目的是快速开发,演示给客户看,而不是实现完整的功能。毕竟有可能原型项目开发完之后,项目没有谈好,就没有下文了。

在上面列举的这两种情况,都是在项目有其他更高优先级的目标时,而故意欠下技术债务,提高开发速度。

但是这并不意味着可以无限制的欠下技术债务。因为借债越多,利息越大。当收益抵不过利息时,就会陷入恶性循环,导致开发效率低下,进度难以保障,最终可能导致整个项目的失败。

如何解决技术债务

通常最好的方法是像我们通常处理金融债务一样,逐步还清本金。当一个团队能够开始偿还技术债务时,他们不仅是在偿还债务,同时也将开始从债务偿还的循环中受益:你偿还的每一笔债务都会导致有更多的时间偿还更多的债务。这是一个正向的循环飞轮。

  • 重写:推翻重来,一次还清

    • 重写是优缺点都特别明显的一个方案。

    • 优点是可以根据当前需求和业务,重写进行良好设计,精简掉不需要的功能和代码。

    • 缺点是重写通常工作量大,在新系统没有完成之前,同时还要对旧系统维护增加新的功能。

  • 维持:修修补补,只还利息

    • 维持现状,只对严重问题修修补补。这是比较常见的策略。

    • 修修补补相对成本较低,不同投入太大精力。但是如果项目有新功能增加的话,越到后面,修修补补的成本会越来越高。

  • 重构:新旧交替,分期付款

      重构是折中的策略。每次只改系统其中的一部分,在不改变功能的情况下,只对内部结构和代码进行重新调整,不断调整优化系统的结构,最终完全偿还技术债务。

      优点是:不会导致系统不稳定;对业务影响小。

      缺点是整个过程耗时相对较久。

  • 综合考量:

      哪一种策略的投入产出比最高。因为不管哪种策略,都需要投入时间和人力成本,只有投入产出比最高的才符合利益。

    总结

    定期重构:

    • 定期重写软件中的组件,重构代码作为有效的预防措施,有助于代码随着时间的推移带来的逐步腐蚀,增加其耐受性,聪明的团队不会等待系统崩溃,而是先发制人地采取行动来提高代码的免疫系统。

      1. 例如基于DDD思想重构项目部分模块,使得系统的扩展性得到提升;

  洋葱架构思想

2. 建立技术bits,为技术债分配专用力量:将中等大小的技术债当作日常迭代的一部分,以一定比例的工作时间用于这类的活动。一种常见的分配是 70% 用于功能开发,20% 用于技术债,10% 用于学习 / 实验。另一种方式是不讨论投入的时间,只是从每个工期的积压工作中拿出固定数量的技术债务。一个明显的问题是有些技术债问题可能很大,这时候需要进行拆分,或者如果真的必要,拿出一大块时间,将比较重要的技术债务当作项目或者独立的重构迭代。

预防才是最好的方法:

  1. 预先投资:好的架构设计、高质量的代码就像一种技术投资,能有效减少技术债务的发生;

  2. 不走捷径:大部分技术债务都是因为走捷径。如果日常能做好 Code Review,单元测试等,都可以帮助预防。

  3. 及时还债:若因为项目进度等客观原因导致不得不欠下技术债务,必须在后续的开发任务中,将解决债务作为任务,安排进开发任务中,及时解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值