用GC的策略,管理团队的技术债务

时间:2023-02-08 16:55:03

在数字化时代,每一个组织的经营都是建立在数字化的系统之上的,而数字化系统的构建,必然就会带来技术债务,这是每一个数字化团队都要面临的一个问题,如何有效的管控技术债务。

技术债务的产生,是技术团队不断迭代构建系统过程中,无法一次性预设所有的需求,而随之产生了系统设计上的扭曲失真。

在了解了技术债务产生的原因后,就可以将技术债务和团队的作为或不作为联系起来,使用一些有效的策略和方法,来最大限度的减少技术债务的积累,保持系统的持续健康。

有效控制技术债务最小化的方法,可以从现代性的软件设计模式中去借鉴思路:垃圾回收算法。

相信熟悉JAVA和Golang等现代开发语言的人,对内存垃圾回收的概念,是非常熟悉的。其实,一个项目的技术债务的产生和积累,也就如同一个程序的内存分配和管理是一样的。

对内存垃圾收集的描述为:

运行程序会创建垃圾(garbage),即已分配但未使用的内存。垃圾的产生是不可避免的,因此我们必须偶尔停下来收集垃圾。如果停顿是可预测的,而且很短,那就更好了。有各种各样的垃圾收集算法,它们具有不同的属性。

对团队技术债务的描述,也可以如此:

运行有时间限制的迭代会产生技术债务,即使用过时的设计编写代码。创造技术债务是不可避免的,所以我们必须偶尔停下来重构代码。如果这些停顿是可预测的、短的,那就更好了。存在各种具有不同属性的迭代软件开发过程。

一个团队的软件开发过程是一个由团队自己运行的算法,它产生并清理了一种我们称之为技术债务的垃圾。

那依次延伸,软件开发过程,就可以使用两种方法来控制技术债务:

  • 第一种方法是清理现有的技术债务。大多数团队已经通过重构来做到这一点。
  • 第二是避免技术债务的产生。这种情况不太常见,但更有趣。

清理法

团队可以在技术债务存在后,通过清理的方式来处理债务。

通常情况下,一个团队在不考虑现有设计的情况下“仓促”完成一个功能,确定技术债务,然后才进行重构以清除债务。有时清理工作会立即进行,但也可能要很晚才得以开展。

小问题可以在几分钟内重构,但大问题可能就需要几天、几周,甚至几个月的投入。当开发人员在编写功能时停下来解决技术债务时,这就像垃圾收集器停下来清理垃圾一样,把时间花在重构上意味着花在新特性上的时间更少,同时当问题越大时,重构所需的时间也就越长。

因为清理债务需要从新功能的构建中去挤占时间,团队会发现自己面临着减少重构的压力,特别是大型系统重构。导致的后果就是,他们只清理了小问题,却延迟了大问题的清理,比如系统的架构。推迟一个小的清理会把它变成一个大的清理,因为随着时间的推移,代码会围绕这个问题构建起来,它也必须被重构。

预防法

团队也可以通过减少技术债务的产生来控制技术债务,也就是说,尽可能的预防技术债务。

譬如,团队通过考虑设计方案,并选择产生最少技术债务的方案来做到这一点。当被要求添加一个新功能时,团队会考虑当前的设计能在多大程度上适应该功能。如果设计已经是合适的,他们就添加功能。但如果设计不合适,他们会先更新设计,然后再添加功能。

对许多开发人员来说,避免问题听起来要比解决问题更好。然而,遗憾的是,一些技术债务是不可避免的,迟早,新的功能需求会成为令人不快的惊喜。

同时,团队也会担心,技术债务规避是一个变相的瀑布式流程,或者更糟,是一个预先设计好的大项目。其实不然,因为瀑布式流程会让团队查看所有的需求,并交付一个系统来完成所有需求。技术债务避免意味着团队迭代地处理需求,在每次迭代中交付一个工作系统。

另外,团队也会担心,技术债务规避会导致分析瘫痪。大部分的时候,团队依然会在每一次的迭代中持续交付新功能。

可选4类清理策略

在基本的2个策略的基础上,我们可以进一步延伸,扩展出一个四象限的策略组合:放任自流,被动清理,主动预防,双管齐下。具体如下图所示:

用GC的策略,管理团队的技术债务

技术债务是一个不可完全驯服的怪物。,我们无法彻底的根除,只能选择合适的策略与之共存。

所以,所有最好的算法,任何团队,都要根据自身具体的情况,譬如团队的结构,系统的规模、业务领域的复杂度、团队能力和经验,以及进度的压力等,综合来选择适合的策略。

放任自流

在一些场景下,团队可以对技术债务采取放任自流的策略。

譬如,你为自己编写了一个快速处理数据的脚本,并且也不打算重用它,为什么要担心技术债呢?

同样,这个策略也可以适用于大一点项目,譬如,大型的电脑游戏,开发者知道他们将为下一款游戏开始新的系统,所以在游戏发行之前,只需忍受技术债务的困扰就可以了。

类似的一次性的系统,放任自流,也是一种可选的策略。

被动清理

被动清理,就是团队只使用技术债务的清理策略。

这是现在大多数团队所采取的策略。团队的重点始终在构建新功能之上,只是抽空来清理一些细小的技术债务。

因此,更大的清理工作就变的有挑战了,所以早期的错误会一直存在,导致的就是以后重构的代价会更大,这是一个潜在的隐患。

当然,识别问题比规避问题要容易的多,所以在开发人员的设计能力有限时,被动的清理依然是有意义的。

主动预防

这种只使用技术债务提前规避的主动策略,在今天大部分团队内是并不常见的。

其实,如果你能通过一些事先的思考,来避免技术债务的产生,这要比陷入明显的问题要有效得多。

另一方面,如果你对正在使用的技术没有充足的经验,你可能会因为错误的假设而浪费了时间。尽管努力避免技术债务,但它还是会发生,所以使用主动预防策略的团队,可能会切换到双管齐下的策略之上去。

双管齐下

当团队希望自身技术债务更低更可控的时候,大部分时候都是采取双管齐下的策略,将清理和预防都使用起来。

譬如,在每次迭代的开始,团队讨论新的功能需求将如何影响当前的设计,这样可以保持迭代设计的重点,并让每个人都对设计有理解和掌握度。

团队可能对系统未来的新功能有一定的前瞻的预期假设,即使他们现在没有在做这些需求,但是因为知道未来会发生什么,可能有助于他们更好的思考今天的设计和决策。

有的时候,一个新功能很难添加到现在的设计中,因为它可能与当前领域的假设是相矛盾,或者很难在当前架构中来构建的。

如果开发人员可以重做设计,并在当前迭代中添加功能,那就太好了,如果不能,他们还可以和产品负责人沟通。在做出决定之前,他们会权衡干系人诉求,进度压力和工程风险等。

最终的答案,可能是先推出该功能,然后再清理技术债务,或者完全推迟交付该功能,或者介于两者之间等。

有限和无限游戏

其实,决定那中策略适合当前团队的关键因素,是在于团队是在玩什么模式的游戏:有限游戏 or 无限游戏。

有限游戏有输也有赢,无限游戏可能会失败,但胜利只意味着你可以继续玩下去。技术债务有点像一场无限游戏:如果你能控制它,你就能继续玩下去。否则,你输了,并宣布技术债务破产。

有严格Deadline的团队是在玩有限的游戏。团队需要按时的完成任务,那就会积累了大量的技术债务。

初创企业也是一系列有限游戏。为了达到下一个里程碑,团队采取了孤注一掷的模式,因为失败意味着公司的终结。

团队缺乏经验,也会迫使你玩一个有限的游戏。如果开发人员不了解问题领域或实现技术,他们就会陷入有限的游戏中,直到他们能够构建一些可行的东西。

当然,从有限游戏,转换到无限游戏时,也会导致技术债务的破产。如果你接受破产,并重启新的游戏时,就需要重新评估你的策略的选择了。

不能试图一直使用一种针对有限游戏的策略,来希望玩转一个无限游戏。

无限游戏更适合双管齐下的平衡策略,既可以通过良好的设计实践避免技术债务,又可以通过重构清理不可避免的债务。

写在最后

避免技术债务破产的核心:就是最小化技术债务。

在迭代构建软件时,就无法避免到技术债务的产生,因为我们永远也无法预期所有的功能需求,系统是在生长演进之中,那我们的设计和代码,就会存在设计上局限性和扭曲。

管理技术债务就如同程序内存分配和管理一样,通过优化和改进团队的开发过程,来控制技术债务的产生和积累,将团队的技术债务最小化,以提升数字化团队的效能和交付价值。

最后的最后,技术债务不能完全消灭,只能合理管控。

以上为学习:https://ieeexplore.ieee.org/document/9520328/ 论文的一些笔记,具体内容可参见原文。