1

I'm trying to apply DDD principles to an application that has a REST API in front and is backed by an SQL storage.

Here's the entity structure I have come up with so far:

Client: 1 ---- * Contract: 1 ----- * Contract-AddOn: 1 ----- * Feature

The REST endpoints will basically represent the same structure. From

/api/clients

up to

/api/clients/:clientId/contracts/:contractsId/addons/:addonId/features/:featureId

I'll also have some business rules like:

  • A client can have only one active contract
  • A contract's addon cannot start or end outside the start-end period of the contract
  • ....

With these 2 rules in mind it sounds to me like the Client should ensure that there's no more than one active contract => Client should be aggregate of Contracts.

And then addon fields are restricted by Contract fields => Addons are entities in a Contract aggregate.

So it seems like everything should go under Contract, but this feels clumsy. And then comes the REST layer which should access the Client aggregate and get the Contract for a client, get its addons to remove a feature from an addon.

I guess I'm missing something in that model. I was considering if the two mentioned business rules are not just policies, but I can't quite grasp the difference between the two and which is used when.

What would be another way to model such relation ship? Or maybe DDD is just too much for a simple model as this one?

2 Answers 2

3

Determine your aggregate root. In this case it sounds like its Client as you have the one contract per client rule.

Pick your api interface.

  • Expose methods on the Client object tree. eg Client.Contract.AddFeature(Feature f)
  • Expose CRUD methods for the Aggregate root. eg Save(Client c);

Either way you can enforce the business rules on the server side, AddFeature can throw an error if the Client has too many features or whatever. But the second allows the client side to also check the rules; as it by definition has access to the entire data structure.

If your AR object is getting too big you can mix and match.

  • Expose method Client.AddContract(Contract c) throw error if Client rules are broken
  • Expose CRUD methods on child object SaveContract(c), client doesn't load the entire AR
2

An important thing to recognize is that your data model, your domain model, and your resource model are different things that should not be tightly coupled together.

There shouldn't be any intersection of aggregates - if client is the root of your aggregate, then all messages to entities within that aggregate are passed first to the client entity, so that it can manage the invariant for the whole.

When you are modeling, especially with regard to the invariant, it is important to keep track of whether your model is the "authority" for some piece of data, or if you are just doing bookkeeping.

1
  • 1
    "When you are modeling, especially with regard to the invariant, it is important to keep track of whether your model is the "authority" for some piece of data, or if you are just doing bookkeeping." I guess that's what confuses me. I do have these entities and each of them should be separately managed. However always under the scope of the entity above it. With that - said I don't want to go through a Client aggregate to reach the separate features. So I need to ensure the invariant between Contracts under a Client but at the same time I feel the Aggreage is becoming too huge to be manageable
    – Makpoc
    Commented Jan 25, 2019 at 12:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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