DRY Principle Tutorial from Scratch (2026)
The DRY (Don't Repeat Yourself) principle is one of the most fundamental concepts in software engineering, yet it is also one of the most misunderstood. Having reviewed thousands of pull requests, I can tell you that violations of DRY come in two flavors: obvious duplication (copy-paste code) and subtle duplication (duplicated knowledge or intent that happens to use different syntax).
This tutorial explores the DRY principle in depth — what it truly means, how to apply it without falling into the trap of premature abstraction, and when duplication is actually the better choice. You will learn practical techniques for identifying and eliminating duplication across your codebase.
What DRY Really Means
The DRY principle was coined by Andy Hunt and Dave Thomas in The Pragmatic Programmer. The formal definition is: "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system." Note the emphasis on knowledge, not code. DRY is about ensuring that every business rule, algorithm, or constraint is expressed once and only once in your codebase.
This distinction is important. Two pieces of code that look similar but represent different concepts are not a DRY violation. Conversely, code that looks completely different but encodes the same business knowledge (for example, the same validation logic written in SQL, JavaScript, and a documentation comment) does violate DRY because that knowledge has multiple representations that must be kept in sync.
// DRY violation: duplicated business knowledge
public class OrderService {
public boolean isValidOrder(Order order) {
return order.getTotal() > 0
&& order.getItems().size() > 0
&& order.getCustomer() != null;
}
}
public class OrderValidator {
public boolean validate(Order order) {
return order.getTotal() > 0 // same logic duplicated
&& order.getItems().size() > 0
&& order.getCustomer() != null;
}
}
// DRY compliance: single authoritative source
public class OrderValidator {
public static boolean isValid(Order order) {
return order.getTotal() > 0
&& order.getItems().size() > 0
&& order.getCustomer() != null;
}
}
// Now OrderService delegates to OrderValidator.isValid()
Code Reuse Techniques
There are several techniques for achieving code reuse in an OOP language. The most common are: extracting a method (when you see the same block of code in multiple places within the same class), extracting a class (when the duplication spans multiple classes but represents a single responsibility), creating a base class (when multiple classes share common behavior and an "is-a" relationship exists), and using composition (when one class can delegate to another class without an inheritance relationship).
Composition is generally preferred over inheritance because it is more flexible — you can change behavior at runtime, you avoid the fragile base class problem, and it models "has-a" relationships which are more common than "is-a" relationships in real-world systems.
// Before DRY: duplicated logging and timing logic
public class DatabaseService {
public void saveData(String data) {
long start = System.currentTimeMillis();
Logger.log("Starting saveData");
// ... actual save logic
Logger.log("Finished saveData in " + (System.currentTimeMillis() - start) + "ms");
}
}
// After DRY: extracted into a reusable utility
public class PerformanceTracker {
public static T track(String operationName, Supplier operation) {
long start = System.currentTimeMillis();
Logger.log("Starting " + operationName);
try {
return operation.get();
} finally {
Logger.log("Finished " + operationName + " in "
+ (System.currentTimeMillis() - start) + "ms");
}
}
}
public class DatabaseService {
public void saveData(String data) {
PerformanceTracker.track("saveData", () -> {
// actual save logic
return null;
});
}
}
When Duplication is Better Than Abstraction
Blindly applying DRY can lead to premature abstraction — creating shared code before you understand the full set of use cases. The Rule of Three suggests that you should wait until you see duplication three times before extracting shared code. The first time you write something, just write it. The second time, feel the pain but consider whether it's truly the same concept. The third time, extract.
Other cases where duplication is acceptable include: when the duplicated code is in different architectural layers (controllers vs services), when the similarity is coincidental (two methods happen to look the same but serve different business purposes), and when the abstraction would introduce coupling between unrelated modules. Remember: duplicated code is a smell, not a disease — sometimes the cure is worse than the disease.
// Acceptable duplication: coincidental similarity, different domains
public class UserController {
public ResponseEntity getUser(Long id) {
User user = userService.findById(id);
UserDto dto = new UserDto();
dto.setId(user.getId());
dto.setName(user.getName());
dto.setEmail(user.getEmail());
return ResponseEntity.ok(dto);
}
}
public class ProductController {
public ResponseEntity getProduct(Long id) {
Product product = productService.findById(id);
ProductDto dto = new ProductDto();
dto.setId(product.getId());
dto.setName(product.getName());
dto.setPrice(product.getPrice());
return ResponseEntity.ok(dto);
}
}
// Extracting a shared mapper would couple User and Product domains unnecessarily
Frequently Asked Questions
What does DRY stand for in programming?
DRY stands for Don't Repeat Yourself. It means that every piece of knowledge should have a single, unambiguous, authoritative representation within a system.
What is the difference between DRY and WET?
WET stands for Write Everything Twice (or We Enjoy Typing) and is the opposite of DRY. WET codebases have a lot of duplication, making changes slower and bugs more likely because you have to update multiple places for a single change.
Can you over-apply the DRY principle?
Yes, absolutely. Premature abstraction — extracting shared code before you understand all use cases — can lead to overly complex, tightly coupled systems. The Rule of Three is a good guideline to prevent this.
How does DRY relate to the Single Responsibility Principle?
DRY and SRP are complementary. SRP ensures each class has one responsibility, while DRY ensures each piece of knowledge exists in one place. Following SRP naturally leads to DRY code, and vice versa.
Originally published on Ayodhyyya. Last updated June 1, 2026.