You know how to implement the domain of your application? It’s simple! So simple, it’s scary.
The other day I explained what the purpose of the domain is: it’s “managing” the application’s state.
There is application state of some kind and form. In my article I argued for keeping it in an event store. But in the meantime, I have let go of that. It’s too narrow a view, I guess. It’s a great choice, but sometimes you can take a shortcut.
So, don’t worry about where you keep your application state. Can be an RDBMS or NoSQL database or the file system or an event store. It’s all good — as long as you really, really make an effort and keep it free from any domain logic. Just use plain data structures. Strive for simplicity. Strive for flexibility. Don’t get attached to your state store schema.
Because much more importantly all this state is not visible to anybody. Nobody should have a clue about how it looks. Really. It’s of no concern to anyone, except, well your domain.
That’s the whole point of the domain: to know, control, change, query, and transform application state as it sees fit. The domain decides which shape and form and technology to use for storing the application state.
The application state is totally encapsulated by the domain. There is no peephole to peer through from the outside and see application state in its original form. It’s like the nucleus in a biological cell which is protected by the cell’s body and membrane and processes.
But isn’t that what all concentric software architecture patterns have been saying since the mid 2000s?
No! Because they assume, that something outside the domain is actually responsible for structuring and managing the application state, call it adapter or layer.
What I am proposing, though, is that the domain itself and no-one else is solely responsible for the domain state. It’s owning the state. Sure, it’s using some kind of adapter/provider to actually store/persist it, but that, too, is part of the domain. No other module of an application has access to that. It’s not “floating around” for anybody to use. Rather it’s intimately contained inside the domain.
Domain logic and domain state cannot be separated. From the outside, there is no separation visible.
Domain logic even depends on the domain state provider. Yes, it’s functionally dependent. The reason I allow that is, that domain logic is truly abstracting from domain state. (For details see my article Dependencies Flow Down Abstractions.)
A second reason why this is unlike your usual concentric architecture: the domain logic shell responsible for keeping the domain state consistent is structured.
The domain logic shell is seamlessly made up of so called Request Processing Units (RPUs).
Each such RPU fully encapsulates a domain capability. All that’s needed to handle a domain request is contained in a RPU. RPUs are independent of each other. They don’t share anything except types and the domain state.
And they all belong together. Collectively the form the domain. It’s like an orchestra of instruments. All focused on playing the same piece, but each fulfilling a different role.
RPUs are almost pure functions. Each is responsible for answering a particular request with a response. Requests are CQS messages, they are either commands or queries.
And if you haven’t slept through “This history of programming” or some like course this should remind you of something. Can you guess?
Yes, it should remind you of an object. An object like Alan Kay had envisoned it back in 1967. Check it out, I wrote a few blog articles about it:
Here’s Alan Kay’s definition of an object:
"I thought of objects being like biological cells and/or individual computers on a network, only able to communicate with messages"
And he also said:
"The big idea is 'messaging'"
That’s what you see in the picture above: messaging. The domain only understands messages. It’s messages in and messages out. It does not know where they are coming from, it does not know where they are going to.
That’s a pure, a radical object like Alan Kay had in mind.
It’s the last object you need to think about. Because all your objects are not really objects in the original sense. Read my blog on Radical Object-Orientation and you’ll understand why I’m saying this to provocatively:
Yes, the whole domain is a single, central, big object. That’s my view of software nowadays. It makes my life so simple.
Why is that? Because I don’t have to worry about all sorts of dependencies. Each RPU is just a “big function” with side effects on the domain state. (But they can easily be contained in tests.)
Each RPU can be replaced on its own, like a part in a car.
No-one outside the domain knows anything about the domain state. It’s there, but secretly hidden behind the RPU facades.
Think of the domain as an Abstract Data Type (ADT) like a Stack<T> or Queue<T>. You don’t know how they are keeping their state. Is it a linked list or just an array? You don’t know and don’t care. ADTs are providing semantics through functions. That’s all. The same is true for the domain.
The RPUs are offering a functional interface to state. They generate views on state. But they never divulge how the state actually looks.
But what about databases, the file system, calling REST services? That’s not a concern of the domain. The domain does not know anything about the outside world. It does not depend on any services.
Access to resources is encapsulated by external providers, but they are not used by the domain. They just exist outside/around the domain. They don’t know anything about the domain either. Domain and external providers just coexist.
Of course, the domain may work with data provided by external providers. Of course, external providers may process data from the domain. But neither accesses the other for that. It’s just shared data contracts (interfaces) between them.
If needed, the domain and external providers are composed into data flows by yet another concern: Reactors.
Reactors don’t contain logic themselves. They do not know any technological API like providers do. Their sole purpose is to connect domain RPUs and external providers into processes transforming client requests into responses.
Reactors, again, are abstractions. They abstract from the details of how a software responds to a trigger. Because it’s always a trigger on a frontend that kicks off processing client requests.
Those client requests — from a user through a user interface or from some other software through an API interface — are received in modules yet of another concern. I call them portals:
Portals receive input through client requests and produce client responses as output. They pass requests on to reactors (or RPUs if things are simple).
Portals are concerned with frontend technologies, providers are concerned with backend technologies (e.g. databases, file system, time, random numbers, communication).
Portals and providers can be called the imperative shell of an application, and the domain is its functional core. A very special functional core, because it actually implements the 60 year old idea of object-orientation. Finally.











