Objects that protect themselvesintermediate
A class with public setters on everything cannot stop anyone putting it in an impossible state; moving the mutation behind a named method is how the rule becomes unbreakable.
A Payment whose state anyone can change, twice, without recording a transaction id. Close the door.
The only route into Paid is MarkAsPaid, it records the id, and it refuses to run twice.
Published in full, before you start — every point is one of these and there is nothing else.
A class with public setters on everything cannot stop anyone putting it in an impossible state; moving the mutation behind a named method is how the rule becomes unbreakable.
A cart that can hold the same product twice, or a quantity that can go to zero, is a bug you will chase through the UI forever — the rules belong in the data layer.