跳转到主要内容
类别: 原则
类型: 软件开发原则
起源: 软件工程,1990年代 / 《程序员 pragmatics》,1999
别名: DRY、不要重复自己、单点真实来源
快速回答 — DRY原则(Don’t Repeat Yourself)指出,每一条知识在一个系统中必须只有一种明确的表现形式。该原则首次在安迪·亨特(Andy Hunt)和戴夫·托马斯(Dave Thomas)1999年出版的《程序员 pragmatics》中阐述,已成为软件开发中最有影响力的原则之一。该原则不仅适用于代码,还包括文档、数据库模式、测试和任何其他系统工件。当信息被重复时,修改需要在多个地方进行,增加了一致性问题和错误的风险。

什么是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仍然是计算机科学课程和专业开发团队遵循的基础原则。

核心要点

1

单一真实来源

每条信息应该只存在于一个地方。当信息需要更改时,应该只有一个位置要更新,消除不一致的风险。
2

减少维护负担

重复的代码需要重复的维护。错误修复、安全更新和功能更改必须一致地应用于每个副本,增加工作量和风险。
3

提高一致性

当知识存在于一个地方时,所有消费者都引用相同的权威来源,确保整个系统的一致行为。
4

实现更好的抽象

识别重复迫使开发者思考代码的本质,通常导致更好的抽象和更优雅的设计。

应用场景

代码重构

将重复的逻辑提取到可重用的函数、类或模块中。使用继承或组合来共享行为而不重复实现。

配置管理

将配置值存储在集中式文件或环境变量中。避免硬编码可能在不同环境中更改的值。

数据库设计

规范化数据库模式以消除冗余数据存储。使用外键和连接,而不是在表之间复制数据。

文档编写

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

经典案例

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

边界与失效场景

DRY原则虽然至关重要,但有重要的局限性。首先,过度热情的DRY会产生不当的抽象。将不相关的概念强制放入共享代码会造成紧密耦合,使原始代码和”重构”版本都更难维护。 其次,过早的抽象是有风险的。DRY应该指导已证实重复的重构,而不是启发投机性泛化。为可能有一天会被重用的代码创建抽象通常会导致复杂、难于理解的系统。 第三,有些重复是可以接受的——甚至是必要的。看起来相似的代码可能有不同的存在原因,强制它们在一起会造成虚假的统一性。测试代码经常因为正当理由从生产代码中复制结构:测试必须能够独立维护。

常见误区

DRY是关于避免知识重复,而不是字面上的代码。有时最清晰的解决方案涉及重复语法,而底层知识保持单一来源。
错误的抽象会使维护变得更难。在提取重复之前,确保抽象准确地代表共享概念。
该原则扩展到文档、数据库模式、API 设计和组织流程。任何重复的知识都是 DRY 处理的候选对象。

相关概念

KISS原则

DRY 通常简化代码,使其更容易理解。KISS 通过强调简单性来补充 DRY,指导如何消除重复。

YAGNI原则

不要构建可重用的组件,直到你需要它们。YAGNI 防止违反 DRY 精神的过早抽象。

单点真实来源

一个相关的数据库概念,数据应该存储在一个地方。DRY 是将这个想法应用到系统中所有知识的方式。

代码重构

改进代码结构的实践,通常通过应用 DRY。重构是实现 DRY 的操作活动。

奥卡姆剃刀

两个原则都偏向简单性。DRY 消除重复,而奥卡姆剃刀消除不必要的假设。

一句话总结

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