From monolithic to microservices — one hell of a hustle?

Swedbank Tech
6 min readNov 23, 2018

I can still remember one Friday in April 2018, when we had just released a new version of our Internet Bank web application to production. A regular release suddenly turned our internet bank upside down, where the majority of customers were unable to access any page. What was the reason for this? Chat! Yes, chat, which is totally unrelated to any critical daily banking functionality. So, we had a blackout — what to do? Rollback? Not possible, as during release we also had database changes installed, which were already in use by numerous applications. Fix the bug and deploy a new version? Not possible, as installation to production would mean 1-hour of downtime for those lucky customers who did manage to use our system.

Back in the day, our releases were huge. It was an event, once a month, when all of the changes would go live in one big bang. Due to the high volume of changes, anything could go wrong. The release process in general was never easy, but when facing the worst-case scenario, we realised we had to minimise the risk of it ever happening again.

How to solve the problem? Based on the definition of the problem, the solution seems easy: make unrelated functionalities independent from one another; go with smaller and autonomous deployments to avoid big bangs; have a rollback possibility in place. Isn’t that the definition of microservices provided by Sam Newman?

“Microservices are small, autonomous services that work together.”

Yes, the most obvious solution is microservices. Now there was only the question: how can we do it with our existing code base? Since moving to microservices was a new approach for us, we decided not to focus on splitting the current monolithic legacy but focus on making a fresh start instead, creating new business applications from scratch and slowly replacing the existing functionality.

An example of what we had, versus what we are planning to have:

Fix your deployments

Docker is the de-facto standard here. We followed the trend; deploying a new application to any environment now takes seconds instead of hours.

Become stateless and work on zero downtime

For every incident or bug in production, the most important part is how quickly we can deploy a possible fix. Thanks to Docker, we have reduced our downtime to seconds, but it is still downtime and a bad experience for customers.

Here, the big challenge was to make our services stateless. After implementing this change, our customers were no longer tied to a specific instance of an application. This gave us an opportunity to install bug fixes and new features with zero downtime whenever we want without interrupting our clients’ on-going activities. As a small bonus, there is no longer a need for people to stay up late at night to install new versions.

Finding a solution to the “stateless” problem also acted as a trigger for us, when choosing which services should be built first. Therefore a new authorisation and authentication solution based on JWT tokens was introduced as an alternative to storing session information in memory.

Less manual testing, more test automation

Now we can deploy changes to our services quickly and without anyone noticing. Releasing new features has never been so quick and easy. This also meant that we could not waste time on repetitive tasks, like regressions, and had to automate our tests as much as possible.

We spent a lot of time covering the code in our new services with automated tests. From a business perspective, we could have spent more time developing new features, but in the long term, this will help us save time. As they say — invest time to save time.

We performed all kinds of tests — UI, API, Unit and Performance. These are now tightly integrated into the build process and are executed automatically on every commit. Merging a new feature into our integration branch is only possible if the build is successful, all of the tests have passed, static code analysis is successful and a fellow software engineer has given the green light via a code review. This allows us to reduce the amount of manual work and at the same time receive feedback about the quality early on.

Monitor your services

Now that you can release often and quickly, you just have to be confident that everything runs smoothly in production, so make sure to set up proper monitoring. It is easy to monitor and analyse logs when you are dealing with one service, even if it is monolithic. However, it can be a bit tricky when you are trying to set up monitoring and logging for several microservices. Luckily, there are many tools that make the implementation of logs much easier, such as Grafana for metrics visualisation, Graylog/Elastic search to analyse logging, Spring Boot actuator to collect metrics and Spring Cloud Sleuth to track requests between different services.

Improve your technology stack

When you have a huge legacy, you most likely do not have the opportunity to choose the technology for business logic implementation because this was decided centuries ago or, in our case, around 10 years ago. Microservices give you the freedom to choose your own stack. For example, our services can communicate using different backend implementations — some teams use Kotlin but others prefer Java. Since we don’t have the dependency, we can easily upgrade to the latest version of components or try totally new approaches, which otherwise require rewriting half of our applications.

It’s also important to mention that to make teams more efficient and to write services faster, it is better to use one common technology stack for all services. Never choose a technology just to play with it or because of its hype.

Yes, currently all of our new services run on the latest JDK!

Get rid of dependency hell

The main issue of the monolithic architecture is the lack of opportunity to upgrade project dependencies. It is quite difficult — if you upgrade one dependency, you need to make changes in thousands of other places in the code. By the time you are finished with the first round, you most likely have to start all over again with new changes. There you are, stuck in the dependency loop. To make things even worse, altering one part of the application can backfire in another part of it.

Without the dependencies, updating to the latest version of Spring has never been so easy!

When building a new service, make sure that you don’t have integration on a database level. We are currently trying to implement an approach in which our service does not want to know anything about any other database tables but our own and access to our database is only provided by an interface.

To sum things up, is it worth the hype? Yes, totally!

Is it one hell of a hustle? Yes, but it’s totally worth it.

We are not trying to say that microservices are the best solution for every organisation. Microservices are hard to implement and they need huge support both from the business and IT side, and everybody in the team must be on board. The company should understand that new architecture will be more expensive in the beginning but easier to maintain in future.

And finally, if modern tech stack, new microservice challenges, with a friendly and motivated team is something what you miss in your life, then join us at Swedbank.

--

--