Jacobian
Jacobian

Reputation: 10862

CQRS commands and queries. Do they belong to Application or Domain level in terms of DDD?

Reading different DDD literature I stumble across one theoretical problem. The problem is whether I should place commands and queries at Application or Domain level.

So, some authors like Scott Wlaschin (in his book Domain Modeling Made Functional) say that

if the command does succeed, it will initiate a workflow that in turn will create corresponding Domain Events

So there is a correspondence between for example "Place Order" command and Domain Event "Order Placed". That makes me believe, that I should place commands and events at one level and organise it like so:

\Model
    \Message
         \Command
             PlaceOrder.lang
         \Event
             OrderPlaced.lang

So, I place all commands at Domain level, while application services call these commands and wrap them for example in transactions.

However, there is another point of view, expressed in Scott Millett book (Patterns, Principles, and Practices of Domain-Driven Design). The quote says:

A command is a business task, a use case of a system, and it lives within the application layer. You should write commands in the language of the business.

Because of this contradiction, I'm not quite sure, what is the most canonical way of treating commands (and queries also). In real world, do they live in domain or application level?

Upvotes: 9

Views: 4845

Answers (3)

Sylvain Lecoy
Sylvain Lecoy

Reputation: 1027

The commands and queries are definitely at the application level.

They are calling application service methods, which are responsible to span transaction, high level logging, and delegate to business objects.

Queries services are also at the application level, returning optimized views of the domain, often by not using the domain repository but instead access directly the data.

Upvotes: 2

iTollu
iTollu

Reputation: 1069

As for me, the main idea of DDD is about Ubiquitous Language, Bounded Contexts and Context Mapping. So, if we focus on these concepts, all other parts become an implementation detail.

15 years ago, when The Blue Book was written, it was time of Java. Nowadays there are different paradigms that come and go.

I like to separate commands, requests, events and responses into different levels. The main problem is that you soon become short of suitable words. But that's a well known issue with programming.

There is a vocabulary at the core of implementation. It is not the whole ubiquitous language, but probably the most part of it. There I model domain-specific classes and structures, mostly using immutable data types. There you put factories and invariants. Vocabulary doesn't depend on other parts of code.

Next, a business core has decision makers, which take commands and produce events or rejects. A command is an intent to change a system's state. Event is a made decision about changing systems's state. Both are immutable and expressed using vocabulary. Command contains a comprehensive data necessary for making up a decision, so that a decision maker doesn't need to retrieve additional data from somewhere. So, a decision maker can be a pure function.

Commands and events are internal to the business core of a system. But you get requests and send responses in some wire format like JSON, XML, ProtoBuf and so on. You should marshal/unmarshal it, add additional data like authentication/identification, different tracing ids, and convert it into some object model, that knows nothing about wire formats. I call these object models a Business Request and a Business Response. This are owned by an application layer.

Request and response alone are not sufficient. Besides their data you need to retrieve additional data from repositories and other dependencies, and persist after a decision about state change was made. So getting a Business Request, gathering data from dependencies, building a Command, sending it to a decision maker, getting an Event or Rejection back, executing this decision (storing to repositories and the like) and producing a Business Response - these are all responsibilities of an application layer.

I don't describe read models, because they can be implemented in many different ways as long as responses from read models come to an application layer expressed with the data types from vocabulary.

So, wire formats and converters to/from business request/response belong to infrastructure adapters layer. Business requests and responses and their converters to/from command/events/rejections belong to an application layer (as well as task to prepare data for decision making and executing made decisions). And commands/events/rejections belong to the functional core.

Terms like request, response, command, event are not very helpful: they are quite overloaded and it is sort of irony, that we use them in the land of non-vague ubiquitous language. But still I hope this helps.

Upvotes: 5

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57367

Because of this contradiction, I'm not quite sure, what is the most canonical way of treating commands (and queries also). In real world, do they live in domain or application level?

The literature is kind of confusing on this point, primarily for reasons of history.

When we are talking about messages, which is to say the API of our application/service; these belong outside of the domain model.

The root issue is that message schema is part of the contract definition between your app and the clients that talk to it. Contracts, especially those that cross organizational boundaries, need to be stable because the cost of change is high.

Contrast this with the in memory representations of your domain model, which are purely an implementation detail, and can be changed whenever you want. Your data model falls somewhere in the middle -- clients don't care what your information looks like in durable storage, but your future application needs to be able to read the information left behind by the predecessor.

When Udi Dahan says that services "share contract and schema, not class or type", he's describing the messages that are being exchanged. Clients aren't required to care what "class or types" we use in the implementation of the domain model.

Now, to be fair, clients aren't required to care what "class or types" we use in the implementation of the application either. The fact that you take a PlaceOrder message (the semantics expressed by a sequence of bytes sent to you on the network) and represent it as an in-memory arrangement of typed memory references is your own business.

What we are paying attention to here is that the code responsible for interpreting the bytes belongs to the parts of the code with the responsibility for communicating with other things, and not the parts of the code that manage the in memory abstraction of the business.

Upvotes: 1

Related Questions