Phil Calçado, former Director of Engineering, SoundCloud
Building solutions with speed and safety at scale.
If you’re like most software developers, team leaders, and architects responsible for getting working code out the door of your company, this phrase describes your job in a nutshell. Most of you have probably struggled at this, too. Getting to market quickly seems to imply giving up a bit of safety. Or, conversely, making sure the system is safe, reliable, and resilient means slowing down the pace of feature and bug-fix releases. And “at scale” is just a dream.
However, a few years ago people started talking about companies that were doing just that. Shortening their time-to-market on new releases, actually improving their system reliability, and doing it all in runtime environments that were able to respond smoothly to unexpected spikes in traffic. These companies were “doing microservices.”
In this chapter we’ll explore what microservices are and what it means to build an application the microservices way. To begin with, we’ll explore the meaning of the term microservices by learning about its origin. Next, we’ll take a look at some of the biggest perceived barriers to adopting microservices. Finally, we share a simple perspective on application development that will help you better understand how all the pieces of microservices systems fit together, a balancing act of speed and safety that we call the microservices way.
To better understand what microservices are, we need to look at where they came from. We aren’t going to recount the entire history of microservices and software architecture, but it’s worth briefly examining how microservices came to be. While the term microservices has probably been used in various forms for many years, the association it now has with a particular way of building software came from a meeting attended by a handful of software architects. This group saw some commonality in the way a particular set of companies was building software and gave it a name.
At the end of our three-day meeting, one of us called out a theme—that year it had been clear that many of the problems people were facing in the wild were related to building systems that were too big. “How can I rebuild a part of this,” “best ways to implement Strangler,” etc.
Turning that on its head, the problem became “how can we build systems that are replaceable over being maintainable?” We used the term micro apps, I seem to remember.
The common theme among the problems that people were facing was related to size. This is significant because it highlights a particular characteristic of the microservices style—it is designed to solve problems for systems that are big. But size is a relative measure, and it is difficult to quantify the difference between small, normal, and big. You could of course come up with some way of deciding what constitutes big versus small, perhaps using averages or heuristic measurements, but that would miss the point. What the architects at this gathering were concerned with was not a question of the size of the system. Instead, they were grappling with a situation in which the system was too big. What they identified is that systems that grow in size beyond the boundaries we initially define pose particular problems when it comes to changing them. In other words, new problems arise due to their scale.
Something else we can derive from James’ recollection of the day is the focus on a goal rather than just a solution. Microservice architecture isn’t about identifying a specific collection of practices, rather it’s an acknowledgment that software professionals are trying to solve a similar goal using a particular approach. There may be a set of common characteristics that arise from this style of software development, but the focus is meant to be on solving the initial problem of systems that are too big.
The revelation that microservices are really about replaceability is the most enlightening aspect of the story. This idea that driving toward replacement of components rather than maintaining existing components get to the very heart of what makes the microservices approach special.
If you are interested in learning more on the history of microservices, visit http://api.co/msabook.
Overwhelmingly, the companies that we talked to have adopted the microservices architectural style as a way of working with systems in which scale is a factor. They are more interested in the goal of improving changeability than finding a universal pattern or process. Finally, the methods that have helped them improve changeability the most are primarily rooted in improving the replaceability of components. These are all characteristics that align well with the core of the microservices ideal.
If you are responsible for implementing technology at your company, the microservices proposition should sound enticing. Chances are you face increasing pressure to improve the changeability of the software you write in order to align better with a business team that wants to be more innovative. It isn’t easy to make a system more amenable to change, but the microservice focus on building replaceable components offers some hope.
However, when we’ve talked to people interested in adopting microservice-style architectures they often have some reservations. Behind the enthusiasm for a new way of approaching their problem is a set of looming uncertainties about the potential damage that this approach might cause to their systems. In particular, after learning more about microservices methods, potential adopters frequently identify the following issues:
They have already built a microservice architecture, but they didn’t know it had a name.
The management, coordination, and control of a microservices system would be too difficult.
The microservices style doesn’t account for their unique context, environment, and requirements.
While we don’t believe that microservices is the answer to every question about a potential architecture choice, we do feel that these particular fears should be better understood before dismissing an opportunity to improve a system. Let’s take a look at each of these barriers to adoption in more detail.
Earlier in this chapter we shared the story of how microservices got their name, but we never actually came up with a concrete definition. While there is not one single definition for the term “microservice,” there are two that we think are very helpful:
Sam Newman, Thoughtworks
Adrian Cockcroft, Battery Ventures
They both emphasize some level of independence, limited scope, and interoperability. We also think that it is important to view “a microservice” in the scope of an existing system. For that reason our definition of microservices also includes the architectural element:
A microservice is an independently deployable component of bounded scope that supports interoperability through message-based communication. Microservice architecture is a style of engineering highly automated, evolvable software systems made up of capability-aligned microservices.
You may find much of what is described in the preceding definition familiar. In fact, your organization is probably doing something like this already. If you’ve implemented a service-oriented architecture (SOA), you’ve already embraced the concept of modularity and message-based communication. If you’ve implemented DevOps practices you’ve already invested in automated deployment. If you are an Agile shop, you’ve already started shaping your culture in a way that fits the microservices advice.
But given that there is no single, authoritative definition, when do you get to proclaim that your architecture is a microservice architecture? What is the measure and who gets to decide? Is there such a thing as a “minimum viable microservice architecture”?
The short answer is we don’t know. More importantly, we don’t care! We’ve found that the companies that do well with microservices don’t dwell on the meaning of this single word. That doesn’t mean that definitions are trivial—instead, it’s an admission that finding a universal meaning for the microservices style is not important when it comes to meeting business goals. Your time is better spent improving your architecture in a way that helps you unlock more business value. For most organizations this means building applications with more resilience and changeability than ever before. What you call that style of application is entirely up to you.
If you are considering adopting a microservice architecture for your organization, consider how effective the existing architecture is in terms of changeability and more specifically replaceability. Are their opportunities to improve? Could you go beyond modularity, Agile practices, or DevOps to gain value? We think you’ll stand a better chance at providing value to your business team if you are open to making changes that will get you closer to those goals. Later in this chapter we’ll introduce two goals that we believe give you the best chance at success.
Earlier in this chapter we shared perspectives on microservices from Newman, Cockcroft, Lewis, and Fowler. From these comments, it is clear that microservice applications share some important characteristics:
Small in size
Bounded by contexts
Built and released with automated processes
That’s a big scope! So big that some people believe that microservices describe a software development utopia—a set of principles so idealistic that they simply can’t be realized in the real world. But this type of claim is countered with the growing list of companies who are sharing their microservice success stories with the world. You’ve probably heard some of those stories already—Netflix, SoundCloud, and Spotify have all gone public about their microservices experiences.
But if you are responsible for the technology division of a bank, hospital, or hotel chain, you might claim that none of these companies look like yours. The microservices stories we hear the most about are from companies that provide streamed content. While this is a domain with incredible pressure to remain resilient and perform at great scale, the business impact of an individual stream failing is simply incomparable to a hotel losing a reservation, a single dollar being misplaced, or a mistake in a medical report.
Does all of this mean that microservices is not a good fit for hotels, banks, and hospitals? We don’t think so and neither do the architects we’ve spoken to from each of those industries. But we have found that the particular way your organization needs to implement a microservice system is likely to differ from the way that Netflix implements theirs. The trick is in having a clear goal and understanding where the dials are to move your organization toward it. Later in this book we’ll shed some light on the principles and practices that help microservices companies succeed.
Two microservices characteristics that you might find especially concerning are decentralization and autonomy. Decentralization means that the bulk of the work done within your system will no longer be managed and controlled by a central body. Embracing team autonomy means trusting your development teams to make their own decisions about the software they produce. The key benefit to both of these approaches is that software changes become both easier and faster—less centralization results in fewer bottlenecks and less resistance to change, while more autonomy means decisions can be made much quicker.
But if your organization hasn’t worked this way in the past, how confident are you that it could do so in the future? For example, your company probably does its best to prevent the damage that any single person’s decisions can have on the organization as a whole. In large companies, the desire to limit negative impact is almost always implemented with centralized controls—security teams, enterprise architecture teams, and the enterprise service bus are all manifestations of this concept. So, how do you reconcile the ideals of a microservice architecture within a risk-averse culture? How do we govern the work done by microservices teams?
Similarly, how do you manage the output of all these teams? Who decides which services should be created? How will services communicate efficiently? How will you understand what is happening?
We’ve found that decentralization and control are not opposing forces. In other words, the idea that there is a trade-off between a decentralized system and a governed system is a myth. But this doesn’t mean that you gain the benefits of decentralization and autonomy for free. When you build software in this way, the cost of controlling and managing output increases significantly. In a microservice architecture, the services tend to get simpler, but the architecture tends to get more complex. That complexity is often managed with tooling, automation, and process.
Ultimately, you must come to terms with the fact that asserting control and management of a microservice system is more expensive than in other architectural styles. For many organizations, this cost is justified by a desire for increased system changeability. However, if you believe that the return doesn’t adequately outweigh the benefit, chances are this is not the best way to build software in your organization.
When you first begin learning about microservice architecture it’s easy to get caught up in the tangible parts of the solution. You don’t have to look hard to find people who are excited about Docker, continuous delivery, or service discovery. All of these things can help you to build a system that sounds like the microservice systems we’ve been discussing. But microservices can’t be achieved by focusing on a particular set of patterns, process, or tools. Instead, you’ll need to stay focused on the goal itself—a system that can make change easier.
More specifically, the real value of microservices is realized when we focus on two key aspects—speed and safety. Every single decision you make about your software development ends up as a trade-off that impacts these two ideals. Finding an effective balance between them at scale is what we call the microservices way.
Speed and Safety at Scale and in Harmony.
The Microservices Way
The desire for speed is a desire for immediate change and ultimately a desire for adaptability. On one hand, we could build software that is capable of changing itself—this might require a massive technological leap and incredibly complex system. But the solution that is more realistic for our present state of technological advancement is to shorten the time it takes for changes to move from individual workers to a production environment.
Years ago, most of us released software in the same way that NASA launches rockets. After deliberate effort and careful quality control, our software was burned into a permanent state and delivered to users on tapes, CDs, DVDs, and diskettes. Of course, the popularity of the Web changed the nature of software delivery and the mechanics of releases have become much cheaper and easier. Ease of access combined with improved automation has drastically reduced the cost of a software change. Most organizations have the platforms, tools, and infrastructure in place to implement thousands of application releases within a single day. But they don’t. In fact, most teams are happy if they can manage a release in a week. Why is that? The answer of course is that the real deterrent to release speed is the fragility of the software they’ve produced.
Speed of change gets a lot of attention in stories about microservice architecture, but the unspoken, yet equally important counterpart is change safety. After all, “speed kills” and in most software shops nobody wants to be responsible for breaking production. Every change is potentially a breaking change and a system optimized purely for speed is only realistic if the cost of breaking the system is near zero. Most development environments are optimized for release speed, enabling the software developer to make multiple changes in as short a time as possible. On the other hand, most production environments are optimized for safety, restricting the rate of change to those releases that carry the minimum risk of damage.
On top of everything else, today’s software architect needs to be able to “think big” when building applications. As we heard earlier in this chapter, the microservices style is rooted in the idea of solving the problems that arise when software gets too big. To build at scale means to build software that can continue to work when demand grows beyond our initial expectations. Systems that can work at scale don’t break when under pressure; instead they incorporate built-in mechanisms to increase capacity in a safe way. This added dimension requires a special perspective to building software and is essential to the microservices way.
Your life is filled with decisions that impact speed and safety. Not just in the software domain, but in most of your everyday life; how fast are you willing to drive a car to get where you need to be on time? How does that maximum speed change when there is someone else in the car with you? Is that number different if one of your passengers is a child? The need to balance these ideals is something you were probably taught at a young age and you are probably familiar with the well-worn proverb, “haste makes waste.”
We’ve found that all of the characteristics that we associate with microservice architecture (i.e., replaceability, decentralization, context-bound, message-based communication, modularity, etc.) have been employed by practitioners in pursuit of providing speed and safety at scale. This is the reason a universal characteristic-driven definition of microservices is unimportant—the real lessons are found in the practices successful companies have employed in pursuit of this balancing act.
We don’t want to give you the wrong idea—microservice architecture is not limited to a simple series of decisions regarding speed and safety of change. The microservices domain is actually fairly complex and will require you to understand a wide breadth of concepts that have a great depth of impact. If it was any other way, this would be a very short book.
Instead, we introduce the microservices way in order to help you understand the essence of the microservices style. All of the significant properties and patterns that are commonly adopted for this style of architecture reflect attempts to deal with the interplay between these forces. The companies that do this best are the ones that find ways to allow both safety and speed of change to coexist. Organizations that succeed with microservice architecture are able to maintain their system stability while increasing their change velocity. In other words, they created a harmony of speed and safety that works for their own context.
The pursuit of this harmony should shape the adoption decisions you make for your own system. Throughout this book we will introduce principles and patterns that have helped companies provide great value to their business. It will be tempting to simply replicate the patterns in your own organizations in exactly the same way. But do your best to first pay attention to the impact of these types of changes on your own organization’s harmony. We will do our best to provide you with enough information to connect those dots.
It also means that you may not find your balance in the same way as other companies. We don’t expect your organization to work the same as the ones we’ve highlighted in this book and we don’t expect your microservices implementation to be the same either. Instead, we hope that focusing on the way that microservices applications are built will help you identify the parts that could work for you.
In this chapter we introduced the original intent of the microservice architecture concept—to replace complex monolithic applications with software systems made of replaceable components. We also introduced some of the concerns that first-time implementers often have, along with some of the practical realities. Finally, we introduced the microservices way, a goal-driven approach to building adaptable, reliable software. The balance of speed and safety at scale is key to understanding the essence of microservices and will come up again throughout this book. In the next chapter we’ll take a closer look at the goals of speed and safety in the context of actual microservice implementations.