正确看待代码冗余
通常来说,我们编写代码要注意代码的可复用性,但也不能教条主义。少数情况下,冗余代码反而可以让软件更健壮,可维护性更好。
本文给出我的一段实际经历,我在开发中故意代码冗余,反而收获了很好的效果。
事件背景与基本情况
当时我任职的企业,项目往往是这样的:玩一段时间就不玩了。这“一段时间”短则几个月,长则两三年。
我参与开发的产品记为 U。U 可以认为是一个能力平台,或者一个能力“中台”。它提供各式各样的能力(CV、NLP 之类的),使用者通过 gRPC 连接到 U,并使用 U 提供的能力拼凑出自己的应用。
我负责开发 U 的接入口 U-Gress。使用方有两个,分别记为 A 和 F。
二者“小同大异”。F 的业务比较简单,A 的比较复杂,而且 A 还需要一个理论性比较强的任务管理模块。
立项时得知,A 和 F 在将来半年会比较快地迭代。
独立演化,彻底冗余
基于对公司的了解,结合该产品的特点,我没有把 U-Gress 设计为一个通用的东西。原因有如下几个:
- 时间紧:通用设计需要更多的时间,那样留给编码的时间就可能不够了。
- 难以控制需求变化的影响面:一旦一个业务需要进行某种改动,很可能会影响其他业务。而且,一个业务不玩了,它对应的代码要不要去掉?去掉吧,影响面不好估计;不去掉吧,留在仓库中给维护平白增加负担。
而二者代码独立的好处就体现出来了。
- 不同业务的代码完全独立,放心修改,互不干扰。
- 若公司决定某个业务不玩了,对应代码直接删掉,无负担。
- 开发更快,交付成功率更高。
- 紧急修复更快更可靠,毕竟不用都测试一遍。
在这样的想法下,我将 U-Gress 实现为三个子程序:
- U-Gateway,记为 UG
- U-Gress-for-A,记为 UA
- U-Gress-for-F,记为 UF
其中,UG 是超轻量的分发网关,它唯一的职责是判断当前的请求(会话)是哪个业务的,并转发。UA 和 UF 是真正承担 U-Gress 职责的,分别面向 A 和 F。
后续发展
正式交付后,运行平稳。
此后的半年,两个业务分别加需求、变需求、修错误,U-Gress 都给出了良好的实现和支持。
正式交付 8 个月后,F 不玩了,UF 下线。果然不出所料。
正式交付 20 个月后,A 不玩了。
结语
代码是否要冗余,金标准是:总体获益是否超过不冗余。
如果是为了隔离性、可维护性提升,就是理性的行为;如果是到处胡乱复制粘贴,没有合理的抽象,就是技术债务。
正确看待代码冗余,实际就是在找一种平衡,让代码既够用又耐用,这是身经百战的工程师的一种修为。

浙公网安备 33010602011771号