Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
DRY Principle is seemingly advocated for or against. In reality, it’s not good or bad so as long as you understand why you’re applying it and for what purpose. Misunderstanding DRY is why your system can turn into a hard to change rats nest.
YouTube
Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.
Don’t Repeat Yourself (DRY)
“Don’t repeat yourself” (DRY), also known as “duplication is evil”, is a principle of software development aimed at reducing repetition of information which is likely to change, replacing it with abstractions that are less likely to change, or using data normalization which avoids redundancy in the first place.
When it comes to DRY, opinions are all over the map. Some folks swear by it, while others argue it’s the worst idea ever. The truth? It’s not inherently good or bad; it’s all about understanding its application.
The key takeaway is that when DRY is applied correctly, modifying any single element of your system shouldn’t force you to change unrelated elements. This principle can be a double-edged sword, and it’s vital to grasp what you’re trying to accomplish with it.
DRY in Action: A Coding Example
Let’s look at some code to illustrate this. Imagine we have two methods: shipDistance
and tollDistance
. Both methods sum distances, but they also convert miles to kilometers, which is the format our system uses.
Now, you might think, “Hey, these methods are similar! Let’s merge them or create a private method for the conversion.” Sounds reasonable, right?
But here’s the catch: in a larger system, that conversion might need to be applied in multiple places.
Now, why does this matter? If you’ve got this conversion method being used throughout your system, changing it could lead to a nightmare. Let’s say you need to adjust the rounding or the number of decimal places. Sure, you might have tests that ensure the outputs are correct, but are you testing that the outputs meet client expectations?
The return type is a double. We can still return a double but start limiting the decimal places. Will that have an negative effect on calling code?
That’s where things can spiral out of control. The more you couple your code together, the harder it becomes to make changes.
Entities vs Activities
Another pitfall is focusing exclusively on entities or nouns in your system. Think about a transportation system with entities like trucks, drivers, orders, and shipments.

While those are important, what really matters are the activities that need to occur. You’ve got capabilities like unhooking a trailer, seating a driver in a truck, and dispatching an order. Those activities are what drive your system.

For instance, seating a driver involves both the driver and the vehicle.
Unhooking a trailer is a totally different concern. It involves a trailer and a vehicle.
If you apply DRY to entities without considering the activities, you can end up creating a tangled mess of dependencies. Each entity shouldn’t represent multiple concepts; instead, focus on the unique capabilities your system needs to support.
Don’t Repeat Business Concepts
When you think about the DRY principle, remember: don’t repeat business concepts. This applies to both entities related to workflows and the capabilities users are trying to perform. If you’re unhooking a trailer, it’s different from dispatching an order, even if they involve similar entities. Each capability should have its own context, and that context should inform how you structure your code.

If you’ve heard of vertical slice architecture and thought it was just about code organization, think again. It’s about increasing cohesion around capabilities to reduce coupling. This approach has been around for a while, but it’s gaining traction because it emphasizes boundaries based on capabilities, not just uniformity in design.
Defining boundaries helps you manage complexity. It doesn’t mean everything needs to be uniform; it just gives you the flexibility to decide how to structure your application. Whether you have a simple application layer or a more complex domain model, it’s about reducing coupling and increasing cohesion.
Applying DRY Wisely
Ultimately, the DRY principle isn’t inherently good or bad. Its value lies in how you apply it. Heavy reliance on DRY can lead to more coupling, making changes harder down the line. It’s a balancing act; too much DRY can become a burden.
Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.