To take overly used e-commerce examples, a shipment class and its behavior would be part of the business domain of your application. A shipment is something real your company use to send products to their customers. It’s part of the business model of your company.

Therefore the logic of this shipment should only appear once in the application.

The reason is obvious: imagine that you need to send shipments to a warehouse. You need to trigger this logic in 76 different places in your application.

No problem: you repeat the logic 76 times.

After a while your boss comes to you and asks you to change the logic. Instead of sending shipment to one warehouse, you need to send them to three different ones.

The result? You will spend a lot of time changing the logic since you will have to change it in 76 places! This is a pure waste of time, a good way to produce bugs and the best method to piss your boss off.

The solution: create a single representation of your knowledge. Put the logic to send the shipment in one place and then use the representation of this knowledge anywhere you need it. In OOP, sending a shipment could be a method of the class Shipment you can reuse at will.

Another quick example: imagine you coded a fancy class to parse B-trees. This can be considered as well as knowledge: it’s an algorithm which should be defined once. The representation of that knowledge should be used everywhere without repeating the knowledge.

Dave is still not convinced though. With a serenity defying the highest spiritual masters through the ages, you give him the final stroke.

“Most people take DRY to mean you shouldn’t duplicate code. That’s not its intention. The idea behind DRY is far grander than that.”

Who said that? Dave Thomas, one of the author of the Pragmatic Programmer, the very same book defining the DRY principle itself!

DRY everything: the recipe for disaster

Dangerous generalities

Let’s take a more real life, interesting example:

I’m currently working on an application for filmmakers. They can upload their movies and their metadata (title, description, cast and crew of the movie…) on it easily. These information are then displayed on a VOD platform.

The content team of my company can as well use the same application to create the movie’s metadata when the filmmakers don’t want to do it themselves.

The filmmakers and the content team have both very different needs. The content team is used to work with CMS, the filmmakers are not.

Therefore we decided to create two interfaces:

The first one without guidance or explanation but where you can enter content as fast as you can for the content team.

Another one explaining everything you should do with a more user friendly approach for the filmmakers.

Here what we did:

We assume that the controllers from the two different applications are almost the same. We basically copy pasted them.

At that point if you plan to kidnap my friends and family to force me to change this code, please don’t. I need them.

This looks like an obvious and ugly violation of the DRY principle: views and controller repeated all over the place.

What were the other solutions? We could have grouped the common logic by using something like a template method, putting all the common logic in an abstract class. However this would have coupled the controllers of the different applications together.

Change the abstract class and every single of your controllers need to support the change.

In a lot of cases, we knew that the views would become different in the future, depending of the application. It would have create a lot of if in the controllers actions if we would have only a set of controller for both applications, not something we want. The code would have been way more complex.

Moreover the controllers shouldn’t contain any business logic. If you recall the definition of the DRY principle, it’s this knowledge, this business logic which should not be duplicated.

In short, trying to apply DRY everywhere can have two results:

Unnecessary coupling

Unnecessary complexity

Obviously you don’t want any of these in your application.

Premature optimization

You shouldn’t apply the DRY principle if your business logic doesn’t have any duplication yet. Again, “it depends”, but, as a rule of thumb, trying to apply DRY to something which is used only once can lead to premature optimisation.

If you begin to generalize something because “it could be useful later”, please don’t. Why?

You will spend time to create abstract classes and whatnot which might be only used in one place. Business needs can change very quickly and drastically.

Again, you will possibly introduce complexity and coupling in your code for… nothing.

Code reuse and code duplication are two different things. DRY states that you shouldn’t duplicate knowledge, not that you should code to be able to reuse everything.

What I learn through the years is this: code for the specific, don’t try to generalize. Even if your managers would love to have 90% of your application reusable for every single use case. In practice this is almost never possible.

Two functionalities, even if at the beginning look very similar, can become very different in the future. If you have any doubt, it is better to copy your code and let it takes different path. It’s way simpler on the long run than having a forest of if nobody understand anymore.

Code first, make it work, and then keep in mind all these principles you know (DRY, SOLID and so on) to refactor efficiently.
DRY principle violation should be handled when the knowledge is already and obviously duplicated.

Duplication of knowledge?

You remember when I stated above that repetition of business logic is always a violation of the DRY principle? Obviously this applies when the same business logic is repeated.

You can hear Dave your colleague developer gently screaming in your ears once again: “This is an obvious violation of everything I believe in! What about the DRY principle? My heart is bleeding!”.

However Dave is again wrong. From an ecommerce perspective, the delivery time of a shipment to a customer (Shipment::calculateDeliveryDay()) has nothing to do with the last day the customer can return his ordered products (Return::calculateLastReturnDay).

These are two different functionalities. What appears to be a code duplication is just a pure coincidence.

What can happen if you combine those two methods in one? If your company decide that the customer has now one month to return his products, you will have to split the method again. If you don’t, the shipment delivery will take one month as well!

This is not the best way to please your customers.

DRY is not only a principle for coding nerds

Even the Gin can be DRY nowadays!

DRY is not something you should only respect in your code. You shouldn’t repeat knowledge in every aspects of your project.

To quote Dave Thomas again: “A system’s knowledge is far broader than just its code. It refers to database schemas, test plans, the build system, even documentation.”

The idea of DRY is simple in theory: you shouldn’t need to update in parallel multiple things when one change occurs.

If your knowledge is repeated two times in your code and you forget to update one representation, it will create bugs. In your documentation it will lead to misconception, confusion and ultimately wrong implementation.

And so on and so forth.

DRY is a principle

At the beginning of my career, I was often victim of analysis paralysis. All those principles where holding me back to be productive and efficient. It was too complex and I didn’t want to screw everything.

However principles are not rules. They are just tools for you to go in the good direction.

Everything has a cost in development. DRY is no exception. Obviously you shouldn’t repeat your business logic all over the place, but you shouldn’t neither tightly couple everything because you don’t want to repeat your code.

In short: be careful not to extract your duplicate code and make everything depend on it.

Don’t get me wrong: extracting code to make it available at one place can be useful. However you need to find the good way to do it depending on your application. It must be a thoughtful decision.

Of course this article is meant to evolve regarding your experience and your vision of the DRY principle. It is a very broad (and philosophical) subject so don’t hesitate to leave a comment.