1

I'm building a REST service in java that does basic CRUD operations on Customers. The easy way would be for me to create one Customer model, and annotate it with JPA annotations so my persistence layer knows how to map it to the DB and add some jackson annotations so that my web layer knows how to deserialize it from http requests and serialize it into responses.

If I'm doing things the correct DDD way, should I have 3 versions of Customer?

  1. A Customer Domain object not polluted by annotations
  2. A CustomerDTO for the web layer with the jackson annotations
  3. A CustomerPersistence object with the JPA annotations

This seems like a lot of versions of the same thing, does anyone do things this way?

  • 1
    DDD doesn't really care about your implementations, except insofar as the ubiquitous language informs your design decisions. A methodology like DDD must necessarily be reasonably language and platform agnostic if it is to be applicable to multiple languages and platforms. – Robert Harvey Feb 12 '18 at 19:57
  • 1
    Instinctively I feel like Eric Evans never intended entities to have three versions of themselves when he wrote his book. I'm quite certain that he wasn't considering JPA and jackson annotations. – Robert Harvey Feb 12 '18 at 20:00
  • I do. But in many cases is overkill. It's just me, I'm kinda paranoic about changes in the last minute. I tend to decouple everything. It also take me longer to develop and test due to the verbosity of the code. Basically #1 and #3 are ok as soon as both models difers each other. Ultimately, what we store is not the domain. It's the state of certain elements of the domain. #2 is ok when consuming #1 would be too costly for the client. Or we are modeling a command-like service. For instance RPCs. – Laiv Feb 12 '18 at 22:10
1

I'm building a REST service [...] that does basic CRUD operations [...]

This is the key to your question: if you're just doing simple CRUD on your entities with maybe a little bit of simple validation, a full blown rich domain model is most likely overkill for your application.

I would recommend to start with a simple, anemic model (annotated as needed), and the corresponding CRUD service classes/methods. If, at some point in the future, your domain logic becomes more complex, it's time to refactor.

At that point, it's quite likely that this 1-1-1 mapping of Web-Domain-Persistence model will break down anyway.

0

This seems like a lot of versions of the same thing, does anyone do things this way?

It does seem like a lot of versions that are currently the same thing.

Logically, you really have three different things going on.

You've got the model's own understanding of its domain. Part of the motivation for investing effort into modeling the core domain well is that you derive a lot of competitive advantage from it. You want a design that is easy to change, so that you can quickly adapt the model to new insights and new opportunities.

You've got the persisted representation; fundamentally, that's a message from a past version of the model to new model. Migrating your database to align it with your new model is potentially expensive, and introduces a counter force to the changes you'd otherwise like to make in the model.

Put another way, you've got a backwards compatibility concern. You don't necessarily need two different representations, but you do need to be able to decouple the model and the persistence, because they are really responding to different forces for change.

It's not absolutely critical, though; as long as you aren't sharing your persisted data to promiscuously, you can perform a migration exercise when you need to.

Your web api, however, has a very different calculus. Like persistence, it has a strong compatibility requirement; but what the API is coupled to is other consumers, outside of the boundary of the service itself. Introducing a breaking change here is extremely painful, because you have to start coordinating changes among what had been separate autonomous units.

They are three logically distinct concerns that happen to have coincident shapes today. YAGNI says that you don't have to separate those concerns yet. Who knows, maybe the project will never be successful enough to justify the work, or maybe you will never actually need to change this part of the app. If things are successful, it's likely you'll know more tomorrow about how to make the change than you do today.

Put another way: keeping the implementations of these concerns is a way of introducing technical debt.

The savvy developer treats technical debt just as the entrepreneur does financial debt. They use it. It speeds delivery, so long as it is properly managed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.