老码农看到的技术债务

“软件和大教堂是类似,都是先构建,然后祈祷”。————Earl Everett

关于技术债务的讨论时而蔓延时而消退,技术债务仿佛是个筐,什么东西都可以往里装,然而当我们企图倒光筐里东西的时候,却发现每人看到的东西都不一样,甚至有时候都数不清里面都有些什么。 作为一个半吊子全栈工匠,试图从一个老码农的视角审视一下技术债务。

一个比喻导致的分歧

技术债务是由敏捷先驱 Ward Cunningham(https://en.wikipedia.org/wiki/Ward_Cunningham)在1992年的一个报告中的一个比喻,大意是做了错误的或不理想的技术决策所导致的债务。由于是个比喻,所以产生了每个人眼中的哈姆雷特。

首先,Steve McConnell将技术债务分为两类:无意的和有意的。 1)无意产生的技术债务:由于缺乏经验而编写了低质量的代码。 2)有意产生的技术债务:根据当前情况进行设计选型,可能很快就能解决当前的问题,有时会变得拙劣。

作为《重构》一书的作者,Martin Fowler认为技术债务产生的利息是指由于鲁莽的设计决策导致需要在未来的研发中付出更多。面对技术债务,可以持续付利,也可以通过重构一次付清。代码中的坏味道也是技术债务,是一种不计后果的债务,会让问题变得更加严重,进而将技术债务划分为4个象限:

Bob大叔则认为坏味道并非技术债务。技术债务的评价标准是真实的项目约束,这些约束是风险和好处并存的。坏味道是由懒惰和外行导致的,总是意味着损失。技术债务要求牢记保持代码的整洁,就好像一个人在背负巨大的抵押债务时需要时刻保持警醒一样。

关于技术债务的更多定义讨论参见http://wiki.c2.com/?TechnicalDebt。

技术债务的现象与类型

将一个比喻作为定义是不严谨的,而且很多人对定义的重要性并不是很关注。于是,可以从现象和构成的角度来看待技术债务。

如何认识无意产生的技术债务呢?当出现如下现象的时候,说明技术债务开始累积: 1)类似的代码在不同的项目/产品间迁移 2)代码已经稳定但回归测试的陈本在增加 3)每一次交付的成本逐渐增加 4)类似feature 开发的周期开始变长 5)在既有代码上开发,还不如推到了重来

技术债务的类型是由产生的原因和方式来定义的,其中一种分类如下:

  1. 战略债务:为了战略利益(例如首次上市)故意为之,并长期存在。

  2. 战术债务:在知情的情况下为了快速收益而产生,适用于短期。

  3. 疏忽债务:在不知情的情况由于缺乏知识和意识而产生。

  4. 增量债务:定期不慎产生的而导致增量债务。

技术债务包括那些现在选择不做的内部事务,但会影响未来的开发工作,例如延迟重构。不包括推迟的功能实现,除非交付功能对客户来说“足够好”的情况下,但不满足某些标准(例如,UI元素不完全符合某些UI标准)。

技术债务的组成

技术债务是多方面的,涉及技术的多个维度,这也是每人眼中都有着自己的哈姆雷特的一个重要原因。

现罗列自己经历或者看到过的一些方面:

  1. 代码债务:代码重复、违反静态分析工具和代码异味等。

  2. 设计债务:设计异味、违反设计规则等

  3. 架构债务:违反架构规则,对非功能性约束认知不足等。

  4. 测试债务:缺乏测试、测试覆盖面不足和不正确的测试设计等。

  5. 质量债务:缺乏稳定性和健壮性的技术验证,QA的自动化不足等

  6. 配置债务:版本控制的模糊,环境参数的混淆等

  7. 平台债务:平台经验的匮乏,云服务融合与应用不足等

  8. 文档债务:存在重大问题的文档、缺乏文档和文档过期等。

针对每一类技术债务,都有着相应的原则和处理方法,有时间再仔细展开。

技术债务的度量之痛

No measurement,No management。令人遗憾的是,很难有相关工具或者框架来提供量化数据对其进行准确而完整的分析。

技术债务并没有一个普遍接受的范围定义,甚至认为已知的bug也构成了技术债务。当前可用的技术债务量化工具仅仅关注几个维度,比如代码债务和一定程度的设计债务和测试债务。对于同其它维度相关的问题,比如架构债务或文档债务,这类工具并没有提供全面的检测支持。实际上,已支持的维度的全面性也是有问题的。

一般,技术债务的量化工具通常会转换成偿还这些债务所需的工作量,而工作量会随问题的严重性、范围、平台、技能等的变化而不同。这样所产生的估计值与实际情况大不相符,最多只是一种近似,而不是准确的结论。

任何类型的债务都会包含本金和利息,而当前的一些所谓的量化工具都关注与技术债务相关的本金,而忽视了利息部分,从而并不可信。利息部分关系到了理解的难度等因素,越发难以准确地量化。

技术债务很好地充当了沟通拙劣设计结果和持续重构需求的隐喻。但试图测量和量化技术债务时,变得同准确测量软件生产力或者量化软件质量一样困难!

技术债务的现金衡量

当然,技术债务的货币化有助于了解技术债务的严重程度,提供了一种跟踪技术债务偿还进度的方法。不过,需要谨慎对待这些成本和工作量估计。

一旦有了与技术债务直接相关的金钱数目,关于软件的多种复杂而麻烦的问题就可能得到答案。Israel Gat提出:除非对于技术债务有一个量化的账单,否则团队都会忽略其重要性。他提到了以金钱方式计算技术债务的需要,以金钱方式计算技术债务有如下好处:

  • 能够告诉团队何时停止开发,开始重构。团队进入重构过程,除非债务得以偿还,否则不加入任何功能。

  • 客户对于软件的风险得以了解。

  • VC们可以以此判断向某项软件产品中投入资金是否理智。

  • 有助于判断软件的支付能力,判断在重构和重写这二者之间做出选择

有哪些有效的方式可以用来将技术债务以金钱衡量呢?

Sonar中的技术债务插件是一种方式。在Sonar的站点上,已经有了对于项目的技术债务分析。要计算成本,首先要使用下面的方式找出债务:

债务(人/天)=修复重复部分的成本 +修复违规的成本 +为公共API做注释的成本 +修复未发现的复杂性的成本 +带入低于阈值复杂性的成本 +在包的层面上切断生命周期的成本

对于每个小时的成本有个默认值,例如人工200块每小时。与之类似,就可以做出各种情况的现金分析,并可以计算出技术债务的总和。

因此,以金钱方式计算技术债务能够深入理解与软件相关的潜在成本。对于所有希望监控技术债务成本并将其保持在一定限额内的敏捷团队来说,这很关键。

直面技术债务

面对已知的技术债务,普遍的经验是防止技术债务的积聚,以及有计划地偿还技术债务。

防止技术债务产生的主要方法是了解开发团队存在的技术债务。开发团队必须了解技术债务,它的各种方面和类型,以及债务对他们的项目的影响。他们必须具备完善的设施与代码质量的概念,干净的编码习惯、设计嗅觉、以及如何重构它们。合适的流程可以帮助开发团队避免技术债务积累,例如代码、设计、架构和测试的审查等。然而,这些流程必须是务实的,否则事与愿违。

对于偿还技术债务而言,首先同样是识别并记录现有债务,优先处理异味,在每个迭代中分期偿还债务。如果一个研发团队的以团队交付功能的数量或修复bug的数量为考核标准,那么团队将只专注于增加功能和修复bug。但实际上,做好它和完成它同样重要。同时,留意可能出现的大规模债务偿还,属于不同维度的债务实例相互影响。在某些情况下,即使债务很高,也不值得偿还技术债务。这些情况包括原型、概念实现和即将废弃的产品所产生的技术债务。此外,如果计划为一个传统项目迁移到一个新的技术、平台或架构,不偿还的技术债务是明智的,因为相关的债务可以在迁移过程中解决的。

管理他人的技术债务

由于不提倡重复造轮子,我们所使用的第三方软件和开源软件产生的技术债务同样会对我们造成影响。它们的Bug会成为我们的Bug,安全漏洞也会成为我们的安全漏洞,错误决定会成为了我们的错误决定。

我们所使用其他软件的代码量可能会非常大,由此产生的技术债务也可能大,甚至超过自己所编写的代码量。根据Sonatype的一项调查显示,80%的Java应用都是由开源组件与框架装配起来的,一个大型系统甚至会使用30多个不同的库或组件。

要想了解这种债务问题的严重性,需要审查代码中使用了哪些第三方开源包与依赖。一旦清楚了其他人的软件可能会造成的影响,就需要评估由此所带来的风险和问题了,并需要紧密追踪这些软件的补丁、升级信息及Bug报告等,这确实不太容易。

知道问题的严重性是一方面,修复问题则是另一方面。对最新的发布打补丁并非易事。最好能在外围打补丁,因为补丁并非总是适合于我们所使用软件的方式:Apache、Tomcat、Web Service库、客户端组件等。我们需要更加谨慎地管理这些后端代码。如果每当出现一个Linux补丁时需要立刻打上,那就说明架构可能有些问题。

升级更是一个大问题了,升级到最新的OS、RDBMS、VM等都涉及到很高的代价与风险。虽然可以通过升级的方式获得在可伸缩性、管理性及新特性等方面的一些优势,不过升级项目还需要更加关注一些潜在的问题:功能回归、兼容性问题、操作流程的变化、对其他系统的依赖变化等等。升级之后,大多数软件会变得更大而不是更好,也许会加入很多新特性,不过可能压根就用不上这些特性,这也意味着需要花更多的时间进行安装、配置和测试。我们需要搞清楚变化的地方,重新进行测试和调优。

技术债务的价值

把技术债务和金融债务来类比,贷款就会产生债务,如果定期还款,那么债务是可接受的,不会产生进一步的问题。但是,如果他不还款,就会以利息作为惩罚,并随着不还款次数的增加而增加。如果很长一段时间不能支付任何款项,那么应计利息使得债务更难以偿还。

同样地,当我们采用一个非最优或次优技术决定,就引入了技术债务。在很长一段时间未偿还累计的技术债务的情况下,软件越来越难以改变,在极端情况下,软件产品变得在技术上已经破产,往往会导致项目终止。利息有复合的性质:开发团队越是忽略或推迟它,随着时间的推移,债务变得越大。因此,是利息使得技术债务成为一个显著问题。

我们谈及技术债务的时候往往都清楚它的种种弊端,却缺乏主动使用技术债务的勇气。 债务具有着现金价值,在金融领域中,货币杠杆的作用显著。 对企业而言,现金流更是关键因素, 所以,没有必要谈债色变,没有债的企业未必都是一流的好企业。

合理使用技术债务,在这个快节奏的时代,我们有责任迅速为客户提供价值。在这种追求中,有各种情况团队必须选择快速或者肮脏的解决方案。需要注意的是,在这种情况下,需要我们以勤奋和务实的态度处理技术债务。

(0)

相关推荐

  • Strikingly CTO 郭达峰:从 Hacker 到 CTO

    2017年6月30日-7月1日,EGO主办的第二届GTLC全球技术领导力峰会在上海举行.会上,Strikingly CTO郭达峰发表了主题为<从Hacker到CTO>的演讲.本文由EGO根 ...

  • 失业半年的45岁老码农,活的不如狗今天听...

    失业半年的45岁老码农,活的不如狗 今天听公司人力资源总监说了个事,前几天来了个45岁的老码农,失业半年,每个月的房贷20000,老婆不工作,2个孩子,面试的时候都快哭了 之前的年薪有600000,说 ...

  • 隄上创新谁述记——老码农的“创新”漫谈

    引子:大学生活是令人难忘的,而大学同学就好像是上天给我们找来的兄弟姐妹.应大学同学王总(Linda)的要求,聊一下"创新".但由于"双十一"耽误了一周,迟迟未能 ...

  • 老码农的AI漫谈

    " 不认识整体就不可能认识局部,同样,不认识局部也不可能认识整体."   --布莱士·帕斯卡(Blaise Pascal) AI 切实地来到了人们的身边,从迷惑到振奋,从憧憬到期盼 ...

  • 没有被了解的API?一个老码农眼中的API世界

    即便做了20多年的软件开发,仍然发现自己经常会低估完成一个特定的编程任务所需要的时间.有时,错误的时间表是由于自己的能力不足造成的: 当深入研究一个问题时,会发现它比最初想象的要难得多,因此解决这个问 ...

  • 老码农眼中的区块链

    大家可能已经听说过比特币.莱特币.以太币等等,以及它们作为一种新货币在市场上的潜力. 有趣的是,很多投资比特币的人也提到了区块链之类的东西. 显然,这项技术是比特币等其他东西的"基础&quo ...

  • 老码农眼中的存储

    存储,是我们码农每天都要打交道的事情,而当我们面对RAID,SAN,对象存储,分布式数据库等技术的时候,又往往似是而非,存储成了我们熟悉的陌生人. 在老码农眼中,存储仿佛是这个样子的. 从计算机结构出 ...

  • 老码农眼中的简明AI

    AI, Artificial Intelligence, 人工智能. 就像每个人眼中都有一个自己的哈姆雷特一样,每一个看AI 都是不一样的.作为一个老程序员,也只是一个工作时间长一些的程序员而已,本没 ...

  • 一个码农,做了十几年技术,为什么突然要搞艺术了?

    Photo by Karyme França from Pexels 可能没有朋友会理解,一个码农,做了十几年技术,为什么突然要搞艺术了?其实一点都不突然. 夜深了,半夜起来睡不着,我想和朋友们聊一聊 ...

  • 码农和技术管理者的区别,到底在哪里?

    正文开始 许多技术管理者都有这样的困惑,我们做技术管理的,写代码的时间越来越少,手越来越生疏,但是参与了更多的技术评审和技术决策,这似乎是件很矛盾的事情. 因此,他们时常感到很焦虑,自己技术能力越来越 ...