Our Code is Hopelessly Entangled With the Monolith!
We really want our code to be a set of services. That unlocks CD and DevOps. However, our code is currently a long ways away from being Service Oriented so we will get to services incrementally.
Our first target is Continuous Integration (CI). We think of CI as a system to rapidly find mistakes so that we can correct them. However, the power of CI comes from an unexpected source — team independence.
Stepping back, most companies organize each set of capabilities to a separate team. Each team makes changes related to its product focus, and all changes related to one product capability will be made by the same team. That makes management simpler. Managers can change company investments by changing team size or by moving teams to work on different capabilities.
CI takes advantage of this relationship between team membership and product focus to allow teams to work more independently.
Good CI allows each team to:
- Edit independently from other teams.
- Verify intent independently from other teams. Know each change works as intended when taken in isolation.
- Compile independently from other teams.
- Integrate independently from other teams. Combine your code with the rest of the product without needing support from those creating the rest of the product.
- Verify interactions independently from other teams. Know each change will work with other teams’ code without having to interact with or wait on those teams.
Completing each step independently allows each person and team to find problems quickly. Each kind of independence makes the next one possible.
Legacy Code Blocks Continuous Integration
All 5 kinds of independence fail with legacy code monoliths.
The legacy code monolith grew along with the teams. It started with one team so everything was together. As the company grew and added teams, the code couldn’t split as quickly as the team responsibilities did. The code stayed all together. Each team learned which kinds of changes it needs to make, but they all change the same classes and methods. This prevents all 5 of the points of independence that make up CI.
Because teams can no longer change, compile, or verify their code independently, mistakes cannot be found quickly. Breaking independence prevents rapid feedback.
Assigning Code to Teams Doesn’t Work
One common solution is to assign code to teams. Each method or class is simply assigned to the team that changes it most often. Unfortunately, that doesn’t work because each chunk of code performs actions related to multiple product capabilities. That means each feature will need changes in code that is now “owned” by multiple different teams. The resulting increase in management complexity and cross-team dependencies overwhelms any gains attained by independent editing.
We want to edit, verify intent, compile, integrate, and verify interactions independently of other teams. Yet our legacy code monolith means that all teams are editing the same code, so nothing can be independent.
The resulting problems include:
- We can’t afford to assign code to teams.
- We can’t change the code structure as quickly as we change team structures.
- We can’t afford to rewrite the monolith.
How can we change the code to allow independence that matches our team structures?
Create a Roadmap to Escape the Monolith
Over the next several months we will enable each point of independence one at a time. This month we will help everyone on the team see the plan, the obstacles, the investments, and the returns we will encounter along the way. Let’s start with the subgoals and their solutions.
A Perfect World: Clean Code
If we had clean code, we would simply achieve each point of independence one at a time. We would implement each technical solution and then leverage it to create the next.
- Enable Edit independently by extracting single-purpose Components. Each component has only one reason to change so only one team will edit it.
- Verify intent independently using Core Unit Tests. Core tests verify the 60% of each component that doesn’t interact with other components.
- Enable Compile independently using Libraries. Library APIs break compilation dependencies between components.
- Enable Integrate independently using Client Ports. Ports and adapters allow the library consumer and provider to collaborate on integration without having to actually share code.
- Verify interactions independently using Port Unit Tests. Ports provide the clean description for integration that allows independent verification of alignment between provider and consumer.
At that point our code will have attained Continuous Integration. Each library can be built and tested independently, and running all the independent verifications gives proof that the system as a whole will work.
Back to Reality: Legacy Code
Unfortunately it isn’t quite that simple. Legacy code throws up obstacles to every step. Organizations see the iceberg of challenge for services, but when we do a scuba dive, there is much more necessary to ensure services will be effective.
This is a multi-month process. It will take us 6 more monthly newsletters to work through the obstacles and solutions. It will likely take you even longer to make those changes in your codebase.
We Started Already: Enabling Unit Tests and Breaking Dependencies
Last month’s efforts to enable basic unit testing has started breaking up dependencies. That’s the first step on the roadmap. Keep doing it!
For the next steps, we address obstacles and create the solutions one subgoal at a time. Managers and PMs will see business value from each phase and understand what investment they need to get there.
Management Support During the Hard Times
It’s important to start out with a clear agreement about the goals, the obstacles, the resources needed, and the rewards expected. Then you can assess outcomes as you go and change direction when you learn something new.
Keep in mind ultimate achievement is getting the code ready for DevOps. That is in every stakeholder’s best interest! However, getting there is hard and takes time, so it’s important to remind them of both the DevOps achievement and how escaping the monolith aligns to their more personalized goals.
- Product Managers can measure how escaping the monolith helps the customer.
- Senior management can measure how it is reducing total organizational cost and risk.
- Direct managers can see team members taking initiative and making improvements that impact the company.
- Partner teams can measure how your change makes life easier for them – and how them making a similar change would help them even more.
When you need operational support — and you will because Legacy Code causes unexpected problems — your entire business community will be prepared. Because they have seen the value over and over, they are much more likely to step in to give you the support that you need to keep at it.
- Get support when you need it.
- Look amazing on your next performance review.
- Address the code problems that cause you frustration.
- Always know the next small step to take, without having to think about it.
- Align all the implementers to share work and make rapid progress on one kind of obstacle at a time.
- Requires thinking from the outsider perspective.
- You will spend time measuring, charting, and tracking data.
- You will spend time communicating about results.
Demo the value to team and management…
Your roadmap demo goes to a wider audience than your sprint demo, so it will happen over email. Each email will consist of a visual story told with an example and a set of charts.
Each story email contains 4 things:
- Hook: Pithy statement of the value increment this week.
- Example: One instance, from the audience’s perspective.
- Progress: The progress chart.
- Impact: Charts showing results of their value measures over time, specific to the role you’re addressing.
Hook: Pithy Statement of Value Increment
This is the first sentence of your email, but write this last.
Examine the impact measures and the example, and provide a 1-sentence statement of what was awesome. Make it clear. Use emotion words. Help your audience feel the result, not just think about it.
Example: One instance, from the audience’s perspective
You are sending a different email for each audience (see recipe for details). Each will contain the same progress measures, but different examples, impact charts, and hooks. Provide an example that is significant to the role you’re emailing.
If possible, use an example that actually happened in the week to someone in the audience. Otherwise use an example that someone could have run into this week but no one did. In either case, show how you fixed it and no one will ever have to worry about it again.
Progress: Progress Dashboard
Show the main progress chart. Remind them of the example and how many instances of that you made go away this week – and how many remain. Let them see that there is still a long way to go, but that you are making consistent progress.
Impact: Their Value Measures – as Charts
Use the value measures you gathered from this audience while you created your roadmap. Place each on a historical chart showing weekly progress. Link from each chart in the email to the project value dashboard provided in the recipe.