26. 如何淘汰万年遗毒的code

前言

这篇文章适合给那些要处理Legacy System(旧系统)的朋友们看,如果你们团队有系统的code是一团乱,而且完全没人知道他为什麽可以动的话,你可以参考一下这篇演讲给的建议。

演讲总结

这篇文章讨论的主题是我们要怎麽处理Legacy System。

那什麽是Legacy System呢?其实就是一个正在线上跑的旧服务,而且这个旧服务非常难维护,改进与扩展。而会这样的原因,通常就是因为它overloaded了,承载了超过原本设计能负荷的事情。

一般来说Legacy System的产生原因是基於一系列的紧急事故(emergency),因为人力与时间不足,所以我们不断的在原本的系统上加上应急方法(workaround),导致欠下一技术债(technical debt)。而有些状况则是因为写原本系统的人离开了,也没好好交接好,想淘汰但又不太确定是谁在用。

无论成因为何,为了处理这种系统,我们可以想到三种方案:

方案一:继续在上面加东西

这通常发生在没时间或没资源的情况下,基本上是下下策,毕竟你不知道什麽时候这个系统会完全扛不住爆炸。

方案二:完全重写一个新的系统

很多时候这真的是蛮不错的选择,但想必他也有很多问题需要考虑:

  1. 没时间重写,或只来得及写一半怎麽办。
  2. Legacy System的复杂性总是被低估因为成功者谬误(success bias)。
  3. Bug需要重新被发现与修正,前人踩过的雷往往会需要重踩一次。
  4. 新的feature会被delay。
  5. 资料迁移(data migration)过程总是非常痛苦。
  6. 还是需要同时维护新旧系统。

方案三:渐近式重写(progressive rewrite)

Progressive rewrite又被称为扼杀者模式(Strangler pattern)。意思就是在既有系统上慢慢抽换掉内部元件,直到整个系统都被重新写过。

这个方式虽然很安全,但是不代表很直观。而它通常花的开发时间会比整个重写还要来的久,但是好处是,比起重写後要完美取代旧系统所需要花的时间可能少了些。因为很可能会少了後面修修补补的部份。

要怎麽做到progressive rewrite呢?

要回答这个问题,讲者想先讨论:什麽是code quality?

当我们讲到code quality,很多人会想到TDD、test coverage、design pattern这些东西,但这些其实并不是评断code质量的依据。

真正判断code quality的是,你有没有办法保持快速deliver feature或快速发现bug。如果你的code quality很高,意思就是对於新的feature你的开发时间并不会随着codebase增加而巨幅增加,理解难易度、debug难度亦然。

因此保持好的code quality的重要关键是模组化(modularization),如果系统可以分割清楚每个元件的任务,便可以轻易抽换内部元件,或轻易增加新功能上去。

有了这个概念後,我们就可以来看应该要怎麽回春(rejuvenation)

  1. 先讲低onboarding这个legacy system的复杂度,让新使用者可以快速的上手与设置好工作环境。
  2. 写好end to end test,确认外部系统与他沟通时的结果是可预期的。
  3. 将code想办法切成小module。
  4. refactor系统让他可以好拆开,与变成可抽换式的系统。
  5. 重写一个一个module慢慢取代旧有系统
  6. 不要丢弃你的旧code,未来可供参考。

Source code rejuvenation is not refactoring

而要注意的是rejuvenation与重构(refactoring)是不同的。

Refactor是修正内部的实作方式,是一种technical的improvement,所以业务逻辑是不会被改到的。但是Rejuvenation是整套的翻修,是会牵扯到要重新设计product本身,所以通常rejuvenation是需要产品经理(PM)们的参与的。

个人心得

这篇演讲对我来说没有太多insight,不过自己倒是在处理legacy system是真的蛮有经验的,毕竟我跟着公司从无法scale的monolithic,一路走到现在拆开来的microservice;加上组织内部一天到晚在reorg,各种handover takeover常常中间都会有资讯消失。所以处理legacy system基本上是每天在做的XD。

什麽时候要重写整个系统?

虽然上面讲的是渐近式重写旧系统,但还是有少部分状况还是重写整个系统比较好的。就是当我们产品要整个重新设计的时候,因为我们不是只是把旧有的code变整齐而已,更多是要重新思考与汰换旧的产品。大忌是,不要搬移与重写没有在用的东西,如果不确定的话就想办法去查出来,看是看request的source还是做公司级别的impact analysis。

至於怎麽做refactor,来自Slack的Maude Lemaire之前有给个talk:How to get away with refactoring。里面讲的主要是Slack之前refactor系统去增加performance的一些细节,对於没有refactor或rejuvenation的人可以看看。

关於淘汰旧系统

不过虽然上面讲了很多,但我觉得淘汰旧系统其实最难的不是重写的部份,而是处理依赖(dependency)的部份。deprecation最痛苦的就是你不知道有没有人在用,而就算知道有人在用,也不见得知道是谁在用你的api。

我们公司一般会使用一个叫Impact Analysis的流程去让整个组织的stakeholder去确认改动与每个team有无关系,但做完後才是痛苦的开始,因为你要去要求他人迁移去用新的系统,或者重新讨论使用的需求,但极有可能大家没时间处理这件事。所以到最後整个搬迁的时间整个就有可能被拉的很长。我们都会开玩笑的说,这种情况就应该要做chaos engineering,直接把旧的API下掉,等大家出了error之後就自然会有动力去迁移了(误)。

不过这里想讲的重点是,因为会有很多依赖关系的问题,所以及早的开始做这些分析与调查,及早的kick-off讨论deprecation的计画,必且同时平行的做掉那些没有相依问题的地方,才有办法早日脱离苦海。


<<:  [Day_28]函式与递回_(7)

>>:  D-03-产生模拟资料 ? NSubstitute

使用bot.py建立起你的第一个机器人

行前作业 注册帐号 需要有自己的服务器或是相应的权限 开始後续作业 搜寻discord develo...

抓取资料库数据 - SQL基础语法(下)

我们学会了单张表的查询与筛选,当资料需要跨表拉取时该怎麽办呢?这时候我们就需要用到JOIN来把表与表...

菜鸟网页基础DAY30(最後一天~~~)

终於撑到了铁人赛的最後一天,这是我第一次参加铁人赛,会参赛的原因是因为在暑假的时候参与了社群活动,然...

[Day2] CSS + JS Clock

[Day2] CSS + JS Clock 运用 CSS 和 Javascript 做一个虚拟时钟 ...

Day9-"格式化符号"

昨天在练习scanf时,题目规定说输入为字串,一开始都是以%d,做为字串的格式,但在printf时发...