如何领导团队做好技术债管理

技术债是 Ward Cunningham 的一个比喻。Ward Cunningham 是敏捷宣言的合著者,也是第一个 wiki 软件的创建者。;那么,如何领导团队做好技术债管理?具体内容我们将在文章中详细描述。

技术债(Technical debt,或 tech debt)在过去几年中成为一个流行的术语。随着时间的推移,我们的代码库和系统往往会变得“有缺陷”,这使得以后更难对其进行更改或构建。

技术债是 Ward Cunningham 的一个比喻。Ward Cunningham 是敏捷宣言的合著者,也是第一个 wiki 软件的创建者。比喻,和模型一样,帮助塑造我们对特定主题的思考。因此,为什么我们称之为“技术债”而不是简单的“有缺陷”?原因是,在某些方面,它类似于金融债务——如果我们不偿还,它会对新功能及其维护造成损害,就像金融债务的利息积累一样。

技术债的一个来源是我们在设计和构建系统时有意识和无意识的权衡,缺乏干净的代码、文档和最佳实践。另一个来源是系统及其生态系统在演化,两年前的完美解决方案现在不再那么完美了。

我将聚焦于技术来说服利益相关者“采纳这个意见”,在产品开发中优先安排偿还技术债。

一、两种积压工作

让我们先看看不要做什么。许多团队最终有两种积压工作——一种是以产品为中心的,另一种是以技术为中心的。这无法再生效是由于多种原因:

1、几乎不可能在积压的项目间穿插其它优先的项目。

2、它助长了“我们 vs. 他们”的心态,这扼杀了团队凝聚力和共同目标。

3、确定优先级是整个团队的工作;把产品代表排除在外是行不通的。除非你对如何分 配团队力量有严格规定(例如,20% 持续用于技术债务),否则这会使工期规划变得更加困难。

保留一个积压工作并在那里添加任何类型的工作。如果你想要统计数据或过滤视图,请随意标记技术债,但请确保将整个积压工作一起安排优先级。

二、不要让技术债成为一场指责的游戏

另一个常见的错误是对技术债的争论充满了指责。我见过一些(工程和产品之类的)管理人员说这样的话,“好吧,如果你一开始就创造了一个更好的解决方案,我们就不会处于现在这种情况”——这是愚蠢的、不人道的,最终也是毫无意义的。

没有什么是完美的。我们都是人,时移世易,万物变迁。接受这一点吧。我们能做的最好的事情就是从我们的错误中吸取教训,应用良好的实践,并尽可能清楚我们做的决策的利弊权衡。

玩指责游戏会使我们的注意力从解决手头的问题上转移开。这使大多数人都有防御性,会将讨论变成不必要的来回扯皮,而不会更接近解决方案。

不带指责的回顾和剖析才是正确的方式。解决方案总是系统性的,而不是针对个人的。

三、如何讨论技术债

现在我们知道了该避免什么,让我们来看看一些讨论偿还技术债的重要性的方法。这通常围绕现有技术债务的风险,由其引起的(维护)辛苦,以及它如何 阻碍新功能 的开发。

根据我的经验,大多数工程师不需要被说服去处理技术债务。事实上,正是他们提出了这一要求。另一方面,工程和产品经理通常需要更多的上下文信息来理解偿还技术债的重要性。

这里,你最好的策略是理解如何用你的利益相关者能够理解的语言提供上下文信息。“好吧,为什么这很重要是无关紧要的”,这样的说法是行不通的。你的待办事项中还有 50 项对他们来说“非常重要”。

还有,不要把它说成是关于你自己的事情。你热衷于解决这个问题是很好的,但是如果它听起来像是你的宠物项目而没有任何进一步的争论,那么它可能不会得到优先考虑。我将向你展示几种构建观点的方法。

题外话:这些都是关于将你的技术债务与你的内部或外部客户以及产品的性能关联起来。

四、风险

一定比例的技术债务附带有相应的风险。一个简单的例子是,当你的解决方案使用的第三方(库 / 服务)即将终止。这里的风险是,如果你不升级或迁移到另一个受支持的解决方案,依赖第三方的系统可能会出现功能失调,或者(例如)将来会收不到安全补丁,从而有可能出现漏洞,这显然对你的用户或客户不利。

当然,并不是每种情况的风险都是同等的——我们是会在下周下线,还是有比较低可能会在两年内发生低影响安全问题,这很重要。查看下面的“延误成本”部分。

另一种风险也与用户保留有关,但是不那么直接。因为不太好的解决方案(想想频繁的宕机和缓慢的服务)造成的低劣体验造成了客户流失的风险。

技术债围绕风险的一些措辞示例:

1、我们可能在 2 个地方修复了一个 bug,但由于代码重复而错过了第 3 个。

2、当前系统的设计可能会导致在高并发场景下的用户体验比较慢。

3、缺乏安全措施可能导致违约和法律责任。

4、由于我们缺乏单元测试,可能会在功能中引入新的 bug。

5、代码库的复杂性和不灵活性导致我们由于开发时间太长而对新功能说不。

为了使你的论点更加有力诚恳,你要尽可能收集数据并使其成为论点的一部分。当然,这并不总是可能的。请记住,数据也可以是行业最佳实践,例如,长测试运行时间 vs. 可接受的测试运行时间。

五、维护的辛苦

在复杂或不灵活的代码库中,大多数任务将花费更长的时间,造成维护的辛苦;通过使用无效或缺失的工具,造成维护的辛苦。这一点,再加上大量的客户和技术问题,可能会使整个团队陷入停顿,因为即使是微小的修复也需要一整天的时间来完成和发布。

现在,你需要 4 个小时来了解系统中发生了什么,另外 2 个小时来使测试通过,因为其中一些测试是不稳定的,还有 1 个小时来部署你的修复程序,因为部署系统 5 次卡住了 3 次。

像上面的情况(应该!)作为一种风险尽量避免,但很多时候,只有当风险严重发生时(人们经常大声抱怨),你才会意识到这一点。

这里的数据主要是传闻的,但你可以很好地了解你会节省多少时间,如果事情都完好运行的话。与你的团队谈谈他们对增加工作量的看法,并提出一个粗略的估计来支持你的论点。

为了帮助你的利益相关者理解其重要性,请描绘一个持续向用户提供价值的更好的世界。

六、开发新功能的效率

这里降低的效率,加上上面提到的辛苦,本身就值得说一说。虽然维护的辛苦会占用团队的时间,导致交付新功能的能力下降,但还有一些其它因素。

1、在难以理解的代码库中工作会降低开发速度(并可能增加引入的新缺陷的数量和严重性)。

2、使用这样的代码库会使得团队投入更多时间和精力来引入新团队成员。

3、在一个设计拙劣或架构过时的系统中实现一个解决方案是困难的。可怕的长达一个 月的重构项目就是这样诞生的。

4、在一个不适合你正在实施的新解决方案的系统中修修补补(基本上围绕现有系统工作)通常会增加由此产生的系统的复杂性,并增加更多的技术债务——这是一个恶性循环!

七、优先级排序技术

7.1 延误成本

“延误成本”并不是一个完整的优先级排序技术,但在考虑风险时,它是一个方便的属性。

延误成本是精益管理中的一个指标。它结合了紧迫性和价值——人类并不擅长区分这两件事。

由于大部分时间我们倾向于只关注生产成本和其它固定成本,我们很难确定优先级,因为一些成本是不可预测的,潜在价值也可能是不可预测的,因为随着时间的推移,这些都不是固定的。更好的方法是计算延误成本。该值表示公司晚于市场或客户期望的时间交付特定功能 / 项目 / 产品所产生的随时间稀释的成本。

计算延误成本随着时间的变化,需要相当成熟的跟踪和监控。计算延误成本随时间变化的另一种方法是选择以下模型之一:

你对某个问题的延误成本模型的判断将告知你的影响评级。

7.2 ICE 和 RICE 得分

你最终会得到许多不同大小和影响的项目,然后变得非常混乱。ICE 有助于为这种混乱带来秩序,它可以通过一种系统性的方法来评估这些项目,并创建一个单一数字表示它们的优先级,你可以简单地借此对它们进行排序。

ICE 代表影响(Impact)、信心(Confidence)和努力程度(Ease/Effort)。RICE 中的 R 代表影响范围(Reach)。

对于其中每一个因素,团队在一组数值点上达成一致,例如:Massive = 3 High = 2, Medium = 1, Low = 0.5, Minimal = 0.25

影响 —— 解决此问题会对客户产生什么影响(记住,客户也可能是内部的!)——或者,在考虑风险时,解决此问题不会产生什么影响?

信心 —— 你对影响(以及可选的努力程度)的估计有多大信心?

努力程度 —— 努力程度通常更容易谈论——解决问题需要付出多少努力?请记住,这是一个相对指标,只能与当前批次中的其它问题进行比较。

响应范围 —— 这将影响多少人?100% 的客户群?还是只有某一特定角色的客户?重要的是,要了解这些分数仅在本地相对环境中有意义,不应跨域进行比较。

一旦你有了这些数字,计算就很容易了:

RICE 得分 = (Impact x Confidence) / Effort or Impact x Confidence x Ease

在这篇很棒的文章中 可以了解更多关于 RICE 和 ICE 的内容。

八、关于如何实际削减技术债务的一些建议

我可以快速重复这些策略来实际削减技术债务。这里没有完美的策略,每一种策略都有利弊权衡。

1、为技术债分配专用力量

有些团队将一定比例的工期时间用于各种类型的工作。一个常见的设置是 70% 用于功能开发,20% 用于技术债,10% 用于学习 / 实验。

这种设置的挑战是,通常比较大的技术债问题无法在 20% 的时间内解决——从一段工期转移到下一个工期,通常会失去上下文,因此重启它们更困难。另一个挑战是,考虑到估计的难度,保持准确地用时几乎是不可能的。你可以尝试限制固定时间,但这需要自律。

2、每段工期都要解决 N 个技术债问题

另一个极端是停止讨论投入的时间,而只是从每个工期的积压工作中拿出固定数量的技术债问题。这里有一个明显的问题,有些技术债问题可能很大,会占用工期的大部分时间。你如何确保时间被均衡分配?

3、将比较重要的技术债务当作项目

有时,技术债务的形式是比较长的项目,实际上需要相应的规划和执行。一个好的技术债项目的关键是真正把它们当作常规项目:明确目标、范围、设定目标(并对目标进行实际评估!)

4、将中等大小的技术债当作涉及该系统或代码库的下一个项目的一部分

所谓的“童子军规则”的一个版本:你应该让代码库和系统变得更好。

一种方法是经常在项目中规划一些额外的技术债偿还。

这里的问题是,技术债丧失了优先权——你偿还什么技术债是由你下一个项目所接触到的东西驱动的。

要做到这一点,你还需要与你的产品同事建立牢固的信任关系,因为这对他们来说似乎是一种职责越权。


最后,推荐我们的管理工具给大家