Note: In what it follows, the term “Entities” refers to both Entities and Aggregates indistinctly.
The Hexagonal Architecture sets a clear distinction between Domain and Application layers, which drives us to locate all entities in the Domain layer for it is there where the meaning (what the software is about) has its home, whereas we must put whatever run factual changes in those entities, as use cases require, in the Application layer.
For example, Customers and Items, as entities, belong to the Domain layer, whereas Sale an Item, Bill an Order, or Ship some Items, belong to the Application layer because they represent in the application (translated to the language the software can understand) what in real life we would consider facts that happened concerning particular Customers and Items.
Just as a brief reminder, in this same Hexagonal Architecture, the UI layer would be where what triggers those changes live, whereas the Infrastructure layer would be where we put every piece of software needed to have the application run (frameworks, ports connecting to databases, file system, message transporters, etc.).
Not all entities are created equal
A simple inspection through the list of entities in any given application would show us that some entities play a role, and have a life span, fundamentally different than others:
- There are Master Entities, which represent in the Domain model that every particular application implements what in real life we would call “entities” too: Customers, Items, Suppliers, Service Providers, Employees, etc. One of the elements of external reality (external to our software) they exhibit is an id of their own: either you decide relying on those ids to identifiy instances of these entities in your application or not, that is a property (ISBN, Tax ID, Social Security Number, etc.) you are likely to handle somehow.
Master entities change in a very slow pace: once created, and approved, you would change them seldom, for instance, to add a new Customer Address, or update the description of an Item, or mark an Employee as not working in the organization anymore. Conversely, master entities show a long lifespan, ordinarily of years.
- There are Transaction Entities, which play in the Domain model what in real life are Orders of any kind (sales, purchases, work orders, etc.), Bills, Shipments, etc.
Transaction entities may suffer plenty of changes, for each change represents a step in the fulfillment of the business process in progress. However, once completed, these entities never change again, and so their lifespan is very short, commonly not more than days.
In opposition to Master Entities, your application will surely need to provide unique ids for every instance of these Transaction Entities.
That distinction between master entities and transaction entities has indeed a long history behind if you accept database tables as true ancestors of entities. In fact, I took both names from the field of Business Intelligence, in which, quite approximately, transaction entities constitute the data origin read to feed the so-called fact tables, whereas master entities play the role of dimension tables, due to their role as axis in the charts where the calculations provided by the BI engine are pictured.
Incidentally, there is another feature that is also different in magnitude between master and transaction entities: their number. With time, the number of transactions grows far quicker than the number of instances of any master entity. Although this is not true in all cases, for it depends on every particular organization, it is often true that the number of Customers is far less than the number of Sales Orders.
So, we might be tempted to state that master entities are fundamental and transaction entities are accidental, for master entities are supposed to be there, perfectly defined and steady, even though while nothing happens to them.
However, as the Spanish philosopher José Ortega y Gasset said, “I am me and my circumstance“; hence, Mr. Ortega would be a master entity, and his circumstances (what impacted, or happened to him), a plethora of transaction entities.
In other words, no matter how permanent we humans might look, our self is defined by a never-ending interaction with our surroundings, in a way that makes us a work in progress which never gets accomplished. It’s that dialogue what really makes us.
Everything in its right place
Time to come back to software. In my opinion, the different roles that both master entities and transaction entities play in the application constitute a fundamental trait which must be made apparent in how we organize the elements of the code.
One easy way to achieve that purpose is to keep them both in the same Domain layer, but segregating one set of entities of the other, for instance, in separated folders. This option is quite conservative, so it might avoid unexpected surprises to eyes dropping a casual gaze on a repo organized like this. But it looks wrong because it ignores the key fact that master entities exist before any use case might run, whereas transaction entities are tightly intertwined to the execution of use cases: with no execution of a particular use case, there cannot be any instance of the related transaction entity whatsoever.
We might say that master entities keep the major part of the meaning of the Domain, whereas the transaction entities only carry an operational meaning. Though appealing, this is wrong, because ultimately all entities are defined out of operational foundations. For instance, Customers are defined because of their action of buying something to the organization; Items are defined because they are what the organization sells, buys, or utilizes somehow.
All Entities, either master or transaction, are defined out of operational traits
Therefore, what looks more natural to me is to relocate the transaction entities in the Application layer. For they belong there as the use cases do too, and, as I said above, with no use cases, there are no transaction entities neither. IMHO, it is not enough that transaction entities are persisted as well to keep their place in the Domain layer, compared to the key facts we have seen:
- Master entities have a lifespan far longer than transaction entities.
- Master entities pre-exist transaction entities, for the former may exist without the latter, but the opposite is not true.
- Master entities have got their own unique ids, whereas transaction entities need to be provided with one by our software.
Does this feel right to you?
Copyright notice: featured image taken from the Java Viet Nam blog, though it is not original of the blogger.