Kyle Brown, IBM Fellow, IBM Garage
One of the most depressing parts of my job is doing postmortems on failed cloud adoption projects. This happens fairly regularly; we get called in to a client to help them understand why the steps they’ve taken toward cloud adoption have not lived up to their expectations. There is often recrimination and finger-pointing all around, and the most important thing I can do in a situation like that is remain calm and help the client arrive at a conclusion based on facts and not supposition. One of the most common problems that I often see resulting in these failures is that the team only went part of the way toward a full cloud-native transformation, and stopped before they got there.
It’s not much of a stretch to say that cloud native isn’t as much of a description of an architecture (although there are definitely cloud-native and non-cloud-native architectures) as it is a holistic description of not only a set of architectural decisions, but also decisions around process and organization that are required to support that architecture. The technical decisions are necessary but not sufficient for a team to be successful at building and especially managing and maintaining cloud native systems. You need all three sets of the following decisions to be coordinated in order to succeed:
Technology — These are (relatively) the easier decisions. They include things like applying a microservices approach, writing components so that they can take advantage of horizontal scaling, and taking advantage of open source technologies so that you can leverage the efforts of the community. But each of these decisions come with corresponding process and organizational decisions that are needed to support the technology decisions.
Team Organization — Microservices implies that you are building your services in small, autonomous teams. This is simply the application of Conway’s Law — if you want your system to be composed of small, decoupled components, then you have to allow your teams to also be small and not tightly coupled to other teams — the loose connection to other teams should echo the architectural approach of only allowing formal inter-process communication through APIs.
Processes — Microservices implies that you are applying DevOps principles to your development processes such as Continuous Integration and Continuous Delivery. But this itself requires you to adopt other specific technical processes such as Automated Testing, and strongly leads you toward Trunk-based development. In fact, it will be much easier for you to adopt these practices if you first adopt development practices like Test Driven Development and Pair Programming.
The problem comes in when a company tries to skip one of these three legs — if you knock out one leg of a stool the entire thing falls down. For instance, a common problem we see that is indicative of a larger problem is when companies tell us they are building multiple “microservices” while at the same time they are applying the SAFe method to manage a very complex interaction of multiple release trains in the resulting system. You can’t require both; this is a self-defeating proposition.
If your design requires multiple complex release trains, then you probably aren’t following one of the key principles of microservices, which is that the DevOps pipelines for each micro service should remain independent of each other (or at least as independent as possible). What’s more, this kind of coordination also strongly implies that your system is more tightly coupled than it should be because you need that level of coordination. What’s more, requiring this level of coordination means that your teams are not truly autonomous — you’re probably just breaking a big team into smaller arbitrary chunks and not giving them true autonomy.
Another root of this kind of thinking can often be traced all the way back to the interaction between IT and the Business. We see this in the following diagram:
The only reason for a team to adopt a cloud-native development approach (such as one incorporating microservices) is so that the team can deliver measurable units of business value, incrementally. But if your business cannot work that way — it cannot think in terms of small units of business value that can be independently delivered over a period of time, then the microservices architecture, and indeed, most of the rest of the cloud native approach, will not be of much value.
So whenever I see an incomplete transformation, my first thought is to sit down with both the business and IT leaders and ask them what their expectations of the cloud adoption were. Often, you’ll see that the expectations differed dramatically. For instance, in an “IT-led” transformation effort, you’ll sometimes see the business left out of the transformation — when in fact, they should not only have a seat at the table, but they should be leading the effort. One symptom of this is when I ask the Agile teams who the Product Owner reports to — if it is someone in IT, then we may have a problem in that the business is really not involved as deeply as they should be. But that’s not the only symptom of an incomplete transformation. A couple of others include:
- If you still have an Architecture Board approving designs, or a Change Control Board approving all releases, then you’ve not really granted full autonomy to your teams. You should be setting guidelines and then just ensuring the teams are working within the guidelines
- If you aren’t able to rapidly formulate and test your business hypotheses (through A/B testing) then you’re not gaining the potential business results that cloud can promise. This all depends on a tight interaction cycle between the business and IT.
There are many other examples of ways in which teams can fail with an incomplete transformation; way too many to list here. With apologies to Tolstoy, “all successful transformations are alike; all unsuccessful transformations fail in their own way.” Sticking to the basics of making sure that all three pieces are enabled, and that IT is aligned with the business is all you need to do, but it’s not easy to ensure that this happens. You have to keep revisiting these basics at every stage in order to push the transformation to completion.
So what positive actions can you take to make sure you follow through on your transformation and not stop in the middle? What does going back to these basics practically mean?
- On the organization side, the first and biggest step to take is to build small (e.g. 2-pizza) teams and grant them the autonomy to make their own technical decisions, and ensure that they have an embedded, dedicated Product Owner who can make their own business decisions. These decisions should be made within limits, but this is the biggest step. Many teams (ours included) have found that a framework like the Spotify model is also good for helping larger teams (e.g., groups of 2-pizza teams) define those limits through collaborative organizations like Chapters, Guilds and Tribes, and to coordinate across small teams.
- On the technical side, make sure that teams are following architectural choices that reduce coupling across services, increase cohesion within components, and ensure that features are able to be added quickly and easily. That includes things like embracing containers, or serverless if you’re writing new code, and ensuring that if you are using techniques like microservices that you’re not introducing “hidden” coupling through shared databases, and that you take advantage of all of the architectural options services can benefit from, for instance, using both synchronous and asynchronous call paths.
- On the process side, the most important step is to adapt the technical practices from Agile development methods like XP that Forsgren et.al. have identified as being the key to success. This includes not only per-service CI/CD, but Test Driven Development, Pair Programming, and most importantly, letting teams drive their own Agile transformation. Top-down education on agile principles and methods is great, but teams perform best if they own the process.