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.
Domain-Driven Design misconceptions often come from treating DDD like a checklist of patterns. Have you ever looked into Domain-Driven Design and thought, “Wow, this is totally overkill”? Well, you’re not alone. And I kind of agree, but not for the reasons you might think.
I say you’re not alone because of this meme I did a video about that keeps giving. Somebody replied, “Learning .NET DDD sent me back to learning MVC. It’s so stressful.” I was kind of confused by this, and then somebody else was as well, saying, “What is the connection from DDD to MVC? It’s design patterns, I think.”
And there’s the smoking gun.
YouTube
Check out my YouTube channel, where I post all kinds of content on Software Architecture & Design, including this video showing everything in this post.
I had a feeling this was going to happen, although I thought maybe, hey, it’s 2025 and we’ve gotten past this now. But clearly not, because a lot of people still think it’s about a checklist. A checklist of patterns you have to apply rather than it simply being a matter of understanding the domain, understanding the business, and modeling it.
The Code We’ve All Seen
Tell me you haven’t run into this.
I’m using the example of a shipment. We have this UpdateShipmentStatus command where we take a shipment ID and what the status is. That’s probably invoked from some MVC controller or endpoint.
Then we have this handler that’s invoked where we pass that command in. What are we doing here? Oh, there’s a repository where we’re getting the shipment. Then we call UpdateStatus and save it.
Let’s take a look at what UpdateStatus does.
Almost nothing. Really just changing the property.
Tell me you haven’t seen this before.
I’ll give you another example you can probably relate to.
Let’s say we have a Customer aggregate. It’s the aggregate root. It’s a domain entity. It has relationships to the order history, the addresses, maybe when you’re looking at this aggregate it also publishes domain events.
Pretty impressive, right?
It’s using all the DDD lingo. You’re looking at this code. It has the relationships. Sounds great.
Not really.
Because it’s not capturing any business logic. Any behavior at all. What it’s really doing is just capturing structure of data. That’s it.
Domain design is not about design patterns. But a lot of people think it is. Which ties back to why people think it’s complicated. They think they have a checklist of patterns, entities, aggregates, value objects, repositories, shared kernel, all these things they read about, thinking, “I need all this stuff to apply DDD.”
And guess what?
You probably aren’t in a domain that even warrants it.
That’s why it seems complicated. Like my code example that needed none of those patterns.
It’s not about design patterns. It’s about the language you use within that domain, the workflows involved, the business logic, and the domain rules.
It’s Called Domain Driven Design
What I’m about to say may sound ridiculous, but take a step back for a second.
Domain Driven Design.
Not pattern driven design.
Not aggregate repository driven design.
Domain. Driven. Design.
It’s in the title. What do you think you’d actually be focusing on?
Probably the domain.
Domain-Driven Design misconceptions have a lot to do with the content published online. To be fair, a lot of the content published around DDD is getting. It doesn’t focus only on the tactical. It talks about the strategic, the stuff I’m talking about: bounded contexts, ubiquitous language, subdomains, context maps. All that.
But people latch onto the tactical. They see entities, aggregates, value objects, and want to disregard everything else and just focus on patterns.
Where DDD Actually Shines
Where DDD shines, in my opinion, is around complexity of a domain, specifically workflows.
Let me give you a simple example in the shipment world.

There’s a whole workflow and lifecycle that a shipment might go through. There’s a business process:
- The order is dispatched.
- The truck or vehicle doing the pickup arrives at the shipper.
- The freight is loaded onto the vehicle.
- It departs from the shipper.
- It arrives at the consignee.
- It’s unloaded and delivered.
I’m simplifying this, but you can imagine multiple shipments for multiple pickups with multiple deliveries, where things are split, part of the freight goes here, another part goes there. It can get very complicated. But there’s a lifecycle. There’s a workflow.
This is where DDD shines.
And you’ll notice in that workflow, I was using language that’s very domain-specific that anyone in it would understand. It wasn’t “update shipment,” like my initial code example where I was just setting a status. It was specific about events and actions that actually occurred.
That’s what DDD is for: capturing decisions, transitions, rules.
So, if I’m using something like an aggregate, that’s what I’m using it for. I have a shipment where I’m making sure it’s always in a valid state because there are state transitions it has to go through.
I’m checking things like:
If I want to arrive at a particular stop, are all previous stops departed? If I’m trying to arrive but something earlier isn’t valid yet, that’s wrong.
Same thing on pickup. Is this the stop you should be departing from? Are there others before it that aren’t in the right state?
We’re making sure we’re always in a valid state.
Think of any example you have in a complex domain. I’m simplifying this, but you get the idea. You have logic tied to workflow, tied to state, making sure it’s always valid.
Where the Value Really Is

I put a lot of value in the strategic aspect of domain design, the language, the modeling.
What does that mean in code?
That’s where the tactical stuff comes in.
Entities, value objects, aggregates. They’re tools. They’re not the starting point.
There is value in the patterns people describe in DDD. Absolutely. But they’re a means to an end.
They’re not where you begin.
And this is why people think DDD is complicated, they’re starting from the tactical and trying to apply that to parts of the system that don’t need it at all.
This is typical. In my shipment example, the shipping workflow might be very complicated, but other parts of your system are simple. They support that complexity. Customer management, CRM, things like that, very basic.
Do they need all the tactical patterns?
No.
Can you still be explicit about language? Sure. But if it’s just CRUD, and it really is just data-driven structures, with no behavior or workflow, that’s fine.
So back to the original example of updating a shipment status. Does that make sense in a shipping system? Probably not.
But maybe if the whole system is just capturing status and nothing more. Maybe the workflow lives in someone’s head, not in software. If that’s all you’re doing, CRUD, why do we have a command, a handler, a repository, a domain entity that’s really just a data bucket with a setter?
That’s not DDD. That’s just applying patterns for the sake of patterns.
The tactical patterns make sense when they actually solve the problem you have. But that only happens once you understand the domain. It can’t be the other way around.
Talk to People First. Patterns Later.
Domain-Driven Design Misconceptions come from starting with patterns. Patterns are not bad. They’re just the wrong starting point.
Start by talking to people within the domain. Model workflows. Use the business’s language.
Then reach for things like entities and value objects.
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.
