The Don’t Repeat Yourself Principle
Repetition is the Root of All Software Evil
The DRY Principle in the Modern Developer’s Design Series is a very important principle.
The Don’t Repeat Yourself Principle States:
Every piece of Code must have a Single, Unambiguous, Representation within a Software Entity
… Cut and Paste is Evil!
The concept complies with the Open / Closed Principle by creating reusable code that can be consumed by more than one calling Software Entity.
When you are developing and find that you are using similar code over and over you should refactor the code into a reusable Private Class, a Public Utility Helper Class or Struct, an Interface or a Method.
If you are passing the same Parameters, Primitives or Object Types, you should refactor them into State DTOs and pass them as a single object.
The State DTO complies with the OOP Practice of Encapsulation, Data Hiding.
Duplicated Code Creates these Issues
… Impossible to Guarantee that all Repeated Instances are Modified when Change is Required
…… Requires Memory Management and Run-time Cycles to Process Identical Code Blocks
The Don’t Repeat Yourself Principle Deep Dive
The DRY Principle defines the responsibility of the Developers and Code Reviewers to be vigilant in ensuring that Developed Code Bases are free from Code Block Duplications.
The definition of the Don’t Repeat Yourself Principle calls for the creation of the following Software Entities:
- Private Helper Methods for Reusable Duplications within the current Type
- Public Class Utility Methods for Reuse in the Current Type and Other Code Types
- The implementation of the Request / Response Pattern for passing State DTO Request Classes that encapsulate repeated Constructor Parameter Patterns that returns a single Complex Composite DTO as a Package Object for the calling class to consume
Compliance with DRY Creates a Code Base that has
… A lower Total Cost of Ownership (TCO) for the Client
…… Throughout the Software Development Life Cycle (SDLC).
Duplicate code within assemblies creates an unmanageable code base for the Maintenance Developer.
When a Change Order is received to modify the repeated code it is very difficult to ensure that all versions of that code have been updated.
The Missed Code Blocks are Generally Found, if Lucky, in QA Testing
… but More than Likely when Deployed to Production.
All efforts must be taken during development and code review to guarantee that the DRY Principle has been complied with in the code base.
Dry violations are easy to identify. Any code block that appears more than one time should be refactored.
If it is unique to that current Software Entity then it becomes a Private Helper Method.
If it could serve more than one Software Type it is refactored into Public Utility Class as a Public Helper Method.
If Class Methods are passing the same parameters, a State DTO should encapsulate the parameters and pass them as an object.
This creates an encapsulated object that could be extended in the future for additional parameters.
The Request / Response Design Pattern, using Composite DTOs, supports an easy implementation of a Generic Method typed to a common Request Base Class and a common Response Base Class.
This Enables an infinite Usage of the Generic Method
… With Different Derived Classes for a Single Reusable Method
This is the Ultimate DRY Principle Compliance!
Here are the major signs of a Software Entity that has violated DRY:
- Conditional Statements – Multiple “ifs” that are processing the results in the same fashion
- Constructor Method Parameters repeated in Overloads or separate Methods – You can eliminate Overload noise using a Composite DTO to pass Constructor parameters. Only use the provided parameters from the calling Method.
- Formatting Code Blocks– Dates, Phone Numbers, Addresses and Contact information like Emails, Web Pages and Twitter Handles that are using a common display format should be refactored into Public Utility Helper Methods for consistency of reuse
- Related or Similar Classes – Methods that are identified as using a common pattern throughout the encapsulated Class are candidates for the Request / Response Generic Method Design Pattern
Here is an example of DRY Violations:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
using System; using System.Collections.Generic; using System.Globalization; namespace DRY.Customer.Legacy { public class CustomerLegacyDisplay { static void Main() { var customerList = GetCustomers(); var infoCustomer = "Customer"; //var infoCustomer = "CustomerList"; if (infoCustomer == "Customer") { Console.WriteLine("Begin Customer Display: n"); var customer = customerList[0]; var idName = string.Format("{0}_{1}_{2}", customer.LastName, customer.FirstName, customer.NameId); Console.WriteLine("tCustomer ID Name: {0}n", idName); } else { Console.WriteLine("Begin Customer Display: n"); foreach (var customer in customerList) { var idName = string.Format("{0}_{1}_{2}", customer.LastName, customer.FirstName, customer.NameId); Console.WriteLine("tCustomer ID Name: {0}n", idName); } } Console.ReadKey(); } #region Helpers private static List GetCustomers() { return new List { new Customer {FirstName = "Joe", LastName = "Smith"}, new Customer {FirstName = "Tim", LastName = "Bo"}, new Customer {FirstName = "Jane", LastName = "Doe"} }; } private class Customer { public string FirstName { get; set; } public string LastName { get; set; } public string NameId { get; private set; } public Customer() { NameId = new Random().Next(1, 9999).ToString(CultureInfo.InvariantCulture); } } #endregion } } |
This demo program create a list of three Customers and either displays the first Customer or all three based on a variable value: infoCustomer.
The string format display block uses the exact same code copied twice to create the displayed output to the Console.
This violates the DRY Principle as it is repeated code
Here are the violations refactored into DRY compliance:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
using System; using System.Collections.Generic; using System.Globalization; namespace DRY.Customer.Refactored { public class CustomerRefactoredDisplay { static void Main() { var customerList = GetCustomers(); //var infoCustomer = "Customer"; var infoCustomer = "CustomerList"; if (infoCustomer == "Customer") { Console.WriteLine("Begin Customer Display: n"); var customer = customerList[0]; CreateCustomerDisplay(customer); } else { Console.WriteLine("Begin Customer List Display: n"); foreach (var customer in customerList) { CreateCustomerDisplay(customer); } } Console.ReadKey(); } #region Helpers private static List GetCustomers() { return new List { new Customer {FirstName = "Joe", LastName = "Smith"}, new Customer {FirstName = "Tim", LastName = "Bo"}, new Customer {FirstName = "Jane", LastName = "Doe"} }; } private class Customer { public string FirstName { get; set; } public string LastName { get; set; } public string NameId { get; private set; } public Customer() { NameId = new Random().Next(1, 9999).ToString(CultureInfo.InvariantCulture); } } private static void CreateCustomerDisplay(Customer customer) { var idName = string.Format("{0}_{1}_{2}", customer.LastName, customer.FirstName, customer.NameId); Console.WriteLine("tCustomer ID Name: {0}n", idName); } #endregion } } |
In the refactored version the common code has been refactored into a private helper method: CreateCustomerDisplay().
This refactored version complies with the DRY Principles as common code is used as a Method Call in each of the two possible Customer displays.
This is a performance increase as well as the Just-In-Time compiler ca use “EnRegistration” to create pointers to the Method Signatures and only use memory for the code when required
They both create the correct displays:


The Refactored Version Complies with the DRY Principle and follows Best Practices for OOP
The benefits of compliance with the DRY Principle:
-
Creates code that is easier to understand
-
Allows the Maintenance Developer to work more efficiently
-
It fosters the creation of Public Utility Classes that support development process consistency
-
It identifies candidates for the Request / Response Design Pattern
-
Fosters a Team Paradigm of Code Reuse
Don’t Be a “Wet” Developer!
The Next Principle Design Series Post:
The Open / Closed Principle
… Brain Surgery is not Required when Putting on a Hat
Latest posts by Brad Huett (see all)
- DevOps: A Bridge to Your DevOps Culture - March 25, 2016
- Embracing Test Driven Development (TDD) - March 25, 2016
- DevOps: Delivering Agile Projects - March 25, 2016


