At the Ecommerce project we have a main split between the app layer and the domain layer.
We aim for the domains to be reusable.
The applications are specific, not meant to be reusable, at least that's not the main goal.
I'd like to share my current thinking snapshot of what I think could help us achieve nice modularity and reusability.
What makes a domain?
- commands as the only input layer
- events as the only output layer
- aggregates as internal mechanism which maintains the state transitions
- they could be objects or functions
In theory, that's all.
In practice, you sometimes need to have something more. Sometimes you will have a read model which exists only for the purpose of this BC (bounded context) to read from. For example, Pricing BC may need to maintains its own internal Pricing Catalog, which to read prices from.
Given the above, we want to keep the commands and events as granular as possible. We want to allow all kind of reusability on top of this.
Some apps may want to have nicer/bigger commands or events. That's great.
They should use the EventSummaryBuilder pattern to build from the small events and provide bigger events.
Similar thing with commands, they may want to build bigger commands - that's great, let's just show how those big commands map onto the existing small commands.
Those builders, at least that's my current thinking, are not part of the BC. They are part of the app layer, because they are a tweak for the application. In a way they are the facade which could/should be maintain by the application, as the domain code consumer.
We can provide them as something reusable, but that's different "blocks".
BCs alone are useful, but they don't create the Feature.
A feature is a set of building blocks which together form a functional and working unit at the application layer combined with the domain/BC.
Let's look at Invoicing.
There's Invoicing BC with its events and commands.
There's a process manager which builds the Invoicing state via reacting to some Pricing events. This is application layer.
There's obviously a way to display the invoice for the customer.
That's a read model.
There's also a way to display the invoice to the admin, usually different than the one for clients. That's another read model.
Those read models have their own storages - they should own it. The migrations should belong to the read models.
The html/json renderers can also belong to read models.
There's this gray area too.
How useful can the BCs be without the accompanying BCs?
Can we imagine the Invoicing BC to work fine without the current Pricing?
I think it should be possible.
One hypothetical scenario is to create a typical Invoicing application, without any ecommerce surroundings.
That's overall the general idea on how things could work.
Things may change, once we have more apps and more reusability which will show which parts of this vision are fragile.