Microservices have gone through a complete hype cycle. From being hailed as the one true way to build systems, to a backlash where they are often considered too difficult and complex. In a way though, they are like most technology – there are trade-offs. You get some benefits and some drawbacks. Here are four features specific to microservices that I have come to appreciate.
True separation. A typical microservice has its own database, and the microservice is only accessible via an API. This means that the microservice internals are not accessible outside it. As long as the API stays the same, the code in the microservice can be changed without any effects to the system outside of that service. You get perfect encapsulation.
In a monolith, you also strive for encapsulation. However, it is more work to enforce it there. You can easily end up with a system where the interfaces between modules start to blur. One module can call a supposedly internal function from another module, and soon there are many more cross dependencies than intended between the modules. Another way you can break encapsulation is through the database. If all modules have access to all the tables in the database, there is a risk that the separation between the modules breaks down because tables intended for one module are read and written to by other modules as well.
Independent scaling. Once the system is separated in different microservices, you can run more instances of services that require more capacity. This is something we have made use of at work, and it is quite convenient. It works in reverse too – you can temporarily scale down a service to no instances. This can be good if you want to make sure there is no traffic in a part of the system while for example doing a database migration.
Multiple languages. With separate microservices, you are free to implement different services in different languages. For example, if you started out writing your services in Python, but you are concerned about performance, you can rewrite them in Go. Or you can leave existing services as they are, but develop new ones using another language. The same goes for other aspects – new services can use another type of database for example. This is quite liberating, because you can experiment with changes (like a different language) in some services without affecting the whole system.
API:s to all the parts. One advantage I didn’t expect is that with microservices you have API:s to all the different parts. This means there is an easy way to interact with every service. This is useful when testing the services. It is also useful for trouble shooting. Many times I have recreated problems by making the same API calls that the code is making. It also makes it easy to access the data each service keeps.
In a monolith you typically also have access to API:s to interact with the system. However, there the access is not as fine-grained as for microservices.
There are of course features of microservices that I don’t like. They are definitely more complex than a single monolith. Network calls between services also make them slower and subject to network errors, something you avoid with a monolith. However, microservices are not all bad. The above four features are aspects of microservices that I really like.