4+1 architectural view model
Once upon a time, I came across a question about a system that was designed according to the microservices architectural style. The question was about how to handle network requests across a scaled-out and load-balanced back-end. When a single visitor accessed the website, it resulted in tens of thousands of HTTP requests in the back-end. With 3 to 4 users, connection timeouts started appearing everywhere. Even though their microservices were loosely coupled and autonomous.
The reason I am sharing this is that everyone immediately understands this behavior is wildly undesirable. Tens of thousands of network requests for a single page request is simply too many. It’s an example of something that went well beyond how we would expect a system to perform. Tens of thousands out-of-process HTTP request for visiting a single page is obviously a problem. But with how many requests is it not a problem anymore? 5000? 1000? 50? 10?
One of the problems here is that likely on paper everything looked fine. There were all these fine-grained services that all would do their own work. They all seemed loosely coupled and autonomous. A monolith is one big block. On paper, the microservices were small, independent blocks that all would do their own thing and are loosely coupled from all the other blocks. Once in production though, every single service relied on many other services, which rely again on many others. An entire chain of RPC requests occurred, often over HTTP, every single one of them inflicted with the fallacies of distributed computing.
On paper everything seemed fine, but in production the experience is quite different.
Different architectural views
Drawing a few boxes on a whiteboard doesn’t make them loosely coupled & highly cohesive and even autonomous by default. You need to look at your architecture from different angles. Philippe Kruchten already described this in what he calls the 4+1 architectural view model.
The “4+1” view model is rather “generic”: other notations and tools can be used, other design methods can be used, especially for the logical and process decompositions, but we have indicated the ones we have used with success.Philippe Kruchten, Architectural Blueprints—The “4+1” View Model of Software Architecture
His whitepaper and other articles on the internet already describe and explain the different views. I don’t think I can add a lot more information there. I want to get a little bit more practical.
One of my favorite subjects in distributed systems is messaging. Communication over HTTP means temporal coupling via Remote Procedure Calls (RPC). Message queues remove the temporal coupling. It introduces different challenges, like eventual consistency. I mention messaging and temporal coupling because those don’t appear in the logical view of your architecture. I’ve noticed more than once that this is the only view used to design a system. Solving temporal coupling in your system via messaging should appear in the Process view and possibly in the Physical view, also called the deployment view.
Duplicating code versus multiple deployments
Another example that I want to highlight is because of my posts on priority messaging. In the third sample that I will write about next, I will separate a few pieces of code and in the logical view, they are very close to the components they belong to.
In the development view, they have names that represent the responsible components, to which the smaller interceptor components belong to. There are four different projects in Visual Studio
StrategicReceiver.Interceptor their names were chosen, to visualize in the development view to which other components they belong to.
In the physical- or deployment view however, the Interceptor components are not deployed with the components they belong to. Instead, they are deployed with the sender. This means the deployment view literally changes how we look at the components, then how we looked at them from the logical view. How they are actually deployed, loaded and used is part of the next blogpost in the Priority Queues – Why you don’t need them series of posts.
I wrote this post for two reasons
- The fact that there are boxes in the logical view of your architecture, doesn’t automagically mean there is decoupling. There are more views in your architecture. Remember that one view doesn’t tell the entire story. There might be coupling, especially temporal coupling, that might incorrectly be considered as decoupling.
- There is a difference in designing a system on paper and how you deploy it, if you consider the 4+1 architectural view models. Embrace the fact that responsibilities can exist in one part of your system. But deploying components from different responsibilities together with other components, doesn’t mean the responsibilities suddenly have changed.
This way you open up new possibilities for a better design and other considerations for deploying your code.