Original Sin: Unidimensional Asymmetry
Back in the day, I was delighted when I first found this three layers’ architectural pattern:
Finally, some order in the chaos!
… but, trying to use something like this in practice was somehow difficult: there are other aspects that does not fit to any of these layers.
Now was clear that, unfortunately, something is wrong with the 3-Layers Architectural Model. … and the “original sin” is the unidimensional asymmetry: the UI-Persistence “line” is the unique dimensions and many other software areas cannot fit here.
The fix: Symmetry!
On of the first actionable and symmetrical model was the UML (Jacobson) robustness diagram. Any use cases could be represented as being realized by objects that are instances of three categories of classes boundary, control and entity
- Boundary, Control, Entity
That is simple, beautiful and symmetric: UI and other I/O (Input/Output) aspects are managed in non- discriminatory manner. One problem: too few guidance.
Koni Buhrer “Universal Design Patterns” goes a little further – four design elements & their recommended interaction could describe everything and offer a symmetrical model:
- Data Entities, I/O servers, Transformation Servers, Data Flow Managers
It is symmetric, it is logical, actionable, but still too few guidance.
What we could need more?
Robert C. Martin and with Clean Architecture and Alistair Cockburn with Hexagonal Architecture have some beautiful answers and guidance (see Uncle Bob biblio for other authors similar works).
With Hexagonal Architecture name, Alistair Cockburn want to make clear the main defect of classical model – unidimensional lack of symmetry: <Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases. > . This architecture model will decouple use-cases (~ the application) and the I/O dependent on technology: “When the application has something to send out, it sends it out through a port to an adapter, which creates the appropriate signals needed by the receiving technology (human or automated).” (quotes from mentioned A. Cockburn post)
Robert C. Martin Clean Architecture make a step further on strategically separating the concerns and present these software areas (quotes from Uncle Bob recommended article )
- Entities – representing the functional part that is application-independent, working at a higher level: domain or enterprise
- Use cases – representing the functional part that is application-dependent, and realize the flow of data using the business domain and enterprise rules
- Interface Adapters – “set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the Database or the Web”; on Uncle Bob View MVC and MVP parts goes here
- Framework and drivers – “frameworks and tools such as the Database, the Web Framework, etc.” And what is most important, according to Uncle Bob, – “This layer is where all the details go. The Web is a detail. The database is a detail.”. Yes, technologies & deployment mode is not the core of your application, it is what will change independently and do you want to decouple them.
I strongly recommend all above described symmetrical models: Robustness Analysis (Jacobson), Universal Design Pattern (Koni Buhrer), Hexagonal Architecture (Alistair Cockburn), Clean Architecture (Robert C. Martin) or Layered Class Typed Architecture (Scott W. Ambler) that are logically equivalent with more or less details.
Simplified representation of symmetrical models:
- Flow control orchestrate I/O parts (symmetrically) and Business Logic, where Entities are the exchanged data
- If the Inversion of Control it is used and the participants to the flow are represented by interfaces, the design will be more adaptable and testable
What we could need more?
There is some asymmetry!
There is some asymmetry in logic architectural areas that is skipped somehow by current models of Hexagonal or Clean Architecture, and this is the reason behind the original mistake of unidimensional linear model:
- There are two kind of interactions for the systems
- The client level interaction – the one with the systems actors
- The resources level interaction – the one to access the its resources (such databases, heavy processing)
- The client level interaction
- Contain – links the system with its clients/actors
- Dedicated flow control to manage (possible) client session state (interaction state)
- The resources level interaction
- Contain – link the system with its resources
- Dedicated flow control to manage (rather) stateless access to these resources
- Each layer is represented in a simplified form here. In fact, it could contains full set of software areas: Entities (Business/Enterprise), Flow Control (Use Case) and I/O adapters.
- Each layer is symmetrical, but the aggregate is asymmetrical, based on actor-resources vectorization
Scaling aspects (performance and others)
- can manage the access to resources with the benefits of its stateless model, using various patterns and tools that are based on this aspect.
- can manage in a decoupled way the possible scaling issues of clients’ data cache
- idem for managing the external interaction aspects
Examples – same services with various forms of interaction
- Generic Model
- UI based Module
- Interaction with the Human User Client is designed with MVP pattern and provide access to system resources via a set of three services, where interaction layer also orchestrates the calls of these (resources access) services
- “Flat” Flow Background Module
- The client/actor is an internal timer. When it is invoked a single (resource) access server, the interaction layer flow could be “flat” (just redirect the call)
- Complex Flow Background Module
- In a similar case, but when the background run it is similar with one or more actions from UI based module: the interaction flow will keep also the state of the client session between successive services calls
Notes about Microservices
Microservices could be a choice for architecture decisions, but my problem is all the talk about “monolith-application” versus “microservices”. I recommend to read first these Robert Martin articles:
In the above proposed model, the “service”
- Has a clear responsibility – manage the access to the system resources
- Has a rather “plain interface” – the service itself is decoupled from its deployment mode
- These areas are decoupled: the services, the way how actors interact to the systems to access them, and their deployment mode. Services are reusable for more types of interactions and more type of deployment
How the microservices fit with this model:
- The service it is in the same micro-monolith (sic!) with its deployment mode
- The client interaction flow mode is out of scope, but it is forced to access a fixed deployment mode (with afferent technology)
Update (May 15, 2017)
Just find from an Alistair Cockburn tweet (see bellow) that he has updated his “Hexagonal Architecture” with a similar “asymmetry” concept:
<<New note on
#hexagonalArchitecture at http://alistair.cockburn.us/Hexagonal+architecture …. Primary/ secondary actor asymmetry (end of the article) Take look if you like>>
Few comments about the difference between the two similar viewpoints:
- I still believe that main split is between cell related to “client interaction flow” and the cell related to “resource access service(s) flow”
- The case when we have primary actors and secondary actors it is just a particular case when the resource access flow could be assimilated to an internal use case and/or with a distinct component
- In a generic case, there is the possibility that “client interaction flow” to be in the same use case and in the same component as the “resource access service(s) flow”
- 2 cell architecture is never about <<UI and back-end services decisions>> (see Cockburn post section “Separating Development of UI and Application Logic“): we have in the same time flow control, business and technology in both “front-end”, interaction cell and in “back end” resources access cell
- UI is not the only way for interaction with system clients: we can have, for example, external request/response interactions or scheduling/timers, listeners etc.
- 2 cell architecture it is not only about separating adapters and ports, it is about separating also the flows in these two categories: client interaction flow and resource access orchestration flow. The whole application is split in two cells, not only the port and adapters.
“Layered class type architecture” from Scott W. Ambler
Universal Design Pattern – by Koni Buhrer
Hexagonal Architecture – by Alistair Cockburn
Clean Architecture – by Robert C. Martin
- .. and check for coming soon book “Clean Architecture”!
Microservices – by Martin Fowler