Do not Repeat Yourself (DRY) is quite contentious these days. While it is one of the pillars of the SOLID principles, it is pretty easy to misinterpret and abuse. It is a balancing act between too much repetition and too much generalization.
There are very few clear guidelines like so many other things in software development. So different people apply it to different levels, which makes code that can look and feel inconsistent or just plain abused. Leaving some to call DRY evil.
I would argue that it is evil not to use it enough, and it is evil to use too much…
What makes DRY evil
DRY is usually applied at the code level. If one sees that you’re about to write the same code that already exists, then it might be a good thing to put it in a function. If a group of classes performs some function that can be used somewhere else, maybe it makes sense to reuse it. If a bunch of functionality can be reused across applications, it might be a candidate for a module or a package.
Then you start reusing everything. And you create hundreds of functions, begin creating generic classes for everything, create packages and push them to npm or NuGet, and grow the tentacles of your software.
Then your requirements change in one place, so you update the reusable functionality; you don’t modify the interface, so no other code is affected. But what happens to the rest of the code that is using it? Is it still valid? Does it still work as it should?
What if you have to change the interface? Then you have to change every call into this functionality. What if your package is used by thousands of applications?
You either end up with code you cannot change or code you cannot reuse. There are ways around that, but at some point, it is no longer simple reuse…
DRY and the Software Factory
In the early days, when modifying solutions was a lot more complicated, I made serious efforts to create reusable libraries for many things. I ended up with dozens of different libraries for data access, client calls, and a lot more.
The Software Factory (SF) problem was not to change the calls to the libraries; it was to make the library available to the generated code. I had to compile it, place it in a specific folder, and add configuration to tell the compiler where to find the libraries.
Once I had better tools to modify the solutions, I started migrating the code for these libraries directly into the solution so it could just be generated along with the code using it.
The Software Factory does not reuse code,
it rebuilds it
Then I started reusing generated code in other generated code. Again, that was problematic because I had to deal with these libraries again. But in addition, I also had compile-time dependencies.
When I started studying micro-services, I started seeing things differently. I wanted my code to be as independent as possible. I tried to reduce, even eliminate, external dependencies. That is when I started to focus on generating most of the reusable code directly in the projects. It became part of the project.
So today, in terms of code reuse, the SF does not reuse and creates multiple copies of the same code.
And that’s OK. The Software Factory does not reuse code; it rebuilds it.
Why is it the ultimate DRY machine, then?
So, if the SF does not reuse code, how can it do DRY? Because it works at a higher level: It reuses patterns, not code.
Patterns are defined as a template for code generation. Once a pattern is specified, all the appropriate code will be written every time it is needed.
It requires no reference to libraries or other code that can get out of sync. It all gets written together at the same time. All the pieces fit with each other all the time.
And, when the pattern changes, the new pattern will be applied everywhere it is needed when the code is regenerated.
The user does not write the code; the system does…