写出可复用代码的基本思想与实践

引言

“代码可复用性问题兼谈团队协作 ” 一文中,谈到难以写出可复用代码的一些不好的习惯和阻碍因素。本文讲讲写出可复用代码的基本技巧和实践。

代码可复用性,关键在于发现业务逻辑里的通用性部分。同时,能够发现业务逻辑里的通用部分,并能提取出来,有助于做出更好的设计,提升研发效率(一次编写,多次使用)。


基本思想

写出可复用代码的基本思想:抽离共性(抽象与标准化)、拆分逻辑(单一职责)、定义接口和API(封装)、函数编程(编程技艺)。

写出可复用代码的基本思想,分为战略和战术两层。

“战略”层面,则需要对逻辑共性和差异的思考和提炼。通常包括两层:

业务无关的技术性逻辑:“将通用性的技术逻辑与差异性的业务逻辑相分离”
业务核心能力抽象:可复用的业务基础设施和领域组件。

战术层面,就是逻辑拆分和接口定义。拆分粒度越细,可复用的可能性越高。通过拆分成一系列有层次的、细粒度的函数或方法,就能建立一个可复用的代码基础。

在逻辑良好拆分的基础上,为每一段逻辑定义易用的接口,做良好的封装,则成功一大半。

最后,还需要掌握一些有用的编程技巧。泛型和函数式编程是一对强大的组合,有助于写出精炼、可复用的代码。 可阅: “一次代码重构的思考及探索”


实践

工具类

工具类是不依赖外部服务的“输入-输出”型函数。工具类最适合于做成可复用的,也容易写单测。工具类和单测都可以通过ChatGPT自动生成。

比如:“构造与使用分离:命中内容高亮及合并的展示问题解决实现”

比如:“精练代码:一次Java函数式编程的重构之旅 ” 重构得到的一系列 Util。


业务辅助类

业务辅助类是不依赖于外部服务的业务辅助工具类。这种类一般很小,能够涵盖很多业务点。而正是业务点的串联,构成了主体业务逻辑。比如:


/**
 * 从 agentDetection 获取可疑脚本信息
 */
public static ScriptDTO getScript(AgentDetection agentDetection) {
    if (AgentDetectionHelper.isInadequateAgentDetection(agentDetection)) {
        return null;
    }
    List<ScriptDTO> scripts = agentDetection.getAgentDetectionDetail().getDetail().getScripts();
    if (CollectionUtils.isNotEmpty(scripts)) {
        return scripts.get(0);
    }
    return null;
}


业务组件类

业务小组件类,依赖外部服务,提供单一的功能。 这种一般粒度比较小。封装成小组件类很适合业务复用。这种业务小组件通常散落在各种 service 的 private 方法里,而导致难以复用。


@Component
public class HostInfoHelper {
 
    private static final Logger LOG = LogUtils.getLogger(HostInfoHelper.class);
 
    private final HostProviderClient hostProviderClient;
 
    @Autowired
    public HostInfoHelper(HostProviderClient hostProviderClient) {
        this.hostProviderClient = hostProviderClient;
    }
 
    public HostDto getHost(String agentId) {
        if (agentId == null) {
            LOG.error("agentId is empty");
            return null;
        }
        HostDto host = hostProviderClient.getHost(agentId);
        if (null == host) {
            LOG.warn("No host found by agentId: {}", agentId);
            return null;
        }
        return host;
    }

}


统一机制的封装

比如 ssdeep 检测。 webshell 和 可疑脚本的 ssdeep 检测的逻辑基本相同。都是一段算法 + 样本检测缓存库 + 样本检测内存缓存 。 可以封装成统一的。公司源代码,就不便公开了。

统一机制需要指明调用来源,方便在必要的时候做差异处理。统一机制封装有点类似微服务提供的外部接口。

制订标准数据格式

比如很多检测能力都要用到文件上传。进程执行可疑脚本检测需要先上传文件,webshell 检测也需要先上传文件,病毒检测也需要先上传文件。如果我要封装一个业务功能,那么首先要封装出这个业务功能所需信息的标准数据格式。然后根据这个数据格式来构建业务功能。


/**
 * 文件上传所需信息
 * 目前文件上传下载主要依赖文件的两个信息:
 * 1. md5
 * 2. fpath: 对于容器来说,fpath 是容器在宿主机里的路径
 *
 * Created by qinshu on 2022/1/11
 */
@Getter
@Setter
@Builder
public class IdsFileUploadInfo {
 
    /** 文件MD5 */
    private String md5;
 
    /** 文件 sha256 值,未来会用这个值 */
    private String sha256;
 
    /** 文件路径 */
    private String fpath;
 
    /** 业务来源,用于文件上传回调 */
    private String app;
 
    /** 操作系统平台,不同平台使用不同上传脚本 */
    private int osType;
 
    /** 上传优先级 */
    private int priority;
 
    /** 文件保存天数,可选 */
    private int keepDays;
 
    /** 主机ID, 可选 */
    private String agentId;
 
    /** 客户ID,可选 */
    private String comId;
 
    /** 业务对象ID,用于查询关联业务表, 可选 */
    private String bizId;
 
    /** 文件上传后是否需要回调,一般是需要回调,更改任务表状态 */
    private boolean callback = Boolean.TRUE;
}


共享库封装

更大层面复用的就是共享库封装。比如入侵检测流程,基本可以看成是一系列组件的执行。每一个组件都可以是可复用的。

可阅: “事件处理业务的简易组件编排框架”


小结

本文提炼了写出可复用代码的一些基本技巧及实践。 要写出可复用的代码,基本思想是逻辑拆分。泛型和函数式编程是一对强大的组合,有助于写出精炼、可复用的代码。具体的工程技术手段有:

  • 工具类
  • 业务辅助类
  • 业务小组件
  • 统一机制封装
  • 制订标准数据格式
  • 共享库。

posted @ 2022-04-09 20:16  琴水玉  阅读(330)  评论(0编辑  收藏  举报