6

Does it make sense to create commands that just hold objects? For example:

public class CreateCommand : IRequest
{
   SomeDTO SomeDTO { get; set; }
}

public class UpdateCommand : IRequest
{
   SomeDTO SomeDTO { get; set; }
}

Or perhaps something like this (deriving):

public class UpdateCommand : SomeDTO, IRequest
{
}

Or commands/requests should be treated as DTOs themselves? I'm confused because I saw many ways of doing things. Also copying all properties to command/request classes doesn't sound like a nice thing to do.

How do you do this in your projects?

Do you map your commands directly to your domain models or you use commands just to pass DTOs?

In case of using MVC framework what should be the input of my controller actions? Should it be a command, or should I create command inside my action implementation and send it? (I guess that will depend on how I model my commands)

Konrad
  • 6,385
  • 12
  • 53
  • 96
  • The command should represent what should be the contract for read/write operation. As there can be multiple properties which is required to represent a command and for segregation of concern I prefer the first option (command holding object). Command and request should be treated as contract to send the data from client to server or vice versa. The DTO (in terms of database) should be different then command and maps to model/entity. (Again all this analogy it's based on my preference) – user1672994 Jun 18 '18 at 11:40
  • 1
    Although some (few) commands applied to a basic aggregate may have a lot of similarities with a DTO (e.g. the `CreateHouseCommand` may have a payload which has most of the `House` properties), most commands should be much lighter in weight than the full `House` domain model, e.g. `PaintHouse(colour: blue)`, and a command like `OpenDoor` might have no additional payload at all. It makes no sense to use the full `House` model as a Command payload for commands like `PaintHouse` and `OpenDoor`. – StuartLC Aug 01 '18 at 12:03
  • 1
    @StuartLC thanks for the example :) – Konrad Aug 01 '18 at 14:58

3 Answers3

3

Does it make sense to create commands that just hold objects?

No, there is no value added to the extra class: no semantics, no behavior...

Or commands/requests should be treated as DTOs themselves?

Commands (in the CQRS sense of the term) are DTO's by nature. They are dumb data bags that circulate between layers/tiers.

Do you map your commands directly to your domain models

It depends if you favor a task-based UI over a CRUD-based UI. If you do DDD/rich domain model - some would even say basic OO encapsulation - you wouldn't map them. Command names would maybe match entity methods, but their contents are not automatically mapped to domain model fields.

In case of using MVC framework what should be the input of my controller actions? Should it be a command, or should I create command inside my action implementation and send it?

I would say both are legit and applicable, except the occasional technical quirk with MVC model binding.

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • I don't think commands are DTOs. I think commands are just methods or operations used for writing data. – Konrad Jun 18 '18 at 13:13
  • "CQRS is a pattern that segregates the **operations that read data (queries)** from the **operations that update data (commands)**" https://learn.microsoft.com/en-us/azure/architecture/patterns/cqrs – Konrad Jun 18 '18 at 13:14
  • 1
    You're confusing form and function. In form, it is a DTO. Also see first answer here: https://stackoverflow.com/questions/30095966/command-pattern-in-gof-vs-cqrs-meanings – guillaume31 Jun 18 '18 at 13:15
  • I think CQRS definition of command has different meaning than gang of four – Konrad Jun 18 '18 at 13:20
  • 1
    Absolutely. By Go4 definition, it is not a DTO. In CQRS, it is indeed. – guillaume31 Jun 18 '18 at 13:22
  • I still don't think it's a DTO in CQRS. https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf See page 18 – Konrad Jun 18 '18 at 13:26
  • There's no mention at all that the command should be a DTO, it's just a method used for writing data. It can be used as DTO when used together with library like MediatR but still – Konrad Jun 18 '18 at 13:27
  • There's no relationship whatsoever between using MediatR and the fact that Commands are, or are not, DTO's. – guillaume31 Jun 18 '18 at 13:39
  • I guess we have a different definition of DTO. Most people do. Let's agree to disagree :) – guillaume31 Jun 18 '18 at 13:40
  • There's a misconception in the definition of CQRS. There's no clear definition of what command really is in CQRS. One definition says it's a method or operation, other says it's a separate class for passing data. – Konrad Jun 18 '18 at 13:45
  • The author of the pattern (Greg Young) confuses it too, in CQRS documents he first describes what CQRS is and later in the document he introduces "Command" model as a way to pass information which completely denies the general principle. – Konrad Jun 18 '18 at 13:47
  • This pattern is heavily over-rated with no clear description on how to perceive things like commands and queries. – Konrad Jun 18 '18 at 13:49
  • 2
    No, definitely not. You're letting yourself be fooled by [metonymies](https://en.wikipedia.org/wiki/Metonymy). When Microsoft say that commands are "operations that update data", they really mean "are *used* to update data". Command **handlers** update data, not commands. Look at the code. – guillaume31 Jun 18 '18 at 13:50
  • CQRS authors aren't confusing their Commands with Go4 commands. You're the one making the confusion. – guillaume31 Jun 18 '18 at 13:51
  • http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/ author just separated methods that write from methods that read without creating any additional data models and said it's enough for CQRS. I'm not saying they confuse commands with go4 commands. They confuse commands with data models and methods/operations. It's not the same. – Konrad Jun 18 '18 at 13:58
  • Notice there's no definition of a handler that handles commands, commands are simple methods of a service with `void` return type and separate interface `CustomerWriteService` – Konrad Jun 18 '18 at 14:05
  • Now when you look at definitions on http://cqrs.nu/ they're completely different. And they describe it with message bus in mind! – Konrad Jun 18 '18 at 14:07
  • You're comparing a "CQRS 101" barebones example with real life applications. Greg Young obviously uses real commands in [other code samples](https://github.com/gregoryyoung/m-r/tree/master/SimpleCQRS). Most CQRS production applications have Command data structures. – guillaume31 Jun 18 '18 at 14:11
  • I think this data-structure applies only to task-based UIs. This definition (you might say correct) of "command" is on page 11 "https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf in section **Task Based User Interface** – Konrad Jun 18 '18 at 14:17
  • When talking about CQRS in CRUD based interface I think there's no such thing as Command that you pass to methods/handlers. – Konrad Jun 18 '18 at 14:18
2

Commands and domain objects, at least in my world, have different design constraints. In particular, commands are part of the API surface - they are part of the contract with other services - and therefore need to have compatible definitions over long periods of time. Domain objects, on the other hand, are local to our current way of doing things - they are part of our organization of data within the black box. So we can change those at any cadence we like.

Commands that cross process boundaries are messages, which is to say byte[]s. That's the bit that needs to be stable, both in form and semantics.

byte[] is domain agnostic, and it's fairly common to pass through several other domain agnostic intermediate stages in "parsing" the message

byte[] -> utf8
utf8 -> DOM
DOM -> Dictionary
...

but we're generally driving toward a domain specific expression of the contract.

See, for instance Mark Seemann

At the boundaries, applications are not object-oriented. A DTO is a representation of such a piece of data mapped into an object-oriented language.

Having coerced the byte[] into a form that is convenient for querying, then we can start thinking about whether or not we want to use that data to start initializing "objects".

The other question that you may be asking - is there value in a having the message data within a generic metadata "envelope". That kind of pattern occurs all the time - the most familiar example being that an HTTP POST is a bunch of generic headers attached to a message-body.

The data and the metadata are certainly separate concerns; it definitely makes sense to keep them distinct in your solution.

I think compositing the data structures, rather than inheriting them, is going to be the more maintainable option.

public class Envelope<Message> ....

might be a reasonable starting point.

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
0

You should treat the command as a "verbal sentence" instructing your domain to do something. For example the "UpdateCommand" instructs your domain to update something. Inside the command you should include the specifics of the command (in your case that dto is fine)...

However be very carefull with those DTO's. You do not want your domain to be dependent on MVC but the other way around. Be sure that the assembly where the dto is living is not of a higher (in the direction of MVC) level than the domain logic.

In your MVC you should have only:

  • Dependency injection setup
  • Controllers & Views

Controllers should only contain the code required to transform from the method (http) parameters (witch are unsecure) to the dto required by the domain, and calling the domain.

At least that is the way I'm doing it.

John Verbiest
  • 349
  • 2
  • 15