Day929.运用自动化工具诊断分析Sharing项目 -系统重构实战

本文介绍了如何运用ArchUnit和Dependencies自动化工具对Sharing项目进行代码分析和重构。首先,按照新的架构设计调整代码结构,然后定义依赖规则,将规则转化为这两个工具的分析规则。通过工具的扫描,发现了项目中的依赖问题和需要重构的部分,为后续的代码优化提供了清晰的路径。
摘要由CSDN通过智能技术生成

运用自动化工具诊断分析Sharing项目

Hi,我是阿昌,今天学习记录的是关于运用自动化工具诊断分析Sharing项目的内容。

之前文章的两个遗留系统常用的分析工具:ArchUnit Dependencies 依赖分析工具

了解了它们的基本使用方法,但是实际落地到项目中,经常会遇到一些问题,比如:

  1. 代码散落各处,约束规则不好写?
  2. 结合架构设计,怎么来设计约束规则?
  3. 约束规则怎么应用到自动化分析工具上?

下面用 ArchUnit 和 Dependencies 对 Sharing 项目进行一次整体分析。

这个分析由五部分组成。

  • 第一部分,将代码结构按新的架构设计进行调整
  • 第二部分,根据代码结构以及新架构设计定义出依赖规则
  • 第三部分,将依赖规则转化成 Dependencies 的 Rule 规则,然后进行扫描分析
  • 第四部分,将依赖规则转化成 ArchUnit 的用例,进行扫描分析
  • 最后,总结现有的代码结构按未来架构设计需要重构的问题清单,作为下一阶段代码重构的输入

一、以新架构设计来组织代码

首先,回顾一下 Sharing 项目目前代码的方式。

如下图所示,所有的代码是以技术维度来组织。

例如把所有页面都放在 ui 的包下,或者把所有的模型都放在 model 下

在这里插入图片描述

这个时候就会遇到代码散落在各处约束规则不好写的问题。

如果不先以未来架构设计的方式来组织代码,那么所有依赖规则的编写只能细分到类,不能按包的维度来编写。

这样首先会导致用例增多,其次规则也会比较分散,给后续维护带来不便。

所以为了更好地进行分析,首先会先按未来的架构设计组织代码。


来看看梳理的新组件划分架构。

在新的架构设计中,横向维度划分了 3 个分层,纵向维度划分了 3 个业务组件、2 个功能组件以及 3 个技术组件。

在这里插入图片描述
根据新的架构图,重新划分新的包结构,如下表所示。


注意,需要让代码的架构以及名称与架构图的设计对应上,这样便于理解和维护。

在这里插入图片描述

接下来,就可以按照新的代码结构进行调整了。

这个时候要注意借助 IDE 的安全重构方法来移动代码,避免手工移动。

比如,可以通过 Move Class 的方法(选中文件后按下 F6 快捷键或者点击 Refactor->Move Class 菜单)进行移动,这样编辑器会自动帮我们调整相关的引用,调整后 Sharing 新的目录结构是后面这样。

在这里插入图片描述

在实际项目落地中,这个步骤有三点注意事项。

  • 第一点,这个步骤最好可以拉通相关的开发、架构等干系人(我们可以通过版本管理系统来查看之前这个文件主要的维护人)一起进行梳理。因为有些文件我们能从类名判断它属于哪个组件,但是有些文件如果之前设计得不好,还需要跟相关的同学确认。

  • 第二点,移动文件会触发 CI 判定这些文件是新增文件,进而触发增量扫描,CI 会将以前遗留的很多问题也扫描出来。但注意,这些问题不是因为移动文件产生的,而是原本就存在于代码库中。需要和相关的干系人进行澄清说明,以免移动后的代码提交无法入库

  • 第三点,工程目录结构的调整会涉及到大量文件的位置变化,需要在团队中进行拉通,避免很多临时分支还在基于旧的代码目录结构进行开发,否则后期会产生大量的代码冲突,解决成本非常高


二、Sharing 架构代码规则设计

基于新的代码结构,就可以设计架构约束规则了。

首先,回顾一下 Sharing2.0 架构的两个重要约束原则。

  • 纵向规则上层组件可以依赖下层组件,下层组件不能反向依赖上层的组件。
  • 横向规则业务组件之间不能有直接的依赖,功能及技术组件之间尽量减少依赖。

基于这两个原则,结合代码结构设计出新的架构核心的 5 个约束规则,可以参考后面这张表格。

在这里插入图片描述

梳理出这些约束规则后,就可以将这些规则转换成工具的规则进行分析了。


三、Dependencies 依赖分析

首先,需要定义各个组件的 Scope,这一步相当于是定义各个组件的范围。

如下图所示,新增一个 Scope 后,可以选择在项目中对应的的目录,当然也可以直接在 Pattern 中写正则表达式来进行定义。

在这里插入图片描述

定义好 Scope 之后,我们将 5 个核心约束规则转化为 Dependencies 的依赖规则。

下图中的 Deny usages of feature in library 表示 feature 范围下的代码不能被 library 范围下的代码直接依赖。

在这里插入图片描述

当完成依赖规则定义后,Dependencies 扫描结果会自动化将所有的异常依赖标记为红色,如下图所示。

在这里插入图片描述

从分析结果可以看出,目前 Sharing 项目有四个组件存在依赖问题,需要解耦,分别为文件组件、消息组件、基座组件以及日志组件。

打开具体有异常的类,IDE 还会自动在代码加上警告的红色线。

在这里插入图片描述
这是 Dependencies 功能与 IDE 高度集成带来的好处,可以在日常开发中就注意到架构约束的问题,避免破坏架构规则。


四、ArchUnit 分析

接下来,ArchUnit 的分析思路也是定义包范围,并将 5 个约束转化为依赖规则。

首先,可以参考 Dependencies 的规则封装形式,将 ArchUnit 的语法也做进一步的封装,这样可以提高代码的复用性,降低后续用例的维护成本。

//某个包只能依赖另外一个包
private static ClassesShouldConjunction target_package_not_dependOn_other_package(String targetPackage, String... otherPackages) {
    return noClasses().that().resideInAPackage(targetPackage)
            .should().dependOnClassesThat().resideInAnyPackage(otherPackages);
}
//某个包只能依赖它自己,不能依赖其他包
private static ClassesShouldConjunction target_package_only_dependOn_itSelf(String targetPackage) {
    return classes().that().resideInAPackage(targetPackage)
            .should().dependOnClassesThat().resideInAPackage(targetPackage);
}

接着,定义不同的分层和组件。因为已经按未来的架构调整了工程目录,所以这一步可以很方便地定义出对应的分层和组件范围。

private static final String BASE = "com.jkb.junbin.sharing.";
private static final String FEATURE = BASE + "feature..";
private static final String FUNCTION = BASE + "function..";
private static final String LIBRARY = BASE + "library..";
private static final String FILE_BUNDLE = BASE + "feature.file..";
private static final String MESSAGE_BUNDLE = BASE + "feature.message..";
private static final String ACCOUNT_BUNDLE = BASE + "feature.account..";

最后将 5 个约束规则转化为 ArchUnit 的架构约束代码。

这个时候前面封装的约束规则方法就起作用了,每个用例只需要传递相关的组件定义就可以了。

//规则1:library包下的类只能依赖自己包下的类,不能依赖function包或者feature包下的类
@ArchTest
public static final ArchRule library_should_only_dependOn_itself =
        target_package_not_dependOn_other_package(LIBRARY,FUNCTION,FEATURE);

//规则2:function包下的类不能依赖feature包下的类
@ArchTest
public static final ArchRule function_should_not_dependOn_feature =
        target_package_not_dependOn_other_package(FUNCTION, FEATURE);

//规则3:account包下的类不能依赖file或者message包下的类
@ArchTest
public static final ArchRule account_bundle_should_not_dependOn_other_bundle =
        target_package_not_dependOn_other_package(ACCOUNT_BUNDLE, FILE_BUNDLE, MESSAGE_BUNDLE);

//规则4:file包下的类不能依赖account或者message包下的类       
@ArchTest
public static final ArchRule file_bundle_should_not_dependOn_other_feature =
        target_package_not_dependOn_other_package(FILE_BUNDLE, MESSAGE_BUNDLE, ACCOUNT_BUNDLE);

//规则5:message包下的类不能依赖account或者file包下的类
@ArchTest
public static final ArchRule message_bundle_should_not_dependOn_other_bundle =
        target_package_not_dependOn_other_package(MESSAGE_BUNDLE, FILE_BUNDLE, ACCOUNT_BUNDLE);

编写完成后,可以直接执行这 5 个用例。

用例执行的结果是后面这样。

在这里插入图片描述

从日志结果可以看出,目前 Sharing 项目有 4 个约束规则不通过,分别是文件组件存在横向依赖、消息组件存在横向依赖、功能组件存在反向依赖以及基础组件存在反向依赖。


五、总结

ArchUnit 和 Dependencies 依赖分析功能对 Sharing 项目进行了一次分析。

为了更加方便地编写架构规则,需要将代码架构先按未来的架构设计进行调整。

接着只需要定义组件的范围以及约束规则就可以了。

最后结合工具辅助,梳理出 Sharing 按未来架构设计需要处理的问题清单。

在这里插入图片描述

开头的 3 个问题你答案:

  • 第一个问题,代码散落各处,约束规则不好写?
    • 对此,需要先按未来的架构设计调整代码结构,方便约束规则的设计
  • 第二个问题,结合架构设计,怎么来设计约束规则?
    • 需要结合架构原则以及代码结构来进行设计
  • 最后一个问题,约束规则怎么应用到自动化分析工具上?
    • 需要将约束规则转换成各个工具上的编写规则

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿昌喜欢吃黄桃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值