How to save your microservices project from a macro fail
Getting immersed in a microservices project? Check out our list of possible risks in the development process in order to safeguard it and improve its chances of success.
The hype has passed, but microservices still stay with us. Today the architectures of most complex systems are partially or fully based on the microservices approach. No wonder that’s the case since splitting into microservices brings a lot of benefits to large-scale applications. Quite often, though, it happens at the cost of increased complexity and a greater challenge for the development team.
To make the life of the team engaged in such a project a little easier and the end user’s satisfaction a little closer, we’ve made up a small checklist with common project bottlenecks. It will quickly signal if you’re are on a very, very slippery road.
You have vaguely defined microservices responsibilities
The right sharing of microservices responsibilities is the foundation for a successful project. The clearer borders you draw between the components, the more loosely coupled system you get. The clearer borders you draw, the fewer chances there are that later you’ll discover some hardly desirable hidden connections between different services.
In reality, it’s difficult to define completely independent fields of microservices responsibility. Dedicated to a certain business process, they are often as well interconnected as the multiple business processes are.
SEE ALSO: Microservices and test automation
Moreover, often the team skips clear bordering from the very beginning imagining that someday in the future they may split them into more independent components. This is a cruel misconception as with the system’s growth and development, the services will get only more tightly coupled and their dependencies only harder to eliminate.
Such connections deprive microservices of their change and update flexibility. Every time you introduce innovation to a service or implement its new version, you need to make sure not to harm its interoperability with other services. And in the worst cases, you are forced to deploy a bunch of services only together.
To avoid such complexities, consider involving in the project domain experts who’re much more aware of the processes happening inside their business domain or company department and can help you uncover not that evident connections. Guided by their deep knowledge, the microservice architect will be able to minimize avoidable interconnection and create as many independent elements as possible.
You allow multiple API variants
APIs should be described in detail and standardized from the very start. Keeping them neutral and reusable, you greatly simplify monitoring, security management and scaling as well as allow the quick introduction of new components (owing to standardization, you have partially ready and tested API elements), streamline future integration with outside components and exposure for external/public usage.
You allow common codes
When it comes to the microservices approach, the don’t-repeat-yourself principle loses its strength. Better repeat yourself and copy-paste than cause excessive coupling by introducing a common library.
Common codes require the special treatment of updates and new versions. Every time you decide your service needs the update of the common library, you should inform other dependent microservices teams and make sure their respective microservices are prepared for the changes.
You strive for strong data consistency
Remember the famous project management triangle of time-quality-cost that has proved itself millions of times? There is a similar one in the theoretical computer science. Its sides are consistency, availability, and partition tolerance. The desire to ensure strong consistency in a distributed system often implies using blocking protocols that significantly increase response time and create additional dependencies, which complicates future scaling and loads the network. In most cases, you can safely settle on eventual consistency.
The problem left pending is long distributed transactions of a critical character, such as ordering, booking operations, etc. In this case, the system may take a user’s money, but they never get their order received or their hotel room booked. To avoid the problem, consider introducing a set of rollbacks or other compensation mechanisms – just like the Saga pattern does – to your system that will cancel the whole operation in case of a partial failure to save UX.
You believe your service saying it’s doing okay
Proper monitoring is essential when you deal with a microservices-based system with many interoperable components. It’s not enough to ensure that each service is working, you should check how well they are working. You may experience a kind of slow work of the whole system and don’t understand what’s wrong since each microservice seems to be in non-fault condition. The reason being that one of your services processes only 150K queries instead of 200K required and makes the rest wait.
SEE ALSO: If you want to check in on the microservices in your Istio service mesh, Kiali’s got you covered
To avoid this and similar problems, you can use such frameworks as Zuul, Hystrix, etc. for Java-based projects that not only check if your services are alive but also report their performance and current state, isolate the crashed service and give it time to recover re-routing the queries. They also provide valuable statistics on your system production and can timely signalize that it needs improvements, e.g., dynamic balancing, for correct work.
You try to prevent relevant failures
With a distributed system, you get practically unlimited failure risks – your services can crash, the network can crash, the network equipment can crash, external systems can crash, etc. To prevent all this sounds like pure science fiction.
So, what to do? Design a system that is fully prepared to overcome multiple emergency cases and sees them as a part of a daily routine. This is often done through failure isolation, tree hierarchy and the introduction of message queues, etc. (consider Akka actors as a good example).
Mistakes in microservices projects are easy to make due to the increased complexity of such projects. And, as such projects take more time, more effort, and more money and, thereby, make the failure result into considerable losses in all these three, the mistakes are harder to afford. Take care of long distributed transactions, clearly divide microservices responsibilities, avoid reckless code sharing, standardize the APIs, introduce thorough monitoring, and you make a good step forward and close the door for a good number of problems with the project.