Best Practices and Tips on Communication, Performance Metrics, and Other Strategies for Monolith Breakdowns
In the world of software development, monoliths are born out of simplicity and necessity.
Say, for example, you are the CTO of a company that is building a new application. You want a small, manageable codebase where all components are in one place and operate as a single unit. This monolithic architecture is straightforward to develop, test, and deploy, making it an attractive choice for startups and small projects.
The developers can leverage a single #technology stack, and all the processes — from database operations to business logistics to server-side rendering — are tightly coupled and run in the same space.
However, as the application grows, new features are added, and the user base expands, this once small and simple monolith can evolve into a complex, sprawling, and rigid structure. This growth, while a sign of success, can also lead to a host of challenges that may necessitate a monolith breakdown.
In my experience as a CTO and global tech leader at major disruptive companies, there are six surefire signals that point to it being time to pivot from monolithic architecture to microservices or modular architecture. If you recognize any of these symptoms or a combination of them at your company, consider a transition from a monolith legacy system:
Scalability Snags: If the monolith has grown so large that it becomes difficult to scale effectively, this might be a sign that a breakdown is needed. This could include hardware constraints, where it's no longer feasible to scale vertically by adding more resources to a single machine, or software constraints, where certain components of the monolith are bottlenecking performance and can't be scaled independently.
Development Slowdowns: As the codebase grows, it may become increasingly complex and difficult to understand in its entirety. This can lead to a decrease in development speed, as developers must navigate a large, complex codebase to make changes or add features.
Team Coordination Problems: If the monolith is so large that multiple teams are stepping on each other's toes during development, a breakdown may be beneficial. With microservices or modular architecture, each team could own a specific service or module, reducing conflicts.
Deployment Challenges: If deploying updates or new features to the monolith is risky or takes a lot of time because a problem could bring down the entire system, breaking down the monolith could allow for safer, more frequent deployments.
Technology Lock-in: Monoliths often force you to stick with a single technology stack for the entire application. If different parts of the application could benefit from different technologies (e.g., languages, frameworks), breaking down the monolith could help because each microservice can use the most appropriate technology for its needs.
Difficulty Isolating Failures: In a monolithic architecture, failures can be harder to isolate and can potentially bring down the entire system. A breakdown can allow for better fault isolation, as a failure in one service doesn't necessarily affect the others.
Once you’ve identified that a breakdown of monolithic architecture is necessary for the health of the team, the product, and the company, the next step is persuading the CEO (and potentially business stakeholders) to authorize the change.
When seeking buy-in from your company’s non-tech executives and leaders, it is critical to avoid tech jargon as much as possible and use terms and concepts that appeal to their business acumen.
Here are six strategies to consider:
Investment Pitch: Position the project of breaking down the monolith as a business investment. Highlight that the return on investment (ROI), in terms of business impact, will be significantly higher than the initial cost (i.e., the engineering months required for the breakdown and the temporary increase in operational costs at the start of the project). The impact can be measured in terms of time to market, increased velocity, better quality, etc.
Business Alignment: Understand your company’s business strategy and goals, and articulate how the monolith breakdown can help achieve these objectives. Explain how the breakdown can also create business impact even if it’s not a part of the current year’s business goals.
KPI Improvement: Use concrete KPIs from the list below to demonstrate the potential improvements that can be achieved through this project. Show how the breakdown can lead to faster development speed, increased deployment frequency, and more efficient resource usage, among other benefits. Estimate concrete numbers of improvement: a 300% increase in X, a 50% improvement in Y, etc.
Explain Tech in Business Terms: Make it clear that this isn't just about refactoring code for fun or for the sake of engineers’ happiness – it's primarily about driving significant business impact in the mid- to long-term.
Pareto Analysis: Conduct a Pareto analysis to identify the 20% of your monolith that, if broken down, will yield 80% of the business impact, and present that to top company execs. The exact measure of impact will vary depending on the business and product specifics.
High-Level Plan with Milestones: Present an attainable plan that outlines the major milestones of the project. Aim to show the first improvements within about three months. This will help build trust with business stakeholders, as they will be reassured they won’t have to wait a year or longer to see the first impact.
Now that you’ve got the C-suite on board, it’s time to get to work. Transitioning from a monolithic legacy system to a microservices architecture while ensuring the system continues functioning is indeed a challenging task. Remember, the transition to microservices should be a gradual process. Start with one bounded context, and as you become more comfortable with the process, continue to break down the remaining parts of the monolith.
Here’s a step-by-step strategy incorporating some important design patterns.
Domain-Driven Design (DDD): Start by identifying the
Anti-Corruption Layer (ACL): Once you've identified a bounded context to convert into a microservice, introduce an
Strangler Fig Pattern: This pattern is particularly useful for gradually replacing a legacy system. The basic idea is to build the new microservices around the edges of the old system, gradually replacing its functionalities. As you develop the new microservices, they take over more and more functionality from the monolith, which eventually gets "strangled".
Backend for Frontends (BFF): If your application has different user interfaces (e.g., web, mobile, third-party APIs), consider creating a separate Backend for Frontend for each interface. This will allow each interface to have a microservice tailored to its specific needs, reducing the complexity and enhancing performance.
Database per Service: Each microservice should have its own dedicated database to ensure loose coupling. Shared databases can create performance issues and tightly coupled services together, defeating the purpose of a microservices architecture.
Continuous Integration/Continuous Deployment (CI/CD): Establish a robust
Observability: Implement comprehensive logging, monitoring, and tracing for your microservices. This is crucial for diagnosing and resolving issues quickly when they arise.
It’s important to note that KPIs and percentages of improvement can vary significantly between different systems, depending on complexity, size of the engineering department, age of the monolith, required functionality, and many other factors. These eight KPIs are ones that I have seen over and over again as true indicators that a monolith breakdown was the correct call:
Productivity (Value Delivered to Customers): If you measure story points by the book, meaning you measure work done that brings additional value to customers and not bug-fixing, work on tech debt, etc., this KPI can jump by 3-5x or more. Sometimes it requires a changing of data models in the system to deliver new functionality to the customers. And it’s extremely hard to do until the monolithic architecture is broken down.
Time To Market/Cycle Time: This can increase up to 300%. However, this improvement may not be immediate. Initially, the development speed might slow down due to the learning curve and the initial overhead of setting up a microservices infrastructure.
Deployment Frequency: With independent deployment of services, you could see an increase of 20% to 50% in deployment frequency.
Failure Rate: In the long term, the failure rate might decrease by 10% to 20% due to the isolated nature of microservices. But keep in mind that in the short term, the failure rate might increase until the kinks of the new architecture are worked out.
Time to Recovery: With isolated failures, you could potentially see a decrease in recovery time by 20% to 40%, as you may not need to restart the entire system when a failure occurs.
Operational Cost/Resource Usage: Improvements in resource usage can be significant, especially for large systems. It all depends on how well you're able to take advantage of the scalability benefits of microservices.
Retention: The engineering team’s happiness will go up significantly after a monolith breakdown. Because they will invest most of their time in making an impact on business rather than wasting time on technical issues related to monolithic architecture/spaghetti code.
Time to Hire: Strong engineers are not very excited about working with monolith and legacy technologies without any option to change. So it will be much easier and faster to hire strong engineers after a monolith breakdown.
Have questions about monolithic architecture at your company or whether it’s time for a breakdown of microservices or modular architecture?
Also published here.