I am looking for some advice on DDD modelling and specifically nested levels of ValueObjects.
Take the below code, this is a dumbed down sample of how my domain is starting to take shape. This is all within my Contracts bounded context and have identified the Contract as the aggregate root. This does make sense based off discussion sessions with the domain expert but I wonder if I am going about this the wrong way.
The issue I have with this nesting is that:
1 - I have now lost the ability to create concise domain events such as TreatyDetailsCreated but instead need to fire events a level above so ContractCreated as an example.
2 - My commands are starting to follow this similar nesting format again causing them to lose clarity
3 - I am now forced to load the Contract each time I am required to update something deep in the graph and that these higher value objects are not required to enforce invariants.
My question is would I be better looking into potentially having my first level nested objects defined as aggreagtes? This would solve my nesting issue and allow me to gain back descriptive domain events. My invariants will only be enforced at the Contract level at the point of submission and will likely be handled within a Domain Service due to the complexities so Contract feels like a logical container more than anything.
public class CreateContractCommand
{
public CreateTreatyDetails CreateTreatyDetails { get; set; }
}
public class CreateTreatyDetails
{
public string Umr { get; set; }
}
public class Contract : Aggregate
{
internal TreatyDetails TreatyDetails { get; private set; }
private Contract() { }
public static Contract Create(CreateContractCommand command)
{
var contract = new Contract {TreatyDetails = new TreatyDetails(command.CreateTreatyDetails)};
//Raise domain events
return contract;
}
}
public class TreatyDetails : ValueObject
{
//Additional properties removed for simplicity
public Umr Umr { get; private set; }
public TreatyDetails(CreateTreatyDetails createTreatyDetails)
{
Umr = new Umr(createTreatyDetails.Umr);
}
}
public class Umr : ValueObject
{
public string Value { get; private set; }
public Umr(string value)
{
//Validate value
Value = value;
}
}