Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Build a Monolith before Going for Microservices: Jan de Vries at MicroXchg Berlin

Build a Monolith before Going for Microservices: Jan de Vries at MicroXchg Berlin

Most developers don’t work at global large-scale companies like Netflix or Spotify. Instead, most developers work in much smaller companies with maybe up to 50 – 80 developers, which don't need massive scaling, Jan de Vries noted in his presentation at MicroXchg Berlin, where he argued that a properly built monolith in many cases is superior to a microservices-based system. With a well-built monolith, it will also be easy to pull services out if necessary.

De Vries works as a consultant at 4DotNet and is a Microsoft MVP on Azure. In his experience, a common reason for a move to microservices is scaling, which for him is a reasonable argument. Another reason used is the freedom for a team to select the development environment and technological stack they prefer. Sometimes this is reasonable due to the requirements at hand, but he notes that this freedom can mean that a company has to maintain several quite different environments which can be very costly.

De Vries argues that a monolith often is easy to deploy and run, and an architecture suitable for many applications. If something is failing, the whole applications is failing, and we know it’s failing. Most of the time we also know how to fix it, and can quickly redeploy. It’s robust and often withstands the test of time. Many of us are maintaining a monolithic solution that was built 10 years ago, and this is still running. The few microservices solutions he has come across have been quite fragile and refactored within three years after they were built.

Most monoliths though, are not very well designed and are hard to maintain, which De Vries thinks is one reason so many developers dislike them. But a properly designed and built monolith is a joy to work with. He thinks it should be designed like silos, which each functional piece of logic a silo with one entry point and output, and not sharing any logic or data with other silos. Designed like this it’s also easy to pull out one silo into a separate service, for example due to very different scaling needs.

One of the first microservices designs De Vries came in contact with was built with several small services, each an entity service on top of a database table in one common database, thus depending on each other to actually work — a distributed monolith. With irony, De Vries notes that it had a business failure that you could sell as a performance feature. When the business complains that performance is slow, you can do a SQL query instead of making a REST call to another service, thus getting maybe a 10-fold increase in performance.

In another project, where De Vries was partly responsible, they started with a few small services with separate responsibilities, but they all shared the same database. This is antipattern because if something is changed in the database, all services can be affected. Another problem is that due to the use of synchronous calls between services, if one service fails, all services communicating with the failing service will also fail. During the years the number of services increased to almost 50, all talking to each other at different levels. He therefore calls this a massive distributed monolith, and notes that there is an official name — a big ball of mud. Due to all the pain points, the system is currently migrated towards a design with more isolated services.

Designing a system using one silo or service for each business function is what De Vries prefers, which means that each function becomes a command or request handler handling everything needed for the function. Often there is a need for services to share some data, but instead of using synchronous calls between services, he recommends sending messages using some type of message bus. Then each service can read the messages it needs irrespective of which service is sending them. One benefit from isolating different parts like this is that they can use different types of technological stacks and data storages depending on the need. De Vries points out though that just because you can, it doesn’t mean you must. He is a proponent for keeping it simple, and prefers using one single technological stack, unless there is a good reason to step out to something else.

If you aren’t sharing any business logic you will probably end up with a lot of duplicated code. We have been taught that duplicated code is bad (DRY); instead, we should abstract the duplication away in some way. De Vries earlier followed this rule, which means that he now has solutions with thousands of interfaces and a lot of compositions in classes that make the code base very complicated to understand. For a new team member, it can take months to understand the code and be able to do something useful. This is for De Vries a lot of wasted time; with less abstractions and more duplicated code, he believes the time can be reduced to one or a couple of weeks. An important rule to consider when deciding to duplicate or not is if two pieces of code change together or not; if the reasons for a change are different, then it is not duplication, but rather it just looks like duplication.

Another advantage with services communicating through messages is that when the business asks for a new function that needs information from more than one service, a new service can be created with its own storage. This new service can then read the messages it needs from the message bus and build the information the business requested. De Vries emphasizes that one challenge when designing services is to find the correct boundaries in a system from a business perspective, and notes that design is hard. Writing the code and build for an individual service is for him relatively easy in comparison.

Using a Correlation ID is a way to correlate a request to one service with subsequent requests made to other services. De Vries calls this a hack due to bad design — a request should be fulfilled in one service without the need to call other services. He notes that it can have value from a business perspective, for instance to correlate all requests from a user to find out how he or she is using the system. He emphasizes though that correlation ID should be used to add business value, not to save a faulty design.

In a presentation at the same conference, Sebastian Gauder talked about migrating a monolith to microservices.

In a presentation at the Reactive Summit 2018 conference, Randy Shoup described an incremental architecture approach to building systems and claimed that we should start with a simple architecture and evolve it as needs arise. In a presentation at QCon New York 2017, he described how to do an incremental migration of a monolithic application into microservices.

Greg Young, in a presentation at the Microservices Conference 2016 at Skills Matter in London, talked about the long history of microservices and that we shouldn’t distribute a system unless it’s really needed, the important thing is isolation between services.

In a blog post 2015, Stefan Tilkov argued that the main benefit of microservices are creating clear and strict boundaries between different parts of a system. He also argued against the idea that a microservices architecture always should start with a monolith, and claimed that building a well-structured monolith with cleanly separated modules that later can be moved out as microservices is in most cases extremely hard, if not impossible.

Most presentations at the conference were recorded and will be available over the coming months.

Rate this Article