如何代码降重

一、使用的相关工具

以下工具都有各自详细说明的文档。除非有必要,下文不再对其相关使用作详细说明。

仓库代码查重工具:https://github.com/kucherenko/jscpd
文本在线diff工具:https://tool.chinaz.com/tools/diff
node轻量级git工具:https://github.com/steveukx/git-js
包与文件引用检查:https://github.com/depcheck/depcheck

二、冗余代码的分类和压缩策略

在这里插入图片描述

2.1 无用代码

无用代码是完全没有被引用的代码。
通过自然发现和depCheck工具,我们可以发现仓库中的无用代码。
我们可以直接删除无用代码。

注意!depCheck工具检查出的无用文件,不一定是真的没有用到。一些看似无用的文件可能会在动态路由构建或者在webpack打包过程中使用,注意甄别。

2.2 重复代码

重复代码是与存量代码内容相同的代码。
通过自然发现和jscpd工具,我们可以发现仓库中的重复代码。
我们可以提升代码的文件层级,然后修改目标引用,以此来解决重复代码。

2.3 相似代码

相似代码是与存量代码内容相似度高的代码。
通过自然发现和jscpd工具,我们可以发现仓库中的相似代码。
代码相似度高不意味着场景通用,对于相似代码需要有选择性的合并:

场景措施
输入输出处理公共format方法
trycatch处理全局捕获/封装请求方法

三、长久治理机制

代码重复度的优化非一日之功。健康的代码重复度需要长久治理机制的形成。

3.1 git-hooks

我的目的是希望在每一次commit之前,都对变更代码进行查重(就像lint-staged一样),那么我们可以构造以下流程:
在这里插入图片描述
package.json配置如下:

{
  ...
  "husky": {
    "hooks": {
      "pre-commit": "node ./scripts/repeat-check",
      ...
    }
  },
  "jscpd": {
    "threshold": 5,
    "reporters": [
      "html",
      "console"
    ],
    "ignore": [
      ".git",
      ...
    ],
    "format": [
      "javascript",
      "typescript",
      "jsx",
      "tsx"
    ],
    "absolute": true
  }
}

新增scripts/repeat-check.js:

/** @description 对当前git暂存区或更改区的代码,进行查重。若查重比超过预设阈值,阻止提交 */

const simpleGit = require('simple-git')();
const jscpd = require('jscpd');
const cloneDeep = require('lodash/cloneDeep');
const config = require('../package.json');

const { detectClones } = jscpd;
const threshold = config.jscpd.threshold || 5;

/** 获取暂存区或更改文件的目录 */
const getChangedFilePaths = (gitStatus) => {
  const stagedFilePaths = gitStatus.staged;
  const changedFilePaths = gitStatus.files.map((file) => file.path);

  return stagedFilePaths.length ? stagedFilePaths : changedFilePaths;
};

/** 获取百分比 */
const formatNumberToPercent = (num = 0) => {
  return Number(num * 100).toFixed(2);
};

/** 在所有重复比对中,筛选出与更改文件相关的 */
const getChangedClones = (clones, changedFilePaths) => {
  const changedFileArr = cloneDeep(changedFilePaths);

  return clones.filter((clone) => {
    const { duplicationA, duplicationB } = clone;
    const { sourceId: absolutePathA } = duplicationA;
    const { sourceId: absolutePathB } = duplicationB;
    const matchPath = changedFileArr.find(
      (changedPath) =>
        absolutePathA.indexOf(changedPath) > -1 || absolutePathB.indexOf(changedPath) > -1
    );

    if (matchPath) {
      changedFileArr.splice(changedFileArr.indexOf(matchPath), 1);
    }

    return matchPath;
  });
};

/** 打印更改文件相关的重复比对 */
const printChangedClones = (changedClones) => {
  console.log(`A total of ${changedClones.length} clones were found.\n`);
  changedClones.forEach((changedClone) => {
    const { format, duplicationA, duplicationB } = changedClone;
    const { start: startA, end: endA, sourceId: sourceIdA } = duplicationA;
    const { start: startB, end: endB, sourceId: sourceIdB } = duplicationB;
    const { line: startLineA, column: startColumnA } = startA;
    const { line: endLineA, column: endColumnA } = endA;
    const { line: startLineB, column: startColumnB } = startB;
    const { line: endLineB, column: endColumnB } = endB;

    console.log(`Clone found (${format}):`);
    console.log(` - ${sourceIdA} [${startLineA}:${startColumnA} - ${endLineA}:${endColumnA}]`);
    console.log(`   ${sourceIdB} [${startLineB}:${startColumnB} - ${endLineB}:${endColumnB}]\n`);
  });
};

const main = async () => {
  const gitStatus = await simpleGit.status();
  const changedFilePaths = getChangedFilePaths(gitStatus);

  const clones = await detectClones({
    ...config.jscpd,
    absolute: true,
    silent: true,
  });

  const changedClones = getChangedClones(clones, changedFilePaths);
  const duplicatedPercent = formatNumberToPercent(changedClones.length / changedFilePaths.length);

  printChangedClones(changedClones);

  if (duplicatedPercent > threshold) {
    console.log(
      `Too many clones(${duplicatedPercent}%), far over over the threshold(${threshold}%).`
    );
    process.exit(1);
  }

  process.exit(0);
};

main();

注意!pre-commit如果已经配置了lint-staged,再加上查重校验,commit耗时可能会比较长(这也是没办法的事情,毕竟全量代码走两次抽象语法树校验耗时是少不了的)

### 如何减少代码冗余 #### 使用抽象化和模块化的概念 通过将通用逻辑提取到单独的函数或类中,可以有效减少代码中的复部分。这种方法的核心在于识别相似的功能并将其封装成可用的形式[^1]。 #### 应用设计模式 某些经典的设计模式(如单例模式、工厂模式等)可以帮助开发者构建更加灵活且无冗余的架构体系。这些模式提供了经过验证的方法来解决常见的软件开发挑战[^3]。 #### 利用现代IDE功能 许多集成开发环境(IDEs),比如 IntelliJ IDEA 或 PyCharm, 提供内置支持用于检测复制粘贴错误以及建议可能存在的优化方案。它们还具备自动构能力,使得调整现有项目变得更为简便快捷[^4]。 #### 借助静态分析工具 对于 Java 而言,像 SonarQube 这样的平台不仅可以帮助发现潜在的技术债务问题,还可以提供关于如何改进整体应用程序质量的具体指导方针;而对于 Python 用户来说,则有 Pylint 和 Flake8 等选项可供选择。这类工具有助于保持高水平的应用程序健康状况,并促进长期可持续发展[^2]。 ```python def calculate_area(length, width): """计算矩形面积""" return length * width # 避免如下写法: area_of_rectangle_1 = length1 * width1 area_of_rectangle_2 = length2 * width2 ... ``` 上述例子展示了当面对多个相同类型的运算需求时,定义一个独立函数的好处——既提高了代码清晰度又减少了不必要的复劳动。 #### 定期进行代码审查 定期安排时间让团队成员互相审阅彼此的工作成果是一种非常有效的手段,它不仅能及时捕捉到那些容易被忽视的小毛病,而且有助于传播良好习惯在整个组织内部形成共识。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值