Don’t Repeat Yourself#

The DRY principle states that “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”

DRY#

The DRY principle is a software development principle that promotes the avoidance of code duplication. It suggests that developers should strive to eliminate redundancy in code by abstracting common functionality into reusable components.

When applied correctly, the DRY principle offers several benefits:

  1. Code Maintainability: By eliminating duplicate code, developers reduce the effort required to maintain and modify the system. Updates or bug fixes only need to be applied in a single place, reducing the chances of inconsistencies or errors introduced through code duplication.

  2. Readability and Understanding: DRY code tends to be more readable and understandable because common functionality is encapsulated in reusable components. It allows developers to focus on the unique aspects of the code rather than repeating similar code blocks.

  3. Efficiency: The elimination of duplicate code promotes efficiency in development. Developers spend less time writing redundant code and can focus on solving new problems or implementing additional features.

However, there are cases where the DRY principle may not always apply:

  1. Premature Abstraction: Applying the DRY principle too early, before the need for abstraction is evident, can introduce unnecessary complexity. It’s important to strike a balance between eliminating redundancy and maintaining simplicity. Only abstract common functionality when it truly adds value and is likely to be reused.

  2. Readability vs. DRY-ness: In some situations, code duplication may be preferable if it enhances code readability or provides greater clarity. Excessive abstraction for the sake of eliminating duplication can sometimes make the code more convoluted and harder to understand.

  3. Trade-offs: Sometimes, duplicating code can be a trade-off for performance optimization or to address specific requirements. Optimizing code for performance might require duplicating code to eliminate method calls or reduce overhead.

To apply the DRY principle effectively, consider the following guidelines:

  1. Identify Common Functionality: Look for patterns or similarities in code that indicate opportunities for abstraction. Extract this common functionality into reusable methods, classes, or modules.

  2. Encapsulate and Reuse: Ensure that the abstracted components are easily reusable across the codebase. Design them with clear interfaces and make them accessible to other parts of the system that can benefit from their functionality.

  3. Review and Refactor: Regularly review the codebase for instances of duplication and refactor accordingly. Keep an eye out for emerging patterns or similar code blocks that can be consolidated into reusable components.

In summary, the DRY principle promotes code maintainability, readability, and efficiency by reducing code duplication. However, it’s important to apply the principle judiciously, considering trade-offs, readability, and the appropriate level of abstraction. Striking the right balance leads to clean, reusable, and maintainable code.

Note here that it is not the same as code duplication. Code dus not necessarily represent knowledge. Code duplication is a symptom of a violation of the DRY principle, but not the violation itself.

The DRY principle is a corollary of the Law of Demeter, which states that each unit should have only limited knowledge about other units.

The DRY principle is also related to the Keep It Simple, Stupid principle (Keep It Simple, Stupid), which states that most systems work best if they are kept simple rather than made complicated; therefore simplicity should be a key goal in design, and unnecessary complexity should be avoided.

The DRY principle is also related to the You ain’t gonna need it principle (You Ain’t Gonna Need It), which states that one should not add functionality until deemed necessary.

Example of violating the DRY principle#
 class Employee {
     private String name;
     private int age;

     public Employee(String name, int age) {
         this.name = name;
         this.age = age;
     }

     public String getName() {
         return name;
     }

     public int getAge() {
         return age;
     }

     public void printInfo() {
         System.out.println("Name: " + name);
         System.out.println("Age: " + age);
     }

     public void printInfo(String department) {
         System.out.println("Name: " + name);
         System.out.println("Age: " + age);
     }
 }

 class Manager extends Employee {
     private String department;

     public Manager(String name, int age, String department) {
         super(name, age);
         this.department = department;
     }

     public void printInfo() {
         System.out.println("Name: " + getName());
         System.out.println("Age: " + getAge());
         System.out.println("Department: " + getDepartment());
     }

     public String getDepartment() {
         return department;
     }
 }

 class Director extends Manager {

     private final String company;

     public Director(String name, int age, String department, String company) {
         super(name, age, department);
         this.company = company;
     }

     public void printInfo() {
         System.out.println("Name: " + getName());
         System.out.println("Age: " + getAge());
         System.out.println("Department: " + getDepartment());
         System.out.println("Company: " + getCompany());
     }

     public String getCompany() {
         return company;
     }
 }

In this example, we have three classes Employee, Manager, and Director that all have a printInfo() method. Each of these methods is almost identical, printing out the employee’s name, age, and some additional information specific to each class.

This is an example of violating the DRY principle because the same code is repeated in each class. If we want to change the way the information is printed, we would have to modify each class individually, which can be error-prone and difficult to maintain.

To follow the DRY principle, we could extract the common logic into a separate method or interface, and then have each class implement that method or interface. For example:

--- Better ---

References#