Hamza, thanks for a very knowledgeable, thoughtful, and well-written article. When my organization embarked on our microservices journey (which began as a distributed computing journey) we were very much concerned about addressing the inevitable increase in complexity created by the increased number of components inherent in the microservice architectural pattern. We needed to understand how we would mitigate that increased complexity before we proceeded further.
Ultimately, we made architectural choices that we believed would increase the benefits of the microservice pattern while managing the complexities. After a few additional discoveries and quite a few adjustments we arrived at a very satisfactory solution for our needs.
First, we settled upon the Domain-Driven Design principle of the domain bounded context. That lead us to implementing a bounded context as a first class service component. Essentially, a read/write logical view of the context's datamodel coupled with enforcement of the context's data handling rules. This fit the way we had been implementing the SOA persistence layer logical data views and physical resource handlers that we had been using for years with our REST API.
Second, we chose a reactive, reentrant, stateless actor model implementation for individual microservices. That lead us to message passing and asynchronous messaging, which lead us to REST for messages and ECST (event-carried state transfer) for events.
Third, we extended the actor model concept of the attached mailbox to include both input and output handling, coupled with the enforcement of preconditions and post conditions for incoming and outgoing messages. This provided us with built-in real time unit tests for all microservices in a dynamically configured environment.
Fourth, we used message and event logging in order to implement a high level of observability and recoverability.
Fifth, and far from least, we chose to implement a self-organizing, rather than hierarchical, configuration and management strategy. We began with the old Sun-implemented Jini distributed component model, which was Java RMI -dependent, and created a self-organizing, message passing, federated broker system that can span multiple cloud clusters and data centers.
The entire architecture depends upon containerization and container orchestration and, within bounds, is self-configuring, self-repairing, and self optimizing. I'm exited to see where we take it next. If you are interested in learning more about it, I suggest reading:
https://medium.com/nerd-for-tech/designing-microservices-4130bc41c046