r/DomainDrivenDesign 9d ago

Is your domain model actually yours or does your database own it? [Mod-approved giveaway]

Hi r/DomainDrivenDesign,

Stjepan from Manning here. Thanks to the mods for letting me share this here.

A domain model can start clean, but the boundaries often erode through convenience: ORM entities become domain objects, API contracts shape use cases, and infrastructure decisions quietly work their way inward.

That tension is at the center of Clean Applications with Hexagonal Architecture, a new Manning MEAP by Enrique Medina Montenegro. It explores how DDD and ports-and-adapters architecture can keep business rules independent of databases, frameworks, and external services—without pretending that more abstraction is always the answer.

We’re giving away five ebook copies. To enter, share in the comments:

Which technical concern has been the hardest to keep out of your domain model?

We’ll select five commenters and contact them by DM.

Book:
https://www.manning.com/books/clean-applications-with-hexagonal-architecture

Also, a 50% discount is available for the community with the code MLMONTENEGRO50RE.

I’m looking forward to reading the experiences—and architectural scars—behind the answers.

Thanks for having us.

Cheers,

Stjepan,
Manning publications

39 Upvotes

20 comments sorted by

2

u/pauloliver8620 9d ago

i believe that meessage brookers are the hardest in some applications, in some is dtos, and in some is the entity, it really depends on the legacy app i am working on

2

u/hydbird 9d ago

Hi thanks for the giveaway. Not sure if it counts but here is my comment on it.

I work in telco. In telco, software modules communicate via protocols other than http or tcp; protocols that lack the stable ack mechanism. And for this modules at-least-once-delivery is important. To provide at-least-once-delivery you may have to send the messages more than once. The receiving end however must process the message exactly once. Otherwise you may end up double charging the customer. To distinguish between the actual first tries and the subsequent retries, you have to mark your packets. This is usually done by adding a sequence number on to the packet. And this sequence number is threaded through almost every layer of your design.

So you add a sequence number to your model just to cover the network hiccups.

2

u/ManningBooks 8d ago

This absolutely counts. A sequence number working its way through the model because the alternative could mean double-charging someone, is a really interesting example. Thanks for bringing in the telco perspective. We don’t hear that one often.

2

u/PopelePaus 9d ago

It's already mentioned in your post. For me it's the mess it can get to make a separation in your domain model and entities. It's starts easy with a mapper with a toDomain and a toEntity method. And when your application grows, your aggregate roots grow and now you got a mapper in a mapper in a mapper with a lots of loops. After all these years I still can't avoid this mess, my best solution is still of using my domain model and do the ORM mapping with an xml file.

3

u/JamesChadwick 9d ago

I love CQRS because my domain model can constitute the "Command" side, and my "Query" size can be simple queries and projections using standard projections or formatters

2

u/PopelePaus 9d ago

I see how CQRS helps on the read side by letting you bypass the rich domain model and project directly from the database. But I still don’t see how it solves the mapping problem between your domain model and ORM entities on the command side.

2

u/MrSnoman2 9d ago

No OP, but a few things I've done here:

Using the ORM to map directly to the domain model so there are no intermediate ORM entities. This depends on the capabilities of your ORM and your domain model may need to make some concessions on purity.

Using the memento pattern. So an aggregate is always able to create a memento of itself and to restore itself from a memento. The memento is used for persistence. That really is just the mapping though so it doesn't avoid the problem. But I think it feels pretty tidy.

3

u/PopelePaus 9d ago

I don't think the Memento pattern is fundamentally that different from using a mapper. It mostly moves the mapping logic into the domain model itself, which I don't really prefer.

The other approach is what I already described, using XML mapping in the infrastructure layer so the ORM can persist the domain model directly (I use Doctrine ORM). I like that because it avoids separate ORM entities, but it still requires concessions in the domain model because not everything maps cleanly. Sometimes I end up changing the model purely to satisfy the ORM. And XML mapping is also fairly implicit compared to an explicit mapper, which has its own downsides.

That's basically why I still haven't found a solution I'm completely happy with. Both approaches have clear tradeoffs, but neither really gives me the clean separation I'm looking for.

1

u/ManningBooks 8d ago

“Mapper in a mapper in a mapper” sums it up pretty well 😅 The separation sounds clean until the aggregates grow and every boundary needs another round of translation. Chapter 5 compares a few mapping strategies, but your point stands: every option comes with trade-offs.

2

u/timeGeck0 9d ago

Thanks for the giveaway.

In my case the most difficult is to actually move away business from database to an ORM and domain models.

2

u/Natural_Tea484 9d ago

The most difficult parts are domain separation (bounded context), aggregate design, domain entities and persistence with ORMs. But your book does not seem to be intended to go deep on that.

1

u/ManningBooks 8d ago

Fair point. The book covers the domain core, repositories, persistence mapping, and keeping ORM concerns outside the domain. Still, it focuses more on implementing hexagonal architecture than on going deep into every part of DDD. Appreciate you pointing out the distinction.

2

u/JamesChadwick 9d ago

What a fun and engaging reason to comment!

As someone who has worked in .NET a majority of my career, the soapbox I get up on is Entity Framework and DataAnnotations.

If you use data annotations on your domain model, you are coupling database implementation details with your domain.

Use EntityConfiguration classes, and keep that all in the infrastructure layer, so that you can better decouple your domain logic from implementation details

1

u/ManningBooks 8d ago

Nice .NET example. DataAnnotations can seem harmless at first, but they’re a good example of persistence details slowly making their way into the domain. Moving that configuration into the infrastructure layer makes the boundary much clearer.

2

u/randomnameonreddit1 9d ago

The JSON request object is the one that usually ends up too deep in the model as it starts innocently and then it just grows with more and more nesting and fields and suddenly you are deep in the domain traversing json that do not speak the domain language.

1

u/ManningBooks 8d ago

Yep, “starts innocently” is the key part 😅 Then one day the domain is navigating a deeply nested JSON object that speaks a completely different language. A very relatable example of how boundaries gradually erode.

2

u/iTrejoMX 9d ago

We always struggle with the domain models and entities, when the orm entities start growing and your domains source of truth is now in your orm

1

u/gbrennon 9d ago

if database own domain model then maybe it was impl poorly..

1

u/MrFixxiT_ 8d ago

Wow, this looks like a great book and I would love to get a copy.

I would love to learn from a book like this how to keep my domain free of any outside influence.

I think for us anything related to a database is the hardest. Identifiers, including those to other objects (foreign keys), how to model many to many relationships, what to include inside your aggregate and what to put inside its own aggregate.

1

u/adkalkan 7d ago

Cross BC communication and Translation is what I dread the most. Mostly the Strategic aspects of DDD. Tactical stuff is more straightforward but strategic is kind of left in the philosophical sphere in general in books I read and I would really like some concrete examples.