准确识别技术债务才是改造遗留系统的破解之道
大厂的遗留系统一般会呈现什么样的特点呢?第一是存量代码规模特别大,其次是技术栈特别全,最后是架构的演进时间长,10 年至 20 年的祖传遗留系统非常常见。
祖传代码
遗留系统的架构通常如上图所示:它可以完整运行,整个系统功能也比较稳定。然而由于技术栈过时造成演进性不足,文档过时或丢失导致与真实的系统脱节,当初的设计者可能已经离开公司,或者升迁到管理层,轻易的改动带来的连锁反应很容易导致整个系统的不稳定。面对这样的遗留系统一般人都会比较谨慎,技术人员更愿意重写而不是做遗留系统的改造。
但从成本上来看改造比推倒重来短期成本要高(分析问题,制定策略),长期成本要低得多(变化及规格丢失导致客户投诉)。考虑到风险成本,我更愿意去做遗留系统的改造而非重构。重写过程中面临需求的双重交付压力,文档缺失规格很容易丢失,在测试阶段仅仅补齐规格就需要很长一段时间,技术人员很容易陷入到技术情结中,重写前承诺的收益往往很难兑现,更换架构和编程语言极易造成团队不稳定,架构师通常会选择他喜欢的语言,程序员通常会选择他擅长的语言,仅仅选择语言就是一门很难的功课,通常 App 开发的选择是 Java、Scala、Go,高性能系统开发选择是 Rust,C++,而胶水类脚本语言开发选择 TS/JS、Python、Lua。
如果你是一个信心满满的架构师,选择了更具挑战的遗留系统改造,动手前你应该知道这个遗留系统有哪些呆账坏账,这些欠账称为技术债务。你不仅要搞清楚都有哪些债务,还要搞清楚欠债的根因是什么。架构与代码代表工程师写的瞬间对架构、代码、业务、环境的认知,随着技术进步,环境变化技术债务就自然产生了,这部分债务属于良性债务,或者说无法避免的债务。另一种债务可能是快速迭代追求商业价值的妥协产物,如果没有重构的投资,或团队缺乏重构的基因,就需要要去改进流程和工具。以我的经验债务的消减需要雷锋,团队文化要求不能让雷锋吃亏。
不同规模遗留系统的特点
规模系统
管理的规模不同,面临的问题就不一样,面临的问题不一样,所采用的方法就不一样。如果你管理一个代码规模 20K 左右的微服务,相信你通过个人能力很快可以将其改造为最佳状态。如果你是一个技术负责人,管理 10 个微服务约 200K 代码,依靠个人能力很难将其改造为最佳状态。你需要想办法在团队中建立起某个机制,比如每日代码集体检视,它解决了日常的管理、能力提升、review 设计思路,每一个 commit等问题,避免了错误的设计落入版本的尴尬场面。那些在检视中投入度比较高,经常能够给别人提出建设性建议(检视意见)的人就是可以重点培养的下一任的 Tech Lead,相信我,集体检视是小团队最有效的管理方式。
如果你是一个技术专家,管理 100 个微服务大概 200 万行规模的代码。这时你仅靠个人能力和代码检视是不够的 。100 个微服务的团队人数一般是 100+,这样的团队规模需要的是一套优秀的实践体系,从软件的架构设计(建模,设计与实现一致),到需求分解(并行,Tasking),再到代码提交(代码持续集成,小步提交,每日检视),最后是测试方法(TDD,BDD,统一测试框架)。
不过我想重点谈一谈如果管理 500 个微服务,大概千万级代码规模。想要管理这样一个组织,让这些服务都按照你想要的方式去进行演进,就要结合上面提到的所有实践,包括个人的能力、团队的氛围、优秀实践,还要多加上一些方法论的应用。其难点在于不能生搬硬套,要为团队量身打造,通过影响力形成团队共识,制定落地策略,下一篇会举例讲解。
再往上管理 5000 个左右微服务,这样的团队通常可能会跨地域。我并没有真实地管理过这么大规模的项目,所以我没有发言权。
不同规模遗留系统的应对策略
小规模策略
高级工程师
我个人认为高级工程师管理一个微服务只要熟读设计模式,可以熟练地使用,就可以把一个微服务改造得非常好。
微服务的开发,可能连使用复杂设计模式的机会都没有,在云原生的领域里已经把单体应用的架构模块设计通过微服务及基础设施解耦掉了,甚至做到了 Serverless。面向云原生开发你只需要专注于把业务代码写出来就可以。
静态扫描工具可以扫出来烂代码,因为烂代码有规则,写好出好代码是没有固定模式的,现阶段识别好代码最靠得住的方案仍然是人工识别。业界比较好的工具如 Codota,它是一款免费 AI 自动补全编码工具,可以集成在 IDEA 中,输入字符后它会自动帮你联想补全最佳代码片段,还可以片段检索。另外就是读一下 Clean Code、Clean Arch、Effective Code、设计模式等书籍,可以帮助你提升自己的代码品位。
技术负责人
如果管理 10 个服务,怎么样确保让这 10 个服务履行你的架构设计意图呢?我做团队技术负责人的时候坚持每天做代码检视。代码检视是一个非常好的手段,谁的代码是 TDD 的,谁做了重构,谁有想法都是一目了然的。前提是检视会议不能只是领导在讲,开发在开小差的状态,在我看来代码检视是每天的黄金 30 分钟。
代码检视实际上有很多优秀实践,比如检视前要求每位同学检视代码前先自己过一遍,想想怎么讲,要有逻辑,要容易让别人听懂,这样才能缩减检视时间。有时候上午写的代码,到下午就忘了今天上午我为什么这样想这样写。
其次,我们对检视的时间有要求,如果你能坚持每天检视,每天检视时间一般不会超过半个小时。检视的第一步就是把 Commit、Comments 过一下,快速地让别人知道我今天干了什么事情。接着快速地浏览每一行代码,在浏览过程中如果遇到一些常见的问题和共性的问题,我们可以在检视中讲一下。
最后,在检视中我们可以尽早发现设计方面的问题,选用更合适的设计模式。代码已经写完以后才发现设计有问题就晚了,这时技术债务就已经形成了。所以代码检视的过程是学习的过程,也是相互促进的过程。我们在代码检视中经常可以发现一些检视的意见领袖,这些意见领袖在我们团队里面就是我们后备的 Tech Lead。
除了检视,我们在团队中还落地了一些优秀实践,比如 TDD。如何落地 TDD?我们要求在新的需求中最好可以用 TDD 的方式,这个是 nice-to-have,并不是 need-to-have,所以在检视中如果谁用了 TDD 的方式,我们会给予他鼓励。
这两年通过微服务火起来的 DDD 炙手可热,今年我们也搞了一些 DDD 的实践——Event-Storming 建模、基于 DDD 的微服务实战项目。DDD 是一个概念,一套理论,如何让大家在实践中把 DDD 落到项目中需要有一个 DDD Demo Project,有先锋团队愿意去尝试,我认为这是团队氛围好的体现。
百万级代码规模策略
技术专家
如果你是一个管理 100 个微服务的技术专家,想要管理这么大的团队,你要做到前面提到的所有实践,实践是累加的过程,理论上来讲你无法跳过小团队管理经验直接到首席架构师。有一些团队的 Tech Lead 并不认可 TDD,不认可 DDD,这是很正常。在我们团队中会尊重不同的 Tech Lead 的选择,永远拒绝一刀切。
除此之外,我认为管理这么多微服务比较重要的是 Metrics。比如去度量团队的架构债务,代码债务有多少,把债务通过公式转换成时间,这样就得到 A 团队的技术债务是 30 分钟,B 团队的技术债务是 3 天。大概有一个 Metrics 的 Dashboard,我们就可以看到它每天的债务是增长的还是燃尽的,如果数据的维度比较多,那么就需要通过一个成熟度评估,比如 Level3,或 3 star 团队。
另外一个是 Backlog,Backlog 并不是一个 list 来记需要干的事情,我们通常会给团队投资一个 Backlog 去做重构或写测试。如果你要求一个团队或者一个工程师写完代码以后必须要带测试,写完代码以后必须要重构,一般来说他不会去做,因为这对他来说没有收益。我认为重构、写测试也是编码,也属于产出,所以要给团队一个 Backlog,给团队一定的比例去做重构和开发者测试。开发者测试包括了 UT、FT、AT 等等,还包括一些性能测试、集成测试。
10 年前,我第一次体验敏捷,那时我还觉得敏捷是一种管理手段。后来我接触了一些极限编程的工程实践和一些优秀的人,和这些人一起工作 1 年后,最终使我认可敏捷。像我司这样的双模 IT 企业比较少,所谓双模就是 IT 加 CT,我的感受是 IT 领域更适合遵循计划,CT 领域更适合响应变化。
给大家讲一个故事,我有一个做硬件的朋友,他每个季度都要出一趟差把他们的设计送到车间去生产出来一批样机。他每次都非常担心,如果样机出现任何设计问题他的麻烦就大了。像这样的开发模式必须充分设计、充分验证,充分测试,才能上线。
转载请在文章开头和结尾显眼处标注:作者、出处和链接。不按规范转载侵权必究。
未经授权严禁转载,授权事宜请联系作者本人,侵权必究。
本文禁止转载,侵权必究。
授权事宜请至数英微信公众号(ID: digitaling) 后台授权,侵权必究。
评论
评论
推荐评论
暂无评论哦,快来评论一下吧!
全部评论(0条)