恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

脚本目录重复代码治理:从18个文件到6个模块的重构实践

  • 首页
  • 资讯中心
  • /
  • 脚本目录重复代码治理:从18个文件到6个模块的重构实践

相关资讯

开放式代码评审框架:从流程搭建到文化落地的完整实践指南 2026/10/12 11:04:29
Open Code Review:一种提升协作效率的透明化评审实践 2026/10/12 11:04:29
计算机网络协议题库解析:TCP拥塞控制与链路层重传机制深度对比 2026/10/12 10:59:29

最新资讯

eNSP 1.3.00在Win11/10安装兼容性配置与避坑实战指南
RNN工程落地:轻量级时序建模与嵌入式部署实战
农作物病虫害识别系统实战:Python机器学习从源码拆解到模型部署
阿里云ECS部署SSM项目:Xshell+XFTP稳定交付实践
DeepLabv3+航拍图像语义分割实战:ASPP与解码器详解
TSN时间敏感网络全解析:时间同步、数据调度与工程落地

今日推荐

Debian新手入门:从部署到日常操作的完整指南
MongoDB复制集扩缩容实战:从rs.add到选主事故复盘
条形码目标检测数据集实战:从YOLOv8训练到部署

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

脚本目录重复代码治理:从18个文件到6个模块的重构实践

发布时间:2026/10/12 11:04:29
脚本目录重复代码治理:从18个文件到6个模块的重构实践 1. 脚本目录里的“重复建设”是怎么发生的1.1 从18个文件、1803行说起某天我打开自己的脚本目录想找一个批量重命名文件的工具。结果翻了一遍发现里面躺着18个文件加起来1803行代码。更让我难受的是其中4个脚本在做几乎一模一样的事情——都是读取某个目录下的文件列表按规则处理后输出结果。区别只在于一个处理图片、一个处理文档、一个处理表格、一个处理日志。这不是个例。我后来跟几位做自动化运维和数据处理的朋友聊发现大家都有类似的经历。脚本目录就像一个杂物间每次遇到新需求就随手写一个写完往目录里一扔下次遇到类似需求时早就忘了之前写过于是又写一个新的。时间一长重复代码越积越多维护成本直线上升。这篇文章想聊的就是当你发现自己的脚本目录里出现大量重复逻辑时该怎么系统性地做一次“代码去重”和“结构重组”。我会从问题诊断、方案设计、实操步骤、避坑经验四个层面展开适合所有写过十几个以上脚本、开始感到维护吃力的开发者阅读。不管你是用 Python、Shell 还是 Node.js 写脚本思路都是相通的。1.2 重复脚本的四种典型形态在动手整理之前先要搞清楚“重复”到底以什么形式存在。根据我的观察和实际整理经验脚本重复大致分为四类第一类复制粘贴型重复。两个脚本之间有80%以上的代码完全相同只是变量名或输入路径不一样。这种最容易识别也最容易合并。第二类逻辑同构型重复。代码结构相似但实现细节不同。比如一个用os.listdir遍历目录另一个用pathlib.Path.glob但后续的处理流程几乎一致。这种需要抽象出公共接口。第三类功能碎片型重复。同一个功能被拆散在多个脚本里每个脚本只做一小部分。比如日志解析功能A脚本负责读取、B脚本负责过滤、C脚本负责统计但实际上完全可以合并成一个带参数的脚本。第四类隐性重复。表面上看两个脚本做的事不同但底层调用的工具函数、配置读取逻辑、错误处理方式完全一样。这种最隐蔽也最值得优先处理。我自己的18个文件里第一类和第二类各占一半左右。那4个“干同一件事”的脚本本质上都是“遍历目录→按规则筛选→执行操作→输出报告”这个流程的不同实例。1.3 为什么我们总是重复造轮子说到底重复脚本的产生有几个深层原因。一是写脚本时追求“快”复制一个现有脚本改改变量就能跑比从头设计一个通用方案快得多。二是缺乏脚本索引写完就忘下次遇到类似需求时根本想不起来之前写过。三是害怕改动觉得现有脚本能跑就行重构万一引入bug反而麻烦。四是没有抽象意识习惯用面向过程的方式写脚本没有把公共逻辑抽成函数或模块的习惯。理解这些原因很重要因为去重不是单纯的技术问题而是工作习惯的问题。如果不在流程上做改变整理完这一轮过几个月又会积累出一堆新重复。2. 去重前的诊断与分类方法2.1 用“功能矩阵”快速定位重复动手改代码之前先做一次全面盘点。我的做法是建一张功能矩阵表行是脚本文件名列是功能模块如“读取配置”“遍历目录”“数据转换”“输出报告”“错误处理”等在交叉格子里标记该脚本是否包含该功能。脚本名称读取配置遍历目录数据转换输出报告错误处理rename_v1.py是是是否否rename_v2.py是是是是否batch_img.py是是是否是log_parse.py否是是是是report_gen.py是否是是否这张表一画出来重复区域一目了然。“遍历目录”和“数据转换”两列几乎全是“是”说明这两个功能最适合抽成公共模块。而“读取配置”虽然出现频率高但每个脚本的配置项不同需要设计成可扩展的配置加载器。提示功能矩阵不需要很精确凭印象填就行。目的是快速找到“高频功能”而不是做严格的代码审计。2.2 判断哪些该合并、哪些该保留不是所有重复都值得合并。我的判断标准有三条调用频率如果某个功能在5个以上脚本中出现合并收益最高。变更频率如果某个逻辑经常需要修改比如输出格式调整合并后只需改一处收益明显。耦合程度如果两个脚本虽然逻辑相似但依赖的外部工具完全不同强行合并反而增加复杂度不如保留独立。那4个“干同一件事”的脚本我最终决定合并其中3个保留1个。保留的那个是因为它依赖一个特殊的第三方库合并进来会让公共模块变得臃肿。这个取舍后面会详细说。2.3 整理前的备份与版本标记这一步很多人会跳过但我强烈建议做。在动手重构之前先把整个脚本目录复制一份命名为scripts_backup_日期。然后在原目录里初始化一个 Git 仓库如果还没有的话把所有文件提交一次打上 tag 比如pre-refactor。cd ~/scripts git init git add . git commit -m 重构前完整备份 git tag pre-refactor这样做的好处是万一重构过程中发现某个脚本有隐藏的依赖关系可以随时回退对比。我就在重构到一半时发现一个脚本被定时任务调用参数格式和预期不一样靠对比备份才快速定位到问题。3. 公共模块的抽取与设计3.1 先抽“工具函数层”去重的第一步是把最底层、最通用的操作抽成独立模块。以我的脚本目录为例出现频率最高的操作包括读取 YAML/JSON 配置文件遍历指定目录并按扩展名过滤文件统一的日志输出格式文件读写时的异常捕获我把这些抽成了一个common_utils.py大概120行。关键设计原则是每个函数只做一件事参数尽量少返回值明确。# common_utils.py import os import json import logging from pathlib import Path def load_config(config_path): 加载JSON配置文件返回字典 with open(config_path, r, encodingutf-8) as f: return json.load(f) def list_files(directory, extensionsNone): 遍历目录可按扩展名过滤 path Path(directory) if extensions: files [] for ext in extensions: files.extend(path.glob(f*.{ext})) return sorted(files) return sorted(path.iterdir()) def setup_logger(name, levellogging.INFO): 创建统一格式的日志器 logger logging.getLogger(name) if not logger.handlers: handler logging.StreamHandler() formatter logging.Formatter( %(asctime)s [%(levelname)s] %(name)s: %(message)s ) handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(level) return logger这三个函数看起来简单但抽出来之后每个业务脚本平均减少了15到20行代码。更重要的是日志格式统一了排查问题时不用再适应不同脚本的输出风格。3.2 再抽“流程模板层”工具函数解决的是“零件”问题但脚本的“装配流程”往往也是重复的。比如那4个脚本都是“读配置→遍历文件→逐个处理→汇总输出”这个流程。这时候可以用模板方法模式把流程骨架固定下来把变化的部分留给子类或回调函数实现。# pipeline.py class FileProcessor: def __init__(self, config): self.config config self.results [] def run(self): files list_files(self.config[input_dir], self.config.get(extensions)) for f in files: try: result self.process_file(f) self.results.append(result) except Exception as e: self.logger.error(f处理 {f} 失败: {e}) self.output_report() def process_file(self, filepath): raise NotImplementedError def output_report(self): raise NotImplementedError这样图片处理脚本只需要继承FileProcessor并实现process_file和output_report两个方法代码量从原来的80多行降到20行左右。而且错误处理、日志记录这些横切关注点自动统一了。3.3 配置驱动的参数设计合并脚本时最大的挑战是不同脚本的参数不一样。比如重命名脚本需要“命名规则”参数图片处理脚本需要“目标尺寸”参数。我的解决方案是用配置文件驱动每个脚本对应一个JSON配置公共模块只读取配置中的键值对。{ input_dir: /data/photos, extensions: [jpg, png], operation: resize, params: { width: 800, height: 600, keep_ratio: true }, output_dir: /data/processed }这样做的好处是新增一种处理类型时不需要改公共模块的代码只需要写一个新的处理函数并注册到映射表里。配置和代码分离也方便非开发者调整参数。注意配置文件不要放在脚本目录里建议单独建一个configs/目录。我一开始混在一起放结果重构时差点把配置文件当脚本删掉。4. 实操从18个文件到6个模块的完整过程4.1 第一步冻结现有脚本建立调用清单在改任何代码之前我先做了一件事找出所有脚本的调用来源。有些脚本是被 crontab 定时调用的有些是被其他脚本 import 的还有些是手动执行的。我用grep在整个 home 目录下搜索脚本文件名整理出一张调用关系表。grep -rn rename_v1\|batch_img\|log_parse ~/ --include*.sh --include*.py --includecrontab* 2/dev/null结果发现有两个脚本被定时任务引用还有一个被另一个更大的分析脚本 import。这意味着我不能直接删除或重命名它们必须先建立兼容层。我的做法是保留原文件名但内容改成一行调用新模块的代码。比如rename_v1.py变成from modules.renamer import main if __name__ __main__: main()这样外部调用完全不受影响内部实现已经切换到新模块。4.2 第二步逐个合并每合并一个就测试重构最忌讳“一口气全改完再测试”。我的节奏是合并一个功能立刻跑测试确认无误后再合并下一个。具体流程是从功能矩阵中选一个高频功能比如“遍历目录”在common_utils.py中实现该功能修改一个脚本让它调用新函数运行该脚本对比输出结果和修改前是否一致确认无误后再修改下一个脚本这个过程比较枯燥但能最大程度降低风险。我合并“遍历目录”功能时就发现原来的脚本里有一个隐藏行为某些脚本会跳过隐藏文件某些不会。如果直接统一成“跳过隐藏文件”会导致部分脚本行为改变。最后我在函数里加了一个skip_hiddenTrue参数默认跳过需要包含隐藏文件的脚本显式传False。4.3 第三步用测试脚本验证行为一致性为了确保合并后的行为和老脚本完全一致我写了一个简单的对比测试脚本。思路是用同一组输入数据分别跑老脚本和新模块对比输出文件的MD5或内容差异。import subprocess import hashlib def file_md5(path): with open(path, rb) as f: return hashlib.md5(f.read()).hexdigest() # 跑老脚本 subprocess.run([python, old_script.py, --input, test_data]) old_result file_md5(output/result.txt) # 跑新模块 subprocess.run([python, -m, modules.new_processor, --config, test_config.json]) new_result file_md5(output/result.txt) assert old_result new_result, 输出不一致这个测试帮我抓到了两个问题一个是新模块的排序逻辑和老脚本不同老脚本按修改时间排序新模块默认按文件名排序另一个是浮点数精度处理有细微差异。如果没有这个对比测试这些问题可能要等到实际使用时才会暴露。4.4 第四步清理与归档所有脚本合并完成后我把不再需要的文件移到一个archive/目录而不是直接删除。保留三个月后再清理。同时更新了 README说明每个模块的用途和调用方式。最终的目录结构从原来的18个散落文件变成了scripts/ ├── common_utils.py # 通用工具函数 ├── pipeline.py # 流程模板 ├── modules/ │ ├── renamer.py # 重命名模块 │ ├── img_processor.py # 图片处理模块 │ ├── log_analyzer.py # 日志分析模块 │ └── report_gen.py # 报告生成模块 ├── configs/ # 配置文件 ├── archive/ # 归档的旧脚本 └── README.md代码总量从1803行降到了约900行但功能覆盖完全一样而且新增处理类型时只需要写一个几十行的模块文件。5. 常见问题与避坑经验5.1 合并后参数不兼容怎么办这是最常见的问题。老脚本A用--dir指定目录老脚本B用--path合并后只能保留一个。我的处理方式是新模块统一用一套参数命名然后在兼容层做参数映射。# 兼容层示例 import argparse parser argparse.ArgumentParser() parser.add_argument(--input, -i, destinput_dir) parser.add_argument(--dir, destinput_dir) # 兼容老参数 args parser.parse_args()这样老调用方式仍然可用新代码则统一用--input。等所有调用方都迁移完成后再移除兼容参数。5.2 循环依赖怎么破抽取公共模块时容易遇到循环依赖common_utils引用了pipeline而pipeline又引用了common_utils。我的经验是严格分层工具层不依赖任何业务层流程层只依赖工具层业务模块依赖流程层和工具层。如果发现反向依赖说明抽象层级设计有问题需要重新划分。5.3 性能反而下降的意外情况合并后有一次发现处理速度变慢了。排查后发现新模块在每次处理文件时都重新读取了配置文件而老脚本只在启动时读一次。解决办法是在FileProcessor.__init__中加载配置并缓存而不是在process_file中反复读取。实操心得重构后一定要做一次性能对比。功能一致不代表体验一致尤其是涉及大量文件处理的脚本。5.4 问题速查表问题现象可能原因排查方法输出结果和老脚本不一致排序逻辑、默认参数不同用相同输入对比MD5定时任务报错参数格式不兼容检查crontab中的调用命令处理速度变慢重复读取配置或重复初始化加计时日志定位瓶颈某些文件被跳过隐藏文件过滤规则不同检查 skip_hidden 参数日志格式混乱多个logger实例冲突统一用 setup_logger 创建5.5 我踩过的最大的坑过度抽象一开始我雄心勃勃想把所有脚本合并成一个“万能脚本”用一个大配置文件控制所有行为。结果写到一半发现配置文件变得极其复杂一个操作要嵌套三四层参数才能描述清楚。后来我退回到“公共模块独立入口”的方案每个业务场景仍然有自己的入口脚本只是内部调用公共模块。这样既减少了重复又保持了每个脚本的独立性。这个教训让我明白去重的目标是减少维护成本不是追求代码行数最少。如果合并后配置复杂度超过了一定阈值就应该停下来重新评估。6. 后续维护与扩展建议6.1 建立脚本登记习惯整理完之后我在 README 里加了一个简单的登记表每新增一个脚本必须填写用途、输入、输出、依赖模块。这样下次想写新脚本时先翻一下登记表看看有没有现成的模块可以复用。脚本名用途依赖模块最后更新renamer.py批量重命名common_utils2024-01img_processor.py图片缩放common_utils, pipeline2024-026.2 定期做“脚本体检”我给自己定了一个规矩每季度花半小时翻一遍脚本目录看看有没有新增的重复逻辑。如果发现两个脚本有超过30%的相似代码就考虑抽取公共部分。这个习惯坚持了半年脚本目录再也没有回到混乱状态。6.3 什么情况下应该停止合并最后说一个反向经验不是所有重复都值得消除。如果两个脚本虽然逻辑相似但一个每周跑一次、另一个每月跑一次而且未来可能朝不同方向演化那强行合并反而会增加耦合。我的判断标准是如果合并后的模块需要频繁加参数来区分场景那就说明它们本来就不该合并。我在实际整理中发现18个文件里真正值得合并的是那4个核心重复脚本其他14个各有各的用途保持独立反而更清晰。去重不是目的让脚本目录变得可维护、可扩展才是。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号