关于代码优化:遗留代码处理技巧与案例演示

45次阅读

共计 2293 个字符,预计需要花费 6 分钟才能阅读完成。

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 总结

遗留代码的解决能力一方面是对技术的要求,另一方面也是对业务把握的挑战。心愿咱们能够逾越荆棘、穿过迷雾,顺利达到胜利的此岸!


作者:冯鸿儒

正文完
 0