无论你是否喜欢把它想成技术债务或是对冲期权,在我们的周围都充斥着糟糕的代码,糟糕的决定,以及这些东西给我们每天的生活带来的影响。但是这些决定所带来的长期影响会是什么?我们真的做了明智的选择吗?Martin Fowler谈论了技术债务的四种类型:从鲁莽的、故意的到偶然的、谨慎的。
故意不计后果的债务
故意不计后果的技术债务就是这样的:开发者(或者他们的经理)会允许那些只可能带来坏结果不可能带来好结果的决定被通过—例如,放弃TDD或者不用任何设计。无论从什么角度来看,这种做法都是非常不专业的。如果开发人员不能做出正确的选择,那么管理者就应该介入,并带入一些能够做明智选择的人进来。 Michael Norton将这称为“令人讨厌的行为,而不是技术债务”。如果我们不能从中受益,并且只是简单地完成任务,写一些糟糕代码,那么这根本不是技术债务,这是垃圾。
不易察觉的债务
不易察觉的技术债务比较有趣。如果我们不知道有更好的东西,我们又怎么会去做一些改变呢?工业标准和最佳的实践都在不断发展。我确定曾经某段时间EJB被认为是很好的组件模型,但现在它绝对被认为是不折不扣技术债务。当前的最佳实践方式很容易就变成未来的垃圾代码。
当开始时,如果我们就已经有了这个领域的知识,或者可能我们从未在这个领域工作过,没有这个领域的知识,可能设计出来的东西会不太相同。有些时候技术债务是不可避免和必然发生的。
谨慎故意的债务
接下来是谨慎而有意的技术债务,这种情况下,我们会有意做一个决定来增加技术债务。这里就有一个再普通不过的决定:
“不管怎样,我们要达到这个季度的目标利润。
我们的市场工作已经开始,所以我们必须在短的时间内抢占市场。
我们已经承诺了交货日期,所以没有太多时间给我们去犯错误。”
有时,我们必须做一些妥协:通过降低工作成果的品质,我们可以更快的完成工作,但我们会稍晚时候付出代价。
不同于其它的技术债务,这是一种特殊的技术妥协。我们故意做决定让代码质量比我们能够达到的质量要差。我们知道这会在以后让我们慢下来;我们知道我们需要回来重做,在所谓的“二期工程”里完善它;但是为了在规定的时间内完成任务,我们接受妥协。
它始终都是正确的决定吗?
1.妥协在短期来看更快,但在长期来看其实更慢
在我们现在就需要的东西与后续可能产生的不明的债务之间做选择时—显而易见,我们始终都会选择妥协。
2.每个妥协都看似渺小,但它们积累起来却非常庞大
不管有多少人都经历过“欠债”,技术债务都会积累起来。我们所做的每次妥协都会增加已有债务的代价。这意味着,每次妥协的代价可能很小,但积累起来后它们会产生巨大的影响。
一开始,我决定不重构一些代码。下一轮时,由于没有很好的重构,很难测试代码,所以我跳过了一些单元测试。第三轮时,我的测试覆盖率非常低,所以我没有信心进行扩展性重构。现在,这段程序真的变得很难测试也很难修改。我的代码在一点一点地,越来越快地恶化。每个妥协都堆积在以前的妥协之上,而且将它们放大。每次妥协看似影响很小,但它们累加起来却让人大伤脑筋。
3.长期的代价很难被量化
当我们同意不重构一段代码时,当我们同意留下一些半成品时,当我们同意为了急于通过测试而采用最小测试项时:这真的很难去估计长期的代价。当然,我们能够估算如何做是正确的—我们知道什么是“真理”。但是,我们如何去估计成本的支出?特别是当它们积累起来时。
我怎么能估计为了解决复杂问题而浪费的时间?时间的损失有可能是因为一个非常难以追查的bug。额外花费的时间可能是因为下一次我无法很容易地重构代码;或者是因为下一次我不敢重构代码,但额外的债务使我不得不这样去做。我怎么可能去量化这个问题?
在IMVU,他们发现他们:
“至少低估了一个量级的技术债务的长期代价”
它始终都是错误的吗?
这里有一些很明显的例子,它们都在产生技术债务;或者至少做得有些不称职。如果你想在客户面前展示一个新特性以判断其是否有价值,那么它不需要很完美,它只需要迅速地出现在那里就行。如果新特性对客户没用,那么你将其删除。你节省了将其做“完美”的成本,并迅速获得了你所需要的信息。这显然是符合成本控制的,是一种管理开发过程的简易方式。
但是,如果展示的这个特性获得成功了呢?那么,你需要制定一个计划清理它,重构它,确保它产生足够的文档并被充分的测试。这就是债务。只要你有一个删除它的计划,无论这个特性是有用或无用—那么这是一个完美而有效的方式。但如果不是这样,那么这个半成品特性可能需要数年时间去构建代码。
不同的是,我们会有一个计划来消除债务。多久我们就会接受一个模糊的承诺“我们会回过头来修复它”,或者,“我们会在第二阶段完善它”。我的墓志铭应该是“现在开始第二阶段的工作”。
在代码中留下债务,且没有任何消除债务的计划,就像一个家伙用一张信用的钱去还另一张信用卡的钱。你让债务产生,而不去处理它。没有偿还债务的计划,你最终将走向破产。
技术债务的风险
也许技术债务最大的危害是它代表的风险。技术债务使得我们的代码更加脆弱,不太容易修改。当我们最近讨论这个问题时,正如@bertvanbrakel所说:
“技术债务会使代码变得僵化”
在我们代码上堆积的债务越多,代码就越难改变。这种僵化会带来最大的风险:我们无法足够快速地改变代码。如果竞争环境和监管环境突然变化?如果一个新的竞争对手出现,彻底改变了我们的行业,我们需要多久才能赶上?如果我们只有一个僵化的代码库,在我们花2、3或4年时间赶上竞争对手时,我们又能得到什么呢?
当然这是指的最坏的情况,这种灵活性的缺失(缺乏创新)会一点一点地损害公司。一旦一个革命性的公司变成老古板,无法作出反应,并只释放衍生产品。当公司发现自己无法创新,跟不上不断变化的局势—它们就会变得无关紧要。这也就是技术债务真实的代价。
没有一个偿还技术债务的计划,没有可靠的办法来估计它所带来的长期成本,我们真的可能做出谨慎而故意的决定吗?这种轻易就能增加技术债务的决定做得是否太草率了呢?