- Home
- Design Principles
- Dry
DRY Design Principle
The DRY (Don't Repeat Yourself) principle is one of the most fundamental concepts in software development. It emphasizes the reduction of code duplication by ensuring that every piece of knowledge (or logic) is represented only once in a system. By adhering to DRY, you can make your code more maintainable, easier to update, and less prone to errors.
What is DRY?
Definition: The DRY principle states that “every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” In simpler terms, it means that you should avoid duplicating code or logic. If a particular functionality or logic is repeated across different parts of your codebase, you should extract it into a single place.
Why is DRY Important?
- Maintainability: When you have the same logic in multiple places, making a change requires updating each instance. This can lead to errors if you miss a spot.
- Readability: Repeated code makes the codebase longer and harder to understand. DRY code is more concise and easier to follow.
- Testability: Duplication increases the number of places where bugs can occur. With DRY, you only need to test the functionality in one place.
Example of Violating DRY
Let's start with an example that violates the DRY principle.
// Before applying DRY: Duplication of logic in multiple methods
class OrderProcessor {
public double calculateDiscount(double totalPrice) {
double discount = 0;
if (totalPrice > 100) {
discount = totalPrice * 0.10;
} else if (totalPrice > 50) {
discount = totalPrice * 0.05;
}
return discount;
}
public void printInvoice(double totalPrice) {
double discount = 0;
if (totalPrice > 100) {
discount = totalPrice * 0.10;
} else if (totalPrice > 50) {
discount = totalPrice * 0.05;
}
double finalPrice = totalPrice - discount;
System.out.println("Final Price: " + finalPrice);
}
}
In this example, the logic for calculating the discount is repeated in both the calculateDiscount and printInvoice methods. This duplication makes the code harder to maintain because if the discount rules change, you have to update the logic in both places.
Applying the DRY Principle
Now, let's refactor the code to follow the DRY principle by extracting the duplicated logic into a single method.
// After applying DRY: Logic is extracted to a single method
class OrderProcessor {
public double calculateDiscount(double totalPrice) {
return getDiscount(totalPrice);
}
public void printInvoice(double totalPrice) {
double discount = getDiscount(totalPrice);
double finalPrice = totalPrice - discount;
System.out.println("Final Price: " + finalPrice);
}
// Extracted method to avoid duplication
private double getDiscount(double totalPrice) {
double discount = 0;
if (totalPrice > 100) {
discount = totalPrice * 0.10;
} else if (totalPrice > 50) {
discount = totalPrice * 0.05;
}
return discount;
}
}
In this refactored version, the discount logic is extracted into a private method getDiscount. Now, both calculateDiscount and printInvoice methods reuse this logic, ensuring that if the discount rules need to change, you only need to update it in one place.
Real-World Example of DRY in Action
Imagine you are working on a web application where users can register and log in. You have some validation logic for checking email addresses. Initially, you might write the same validation logic in both the registration and login components, which would violate DRY.
Instead, you should extract the email validation logic into a utility class or a separate method, which can then be reused across different parts of your application.
// Utility class for DRY code
class ValidationUtil {
public static boolean isValidEmail(String email) {
return email != null && email.contains("@") && email.contains(".");
}
}
class Registration {
public void registerUser(String email, String password) {
if (ValidationUtil.isValidEmail(email)) {
// Registration logic
} else {
System.out.println("Invalid email address");
}
}
}
class Login {
public void loginUser(String email, String password) {
if (ValidationUtil.isValidEmail(email)) {
// Login logic
} else {
System.out.println("Invalid email address");
}
}
}
Here, the email validation logic is centralized in the ValidationUtil class, ensuring that it's consistent and easy to maintain.
Avoiding Over-DRYing
While DRY is an essential principle, it's also important to avoid over-applying it. Sometimes, slight duplication might be acceptable if it makes the code clearer or if the duplication isn't likely to change. The key is to strike a balance between avoiding unnecessary repetition and maintaining code clarity.
Conclusion
The DRY principle is all about reducing redundancy in your codebase. By following DRY, you can make your code easier to maintain, more readable, and less prone to bugs. As you develop your applications, always look for opportunities to eliminate duplication and consolidate logic into single, reusable components.