1

I need some expert guidance. I'm trying to learn the concepts as well as implement them, and it's possible I might be over-engineering some. But that's OK, because I am wanting to learn and gain experience more so than keep it simple. I'd like to apply the concepts of DDD and CQRS in my project but I'm having trouble figuring out how to put it all together. I need to design and implement the ItemManagement bounded context, which is part of a larger system.

First, there is going to be an MVC web application that users can use to manage item inventory. Some basic use cases are create item, edit, check-in/check-out.

Next, I want an external Web API that will this site will use for querying data and respond to commands (and also be available to other bounded contexts).

Putting these two things together is where I need guidance, especially with the command side. The way I have it imagined is that I can send command objects to their respective url of the API i.e. api/v1/items/create, api/v1/items/{id}/edit, api/v1/items/{id}/checkin, api/v1/items/{id}/checkout. But then I get stuck. After receiving a command in the API, what steps are followed to apply the command to a domain entity, validate against any business rules, and ultimately persist the changes? Here's how I was imagining it

    public class Item
{
    public int Id { get; private set; }
    public string ItemName { get; private set; }
    public bool Available { get; private set; }

    public Item(int id, string itemName, bool available)
    {
        Id = id;
        itemName = ItemName;
        Available = available;
    }

    public Item(CreateItemCommand command)
    {
        Id = command.Id;
        ItemName = command.ItemName;
        Available = command.Available;
    }

    public void Edit(EditItemCommand command)
    {
        ItemName = command.ItemName;
        Available = command.Available;
    }

    public void CheckIn()
    {
        Available = true;
    }

    public void CheckOut()
    {
        Available = false;
    }
}

public class CreateItemCommand
{
    public int Id { get; private set; }
    public string ItemName { get; private set; }
    public bool Available { get; private set; }
}

public class EditItemCommand
{
    public int Id { get; private set; }
    public string ItemName { get; private set; }
    public bool Available { get; private set; }
}

Then, in my API actions, I would handle these commands as such:

Create

        Item item = new Item(createCommand);
        _repository.Add(item);

Edit

            Item item = _repository.Get(id);
        item.Edit(editCommand);
        _repository.Save(item);

Checkout

            Item item = _repository.Get(id);
        item.CheckOut();
        _repository.Save(item);

There's none in this example, but any domain invariant violations would result in exception being thrown from the domain model and ultimately coming back to client in form of 500 error.

I am on the right path here or is this way off from proper form/practice? Thank you very much for your time.

1

I am on the right path here or is this way off from proper form/practice?

You are on the right path.

The way I have it imagined is that I can send command objects

This spelling isn't quite right -- you aren't sending command objects, you are sending command messages. See At the Boundaries, Applications Are Not Object Oriented.

You'll want to be careful with the vocabulary here; command messages aren't the same thing as the Command pattern described in the Gang of Four book, and neither of those is quite the same as what Grady Booch's Command Query Separation.

The reference you want here is Enterprise Integration Patterns, where Hohpe describes the relationship between command messages and command objects.

After receiving a command in the API, what steps are followed to apply the command to a domain entity, validate against any business rules, and ultimately persist the changes?

You'll normally first validate the message -- which is to say make sure that the message of itself conforms to your specification. You then hand that message off to the domain model to check the message against the current state, and compute appropriate changes.

any domain invariant violations would result in exception being thrown from the domain model and ultimately coming back to client in form of 500 error.

That's probably not quite right -- if the domain model does the right thing by protecting the state from a wrong message, then you should be using a 4xx status-code.

RFC 5789 includes a decent overview of how you might discriminate among the different members of the 4xx class of status-codes.

  • Good explanation, thank you. You're right - poor choice of wording on my part regarding commands. Messages, not objects. I also agree on the 4xx class of status codes, I had a mental slip-up when I said 500. Is it OK to accept commands into constructors and methods within my domain model, or is it more recommended to destruct the command upon receiving and send the individual fields contained within? – user1560457 Sep 9 '18 at 15:30
0

Sorry, you are off I think.

With the command pattern you are supposed to put the logic in the command object.

Obviously this means you can't send them over the wire. Only the data can be serialised.

Your command objects, stripped of their logic are now just parameter lists.

  • Are you sure about that? If I took the logic out of the domain entities then my models become anemic and aren't self-validating. – user1560457 Sep 9 '18 at 12:08
  • @user1560457 I think terminology might be confusing things? It's physically impossible to send logic over the wire. Logic can only exist in your MVC app or in your API. You can send data (messages) between those applications, but messages aren't domain entities. I would think that your domain entities should exist only inside your API; the MVC app shouldn't have any knowledge of domain entities. The only thing the MVC app should know how to do is to send/receive messages to/from the API. Also, you don't need self-validating messages since validation is a responsibility for the API. – Ben Cottrell Sep 9 '18 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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