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?