How micro should a microservice be?
Two days ago I’ve participated in a JUG meeting in Poznań which special guest was famous Java rock star Adam Bien with his presentation called Microservices in 2016 — What Worked Well. The session was focused on the typical Bien’s stack: JEE microservices & Docker and overlapped with his presentation on Devoxx Poland 2016. But don’t get me wrong - it was totally worth it!
The Bien’s way
One of the most controversial topics during the session was the preffered size and the granularity of microservices. Bien’s approach is to start with a monolith app (single WAR) and split it only when you have a good reason for it (like security requirements). He typically ends up with just a few microservices (eg. about 5), that not always have to encapsulate just one feature. At the same time they should be ‘micro’ in terms of the WAR size and a minimalistic dependecy set - ideally limited only to JEE libs provided by the application server. Probably the most powerful feature of his development model is the speed - he packages and deploys WAR into dockerized application server blazingly fast (seconds!). But are his microservices really ‘micro’?
The other way
One of the meeting’s participants presented quite different approach. In the project he works on, there are about 40 microservices communicating with each other. The difference is they are made with different technologies (not only Java) and they don’t necessary have small dependency set. The main rule they follow is ‘one microservice for each feature’. Question he asked Bien was about the difference between these approaches. He also emphasised that they are really satisfied with this architecture, even if it’s more complicated and requires additional services orchestration. It seemed that he suggests that his microservices are more micro than Bien’s…
Adam Bien doesn’t doubt his approach and he has multiple reasons for that. What he proposes (and offers as a consultant) is not only a software stack but a complete workflow - from developing code, through the deployment and testing. It’s proven, it’s stable and it’s fast. Keeping the number of services small enables him to reduce the need of the orchestration layer which drastically simplifies the whole architecture. The trick he uses is emphasising that term microservice doesn’t have a single sharp definition :-)
It doesn’t mean obviously that the other guy was wrong - it all depends on the given scenario. Service per feature gives you a freedom of language & technology choice (which may or may not be a good idea) and very strong feature isolation. The changes you make may have smaller impact on other features (because they’re not in the same WAR anymore), and it’s easier to scale up just the thing you need.
Don’t be orthodox!
At Consdata, inspired by Bien’s Airhacks workshops, we developed a banking mailbox application based on microservices (more details on this Bien’s blog post). What I’ve learned during the project is that:
- each microservice should be logically consistent (in terms of features and responsibility)
- pure JEE is nice and sufficient to many use cases, but if you need something else just use it (don’t implement it yourself just because of the JAR size)
- keep WARs size reasonably small (but don’t fight with everything around)
- deployment with docker (especially when you have hierarchical images structure) is an order of magnitude faster than the classic way (even if you haven’t removed everything from your dependencies)
- make your services micro in terms what you really need in the specific scenario - it’s not the war between Vim and Emacs
- keep things simple! (as always)
PS. We all know that Vim is the best, right? :-)