And how it shows up in Microservice Architectures
This is a first in a series on software architecture that I am planning to write. I will be focused mostly on architectures that I have discovered in the wild by inheriting an older project or have implemented myself.
As the name suggests this architectural style focuses on layering. Layering provides abstraction and separation of concerns. Often different layers run on separate hardware and are individually protected ensuring only a specific neighbouring layer has access.
What’s being Layered?
Usually the layering is driven by two factors. Technical and business capabilities and organizational structure — often these can be somewhat intertwined.
The UI Layer for example would often be driven by security and usability concerns. On the other hand, the Persistence Layer would be driven by data access, data security, and privacy concerns. By separating these concerns teams can ensure consistency and focus on their specific work. Developers working on the UI Layer don’t need to worry about privacy or data security as the Persistence Layer will ensure that data stored is secured, potentially encrypted, and that data access is controlled. Similarly, developers at the Persistence Layer don’t need to worry about how data is being displayed, how long text is handled, etc. Teams can become focused and achieve mastery at the layer that they are developing and maintaining.
Additionally, each layer has its own access control. This provides additional safe guards. Only the UI layer would traditionally be exposed to the internet — all underlying layers would be open only to layers above it. This ensures that there is a small attack surface.
Often these layers also match business functions of teams. A database team might maintain the database layer — ensuring servers are optimized and patched. A digital design team, or even a third party agency, may be maintaining the UI layer.
The utopia of Layered Architecture is that one day we can swap out an Oracle DB with SQL Server and we would only need to only modify the Persistence Layer. All other layers will remain as is and will not even have to be tested after the Persistence Layer has been thoroughly vetted.
In reality, nobody is going to swap out a database, primarily because a production database has sensitive information that nobody wants to risk loosing during a migration attempt. Validating that the data migration was successful is equally painful and nobody’s idea of a desirable project.
Security is heightened by a Layered Architecture. The Persistence Layer would typically be closed to the world and only open to the Business Logic Layer and the database itself. A hacker coming in through the UI Layer would have to hack multiple independent systems to finally penetrate to somewhere worth hacking into. Obviously, this may not always happen as organizations may get sloppy and be weak with the security of inter-layer communication.
Layered Architectures introduce technological independence but inadvertently end up creating logical coupling across distributed environments.
A UI Layer may capture a profile change — e.g. a user updated their home address — this home address needs to travel through several layers, unmodified, to the Persistence Layer to finally be stored in a database. If for some reason this didn’t work, debugging will be challenging as we have to follow the data through several layers. The UI Layer can only talk to the layer directly below it (or in theory the layer directly above it). Any change within any of the intervening layers may have triggered the address to be lost. As a result layers become strongly coupled in terms of the API they can expose and the modifications they can make to their codebase.
There is an option to open up layers, but as Layered Architectures evolve teams adjust to reduce the need to modify many layers. They think in patterns that allow them to minimize changing more than one layer, essentially pigeon holing the architecture into a single corner. Developers may find that they don’t want to edit the UI Layer and the Aggregation Layer as that may require testing and debugging two layers including the network connection between them. Slowly, Layers become manipulated and drift into all purpose zones, and may even start resembling the big ball of mud.
Layered Architectures can succeed but need strong governance to ensure that feature creep doesn’t leave the layers porous.
Microservices and Layered Architectures
When working on a Microservice Architecture, layers may appear in two different ways — one good, one not so good.
- Release Velocity and Technology
An Engagement Layer may be separate from a Business Capabilities Layer. Architects and developers may chose easier to code and faster to modify solutions like NodeJS and MongoDB for engagement focused content that may change frequently and needs to keep up with user demand. On the other hand, core business capabilities will not change overnight and architects may choose more robust enterprise type technology stacks like Oracle and Java. Over time a distinct separation will appear and it would be advisable to introduce a gateway between the two to further ensure independence. This is a good thing and an aspect of evolutionary architecture.
2. Conway’s Law
Organizations design systems that reflect the communication structure of the organization. Often large enterprises may have teams with directors and VPs that feel they own a specific business capability. This maybe good — they want to ensure reliability to many clients that rely on their services, or bad — they simply want to push their weight around and stay relevant. Either way, teams will adjust and treat other team’s business capabilities as black boxes and build abstractions around them. What emerges is a Layered Architecture of sets of Microservices consisting of specific team’s business capabilities.
This hampers innovation as consuming teams are not aware of the actual potential inside another layer. Teams in the same organization end up having to innovate in isolation.
If you are still maintaining a monolith you maybe sitting on an n-tier Layered Architecture. If you are swimming (or drowning) in a Microservice ocean you may see layers emerge. Layers can be good if you maintain them properly — they need strong governance.