一、项目背景
本次软件开源课程中,参与 OpenHUTB/nn 仓库的维护与改进工作。软件开源的意义在于促进共享、推动协作、提升质量、减少重复开发,并帮助开发者在真实项目中成长。
二、模块介绍:什么是 setup_tool
setup_tool 模块本质上是一个 命令行版 setup 流程演示工具。它并不真正执行复杂安装,而是模拟 setup 过程中的多个步骤,并把整个流程以“进度条、步骤编号、状态输出、最终汇总”的形式展示出来。
从功能上看,它主要完成以下任务:
- 显示当前正在执行的步骤
- 输出整体进度百分比和当前步骤编号
- 估算已经消耗的时间和剩余时间
- 对每一步输出状态结果,例如
OK、SKIP、ERROR - 在流程结束后给出总结信息,例如总步骤数、总耗时、跳过数、下载数和错误数
从代码结构上看,模块主要由两部分组成。
第一部分是 ProgressDemo 类。
这个类负责处理与显示相关的逻辑,包括进度条显示、状态计数、时间统计和最终汇总输出。
第二部分是 main() 函数。
main() 负责组织演示流程,也就是决定要执行哪些步骤、每个步骤包含哪些动作、以及整个脚本以什么模式和速度运行。
可以把它理解成一个“小型命令行流程演示器”。
三、原始版本存在的问题
在开始改进之前,setup_tool 模块虽然能运行,但从工程化角度看,主要存在以下几个问题。
1. 主流程中存在大量重复代码
原始版本的 main() 函数中,每一步几乎都是手写一段类似逻辑:
- 调用
show_progress() sleep一段时间- 输出一步的结果
这种写法直观,但重复度很高。一旦步骤变多,代码会迅速膨胀,后续如果需要增删步骤,就要修改很多重复代码。
2. 演示速度是写死的
原始版本中每一步的等待时间都直接写在代码里,例如 time.sleep(1) 或 time.sleep(2)。这样导致脚本只能以一种固定节奏运行。如果想快速展示,就必须手工改代码;如果想慢速观察,也同样需要改代码。
3. 演示流程只有一种模式
原始脚本默认总是执行完整流程。对于完整功能展示来说没问题,但如果只是课堂汇报或者快速演示核心步骤,这种“只能完整运行”的方式就不够灵活。
4. 缺少基础测试保障
虽然脚本能运行,但像状态计数这样的核心行为,原来缺少最基本的验证。例如跳过数、下载数、错误数这些计数逻辑,最好通过测试确认其行为正确。
四、改进思路
对 setup_tool 的改进不是一次性大改,而是采用了逐步递进的方式。
整体思路是:
- 先整理结构,让重复逻辑收敛
- 再增加功能,让脚本更灵活
- 最后补充测试,让关键行为有验证依据
这条路线的核心不是盲目加功能,而是先把结构打理清楚,再在清晰结构上做增强。
五、具体改进内容
5.1 结构优化:把重复的步骤执行逻辑改成“步骤列表 + 循环执行”
这是整个改进中最关键的一步。
修改前
原始版本中的步骤执行是逐段硬编码的,例如:
# Step 1
demo.show_progress("Checking hutb_downloader.exe")
time.sleep(1)
demo.step_result("skip", "hutb_downloader.exe already exists")
# Step 2
demo.show_progress("Checking dependencies directory")
time.sleep(1)
demo.step_result("skip", "dependencies directory already exists")
这种写法会在 main() 中反复出现。
修改后
把这些步骤整理成统一的数据结构,用 steps 列表描述步骤,再通过循环统一执行:
steps = [
{
"description": "Checking hutb_downloader.exe",
"actions": [
{"type": "sleep", "seconds": 1},
{"type": "result", "status": "skip", "message": "hutb_downloader.exe already exists"},
],
},
{
"description": "Checking dependencies directory",
"actions": [
{"type": "sleep", "seconds": 1},
{"type": "result", "status": "skip", "message": "dependencies directory already exists"},
],
},
]
demo = ProgressDemo(total_steps=len(steps))
for step in steps:
demo.show_progress(step["description"])
for action in step["actions"]:
if action["type"] == "sleep":
time.sleep(action["seconds"])
elif action["type"] == "print":
print(action["message"])
elif action["type"] == "result":
demo.step_result(action["status"], action["message"])
这样,原本写死在 main() 里的重复逻辑就被统一抽象成了“步骤数据 + 循环执行”。
运行方式
python src/setup_tool/main.py
改进效果
这一改动带来了几个直接收益:
- 减少重复代码
- 使主流程结构更清晰
- 后续如果增加或删除步骤,只需要改步骤数据
- 为后续继续增加参数和模式提供了基础
这一步可以理解为:
把固定写死的流程,改造成了数据驱动的流程。
5.2 功能增强:增加演示速度配置
在完成结构整理之后,我继续为脚本增加了速度参数,使演示节奏可以通过命令行选择。
修改前
原来的 sleep 执行方式是固定的:
if action["type"] == "sleep":
time.sleep(action["seconds"])
也就是说,运行速度完全写死。
修改后
我引入了 argparse,增加了 --speed 参数,并定义了速度倍率:
import argparse
def parse_args():
parser = argparse.ArgumentParser(
description="Setup tool progress display demo"
)
parser.add_argument(
"--speed",
choices=["fast", "normal", "slow"],
default="normal",
help="Set demo speed: fast, normal, or slow",
)
return parser.parse_args()
args = parse_args()
speed_map = {
"fast": 0.3,
"normal": 1.0,
"slow": 1.5,
}
speed_factor = speed_map[args.speed]
if action["type"] == "sleep":
time.sleep(action["seconds"] * speed_factor)
并且在运行标题中增加了显示:
print(f" Demo speed: {args.speed}")
运行方式
python src/setup_tool/main.py --speed fast
python src/setup_tool/main.py --speed alow
改进效果
这一改动让脚本从固定速度,变成了可根据场景调节速度的工具。
5.3 测试补充:增加基础行为测试
为了让前面的结构优化和功能增强更可靠,补充了针对 ProgressDemo 的基础测试。
测试内容
新增了一个测试文件,用于验证:
- 初始化状态是否正确
step_result("skip", ...)是否会增加skippedstep_result("download", ...)是否会增加downloadedstep_result("error", ...)是否会增加errors
测试运行结果为 4 个测试全部通过。
改进效果
这一改动的意义在于:
- 让模块的核心行为不再只是“看起来对”,而是“有测试验证”
- 为后续继续修改这个模块提供安全保障
- 体现了较完整的软件工程流程:
结构调整 → 功能增强 → 测试验证
5.4 功能增强:增加演示模式配置
这是最后一步,也是最适合课程结课汇报展示的一步。
修改前
原始脚本只能执行一套完整步骤,所有演示场景都必须跑完整流程。
修改后
在命令行参数中增加了 --mode:
parser.add_argument(
"--mode",
choices=["basic", "full"],
default="full",
help="Set demo mode: basic or full",
)
然后把原有完整步骤集合命名为 full_steps,再从中提取核心步骤组成 basic_steps:
basic_steps = [
full_steps[0],
full_steps[2],
full_steps[6],
full_steps[8],
full_steps[10],
]
接着根据模式选择执行步骤:
if args.mode == "basic":
steps = basic_steps
else:
steps = full_steps
demo = ProgressDemo(total_steps=len(steps))
并在标题区增加了当前模式显示:
print(f" Demo mode: {args.mode}")
运行方式
python src/setup_tool/main.py --mode full
python src/setup_tool/main.py --mode basic
改进效果
加入模式配置之后,脚本可以根据场景切换不同的流程集合:
full:完整演示,适合完整展示模块能力basic:精简演示,适合课堂快速汇报
速度参数和模式参数可以组合使用,例如:
python src/setup_tool/main.py --mode basic --speed fast
python src/setup_tool/main.py --mode full --speed slow
这意味着 setup_tool 不再只是一个固定脚本,而是真正具备了“按不同场景选择流程”的能力。
六、最终效果总结
经过这些连续改进,setup_tool 模块完成了从“固定 demo 脚本”到“灵活命令行工具”的提升。
改进前
- 步骤逻辑写死,重复代码较多
- 演示速度固定
- 演示模式单一
- 缺少针对核心行为的测试
改进后
- 步骤执行逻辑结构化
- 支持速度配置
--speed - 支持模式配置
--mode - 核心行为具备基础测试支持
如果用一句话概括最终成果,那就是:
把一个固定流程、固定速度、固定模式的演示脚本,逐步改造成了一个结构更清晰、速度可调、模式可选、具备基础测试的小型命令行进度演示工具。
七、这部分工作的价值
1. 对代码本身的价值
setup_tool 模块的结构更清晰、重复更少、扩展更方便,代码维护成本下降了。
2. 对功能演示的价值
脚本可以根据不同场景选择不同的速度和模式,更适合课堂汇报和展示。
3. 对工程实践的价值
这部分工作体现了一条完整的软件工程改进主线:
- 先理解模块职责
- 再整理主流程结构
- 再做功能参数化
- 再做模式配置化
- 最后补上基础测试
这比单纯“修几行代码”更能体现工程思维。
八、结论
在这次课程实践中,我最终将重点放在 setup_tool 模块,并围绕它完成了连续的结构优化、功能增强和测试补充工作。
这个模块原本只是一个固定流程的 setup 演示脚本,而经过改进之后,它已经具备了:
- 更清晰的步骤组织方式
- 更灵活的速度调节能力
- 更灵活的模式切换能力
- 更基本的行为测试保障