I'm having trouble modelling a relationship in DDD. I have four entities:
- Claim - defines access to a Service.
- Service - a web service. A Service has many Claims and can belong to any number of Teams.
- Role - contains a collection of Claims from any number of Services. Roles always belong to a Team.
- Team - contains a collection of Roles, and Services.
When I remove a Claim from a Service, it should also be removed from all Roles that have that Claim assigned to them. Equally, when I change the name of a Service, that name should be reflected in all the Teams.
I currently have a Service aggregate root (to allow Services to be added and altered independently of any one Team), and a Team aggregate root (to allow management of Team-specific Roles). This creates two problems:
- Changes in the Service aggregate are not reflected in the Team aggregate
- When a Claim is removed from a Service, there is no way to cascade this into the Team's roles.
There's something clearly horribly wrong with my model, and was wondering if anyone can illuminate where I've gone awry.
-
1This sounds like a description of your attempted solution to model the problem, but without any description about the problem itself. See What is the XY problem?Ben Cottrell– Ben Cottrell2016年04月14日 15:11:40 +00:00Commented Apr 14, 2016 at 15:11
-
The requirements are specified in condensed form in the first four bullet points.pixelbadger– pixelbadger2016年04月14日 15:46:50 +00:00Commented Apr 14, 2016 at 15:46
-
1Note that DDD is not a software development methodology; it is a software design methodology. Nothing in DDD prevents you from actually writing code that performs your required functions.Robert Harvey– Robert Harvey2016年04月14日 15:55:10 +00:00Commented Apr 14, 2016 at 15:55
1 Answer 1
Why does a Role have a direct relation to Service, when the relation obviously requires a Claim to exist? Just forget about that one.
Respectively where is there a relation between Service and Team? Add an indirection via an Ownership entity to model that.
Choosing Team and Service as the only root aggregates is correct.
Team 1 <-> * Role
Role 1 <-> * Claim
Service 1 <-> * Claim
Team 1 <-> * Ownership
Service 1 <-> * Ownership
By making the relations traversable in both directions, you can already reach each entity required to access all related information required.
There is no actual need to ever store Service names in a Team, that information can be aggregated by navigating both along the Claim and the Ownership relations.
As a Claim holds both a reference on a Role and on a Service, you must traverse both parents when deleting a Claim. The same goes for Ownership. It doesn't matter which parent owns the child and which just holds a reference, that's just an implementation detail.
-
1My understanding was that relationships should have a single traversable direction.pixelbadger– pixelbadger2016年04月14日 16:08:42 +00:00Commented Apr 14, 2016 at 16:08
-
1Navigation may be allowed either unidirectional or bi-directional, that doesn't matter. What you mean is probably parent-child relations in languages which differentiate between objects (as values) and references, as there can be at most (or depending on the language: exactly) a single owner. But even then you may always add a reference for navigating the opposite direction. Doesn't matter at all for languages with garbage collection, as they usually don't even know a concept of ownership.Ext3h– Ext3h2016年04月14日 16:16:00 +00:00Commented Apr 14, 2016 at 16:16