Value Objects are classes that represent more than simply an integer value or a string value. They have no identity, as in $10 or “cat”. Some argue that value objects should not be used in commands and events. However, I don't see why not.
Events are classes that represent things that happened. Optimally, DDD/CQRS/ES systems should not be CRUD systems, so events are usually more meaningful than “NameChanged”. Many argue that only the heart of an application that represents real domain knowledge should be build using DDD/CQRS/ES, and that it is overkill for CRUD applications. Some funcionalities ES gives us out of the box are
Building DDD/CQRS/ES applications really isn't that much more complicated or involved than building CRUD applications. On top of that, as soon as a CRUD application becomes a little more complex and has more and more requirements, a CRUD architecture becomes very limiting very soon. Adding things such as logging, optimized read models, messaging, (semi-) automated processes, etc. to a CRUD application will be extremely cumbersome and sub-optimal. In my opinion, you may as well go straight to the DDD/CQRS/ES architecture. I do see the value of CRUD for simple bounded contexts such as tenant and licensing management - parts of the application that do not change much and that do not require most of the above functionalities.
The domain is the heart of the application. This is where the business logic and domain knowledge resides. Domain experts need to be involved and interviewed in order to build a meaningful domain. The domain gives us the competitive advantage, containing the knowledge, experience and expertise of the domain experts involved in designing the domain. Note that the domain does not implement authorization logic. A manufacturing process knows how to manufacture a certain product, and will produce an output (Events) based on the inputs (Method Arguments) it is given. It does not verify if the person initiating the process has the right to do so. If the person gives it valid inputs, it will perform its task. An upstream component is responsible for allowing only authorized people to initiate manufacturing processes.
The Domain consists of Aggregates. An Aggregate is comprised of an Aggregate Root, Entities and Value Objects. Aggregate Roots are the entry point into the Aggregate. They have global identities and contain entities with local identities inside the aggregate, and Value Objects which do not have an identity. Aggregates are responsible for the implementation of the business logic and for maintaining all invariants of the domain. When applying CQRS and Event Sourcing, Aggregates only have void methods and publish Events. Events are the result of the Domain implementing its business logic. They contain everything relevant to what happened inside the method call, in order for denormalizers to comprehensively build read models from the events and other subscribers to the Events to react to them in other ways.
Since Aggregates are self containing and maintain the Domains invariants, Units of Work (UoW) - in Databsase Terms Transactions - are most commonly not required. In case invariants involve more than one Aggregate, a Domain Service can be introduced. The Domain Service will make calls to all Aggregates involved and maintain the invariants spanning the Aggregates. It is often said that if you need a Domain Service, then your Aggregates are poorly designed. Maybe so, maybe not. Designing Domains is more art than science, requiring a lot of experience.
If the domain happens to be purely CRUD, Aggregates could be skipped altogether. The Domain would simply consist of Events, and the Application could translate method calls from the outside directly to events. The business logic and maintenance of invariants would then reside inside the Application, not inside the Domain. This would represent a CRUD/ES application architecture style, which would have all of the above mentioned benefits of Event Sourcing, and probably is a good alternative to DDD/CQRS/ES for CRUD applications.
Commands are messages representing method calls. They can be serialized and sent across the wire, onto message buses, and so on. The application then translates the commands into method calls on Aggregates or Domain Services inside the Domain. Commands are not required. They represent one of several ways to prompt the Application to do something. The benefit of Commands are that
Privileges are at the heart of authorization.