yagni

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

YAGNI — You Aren't Gonna Need It

YAGNI — 你不会需要它

Before Applying

应用前准备

If
.agents/stack-context.md
exists, read it first. Apply this principle using idiomatic patterns for the detected stack. For framework-specific details, use context7 MCP or web search — don't guess.
如果存在
.agents/stack-context.md
文件,请先阅读它。针对检测到的技术栈,使用符合其惯用模式的方式应用该原则。若需框架特定细节,请使用context7 MCP或进行网络搜索——不要凭空猜测。

Principle

原则核心

Do not build for hypothetical future requirements. Build what is needed now, and refactor when actual requirements emerge.
不要为假设的未来需求进行开发。只构建当前所需的功能,当实际需求出现时再进行重构。

Why This Matters in Production

该原则在生产环境中的重要性

Speculative code is the #1 source of accidental complexity. Every abstraction, configuration option, or extension point you add "just in case" has a real cost: it must be understood, tested, maintained, and debugged. Unused code paths are the most dangerous — they rot silently, give false confidence in test coverage, and create surface area for bugs.
Premature generalization is worse than duplication. Duplication is obvious and easy to fix later. A wrong abstraction is painful to undo because other code grows to depend on it.
投机性代码是意外复杂度的首要来源。你为‘以防万一’而添加的每一个抽象、配置选项或扩展点都有实际成本:必须有人理解、测试、维护和调试它们。未使用的代码路径是最危险的——它们会悄然腐化,给人测试覆盖率充足的错误信心,还会增加出现bug的风险。
过早的泛化比代码重复更糟糕。重复代码很明显,后续也容易修复。而错误的抽象则很难撤销,因为其他代码会逐渐依赖它。

Rules

遵循规则

  1. Solve the problem in front of you. If you have one use case, write code for one use case. Not two. Not "what if later."
  2. Three strikes, then abstract. The first time you write something, just write it. The second time, note the duplication. The third time, extract the pattern — now you have enough data to design the right abstraction.
  3. Delete speculative code paths. If a feature flag has never been toggled, a configuration option has never been changed, or a parameter has never been passed anything other than the default — remove it.
  4. Don't build plugin systems for one plugin. Interfaces, registries, and extension points are justified only when you have multiple concrete implementations today.
  5. Prototype when uncertain. If you aren't sure whether something will be needed, spike it in a branch. Don't merge speculative infrastructure into main.
  1. 解决眼前的问题。如果你只有一个用例,就只为这一个用例写代码。不要考虑两个,也不要想‘以后万一呢’。
  2. 三次重复再抽象。第一次写代码时,直接实现即可。第二次遇到重复时,标记出重复点。第三次出现时,再提取通用模式——此时你已有足够的信息来设计正确的抽象。
  3. 删除投机性代码路径。如果某个功能标记从未被切换过、某个配置选项从未被修改过,或者某个参数从未传入过默认值以外的内容——就把它删掉。
  4. 不要为单个插件构建插件系统。只有当你现在就有多个具体实现时,接口、注册中心和扩展点的存在才是合理的。
  5. 不确定时先做原型。如果你不确定是否需要某个功能,在分支中进行原型开发。不要将投机性的基础架构合并到主分支。

Anti-Patterns

反模式示例

  • Adding parameters "for flexibility" that only ever receive one value
  • Building an event system when you have two components that could just call each other
  • Creating abstract base classes with a single concrete implementation
  • Writing configuration files for values that never change
  • Adding database columns "we might need later"
  • Implementing caching before measuring whether there's a performance problem
  • Building a microservice when a function call would suffice
  • 为了‘灵活性’添加参数,但该参数永远只接收一个值
  • 明明两个组件可以直接调用,却要构建事件系统
  • 创建只有一个具体实现的抽象基类
  • 为永远不会更改的值编写配置文件
  • 添加‘以后可能需要’的数据库列
  • 还未衡量是否存在性能问题就实现缓存
  • 函数调用就足够的情况下,却要构建微服务

Examples

示例对比

-- 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原则:为单个操作构建通用的“处理器”
class DataProcessor:
    def __init__(self, strategy, validator, transformer, output_format):
        self.strategy = strategy
        ...

-- 实际需要:一个简单函数
def process_csv_upload(file):
    rows = parse_csv(file)
    validate_rows(rows)
    save_to_db(rows)
-- 违反YAGNI原则:过早抽象
interface INotificationService
class EmailNotificationService implements INotificationService
class SMSNotificationService implements INotificationService  // “我们以后可能需要这个”
class PushNotificationService implements INotificationService  // “以防万一”

-- 实际需要:当前只需要发送邮件
def send_welcome_email(user):
    mailer.send(to=user.email, template="welcome")

Boundaries

适用边界

  • YAGNI does not mean ignore architecture. Good structure (separation of concerns, clear module boundaries) is not speculative — it makes future changes cheaper. YAGNI targets unused features, not good design.
  • YAGNI does not mean skip error handling. Handling known failure modes (network errors, invalid input, disk full) is not speculative — those things will happen in production.
  • YAGNI does not mean avoid extensibility at zero cost. If making code extensible costs nothing (e.g., using a map instead of a switch statement), do it. YAGNI targets costly abstractions.
  • Tension with DRY: Sometimes YAGNI wins — it's better to have two similar-but-not-identical functions than to prematurely unify them behind the wrong abstraction.
  • YAGNI并非意味着忽视架构设计。良好的结构(关注点分离、清晰的模块边界)不属于投机性设计——它能降低未来变更的成本。YAGNI针对的是未使用的功能,而非良好的设计。
  • YAGNI并非意味着跳过错误处理。处理已知的故障模式(网络错误、无效输入、磁盘已满)不属于投机性操作——这些情况在生产环境中肯定会发生。
  • YAGNI并非意味着要拒绝零成本的可扩展性。如果让代码具备可扩展性无需任何成本(例如,使用映射而非switch语句),那就去做。YAGNI针对的是成本高昂的抽象。
  • 与DRY原则的权衡:有时YAGNI优先级更高——与其用错误的抽象过早统一两个相似但不完全相同的函数,不如保留它们的重复。

Code Review Checklist

代码评审检查清单

  • Does this change introduce any code paths that aren't exercised by current requirements?
  • Are there parameters, configs, or options that only have one possible value today?
  • Could this abstraction be replaced by a direct implementation without loss of functionality?
  • Is this interface/trait/protocol justified by multiple concrete implementations?
  • Would a simpler approach work for the current scope?
  • 本次变更是否引入了当前需求未覆盖的代码路径?
  • 是否存在当前只有一个可能取值的参数、配置或选项?
  • 这个抽象是否可以被直接实现替代,且不损失任何功能?
  • 这个接口/trait/协议是否有多个具体实现来支撑其合理性?
  • 针对当前范围,是否有更简单的实现方式?

Related Skills

相关原则

  • kiss: When the issue is complexity rather than speculation
  • solid: When designing abstractions that are justified
  • dry: When deciding whether to extract a pattern (YAGNI says wait for 3 occurrences)
  • KISS:当问题核心是复杂度而非投机性设计时使用
  • SOLID:当设计具备合理性的抽象时使用
  • DRY:当决定是否提取通用模式时使用(YAGNI原则建议等出现3次重复再进行)