Innovation in Iteration: A Developer’s View on Quality & Legacy Code
- March 04
- 4 min
DRY is one of the most common principles in software development. This abbreviation stands for “Don’t repeat yourself” and is one of the first clean code rules each developer learns. There is not much to explain with it: we should focus on avoiding logic duplication. This concept was introduced in “The Pragmatic Programmer” by Andrew Hunt and David Thomas by the quote: “every piece of knowledge must have a single, unambiguous, authoritative representation within a system”.
Why is this concept so useful? For example, if we have to change something in code that is written in multiple places there is always a risk that some place will be omitted by mistake and cause bugs. With only one block it is much easier to provide modifications with less risk of error.
Adhering to DRY promotes a modular codebase, which facilitates code organization and promotes a more systematic approach to development. It encourages developers to identify patterns and abstractions in their codebase, leading to more scalable and extensible software solutions.
But is the DRY way always the right way to go? That was the question we asked ourselves when we had to create a testing framework for one of our clients. After facing an already existing code base, we realized that blindly sticking to DRY rules might not always be optimal in the context of for example testing frameworks. The code was uneasy to follow, very hard to read and dedicated probably to very experienced QAs. That is why after careful consideration we decided to modify our approach to make code tell the whole story so even someone with limited programming skills can easily read and write tests.
Let’s take a look at two Hicron pages and contact forms:
This is the contact form from Hicron Software House:
This is the contact form from Hicron:
At first glance, both of the forms look alike. For this example, we will assume that both forms have the same elements to find them by. With DRY rules, we would probably try to add one method to fill the contact form.
This code will work perfectly for Hicron Software House form, but something is missing from hicron.com. So, now we have to add one additional argument and one conditional:
That does not look so bad, but what if there will be more contact forms? Like this one:
We have to add another conditional and another argument here:
With more cases, and more forms, the complexity of the code grows, and maintaining and debugging becomes more difficult. Also, the readability of code is reduced, and is hard to read and understand. The logic flow is harder to follow, especially if there are nested if statements. Future modifications are also harder to implement.
In our implementation instead of rigidly following the DRY principle, we decided to do things in a more pragmatic approach.
Each class of contact form has similar methods, simplifying the usage and maintenance of our codebase. As the methods have consistent names and behaviors across various classes, developers can quickly grasp how to interact with them. This approach made our code more resilient to changes in requirements or implementation details of each contact form. If any form differs from the others, having separate classes with distinct methods allows us to avoid unnecessary complexity or dependencies. For instance, instead of adding conditions or arguments to a method, we can create different methods tailored to each form, such as
fillNeededTechnologies("Angular")in NewContactForm.class
or
checkInformationClause() in HicronContactForm.class.
With this project, we prioritized practicality over sticking to the DRY principle. While we didn’t discard the principle entirely, we found that, in this instance, the advantages of code reuse or abstraction were overshadowed by the simplicity and clarity derived from employing straightforward, self-contained classes and methods. It’s essential to ensure that the chosen approach remains maintainable, understandable, and scalable as the codebase evolves over time. By carefully evaluating when to apply DRY principles and when not to, we were able to deliver a solution that met both the client’s expectations and our own quality standards.
While the DRY (Don’t Repeat Yourself) principle is important, it’s not always the best approach. Sometimes, prioritizing simplicity and clarity over code reuse leads to more maintainable code. Context, trade-offs, and the evolving nature of codebases all play roles in deciding when to apply DRY. It’s crucial to balance its benefits with practical considerations in software development.