本文最初发布于 Kyle Brown 的个人博客(kè),经原作者授(shòu)权由(yóu) InfoQ 中文(wén)站翻译并分(fèn)享。
让我们面对现实吧,2020 年是奇怪的一年。其中有一个奇怪的小现象,自(zì) 2012 年以来,美国的个人储蓄率首(shǒu)次出(chū)现增长(而且是以(yǐ)惊人的(de)速度增(zēng)长),而(ér)不是保持(chí)基本稳定 [1]。虽然这其中大部分都与流行病有关,但这也许可以在(zài)一定程度上(shàng)表明,消费(fèi)者(zhě)已经(jīng)开始意识到(dào),你不能一直借钱而不偿还你(nǐ)所欠下的债务。我希望企(qǐ)业(yè)能够意识到,同样的原则也(yě)适用于技术债务(wù),就像适用(yòng)于(yú)金融债务一样。这(zhè)个类比可能会让一些人觉得不太舒服(fú),但这实际上(shàng)是(shì)一个非常著名的思想,它最(zuì)早是由 Ward Cunningham 在(zài) 15 年前提出 [2],并由(yóu) Joshua Kerievsky 在 2005 年进一步发展 [3]。
简单地(dì)说,当开发团队为了完成其他活(huó)动而放弃重要的软件开发活动时,就会产生技(jì)术债务。通常,他们的想法是(shì),他们(men)会“回过头去”完成这项活动,但意图往(wǎng)往不会转(zhuǎn)化为(wéi)活动。这类活(huó)动可能非(fēi)常简单,如编写(xiě)文档,但也可能是更棘(jí)手(shǒu)的活动,比如修改一(yī)段代码,让它更容易理解和维护,或(huò)者是更(gèng)新因为代码变(biàn)化而过(guò)时(shí)的设计(jì)文档。
我最近在(zài)处理几个客户的问题,我感觉(jiào)自己就像一个(gè)消费者债(zhài)务顾问,在和(hé)一(yī)对背负着巨额抵押贷(dài)款的夫妇谈话,他们的信用卡余额在不(bú)断(duàn)增加,而且他们(men)的孩(hái)子即将出生(shēng)。在每一种情况下(xià),我们都快要被技(jì)术债(zhài)务压垮了,我们必(bì)须找到一些方(fāng)法来减少债务,同时继(jì)续开发新功能(néng)并继续(xù)前进。我提出(chū)了一套实践(jiàn)方法(fǎ),步骤和信贷(dài)顾(gù)问给他们客户的建议类似。让我们看看这些步骤,看看如何把他们(men)应用于许多项目都面临的技(jì)术债务(wù)状况。
这一步最关键。一旦团(tuán)队(duì)决定必(bì)须偿还他们的技术债务(这不(bú)是一个容易的决(jué)定——而且必须与业务一起做出),他们(men)就必(bì)须弄清(qīng)楚他们实际上欠了(le)多(duō)少债务。我(wǒ)发现(xiàn),最好的方法(fǎ)是进行自上而下(xià)的设计和代码审查(chá)。
首(shǒu)先看看(kàn)你的设(shè)计文档。它是(shì)最新的(de)吗?它是(shì)否准确地描述了设计中最重(chóng)要的点?然后,你可能想首先审查(chá)下代码的哪(nǎ)些部分给你带来了最大(dà)的麻烦——哪(nǎ)些部分最难修改?哪些(xiē)地(dì)方出错率最高?那些部(bù)分对(duì)你的业务(wù)来说最(zuì)重要?找出这(zhè)些(xiē)问题的答案,可以(yǐ)帮助你对你需要做的事情进行排序,找(zhǎo)出方(fāng)法改善你的处(chù)境。
系统(tǒng)中(zhōng)并不是只有代码和文档(dàng)会导致技术债务。另一个需要考虑的关(guān)键因素是运(yùn)营债务(wù)——例如,你是否运行在(zài)数据库或(huò)应用程序服务器等平台软(ruǎn)件构成的后台上?你的运营团(tuán)队是否在手动执(zhí)行应该(gāi)自动化完成(chéng)的任务,既(jì)浪费时间又浪费钱?你是否有适当的监控,以便在问题导(dǎo)致(zhì)站点宕机(jī)之(zhī)前发(fā)现问题,或者你是否(fǒu)把时间浪费在了事(shì)后分析上?
通常,最好(hǎo)是请一个外部(bù)专家来帮助你评估项目(mù)状(zhuàng)态。引入一(yī)名外部人员让你可以获得一份纯粹是基于解决方(fāng)案技术优越(yuè)性的评估,而不受办公(gōng)室(shì)政治或(huò)个人对某些代码的情感所(suǒ)影响。
最(zuì)终的(de)评(píng)估需要(yào)描述需要更改(gǎi)的内容,按照优先级进行排序,并提出代码更改建议,以及列出的每个更(gèng)改的估(gū)算成本。一旦你掌握了(le)这些事实,你就可以(yǐ)开始与业务所有者协商(shāng)你(nǐ)要偿还哪些债务以及以什么顺序偿(cháng)还。
虽然上一步是整(zhěng)个计(jì)划(huá)中最重(chóng)要(yào)的一步,但第二(èr)步通常会导致与业务最针锋相对的讨论。其中最难的部分是学会组织文化(huà)变革(gé),这(zhè)样你(nǐ)就不会让积(jī)累的债务超过合理的服务能力。就拿我们(men)的(de)金融债(zhài)务来说,这也(yě)是一件非常困难的事情——改变(biàn)你的消费(fèi)习惯,只买你需要的东西,而不是用信用卡购买你(nǐ)想要的东西,这是一件非常(cháng)困(kùn)难的事情。
为了(le)修(xiū)复发现的问题,你必须花时间来实现修复,这意味着你(nǐ)在纠正问题时会搁置新的开(kāi)发。关于这一点,没有什么完(wán)美的方(fāng)法,无论你采取什么方法,你都(dōu)需要与(yǔ)业务协商如何平衡技术债务偿还和新功(gōng)能开发。下面是一些我们(men)认为有效的策略。
在用户故事(shì)中包含债务偿(cháng)还(hái)活动。如果前面的步骤(zhòu)已经形成了一组(zǔ)按大小分类并排好序的活动,那么你可以(yǐ)与(yǔ)业(yè)务合(hé)作(zuò),确保在(zài)每个(gè)开发(fā)周期中都包含其中一部分活动(dòng)。比较(jiào)难的是平衡债务偿(cháng)还活动和涉及(jí)同(tóng)一代码(mǎ)区域(yù)的新功能开发。例如,如果你(nǐ)正在开发一个电子商务网站(zhàn),并且你(nǐ)发现大多数问题都是发生在结帐时,你可能想要把涉及(jí)这(zhè)一(yī)部分的新功能开发推迟到(dào)你偿还该部(bù)分的技术债务时(例如,重构代码或更新文档)。在这种情况下,在更改的过程(chéng)中添加新的促销活动或更改产品页面将(jiāng)是合理(lǐ)的选择(zé)。
采用贝塔测试。如果你构建(jiàn)的基础设施(shī)可(kě)以(yǐ)支撑两个(gè)网站(一(yī)个是主(zhǔ)网(wǎng)站,另一个是“测试”网(wǎng)站(zhàn)),那么你(nǐ)可以在重构主代(dài)码流的同时(shí)继续(xù)在测试(shì)网站上开发新功能。这(zhè)样做的好处是不会减慢任(rèn)何新功能(néng)开发(fā)的速度,但代价是,当对(duì)测试站(zhàn)点(diǎn)的更改必须重新集成到主站点时,集成(chéng)难(nán)度(dù)会(huì)增加。
在这种情况下(xià),我们可以和(hé)信用卡债务偿还策略做个对比,考(kǎo)虑两种不同的确(què)定债务偿(cháng)还优先级的方(fāng)法。第一种(zhǒng)可能的策(cè)略(luè)是“最(zuì)高利率优(yōu)先”。在信贷领域,这种策(cè)略是(shì)先(xiān)偿还(hái)利率最高的信用卡,因为这类信用卡支付的利息最高。在技(jì)术领域(yù),这意味着你可(kě)以首先考虑(lǜ)承担影(yǐng)响最大的任务。如果你解决了这些(xiē)问题,通常就可以为(wéi)其他更(gèng)改扫(sǎo)清障碍,并且(qiě)可能在性能、可(kě)维(wéi)护性(xìng)等方面获得最大的回报。
另一种可(kě)能的策略是“最低余(yú)额优先”策略。用信用卡的(de)术语来说,这意味着(zhe)先还清余额(é)最(zuì)低的信用卡——事(shì)情(qíng)很快就完成(chéng)了,这会让(ràng)你(nǐ)立即获得一种成(chéng)就(jiù)感。对于技(jì)术(shù)债务,一个类似的策(cè)略是首先处理最小的修(xiū)复,如果(guǒ)你必(bì)须说服业(yè)务或管理人员偿还技术债务(wù),或者如果你所在的(de)公司非常注(zhù)重结果导向(xiàng),只(zhī)有快速取得进(jìn)展才能为更(gèng)大的工作争(zhēng)取到资金支持,这会(huì)特别有用。
这里的关(guān)键(jiàn)是,让(ràng)偿还债(zhài)务成为你长期活动的一部分。这不是一次性(xìng)交易;对于“重构”[4] 这类(lèi)术语,人们不再(zài)像几年前它开始流(liú)行时那样抱(bào)有(yǒu)幻想,因为他(tā)们希望最好是可以从长期投资(zī)中获得短期结果。你总是会招致新的(de)债务;关键是确保你能(néng)在合理的时间内偿还,而不(bú)是让它(tā)越积越(yuè)多(duō)。
最后,你需要能够报告你在债务偿还活动中取得的进展。采集一(yī)些指(zhǐ)标,用于向(xiàng)管理和业(yè)务证明(míng),花费在(zài)这些活动中的时间(jiān)是值(zhí)得的,这点特别重要。例如,很多(duō)时候你需(xū)要重构(gòu)代(dài)码来提高性能(néng),这时,手(shǒu)上(shàng)有正确的统(tǒng)计数据来显示用户体(tǐ)验的改进是(shì)很(hěn)重要的。同样,当你在(zài)改进一个简(jiǎn)单的(de)代码库时,添加(jiā)新(xīn)特性(xìng)的(de)速度是另一个(gè)向业务证明价值的重要指标。
遵(zūn)循这些步骤并不能解决技术债务相关的所有(yǒu)问(wèn)题,但它们(men)至少可以让你系统性(xìng)地(dì)确定需要做什么,可以为开发过程带来(lái)什么(me)价值,以及(jí)变更在多大程(chéng)度(dù)上解(jiě)决了问题(tí)。如果你坚(jiān)持(chí)这样做,那么这应该可(kě)以使你的开发工件更容易维护,并且(qiě)应该可以减少你(nǐ)的开发压(yā)力。