学习目标
一个能独立检查的规则函数,以及清楚的输入、输出和调用边界。
适用场景
虚构预约页面同时做优惠计算、读取数据库、发送邮件和显示错误。每改一种价格规则都得动界面、接口和通知代码。练习代码是示意,不是可直接上线的计费模块。
准备条件
- 一个确实反复修改或难以验证的函数;单凭文件行数不启动重构。
- 已确认的当前业务规则与原行为用例,不用模型猜优惠和税费。
操作步骤
沿一次真实修改寻找混杂职责
选最近一次需求,例如“新增一种优惠”。圈出为了同一规则一起变化的地方,再标出与规则无关的 I/O。先找到重复知识和修改牵连,不按“每个文件不得超过多少行”机械拆分。
变更记录,而不是目录美化规则:本练习仅有固定金额优惠,结果最低为零。 规则出现处:服务端报价函数、邮件模板里的另一次计算。 I/O:查价、存订单、发邮件。 候选:报价规则集中一处,邮件只展示已确认报价。 不做:通用插件系统、微服务、五种策略类。 未知:真实项目的币种、退款、税费,应另行确认。定义一个小而完整的规则接口
让规则函数只接收已经取得的数据,返回计算结果;由调用者处理存储与通知。边界应减少调用者必须知道的事情,而不是把原大函数拆成一堆依赖全局状态的小函数。
最小 TypeScript 示意type QuoteInput = { subtotalCents: number; discountCents: number }; export function quote({ subtotalCents, discountCents }: QuoteInput): number { if (![subtotalCents, discountCents].every(Number.isSafeInteger) || subtotalCents < 0 || discountCents < 0) { throw new Error("Amounts must be non-negative safe integer cents"); } return Math.max(0, subtotalCents - discountCents); } // 外部负责取得输入、存储结果;此函数不读数据库、不发送通知。先验证已确认的边界例子
用正常、零值、优惠超额和非法输入检查规则。不要给示意代码补编真实财务规则;如果价格需要多币种或小数精度,重新明确契约。保存报价后,通知应展示同一份结果,避免不同出口重新计算出差异。
示例输入与预期subtotalCents=1000, discountCents=200 => 800 subtotalCents=0, discountCents=0 => 0 subtotalCents=1000, discountCents=1200 => 0 discountCents=-1 或 1.5 => 拒绝 存储或通知失败 => 由调用流程处理,不改写报价规则用下一次修改判断边界是否值得保留
模拟再调整同一条真实规则,记录需要理解和修改哪些地方。若只多了文件跳转、调用者仍要拼装全部细节,就撤回无益的拆分。架构好坏看改变是否更安全、更易理解,不看模式名称和层数。
常见误区
- 复制三份相似代码就马上写通用引擎。
- 先确认是否是同一业务知识;仅外观相似、变化原因不同,可以保持独立。
- 把数据库错误悄悄转换成报价为零。
- 区分规则结果与外部失败,向调用者保留可处理的错误语义。
验收清单
- 拆分来自实际修改牵连,而非行数阈值。
- 规则输入输出、单位和非法值处理明确。
- 不同出口没有各自复制一套报价规则。
- 同一修改场景下,调用者需要了解的细节确实减少。
资料与版本
本文为原创方法整理,示例与提示词需按项目调整;不代表真实用户研究或账号执行结果。