2.2 绿与重构:最小实现和整理时刻


2.2 绿与重构:最小实现和整理时刻

本节摘要:绿灯阶段的核心纪律是"最小"——只写让当前测试通过的代码;重构阶段的核心纪律是"只改结构不改行为",且每轮都做。本节给出"最小"的三条判据、常用重构手法清单与节拍控制法,并用密码校验器演示一次完整的整理。读完你应能让循环的第段(绿、重构)稳定运转,不再积压"有空再整理"的债务。

某天下午,灯塔小组的工位上停着两行红字:密码校验器的首条测试还红着。新人小林挽起袖子就想一口气把长度、数字、大写、特殊字符全写了——反正都是要做的。老周按住他:"这条测试只审长度。你今天多写的每一行,都是没有测试作证的自白。"这是绿灯阶段每天都要打的仗:技术上有能力写更多,纪律上只许写刚好够的那部分。

绿:给"最小"立三条判据

"最小实现"不是鼓励你写丑代码,而是划定举证责任:任何超出当前测试要求的功能,都没有证据表明它被需要。落到操作上,三条判据帮你在写与不写之间做裁决:

  1. **这条测试要求它存在吗?**长度校验的测试不要求数字检查——不写。
  2. **删掉它测试会红吗?**会红,说明是必要实现;删了照样绿,多半是提前量。
  3. **它能用更笨的方式写吗?**能用直白写法就别上抽象,复杂度留给重构阶段去挣。

回到密码校验器,最小实现长这样:

# shop/password.py from dataclasses import dataclass, field @dataclass class Rating: valid: bool reasons: list[str] = field(default_factory=list) def rate(password: str) -> Rating: reasons = [] if len(password) < 8: reasons.append("长度不足") return Rating(valid=not reasons, reasons=reasons)

小林想顺手加上"缺数字"的判断,被 not reasons 这个表达式拦住了:它还没有对应的测试,加了也不会有红灯为它作证。留到下一轮循环,让它自己的红灯把它带进来——这就是"实现是被测试逼出来的"的字面意思。

⚠️ 最小不是偷工:有人把最小理解成 return Rating(valid=False, reasons=["长度不足"]) 这种写死答案的伪实现。伪实现合法,甚至是个流派(先走通流程再泛化),但下一轮循环必须把它换掉,不能让它蒙混过关——判据就是新红灯来时它必死。

重构:绿了之后的那几分钟

测试全绿,代码行为正确,现在可以放心动结构。TDD 把重构钉进节律而不是挂在口号上,靠的就是这个时机:每轮绿灯后,花三到五分钟整理。整理什么?按需从下面这份手法清单里挑,一次别超过三种:

手法 动作 典型信号
提取函数 把一段意图完整的代码拎成具名函数 注释比代码长、函数超过屏
重命名 变量、函数、参数改成说人话的名字 名字需要注释解释
防卫子句 提前返回,拍平嵌套 if 里套 if,心算嵌套深度
消除重复 相似代码合并成一个实现 改处要同步改多处
魔法值具名 魔法数字字符串提成常量 代码里躺着 8、0.85 这类裸值
参数对象化 一组总同进退的参数打包 函数签名越来越长
移动函数 函数搬到更亲近它的类或模块 函数老问别人的数据
合并条件碎片 同一对象的系列判断收拢 一堆 if 各查各的标志位
以查询代临时变量 复杂中间结果提成具名查询 临时变量需要注释解释

表是菜单不是任务——每次重构窗口只挑一两种,挑的标准是"哪个信号此刻真实存在"。手法清单的完整版在任何一本重构词典里都有,此处收录的是红绿节律里高频出场的那批:它们共同的特点是几分钟内可完成、且天然把代码朝"下条测试好写"的方向推

对刚才的实现动手:密码最短长度硬编码在条件里,且校验规则注定要长一串,先把"单条规则"抽象出来,给后续规则留好插槽:

# 重构前:规则内联在 rate 里,加规则就得改函数体 def rate(password: str) -> Rating: reasons = [] if len(password) < 8: reasons.append("长度不足") return Rating(valid=not reasons, reasons=reasons) # 重构后:规则收敛为函数清单,rate 只负责汇总 MIN_LENGTH = 8 def _check_length(password: str) -> list[str]: return [] if len(password) >= MIN_LENGTH else ["长度不足"] def rate(password: str) -> Rating: reasons = _check_length(password) return Rating(valid=not reasons, reasons=reasons)

每改完一步跑一遍测试,绿了再动下一处。行为没有分毫变化——测试可以为证——但下一个规则到来时,只需要往函数清单里加一项,不用再拆开 rate 的内脏。重构的红利总是兑现在下一轮,这就是它值得每轮都做的原因。

图:重构前后代码结构对照图

图:重构前后代码结构对照图

节拍控制:循环的秒表

老周团队的规矩是:一轮循环十分钟为软上限。红灯阶段两三分钟,绿灯阶段两三分钟,重构阶段三五分钟,超时即视为切片过厚或实现思路跑偏。计时不是形式主义——循环速度就是反馈速度,反馈速度决定你能承受多大的重构、多小的提交粒度。如果发现自己连续几轮都超时,回头检查红灯的切片是不是混进了多个行为。

💡 提交也是节律的组成部分:每轮循环结束就 commit,提交信息用测试名。一天下来提交历史就是当天的需求账本,回滚粒度天然细到行为级。

收进工具腰带

  • 三条判据拦住提前量:测试要求吗、删了会红吗、能更笨吗。
  • 伪实现合法但寿命只有一轮:新红灯必须杀死它。
  • 重构手法清单是菜单不是任务:每轮挑一两种,顺手即可。
  • 十分钟软上限:超时说明切片厚,退回红灯阶段重切。
  • 绿与重构的手感练熟后,下一节把它们串成三轮完整演练——看一个密码校验器怎样在节律里长成形。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U