一、前言
在现代软件开发中,技术债务(Technical Debt)已成为一个不可忽视的重要概念。它指的是在软件开发过程中,为了追求短期目标而做出的妥协,导致未来需要付出额外成本来修复这些妥协所带来的问题。技术债务的管理不仅影响项目的质量和可维护性,还直接关系到团队的工作效率和公司的长期发展。
1、什么是技术债务?
技术债务的定义可以追溯到Ward Cunningham,他将其比喻为“借款”,即在软件开发中选择了一个较为简单的解决方案,而非最佳实践。这种选择虽然在短期内能加快开发进度,但却可能在未来导致更高的维护成本和更复杂的技术问题。
为了提升需求开发速度,我们有时会在应当采纳最佳方案时作出妥协,转而选择那些短期内能迅速推进项目进程的方案。然而,这种做法往往会导致未来的错误问题增多,并给自己带来额外的开发负担。这种技术层面的抉择,犹如背负了一笔债务。
2、技术债务的分类
同样,技术债务也有其层次之分,通常根据其影响程度和解决的紧迫性,我们可以将其划分为四个象限,即技术债务的四象限模型。
技术债务可以根据不同的标准进行分类:
有意和无意两种:
有意技术债务:团队明确意识到当前的解决方案并非最佳选择,且计划在未来进行改进。
无意技术债务:团队在缺乏足够信息或经验的情况下做出的选择,往往潜伏较久,难以察觉。
鲁莽型和谨慎型:
鲁莽技术债务:由于缺乏规划和规范而产生的债务,通常会导致严重的后果。
谨慎技术债务:在项目进度中做出的合理妥协,虽然存在风险,但在可控范围内。
3、技术债务全景图
根据卡内基-梅龙大学软件工程研究所(SEI)的Robert Nord在《The Future of Managing Technical Debt》中提出的“技术债务全景图”,技术债务可以从多个维度进行分析:
这张全景图清晰地展现了技术债务的多个层面,包括那些通常与架构相关联的债务、因环境变化而产生的技术差距型债务,以及主要由内部代码质量低下引起的小粒度技术债务。
此外,通过这张图,我们还可以洞察到两个重要的方向。
可演进性
本质上,架构的元特征描述的是软件架构在演进过程中趋于目标的能力。这种演进目标并不仅限于支撑功能快速迭代的灵活性,同样可以涵盖其他重要的架构属性,如高可用性和可扩展性。
可维护性
狭义上的代码问题主要涉及代码的易理解性、问题的易修复性,以及在现有基础上的易扩展性。这些因素共同影响着代码的质量和可维护性。
二、背景
当技术债务已经严重影响了公司的运作、工作的效率时,才会着手去处理这些方面的问题,可要付出的代价就太大了。
随着滴滴国际化业务的快速发展,技术栈的多样化使得技术债务的管理变得愈发复杂。当前,研发所需的语言已不仅局限于平台原生语言,跨平台技术(如Flutter及其Dart语言)逐渐成为主流。这一转变带来了新的技术债务挑战,尤其是在代码质量和架构设计方面。
1、演绎过程
在项目的初期阶段,我们面临着快速上线和快速迭代的压力,因此问题的积累是不可避免的。然而,随着我们的不断发展,我们意识到如果继续这种状态,将会对项目的质量和成本带来双重风险。同时,随着业务逐渐融入Flutter跨平台能力,我们在学习和研发Flutter的过程中,也遇到了诸多挑战。特别是随着Flutter SDK的不断升级,我们在这个过程中也积累了大量的技术债务,例如空安全适配问题。目前,我们的SDK版本支持2.12.0,这是一个允许空安全和非空安全混合的版本,因此存在很大的隐患。
2、影响分析
1)对开发的影响
也许某一天我们接收了一个陌生的模块,也许是自己曾经的代码,发现如同屎山一样,如下图,自己都看不懂了,为了应付快速迭代的需求,只能不停的往这上面堆,这个屎山也会愈发庞大和混乱,如果这样继续下去,知道某一天因为一个小小的Bug,你需要花半天的时间来排查问题出在哪里,最后当你觉得问题终于改好了的时候,却不料碰了不该碰的地方,结果就是 fixing 1 bug will create 10 new bugs,甚至程序的崩溃。
(图片由AI生成)
我们需要正确面对、积极面对这个事情,它不是没有技术含量,他能给我们带来更多的技术和业务上的挑战。
2)对效率的影响
技术债务的治理本质上是提升效率的过程。
治理不当将导致开发周期延长、资源浪费和团队士气下降。因此,及时识别和解决技术债务是确保项目成功的关键。
3、现状梳理
业务发展至今,通过整理存量问题和结合监控报警沉淀的问题,可以看出目前工程存在的问题方向。(非最全)
1)代码复杂
在快速迭代过程中,往往忽视了良好的代码组织与模块化设计,导致组件间出现高度耦合的现象。此外,类文件行数过长也是一个需要关注的问题。这些问题可能会影响代码的可读性和可维护性,进而降低开发效率。因此,我们需要重视代码结构的优化和模块化设计,以降低组件间的耦合度,并合理控制类文件行数,从而提高代码质量。
2)架构混乱
业务架构在从初期到后期的迭代过程中,经历了逐步分化和尝试等阶段,尚未形成统一的结构走势。
目前存在新旧架构混合使用的情况。
3)代码风格
在Flutter跨平台代码中,代码结构和规范风格的不统一是一个常见问题。这主要是由于不同IDE的使用,很容易引发代码风格上的冲突,进而带来潜在的风险。为了提高代码的可读性和可维护性,降低风险,我们需要确保在整个代码库中保持一致的代码结构和规范风格。
4)基建混乱
在业务组件基建和服务基建方面,由于缺乏统一的最佳实践范式,导致使用层的代码出现混乱。这一问题亟待解决,以确保代码的整洁性和可维护性。
5)工程效率
管理缺乏统一性,功能分散,导致功能可用性低下。
6)性能债务
解决由持续SDK升级触发的报警问题
优化内存管理
清理未使用的资源和已下架的代码
实施lint代码质量检查与治理
进行空安全适配(针对Flutter框架)
三、目标
1、产物目标
1)一套简易可视化运营平台
结合Lean平台,对Lean平台录入信息,通过脚本产出自定义报告。
增加巡检能力,周频次跟进问题状态。
2、稳定性目标
1)沉淀问题,整合债务
通过深入剖析问题和细致整合债务,将技术债务治理提升为确保系统稳定性的关键环节。
3、质量目标
1)提高代码质量
提高代码质量,确保代码符合Lint标准。
完成Flutter的空安全适配。
四、面对挑战
1、业务挑战
稳定性的设计需要针对老业务流程进行二次梳理,如何保证线上稳定性是关键。
在需求中不断植入Fix的问题,确保技术债务的及时解决。
2、技术挑战
优化思路和设计需要更全面的考虑。
如何通过架构设计更完美地落地修改和重构。
对技术的深入理解是实现更好方案的基础。
五、治理方案
1、债务整体架构
1)方向:通过对当前问题的归纳,合理划分技术债务的治理方向
业务架构:主要以业务代码实现为主,最佳范式等;
基建:对接底层基建能力,使用上不合理不舒服的点。
代码:实施代码规范、Lint治理和代码格式化。
效能:所有辅助程序运行的脚本能力。
2)治理运营:一套可持续运行的方案
任何人不管问题的大小,都可以畅快的提出问题(不是谁提出谁修改,你只管提),把痛点问题进行描述,通过Lean平台记录,并会有专门的人(提出人)标记方向(分类),负责的同学或者感兴趣的同学都可以进行认领,并做出合理的方案和同步进度。
3)沉淀:通过这些点沉淀能力,不断的下沉能力,解耦业务。
4)建设:
非开源:可以按照产物进行成果分享。
开源:是最好的状态,开源我们一些厉害的能力,无论是什么方向的结果。
2、债务治理机制
为了解决这些问题,我们决定采取一系列措施来优化我们的项目和技术栈,并最终沉淀出一套我们可执行可长期运营的方案。
1)识别
技术的持续改进离不开团队中每个人的努力,因此需要每个成员都积极参与。在日常交付中,团队成员应该持续识别和记录需要改进的问题并将其放入Lean平台中,以便在技术改进会议中与团队同步。
此外,团队还可以定期组织头脑风暴,以收集技术痛点和改进建议。
2)可视化平台
通过一个共享平台,我们可以高效地录入和展示信息,从而更清晰地一览所有问题的分布情况和各类问题的占比。这样的设计不仅提升了工作效率,还使得数据分析更加直观、便捷。
3)优先级
我们时常会遇到的问题是,需要改进的地方太多,尤其是对于遗留系统。怎么办?先排优先级。我们可以基于价值/成本矩阵来评估改进任务的价值和成本。
基于矩阵:
优先解决高价值+低成本的技术债。
尝试将高价值+高成本的技术债拆分为高价值+低成本的技术债,“尽早、频繁、小批”地进行PDCA(Plan/Do/Check/Adjust)的迭代解决。
在没有高价值+高/低成本的技术债时,再来考虑低价值+低成本的技术债。
最后如果只剩下低价值+高成本的技术债,还是先拆分,再解决,或可考虑直接移除。
4)执行
债务问题,是无法集中清理的,每个人每天都有自己的业务需求,所以我个人认为可以存在两个进度方式:
在版本跌在中,引入20%的工作量进行技术任务的改进。
在技术架构升级或者重构等方案中,评估债务任务的清理。
总结&公式
每周固定时间进行报告产出。
存在这个能力,就能更好的整体观测治理的大盘,有助于促进治理的节奏,不会石沉大海。
让债务问题成为一个话题榜,成为一个论坛贴。从枯燥变成一种可持续输出知识点的平台。
(热门标签贴)
我认为在技术债务管理中,这一步是很重要的,我们需要分享解决的思路和成果,它是具有价值的,分享的过程是信息同步也是团队认知的对齐。
(自定义报告生成平台)
总结
通过这套精心设计的治理机制,我们能够高效地对问题进行细致分类,并实现有条不紊的治理。结合先进的可视化平台Lean+报告产出平台,我们可以实时追踪问题的处理进度。这一机制不仅帮助我们成功解决了问题,还促进了宝贵知识的积累和共享,形成了丰富的知识库。
3、稳定性方向沉淀
公司层面一直在推进稳定性,通过事前、事中、事后三个阶段进行预防、监控、复盘总结,形成一个闭环流程。
在技术债务治理方面,我认为它扮演着事前过滤器的重要角色。通过运用技术债务治理的手段,我们可以有效地识别并处理许多潜在隐患,从而为系统的稳定性奠定坚实基础。
在整体稳定性的三个阶段中,事中和事后阶段能够持续揭露技术债务问题的多维面貌,并对其进行系统归纳与整理。这些宝贵的经验教训随后被转化为事前阶段的预防性过滤网,从而助力我们更加精准地预防和应对未来潜在的问题挑战。
总结
在事中、事后阶段,我们要能够及时发现并沉淀归纳债务问题,确保问题留痕、总结到位,并达成共识,以便更出色地完成事前规划的任务。
4、代码质量治理
1)lint治理
从此时此刻起:债务问题不再新增,趋势线逐步下降;
严格执行代码规范、CR机制、Dlinter统一规范,提交高质量代码。
工程配置规则、远程代码配置规则开启,自动reject。(Flutter 配置为主)
2)空安全适配(Flutter)
我们强烈建议你按顺序迁移代码,先迁移依赖关系中的处于最末端的依赖。例如,如果 C 依赖了 B,B 依赖了 A,那么应该按照 A -> B -> C 的顺序进行迁移。
3)迁移时序层
从底层服务类出发,逐层向上适配。
六、总结
技术债务是项目进程中难以避免的现象,然而,如何将其控制在可管理范围内,却是我们必须深思的问题。要想有效预防和化解技术债务,离不开优秀开发人员的贡献,而团队的协同合作更是至关重要。借助这套精心设计的治理机制,我们能够对各类问题进行科学分类和有序治理。同时,结合高效的可视化平台,我们可以实时追踪问题进展,不仅及时解决现有问题,还能在此过程中积累并提炼出大量宝贵的共享知识资源。
七、结论
技术债务在现代软件开发中屡见不鲜,然而,借助高效的治理策略与团队的协同合作,我们完全有能力将其潜在影响压缩至最小。不懈的学习与持续的改进乃是项目取得成功的基石,唯有如此,我们方能在日新月异的技术浪潮中稳立潮头,保持强劲的竞争力。
技术债务是一个普遍存在的问题,它不受平台或编程语言的限制。我们应该共同努力,不断学习和提升自己,以应对这一挑战,共同推动技术进步。
如果字段的最大可能长度超过255字节,那么长度值可能…
只能说作者太用心了,优秀
感谢详解
一般干个7-8年(即30岁左右),能做到年入40w-50w;有…
230721