2

I have a class Document and document has a status:

public enum DocumentStatus : byte
{
    Incompleted,
    Completed,
    Cancelled
}

Now I have a dilemma I can't solve alone.

Should Document have methods like Cancel and Complete and domain events like DocumentCancelled and DocumentCompleted

public class Document : Entity, IAggregateRoot
{
    ...

    public DocumentStatus Status { get; private set; }

    public void Cancel()
    {
        Status = DocumentStatus.Cancelled;
        this.AddDomainEvent(new DocumentCancelled(this));
    }

    public void Complete()
    {
        Status = DocumentStatus.Completed;
        this.AddDomainEvent(new DocumentCompleted(this));
    }
}

Or would it also be fine to make Status setter public and have domain event like DocumentStatusChanged?

public class Document : Entity, IAggregateRoot
{
    ...

    private DocumentStatus _status;

    public DocumentStatus Status
    {
        get => _status;
        set {

            this.AddDomainEvent(new DocumentStatusChanged(this, _status, value)); // oldValue, newValue

             _status = value;
        }
    }
}

In this case is this better than using a method like:

public class Document : Entity, IAggregateRoot
{
    ...

    public DocumentStatus Status { get; private set; }

    public void SetDocumentStatus(DocumentStatus status)
    {
        this.AddDomainEvent(new DocumentStatusChanged(this, Status, status)); // oldValue, newValue
        Status = status;
    }
}

Sorry if this sounds trivial or stupid but I'm new to DDD and trying to follow the best practices.

4 Answers 4

1

Should Document have methods like Cancel and Complete and domain events like DocumentCancelled and DocumentCompleted

Don't create events if your application won't be listening to them. Unless you are working on a traditional application (i.e. desktop or phone) then the events are not very helpful. The methods are a good idea. They make the Document status a read-only attribute, and the act of cancelling or completing a document is free to have other actions than simply setting state. That's a good thing.

Or would it also be fine to make Status setter public and have domain event like DocumentStatusChanged?

Again, same comment about events. If you have to add any additional logic (like validations etc.) then a simple setter is going to make your code hard to follow.


The biggest question I have back to you is where is your Domain Model being used? Web applications and standard UIs have different ways they are meant to talk to each other. If your model doesn't have to notify any other code, there doesn't need to be a notification.

There is another option:

class Document : Entity, IAggregateRoot
{
    public DocumentStatus Status { get; private set; }

    public void Cancel()
    {
        this.AddDomainEvent(new DocumentStatusChanged(this, Status, DocumentStatus.Cancelled));
        Status = DocumentStatus.Cancelled;
    }

    public void Complete()
    {
        this.AddDomainEvent(new DocumentStatusChanged(this, Status, DocumentStatus.Completed));
        Status = DocumentStatus.Completed;
    }        
}
3
  • The domain model is being used on the server. I'm building a Web API. Thanks for the detailed answer!
    – Konrad
    Aug 20, 2018 at 19:29
  • I would use the events for example if I wanted to make some kind of modular system, so I could attach plugins at run-time and they could react to particular events. So I think they're not only useful in desktop and mobile apps.
    – Konrad
    Aug 22, 2018 at 8:46
  • They also help you to later add new features, you want to do something when something happened so just listen to an event and put your logic there instead of adding new lines and putting all logic in one place. There's surely some more appropriate term for that (flexibility?) but you get the point I think.
    – Konrad
    Aug 22, 2018 at 8:51
3

In this case, you should probably be using the language of your domain experts as a guide -- one way of thinking about domain modeling is that we are trying to create a domain specific language that matches the problems that we are trying to solve.

Very few domains use "set" as a first class concern in the language.

For instance, we "place", "complete", and "cancel" orders. So we would prefer to model that language, rather than using spellings like "set status".

2

If all transitions between states are valid I'd probably just make a property with public getter + setter, its the simplest thing that could possibly work and take virtually no code.

Where you definetly will want to put in methods imho is if certain transitions are forbidden e.g. cannot go from cancelled -> complete

3
  • 1
    Yeah but you can still put that logic in the setter to check if the current state is cancelled and if the new state is going to be completed and throw an exception.
    – Konrad
    Aug 20, 2018 at 12:11
  • 2
    @Konrad: You could, but for users of the class, it would be more clear if they had Complete and Cancel methods that could fail because the document is in an incorrect state. That gives usually a lot less confusion than a more generic state setter that could fail. Aug 20, 2018 at 12:43
  • @BartvanIngenSchenau makes more sense
    – Konrad
    Aug 20, 2018 at 12:56
0

You could use the setter for this. It is, in fact, used in the real world for implementing things like two-way binding in Windows Forms and EF proxies. But this doesn't mean you should use it too.

Properties are mostly intended for getting and setting values. There might be developers that don't expect side effects or expect immediate return when getting/setting a property. Using a method instead of a property better specifies the intent and it also shields you from possible changes later on when you might need parameters when changing the status.

Your Answer

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

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