> ## Documentation Index
> Fetch the complete documentation index at: https://meta.niceshare.site/llms.txt
> Use this file to discover all available pages before exploring further.

# DRY原则

> DRY原则（不要重复自己）倡导消除代码和文档中的重复。了解其起源、应用以及DRY如何提高可维护性。

<Info>
  **类别**: 原则<br />
  **类型**: 软件开发原则<br />
  **起源**: 软件工程，1990年代 / 《程序员 pragmatics》，1999<br />
  **别名**: DRY、不要重复自己、单点真实来源
</Info>

<Note>
  **快速回答** — DRY原则（Don't Repeat Yourself）指出，每一条知识在一个系统中必须只有一种明确的表现形式。该原则首次在安迪·亨特（Andy Hunt）和戴夫·托马斯（Dave Thomas）1999年出版的《程序员 pragmatics》中阐述，已成为软件开发中最有影响力的原则之一。该原则不仅适用于代码，还包括文档、数据库模式、测试和任何其他系统工件。当信息被重复时，修改需要在多个地方进行，增加了一致性问题和错误的风险。
</Note>

## 什么是DRY原则？

DRY原则是一种软件开发哲学，主张消除代码、文档和其他系统工件中的重复。其核心思想看似简单却非常有力量：任何知识片段——无论是业务规则、计算、数据结构还是用户界面元素——都应该只存在于一个地方。当相同的信息出现在多个地方时，开发者必须记住更新每个实例，造成持续的维护负担，并引入错误的机会。

> "重复是设计良好系统的主要敌人。" — 安迪·亨特和戴夫·托马斯，《程序员 pragmatics》

该原则通过《程序员 pragmatics：从小工到专家》（1999年）获得了广泛认可，这本有影响力的书籍确立了软件开发的许多最佳实践。然而，这个underlying idea早在这本书之前——程序员早就认识到复制逻辑会造成维护噩梦。亨特和托马斯所做的是清晰地阐述了这个原则，并给了它一个令人难忘的名字。

DRY适用于多种形式的重复。代码重复发生在相同逻辑出现在多个地方时。文档重复发生在同一信息在多个文档中被解释时。数据重复发生在相同数据存储在多个位置时。模式重复产生于数据库结构相互镜像时。该原则要求开发者为每条知识确定单一权威来源，并构建引用该来源的系统。

### DRY原则的三层理解

* **入门**: 在复制粘贴代码时，停下来问："我可以将其提取为一个可重用的函数或变量吗？"即使是小规模的重复也会随着时间累积。

* **实践**: 在多个层面应用DRY——函数、类、模块和服务。使用继承、组合和配置管理等技术来集中知识。

* **进阶**: 认识到过度积极的DRY会产生不当的耦合。有时重复比错误的抽象更可取。平衡DRY与YAGNI和KISS原则。

## 起源

DRY原则在安迪·亨特和戴夫·托马斯1999年出版的《程序员 pragmatics：从小工到专家》中正式介绍。这本成为软件开发文献基石的书籍将DRY描述为构建可维护软件的核心原则。亨特和托马斯认为，重复导致系统更难理解、修改和扩展。

该原则建立在软件工程的早期 ideas 之上。数据库设计中"单点真实来源"的概念早于DRY，像在一个地方定义常量并在整个代码中引用它们的做法也是如此。DRY具有影响力的原因是它在所有知识重复形式中的广泛应用，不仅在代码中，还包括文档、流程和组织结构。

DRY流行的时机意义重大。1990年代后期见证了大型软件系统的增长，开发者越来越面临重复代码库的维护挑战。DRY为做出设计决策提供了清晰的启发式方法，这些决策将在系统的整个生命周期中受益。今天，DRY仍然是计算机科学课程和专业开发团队遵循的基础原则。

## 核心要点

<Steps>
  <Step title="单一真实来源">
    每条信息应该只存在于一个地方。当信息需要更改时，应该只有一个位置要更新，消除不一致的风险。
  </Step>

  <Step title="减少维护负担">
    重复的代码需要重复的维护。错误修复、安全更新和功能更改必须一致地应用于每个副本，增加工作量和风险。
  </Step>

  <Step title="提高一致性">
    当知识存在于一个地方时，所有消费者都引用相同的权威来源，确保整个系统的一致行为。
  </Step>

  <Step title="实现更好的抽象">
    识别重复迫使开发者思考代码的本质，通常导致更好的抽象和更优雅的设计。
  </Step>
</Steps>

## 应用场景

<CardGroup cols={2}>
  <Card title="代码重构">
    将重复的逻辑提取到可重用的函数、类或模块中。使用继承或组合来共享行为而不重复实现。
  </Card>

  <Card title="配置管理">
    将配置值存储在集中式文件或环境变量中。避免硬编码可能在不同环境中更改的值。
  </Card>

  <Card title="数据库设计">
    规范化数据库模式以消除冗余数据存储。使用外键和连接，而不是在表之间复制数据。
  </Card>

  <Card title="文档编写">
    编写一次解释概念并在整个过程中引用该说明的文档。避免在多个地方重复相同的信息。
  </Card>
</CardGroup>

## 经典案例

Ruby on Rails 框架 famously 体现了DRY原则。Rails 引入了"约定优于配置"的概念，通用模式被定义一次并自动应用于整个应用程序。例如，Rails 中的模型定义自动生成数据库访问方法——相同的逻辑不会在多个地方重复。当 Rails 开发者需要更改模型与数据库的交互方式时，他们在一个地方进行更改，它会传播到整个应用程序。这种方法使 Rails 应用程序的维护和修改变得非常容易，开发者报告称，与不太强调 DRY 的框架相比，重复代码明显更少。

## 边界与失效场景

DRY原则虽然至关重要，但有重要的局限性。首先，过度热情的DRY会产生不当的抽象。将不相关的概念强制放入共享代码会造成紧密耦合，使原始代码和"重构"版本都更难维护。

其次，过早的抽象是有风险的。DRY应该指导已证实重复的重构，而不是启发投机性泛化。为可能有一天会被重用的代码创建抽象通常会导致复杂、难于理解的系统。

第三，有些重复是可以接受的——甚至是必要的。看起来相似的代码可能有不同的存在原因，强制它们在一起会造成虚假的统一性。测试代码经常因为正当理由从生产代码中复制结构：测试必须能够独立维护。

## 常见误区

<AccordionGroup>
  <Accordion title="DRY意味着永远不复制代码">
    DRY是关于避免知识重复，而不是字面上的代码。有时最清晰的解决方案涉及重复语法，而底层知识保持单一来源。
  </Accordion>

  <Accordion title="DRY总是提高可维护性">
    错误的抽象会使维护变得更难。在提取重复之前，确保抽象准确地代表共享概念。
  </Accordion>

  <Accordion title="DRY只适用于代码">
    该原则扩展到文档、数据库模式、API 设计和组织流程。任何重复的知识都是 DRY 处理的候选对象。
  </Accordion>
</AccordionGroup>

## 相关概念

<CardGroup cols={3}>
  <Card title="KISS原则">
    DRY 通常简化代码，使其更容易理解。KISS 通过强调简单性来补充 DRY，指导如何消除重复。
  </Card>

  <Card title="YAGNI原则">
    不要构建可重用的组件，直到你需要它们。YAGNI 防止违反 DRY 精神的过早抽象。
  </Card>

  <Card title="单点真实来源">
    一个相关的数据库概念，数据应该存储在一个地方。DRY 是将这个想法应用到系统中所有知识的方式。
  </Card>

  <Card title="代码重构">
    改进代码结构的实践，通常通过应用 DRY。重构是实现 DRY 的操作活动。
  </Card>

  <Card title="奥卡姆剃刀">
    两个原则都偏向简单性。DRY 消除重复，而奥卡姆剃刀消除不必要的假设。
  </Card>
</CardGroup>

## 一句话总结

<Tip>
  不要重复自己——重复造成维护噩梦，因此将共享知识提取为所有系统部分引用的单一权威来源。
</Tip>
