关于 yagni
面向软件开发者的 YAGNI 原则技能,主张围绕当前需求实现功能,等实际需求出现后再抽象。内容包括判断规则、反模式、边界说明和代码审查清单。
主要功能
- 01聚焦当前需求
- 02三次重复后再抽象
- 03移除推测性代码
- 04避免过早扩展机制
- 05代码审查检查清单
适用场景
- 01评估是否需要新增抽象
- 02审查配置项和未使用代码路径
- 03处理重复代码与抽象时机
MCP 相关
说明建议在框架相关问题上使用 context7 MCP 或网页搜索;若存在 `.agents/stack-context.md`,应先读取。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jordancoin/ codingskills --skill yagni安装后在 Claude Code 中输入/yagni确认已加载。
详细介绍
YAGNI — 你不会需要它
应用前
如果 .agents/stack-context.md 存在,请先阅读。使用检测到的技术栈所惯用的模式来应用这一原则。对于特定框架的细节,请使用 context7 MCP 或网页搜索,不要猜测。
原则
不要为假设中的未来需求构建功能。只构建当前所需的内容,并在实际需求出现时再重构。
这在生产环境中为何重要
投机性代码是意外复杂性的头号来源。你添加的每个“以防万一”的抽象、配置选项或扩展点都有实际成本:必须理解、测试、维护和调试。未使用的代码路径最危险——它们会悄无声息地腐朽,给人测试覆盖率良好的错觉,还会扩大 Bug 的影响范围。
过早泛化比重复更糟。重复显而易见,之后也容易修复。而错误的抽象很难撤销,因为其他代码会逐渐依赖它。
规则
- 解决眼前的问题。 如果只有一个用例,就为这一个用例编写代码。不是两个,也不是考虑“以后万一”。
- 重复三次,再抽象。 第一次遇到时,直接编写代码。第二次遇到时,留意重复。第三次遇到时,提取模式——此时你已有足够的信息来设计正确的抽象。
- 删除投机性的代码路径。 如果某个功能标志从未启用过、某个配置选项从未更改过,或某个参数从未传入默认值以外的值,就删除它。
- 不要为一个插件构建插件系统。 只有在当前已有多个具体实现时,接口、注册表和扩展点才有其必要性。
- 不确定时先做原型。 如果你不确定是否需要某项功能,可以在分支中快速试验。不要把投机性的基础设施合并到主分支。
反模式
- 添加“以提高灵活性”的参数,但它们始终只接收一个值
- 只有两个组件时,它们本可以直接互相调用,却仍构建事件系统
- 创建只有一个具体实现的抽象基类
- 为永远不会改变的值编写配置文件
- 添加“以后可能需要”的数据库列
- 未衡量是否存在性能问题就实现缓存
- 本可以通过函数调用解决,却构建微服务
示例
-- YAGNI violation: generic "processor" for one operation
class DataProcessor:
def __init__(self, strategy, validator, transformer, output_format):
self.strategy = strategy
...
-- Actually needed: one function
def process_csv_upload(file):
rows = parse_csv(file)
validate_rows(rows)
save_to_db(rows)
-- YAGNI violation: premature abstraction
interface INotificationService
class EmailNotificationService implements INotificationService
class SMSNotificationService implements INotificationService // "we might need this"
class PushNotificationService implements INotificationService // "just in case"
-- Actually needed: you only send emails today
def send_welcome_email(user):
mailer.send(to=user.email, template="welcome")
适用边界
- YAGNI 不意味着忽略架构。 良好的结构(关注点分离、清晰的模块边界)并非投机——它能降低未来改动的成本。YAGNI 针对的是未使用的功能,而不是良好的设计。
- YAGNI 不意味着跳过错误处理。 处理已知的故障模式(网络错误、无效输入、磁盘已满)并非投机——这些情况会在生产环境中发生。
- YAGNI 不意味着避免零成本的可扩展性。 如果让代码具备可扩展性不需要任何成本(例如,使用映射而不是 switch 语句),就这么做。YAGNI 针对的是成本高昂的抽象。
- 与 DRY 的取舍: 有时应优先遵循 YAGNI——保留两个相似但不完全相同的函数,也好过过早地用错误的抽象将它们统一起来。
代码审查清单
- 此更改是否引入了当前需求未覆盖的代码路径?
- 是否存在当前只有一个可能取值的参数、配置或选项?
- 能否用直接实现替代此抽象,而不损失功能?
- 此接口/trait/协议是否有多个具体实现作为依据?
- 对于当前范围,是否有更简单的方案可行?
相关技能
- kiss:问题在于复杂性而非投机时
- solid:设计有充分依据的抽象时
- dry:决定是否提取模式时(YAGNI 建议等到出现 3 次)
评论
支持 Markdown