遗留代码处理技巧与案例演示

遗留,代码,处理,技巧,案例,演示 · 浏览次数 : 574

小编点评

**遗留代码处理能力** **1. 遗留代码本质** * 技术债务:影响程序可读性、可修改性、可复用性、可维护性、可测试性等。 * 业务原因:繁多流程、复杂场景、缺少文档等。 **2. 遗留代码处理过程拆解划分为三个阶段** * 梳理:从代码中推断业务模型、交互和规则。 * 重构/重写:对软件要素进行重构或重写,提升代码可读性或结构合理性。 * 替换/验证:通过重构/重写,进行代码替换,验证代码逻辑是否正确。 **3. 案例演示** **3.1 案例 1:强耦合** * 需求:用户可以通过银行网页转账给另一个账号,支持跨币种转账。 * 重构关键设计点: * 将业务层与数据存储和业务逻辑分离。 * 使用访问者模式对老代码逻辑进行编排。 **3.2 案例 2:提高老代码的复用性** * 需求:现有的策略被很多代码使用,需要根据不同的业务方在每个策略执行前做不同的前置逻辑处理。 * 解法分析: * 使用访问者模式将数据结构和作用于结构上的操作解耦合。 * 采用访问者模式,将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。

正文

1 什么是遗留代码

本质是一种技术债务,产生原因一方面是业务原因:如业务本身场景繁多、流程复杂等;另一方面是技术原因:如代码不规范、设计不合理、祖传代码文档注释缺失等。它会影响我们的程序很多方面:如可读性、可修改性、可复用性、可维护性、可测试性等。

2 遗留代码处理过程拆解

划分为梳理->重构/重写->替换/验证三个阶段

2.1 梳理

遗留代码的处理是一种逆向工程,从已有的代码+数据模型+文档倒推出业务模型、交互和规则,在保真的前提下再重新构建代码+数据模型+文档。
我们这里可以参考下DDD领域驱动设计里战略设计部分常用的工具(事件风暴法)来进行这部分梳理工作。

事件风暴本质上是一种系统建模的方法,与它处于对等位置的,会有“UML建模”、“事件驱动建模”等。事件风暴跟敏捷开发里的一些理念(如用户故事)的产生背景类似,都是在理性思考无法应对变化频繁且文字难以描述的情况下,通过一些辅助性的提示卡片、视觉手段,辅以相关人员的集中、高频沟通来完成对于业务的准确把握和抽象建模。

事件风暴的过程:

  1. 通过梳理业务流程,创建相应的领域事件(Event)
  2. 补充引发每个领域事件的命令(Command)
  3. 通过实体/聚合把命令和事件关联起来
  4. 划分领域边界及事件流动线条
  5. 识别用户操作所需的关联视图及其角色

事件风暴的产物:

  1. 领域对象 即实体/聚合。这里的领域对象并非数据库模型, 而是与业务紧密联系的“对象”。因为事件风暴是一种面向对象的建模方式, 而不是面向数据库的建模方式。
  2. 领域事件 即对象在某些操作或特点时点下所产生的事件, 这些事件将决定之后多个聚合和限界上下文(BC)之间的通讯方式。
  3. 限界上下文 当所有的对象(实体/聚合)被梳理出来后,属于同一种“通用语言”的对象, 则会被归入同一个限界上下文边界内;不属于同一种“通用语言”的对象, 则会被边界给分割开,划入不同的子域或限界上下文。

梳理结果示例:

2.2 重构/重写

通过重构/重写对软件要素进行重新组织,使其不改变外部行为的情况下,提升代码的可读性或使其结构更合理。

针对不同层次的软件要素要做不同的处理和控制:

并且整个重构/重写过程有些需要遵照的原则:

  1. 单一职责:可以将依赖归拢,统一行为和控制。权责明确,场景明确。
  2. 单一原则:消除重复的数据声明、行为;因为单一所以保证了复用,统一标准 ,可装配性。
  3. 封装原则:不需要过度关心依赖类内部实现,最好一个.就能调用。
  4. 归属原则:上帝的归上帝,凯撒的归凯撒。谁提供的数据更多,归属于谁。
  5. 抽象层次:越高层的抽象越稳定,越细节的东西越容易变化。举例:接口应传递职责而非实现细节。
  6. 开闭原则:对修改关闭,对扩展开放。
  7. kiss原则: 好理解,好维护。
  8. 清晰原则:只读小部分代码就可以知道怎么改逻辑,做扩展。而不是要通读所有代码,才能理清。

其中有两点落地细节我们具体分析下:

  1. 业务逻辑的处理
    业务代码和技术代码解耦
    主流程代码和附加流程代码解耦
    长链路的拆解编排
  2. 关注点的分离
    双向依赖:上下文之间缺少一层未被澄清的上下文,或者两个上下文其实可被合为一个;
    循环依赖:任何一个上下文发生变更,依赖链条上的上下文均需要改变;
    过深的依赖:自身依赖的信息不能直接从依赖者获取到,需要通过依赖者从其依赖的上下文获取并传递,依赖链路过长,依赖链条上的任何一个上下文发生变更,其链条后的任何一个上下文均可能需要改变;

2.3 替换验证

大概分为以下几个要点:

  1. 领会意图,抽取用例,增加可复测性
  2. 增加可监测性
  3. 分成小块,逐步替换
  4. 试点、看到成效

可借助过程管理工具如PDCA法进行管理

3 案例演示

3.1 案例1:针对强耦合的实现做重构

原始需求:案例为一个转账服务,用户可以通过银行网页转账给另一个账号,支持跨币种转账。同时因为监管和对账需求,需要记录本次转账活动。

原始架构:是一个传统的三层分层结构:UI层、业务层、和基础设施层。上层对于下层有直接的依赖关系,导致耦合度过高。在业务层中对于下层的基础设施有强依赖,耦合度高。我们需要对这张图上的每个节点做抽象和整理,来降低对外部依赖的耦合度。

重构关键设计点:

重构后代码特征:

业务逻辑清晰,数据存储和业务逻辑完全分隔。
Entity、Domain Primitive、Domain Service都是独立的对象,没有任何外部依赖,但是却包含了所有核心业务逻辑,可以单独完整测试。
原有的转账服务不再包括任何计算逻辑,仅仅作为组件编排,所有逻辑均delegate到其他组件。

3.2 案例2:提高老代码的复用性

原始需求:现有几个策略实现类,被很多代码使用。现在需要根据不同的业务方在每个策略执行前做不同的前置逻辑处理。

解法分析:尽量避免把逻辑耦合到已有的实现类中。引入外部类进行控制反转。这里我们使用访问者模式。

访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。

具体实现:

重构后代码特征:

可以通过访问者对老代码逻辑进行编排,将修改外置,减少对老逻辑的影响
通过java8默认接口实现提供默认访问行为,避免大量策略子类的感知,只需要需要提供自己实现行为的子类对默认实现进行覆写

4 总结

遗留代码的处理能力一方面是对技术的要求,另一方面也是对业务掌握的挑战。希望我们可以跨越荆棘、穿过迷雾,顺利到达成功的彼岸!

作者:冯鸿儒

与遗留代码处理技巧与案例演示相似的内容:

遗留代码处理技巧与案例演示

1 什么是遗留代码 本质是一种技术债务,产生原因一方面是业务原因:如业务本身场景繁多、流程复杂等;另一方面是技术原因:如代码不规范、设计不合理、祖传代码文档注释缺失等。它会影响我们的程序很多方面:如可读性、可修改性、可复用性、可维护性、可测试性等。 2 遗留代码处理过程拆解 划分为梳理->重构/重写

Dive into TensorFlow系列(1)-静态图运行原理

接触过TensorFlow v1的朋友都知道,训练一个TF模型有三个步骤:定义输入和模型结构,创建tf.Session实例sess,执行sess.run()启动训练。不管是因为历史遗留代码或是团队保守的建模规范,其实很多算法团队仍在大量使用TF v1进行日常建模。我相信很多算法工程师执行sess.run()不下100遍,但背后的运行原理大家是否清楚呢?不管你的回答是yes or no,今天让我们一

husky的使用

前言 在做个人项目的时候遇到一个需求,要在编完代码之后代码提交之前生成一个预览文件,手动执行脚本难免会遗漏。然后就想到之前在工作中使用过的husky,正好拿过来用一用; husky是什么? husky是一个给git增加 hooks 工具 打开文档发现husky的版本已经更新到8.x了,这时候就照着新

Nginx的再学习

## 第一部分 Nginx的版本 Nginx官网提供了三个类型的版本 Mainline version:Mainline 是 Nginx 目前主力在做的版本,可以说是开发版 Stable version:最新稳定版,生产环境上建议使用的版本 Legacy versions:遗留的老版本的稳定版 ma

[转帖]tiup cluster scale-in

https://docs.pingcap.com/zh/tidb/stable/tiup-component-cluster-scale-in tiup cluster scale-in 命令用于集群缩容,缩容即下线服务,最终会将指定的节点从集群中移除,并删除遗留的相关文件。 下线特殊处理 由于 T

订单逆向履约系统的建模与 PaaS 化落地实践

本文重点介绍了京东零售电商业务在订单逆向履约上面的最佳技术实践,阅读本文,读者可以了解到整个快退平台新系统设计的底层逻辑,也可以参考本文并结合实际场景,将方案应用在遗留债务系统改造、业务和技术建模中。

Linux 内存管理 pt.3

哈喽大家好,我是咸鱼 在《Linux 内存管理 pt.2》中我们学习了多级页表和大页,我们知道了由于历史遗留的问题,Linux 的页通常为 4KB 这样就会导致一个页表里面会有特别多页,为了解决这个问题,Linux 提供了两种解决方案——多级页表和大页 那么今天继续我们的 Linux 内存管理学习,

记一次 .NET 某游戏网站 CPU爆高分析

一:背景 1. 讲故事 这段时间经常有朋友微信上问我这个真实案例分析连载怎么不往下续了,关注我的朋友应该知道,我近二个月在研究 SQLSERVER,也写了十多篇文章,为什么要研究这东西呢? 是因为在 dump 中发现有不少的问题是 SQLSERVER 端产生的,比如:遗留事务,索引缺失 ,这让我产生

遗忘的教训:关注细节,珍惜当下

周末聚餐是生活中的一种美好体验,大家可以围坐在餐桌旁,品尝各式佳肴,畅谈人生、工作、兴趣等话题。而这次聚餐中,商家还送了一些小玩具在餐桌上,增添了许多童真和快乐。 可是,我们在享受美食和欢声笑语的同时,也有些隐忧。果不其然,我把一个小玩具放在餐桌旁,本来想着吃完饭收拾好了再带回家送给娃的,但最后不知

Django容易被遗忘却无比重要的框架默认文件介绍及使用方法

**在Python Web开发领域,Django框架的地位犹如璀璨的明星,其全面、高效和安全的特性使其在全球范围内广受欢迎。本文将全面解析Django框架的默认文件,并深入探讨每个文件及其组成的意义和用途,透彻展示这个强大框架的文件结构和设计原理。** 首先,让我们看一下创建一个新的Django项目