过去几个月里关于技术债务出现了一些讨论也引发了一个问题哪些类型的设计缺陷应该被归为技术债务哪些不应该对于研发团队来说理解技术债务象限有助于更准确地识别代码质量问题、评估重构优先级并与非技术管理者沟通技术债务的真实成本。一个典型观点认为混乱的代码并不等同于技术债务。其理由是如果混乱代码是由不懂良好设计实践的人写出来的那么它不应该被称为债务。技术债务这个概念应该保留给那些经过审慎权衡后主动选择某种设计策略的情况。也就是说团队明知这种设计从长期来看不可持续但为了获得短期收益例如尽快发布新版本仍然选择这么做。关键在于这类债务虽然可以让团队更快创造价值但也需要尽快偿还。在我看来争论某种设计缺陷是否“算”技术债务本身就不是一个特别有价值的问题。技术债务是一种隐喻所以真正的问题应该是这个债务隐喻是否有助于我们思考如何处理设计问题以及是否有助于我们有效传达这种思考。债务隐喻的一个重要优势在于它非常便于与非技术人员沟通。我认为在这两类情况下债务隐喻都适用区别只在于债务的性质不同。混乱代码代表的是鲁莽债务它可能带来高昂的利息支出或者导致漫长的本金偿还周期。我们接手过一些债务严重的代码库项目在与客户管理层讨论如何处理这些问题时发现债务隐喻非常有用。债务隐喻提醒我们面对设计缺陷时其实存在不同选择。为了发布而审慎承担的债务如果利息支出足够低例如缺陷位于代码库中很少被修改的部分那么可能并不值得偿还。因此真正有用的区分不是“债务”与“非债务”而是“审慎债务”与“鲁莽债务”。技术债务的两个维度审慎与鲁莽、主动与无意在刚才的例子中还有另一个有趣的区分。不仅存在审慎债务和鲁莽债务的区别也存在主动债务和无意债务的区别。审慎债务之所以通常是主动的是因为团队清楚自己正在承担债务因此会认真权衡提前发布带来的收益是否大于未来偿还债务的成本。而一个完全不了解设计实践的团队则可能在毫无意识的情况下承担鲁莽债务甚至不知道自己已经背负了多重的债务。当然鲁莽债务也未必都是无意产生的。一个团队可能了解良好设计实践甚至有能力实践却因为认为自己“没有时间写干净的代码”而选择快速、粗糙地完成工作。我赞同一些软件工程专家的观点这通常是一种鲁莽债务因为人们低估了良好设计的收益拐点。优秀设计和整洁代码的最终目的是提升开发速度。否则软件工程领域也不会有那么多经验丰富的实践者长期反复讨论设计质量与代码整洁性的问题。把债务按照“鲁莽 / 审慎”和“主动 / 无意”两个维度划分就形成了技术债务象限。到目前为止我只讨论了其中三个象限。那么是否存在“审慎但无意”的技术债务呢虽然听起来有些奇怪但我认为它确实存在。而且对于优秀团队来说这不仅很常见甚至不可避免。审慎但无意的技术债务最近我和一位同事聊起他刚结束的一个项目。这个项目交付了很有价值的软件客户也很满意代码也很整洁。但他仍然对代码不太满意。他认为团队做得不错可直到项目结束时他们才真正意识到一开始的设计本该是什么样子。我经常从最优秀的开发者那里听到类似说法。关键在于编程本身也是一个学习过程。很多时候你需要在一个项目上工作一年才能真正理解最好的设计应该是什么样的。也许正如一些经典软件工程观点所建议的那样可以先花一段时间构建一个系统然后把它丢掉从头再来。但在现实中这种做法很难让人接受。实际情况往往是当你终于明白最佳设计应该是什么样子时也会意识到自己已经在无意中欠下了一笔债。一些软件工程实践者所讨论的正是这种类型的债务。此时支付利息还是偿还本金的选择仍然存在因此债务隐喻在这种情况下依然适用。然而用债务隐喻解释这类问题也有一个难点我很难想到一个现实中的财务类比能够准确对应“审慎但无意产生的债务”。因此我认为这种债务很难向管理者解释清楚。如何看待技术债务象限我的观点是这类债务不可避免因此团队应该预期它会发生。即使是最优秀的团队也会在项目推进过程中遇到债务问题。也正因为如此我们更不应该鲁莽地用劣质代码主动堆积更多债务。真正成熟的研发团队并不是完全没有技术债务的团队而是能够识别技术债务类型、理解债务利息、判断是否需要重构并有意识地管理技术债务象限的团队。在实际研发管理中团队也可以借助PingCode这类智能化研发管理工具将技术债务识别、需求清理、评审排期、开发测试、发布上线和 Wiki 知识沉淀串联起来让技术债务不只停留在讨论中而是进入持续可追踪、可治理的研发流程。