Skip to footer content
Iron Academy Logo
C# Common Problems

DRY Principle in C#: Why Code Duplication Is Hurting Your Codebase – Explained by Derek Comartin

Derek Comartin
8m 01s

When we talk about writing maintainable code in C#, one fundamental concept that often surfaces is the DRY principle — Don't Repeat Yourself. It's a pillar of software development that aims to eliminate redundancy, reduce code duplication, and improve code maintainability.

But like many design principles, DRY can be misunderstood and even misapplied. In his video "DRY principle is why your codebase sucks?", Derek Comartin from CodeOpinion.com offers a candid and pragmatic look at how the DRY principle should and shouldn't be used — especially when developing in .NET Core or similar ecosystems.

In this article, we’ll dive deep into Derek’s explanations, walking through his examples and commentary from the video. Whether you're starting a new project in Visual Studio, maintaining an existing code base, or simply refactoring for better code reusability, Derek’s insights are practical and relevant.

DRY Principle Defined

At the start of the video, Derek frames the context many developers face: dealing with a system that's difficult to modify — a tangled mess of repeated code and redundant logic.

He introduces the DRY principle in C# as a strategy to reduce code repetition, but warns that it's often misinterpreted. As Derek explains at 0:28:

“When DRY is applied successfully, a modification to any single element of the system does not require a change to any logically unrelated elements.”

This distinction is critical. The DRY principle aims not just to avoid duplicate code, but to promote separation of concerns and proper code reuse — leading to maintainable, dry code that’s easier to test and refactor.

Practical Example: Distance Conversion

To make things tangible, Derek offers a simple example in C#. He writes two methods:

  • ShipDistance

  • TollDistance

Each calculates distances in miles, then converts them to kilometers — using the same logic in both methods. This is classic code duplication.

Instead of having the same piece of code in multiple places, Derek shows how you could extract the conversion logic into a private method — MilesToKilometers() — a basic but effective way of refactoring code for reusability.

He illustrates this using the typical console app structure: a class Program with a static void Main. It's the kind of structure many developers use when testing logic or experimenting with a new user input scenario like public int age, string username, string password, etc.

DRY vs. Over-Coupling

While abstracting logic into a reusable method or a separate class sounds ideal, Derek urges caution. Overusing DRY, especially across an entire application, can lead to dangerous levels of coupling.

For example, if you place conversion logic into a shared utility used by multiple projects, and later change its rounding behavior or decimal precision, the change could unexpectedly affect many areas. As Derek puts it at 2:31:

“Are clients expecting two decimal places? What happens if we change it to zero?”

This is a cross-cutting concern — logic reused by many parts of the system — and it illustrates the risk of centralizing too early or without clear boundaries.

Derek’s advice here echoes the Single Responsibility Principle and the Dependency Inversion Principle, two other SOLID principles critical to keeping your code adaptable and modular.

Code Bloat from DRY Gone Wrong

Another problem with DRY misuse is code bloat — where trying to abstract everything leads to bloated utility classes or overly generic methods. Derek warns that over-DRYing logic can cause more harm than help, especially in large systems where bug fixes in one area can break others due to shared dependencies.

The key, according to Derek, is knowing when not to share code — especially if it results in tightly coupled modules. DRY isn't a rule; it's a guideline that must be used with context.

DRY Applied to Entities: A Recipe for Complexity

Derek identifies a common developer tendency: organizing systems entirely around entities like Truck, Order, Driver, and Shipment. While it's tempting to reuse the same class or object across different methods, this often leads to repeating concepts and unwanted coupling.

He argues that business capabilities — not just data structures — should drive the architecture. For instance, “dispatching an order” is a different concern than “unhooking a trailer,” even if they involve the same entities.

At 4:45, Derek explains:

“A singular entity in your system does not need to be a representation of multiple concepts.”

This highlights a deeper architectural insight: entities with the same name (Vehicle, Trailer) might represent different responsibilities in different workflows. Using them interchangeably creates confusion and tightly couples unrelated business logic.

DRY and Business Capabilities

To resolve this, Derek introduces Vertical Slice Architecture (VSA) — a pattern that structures applications around business capabilities instead of layers. Each “slice” includes everything needed for a specific action or use case — from request to database — encapsulated and self-contained.

He emphasizes that DRY code is good within a slice — inside a single location — but applying DRY across slices can lead to entangled dependencies. At 6:44, he adds:

“It’s just about reducing coupling, increasing cohesion... and one way of doing that is: don’t repeat concepts within a boundary.”

This boundary-driven thinking gives you flexibility. You might have a full domain model in one slice, and just a lightweight data model in another. It's up to the needs of the slice — a pragmatic approach aligned with The Pragmatic Programmer philosophy.

Final Thoughts

Derek closes by reframing DRY as a tool, not a law. As he puts it at 7:00:

“It’s just understanding how you’re applying it. If you’re applying it heavily, you potentially have more coupling.”

So before extracting that validation logic, connection string, or converting repetitive code into a separate method, consider whether doing so will actually make your entire code base more maintainable — or just harder to change.

Conclusion

Derek Comartin's breakdown of the DRY principle in C# shows how a seemingly simple rule can backfire when applied without nuance. By walking through code examples, discussing practical scenarios, and stressing software design principles, he reveals the balance needed between reusability and modularity.

To significantly enhance your development process, remember:

  • Use DRY to refactor redundant code within a clear boundary.

  • Don’t DRY up entities that serve different business purposes.

  • Respect context when centralizing logic — especially across multiple places or projects.

  • Consider unit testing and how dependency injection might affect shared code.

By applying these lessons, you’ll write more efficient, modular, and maintainable C# code — and avoid turning your codebase into a rat’s nest of duplicate logic and tangled dependencies.

You can watch Derek Martin's full video for more insights on CodeOpinion's YouTube channel.

Hero Worlddot related to DRY Principle in C#: Why Code Duplication Is Hurting Your Codebase – Explained by Derek Comartin
Hero Affiliate related to DRY Principle in C#: Why Code Duplication Is Hurting Your Codebase – Explained by Derek Comartin

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!