Splitting the Solution - Part I
Topics: DrDoctor tech
Starting on the path to break the monolithRecently it has become clear that microservices are not a silver bullet. It is almost as common these days to see a blog post that warns developers to steer clear of microservices as it was five years ago to see one that praised them as the holy grail.
I do agree with the sentiment that development teams should start off with a well designed monolith rather than starting to straight away define their microservice boundaries. When starting out it is impossible to predict how your idea of the business and the business domain will evolve as things mature.
This well designed monolith has been the chosen (explicitly or not) path at DrDoctor. This path has worked very well for the past 7 years and in many aspects still works very well. Our services, websites and infrastructure are resilient, using a distributed message bus architecture. Our build and deploy pipeline is well established and easy enough to understand and we are still delivering features quickly (releasing to production 5+ times a week).
However 7 years later we have evolved from a single development team of 2 developers working from a shared backlog of work. We now consist of four separate development teams ("pods") of developers all working on different product areas and separate backlogs of work. We currently have 11 developers working in four different time zones and the pain
points of a large monolithic code base are starting to show as we scale.
- Size of the solution
- At a size of 210 .NET projects (and counting) in a single solution, even the beefiest new laptops sometimes struggle with the processing power required.
- Switching feature branches, rebuilding, running tests, debugging locally are increasingly becoming more painful as the solution grows. Even small chunks of time zones spent waiting for these can slowly hinder a developers productivity throughout the working week.
2. Build times
- At DrDoctor we follow best practice by having an automated CI pipeline using Teamcity. Whenever a commit is pushed to our bitbucket repo, a new build will be triggered in Teamcity for both master and feature branches.
- The build process builds the entire solution and runs ALL tests (unit tests, integration tests, spec tests, js tests etc). This is brilliant for ensuring we avoid breaking existing functionality when making changes.
- Our monolith contains over 30 different services, websites or console applications / agents that get deployed.
- Although we can manually exclude / include these during releases it is sometimes easier and safer to just deploy them all, for example if you have changed a shared library which may be used in multiple places.
4. Encourages "bad habits"
- When developing a new feature or service it often feels much easier to just add it to the existing solution as we have a lot of useful code we can utilise. We do not currently have internal APIs that our services can use to fetch data so we end up using the already existing repository classes defined in the monolith.
- This is a catch 22 as it makes it harder for us to develop new services outside of the monolith so the monolith instead grows larger.
It is worth noting that we have been putting a lot of work in over the last 12 months to make sure our bounded contexts are correct which has involved a fair chunk of refactoring and shifting classes and projects around. This has put us in a good footing for the next step.
We are now acknowledging that the pain points are outweighing the simplicity that comes with a monolith codebase. A dedicated team has now been allocated for 2020 to start breaking the monolith apart. Stay tuned for the next episode where I will highlight the decision making process to decide how to start tackling this beast!