I'm interested to see how supporters of the "Always-Valid" entity approach (vs isValid method later) would suggest modelling a object with collections. I really like the idea behind this approach, but I am having difficulty with implementing it as my objects get a bit more complex. I'm wondering, do I need to force users to only use one update method, with all fields specified?
In example:
public Meeting
{
public string Name {get; protected set;} -- must have
public DateTime Time {get; protected set;} -- must have
public IWine Wine {get; protected set;} -- optional
public string Notneeded2 {get; protected set;} -- optional
public string Notneeded3 {get; protected set;} -- optional
public string Notneeded4 {get; protected set;} -- optional
public string Notneeded5 {get; protected set;} -- optional
public string Notneeded6 {get; protected set;} -- optional
public IUser Chair {get; protected set;} --must have
public List<IUsers> Users {get; protected set;} --must have
public bool isBoardRelated {get; protected set;} --must have
public List<IBoardUsers> {get; protected set;} -- if isBoardRelated, then must have
private void CheckInvariants()
{
if (blah == null &&....etc)
{
throw new ModelInvariantCheckException("Catch me and cry");
}
}
}
So, should the following present the user with only one constructor and one update method with all fields specified? Or should multiple constructors be used? Would allowing certain properties (optionals) to have public setters make things inconsistent?
Or do people prefer using an isValid method that must be called later?
I must say, my preference is to have invariant checks as it feels safer, but having to add every property to both constructor and update method makes things a lot slower when calling between layers, and even object setup. Collections consisting of always-valid classes exacerbates this.
When practicing Domain Driven Design, you want to avoid a big Update method. Update methods don't capture the language of your domain - they bring database language into your domain. Try to make the language explicit, and you will be able to extract value objects, invariants and intent-revealing methods that mutate the state of your entity.
Maybe you can find some inspiration here.