Continuous Delivery for Architects
Ford, Neal
Yesterday’s best practice is tomorrow’s anti-pattern. Architecture doesn’t exist in a vacuum, a painful lesson developers who built logically sound but operationally cumbersome architectures learned. Continuous Delivery is a process for automating the production readiness of your application every time a change occurs–to code, infrastructure, or configuration. Some architectures and practices yield code that works better in this environment. This session takes a deep dive into the intersection of the architect role and the engineering practices in Continuous Delivery. I first set context for the information you must master before delving into the nuances of modern architectural concerns. I discuss the role of metrics to understand code, how Domain Driven Design’s Bounded Context reifies in architecture, how to reduce intra-component/service coupling, the tension between coupling and cohesion, microservices architectures, and other engineering techniques.
 All right, good morning everyone. As you've probably guessed, this is the session on continuous delivery for architects. My name is Neal Ford. I work for ThoughtWorks. I'm going to talk about three things in this talk. First some concepts around the intersection of continuous delivery and architecture. That's where I'm spending most of my professional time right now is that intersection. Oh, and keynote just crashed. It's nice. So, it's a nice way to start out the talk. So, let's get that started again. Sorry about that. One minute. Let's try that again, shall we? So, my agenda for this talk, I'm going to talk about some concepts. This is one of the tricky things about talking about architecture. There are all these kind of seemingly peripheral but important concepts that kind of lurk on the edges of the ideas and software architecture. I'm going to spend a lot of time talking about components. And really when you talk about architecture and continuous delivery, there are two kinds of components you care about. You care about libraries and you care about services. And I'll talk about engineering practices for both of those. And then finally, some evolution strategies because I suspect that many of you are in this very common situation where you have a monolithic architecture. The good news is it's so common that it has an industry anti-pattern called the ball of mud. The bad news is even though it's so common it has its own name, it still sucks if you have one. So, I suspect that many of you are in the process of going from a monolithic architecture into a services or maybe even microservices style of architecture. And I'll talk about some evolutionary steps to allow you to do that. But first let's talk about some concepts. And of course, if we're going to talk about continuous delivery in architecture, we have to talk about the concepts behind continuous delivery. Really this is the same kind of feedback loop that you get with continuous integration. It's just broader in two really important ways. So here's a definition of the idea of a deployment pipeline, for example, in continuous delivery. But it enables you to get fast automated feedback on the production readiness of your application every time there's a change. Notice that we're looking for production readiness here, not just I pass some tests somewhere along the line, which is kind of the bar for continuous integration. Here we're trying to assess will this react properly in a production like environment. So that's one important broadening of the ideas of continuous integration. The other is the triggering mechanism. Because in the continuous delivery world, we trigger the changes in code just like we do in continuous integration. We also trigger any changes in the ecosystem. So we view software as a complete ecosystem in the continuous delivery world. It encompasses not just the source code, but also the operating system and the configuration for the application servers. All those things that are required to make that architecture operationalized, that's the entire ecosystem for code. And anytime something permutates, something changes that ecosystem, we want to react to that as eagerly as we possibly can. That's this idea of having a really broad triggering mechanism to try to incorporate change. One of the key things that you're going to encounter as an architect on a continuous delivery style project is building a deployment pipeline. And there's a whole bunch of stuff about building a deployment pipeline. It can be something as simple as a simple CI server with a bunch of plug-ins and augmentations, or it could be as sophisticated as the open source Go CD tool. But this is going to be your responsibility as the architect to construct what this deployment pipeline looks like. There's no predefined set of stages. There's some common stages that people use, but no predefined have to have these stages. And so it's your job to put these things together. And so you may have a commit that does the continuous integration job of unit testing, et cetera. And then maybe functional testing and more broad user acceptance testing using some sort of mechanism like Selenium or Sahi or Geb running tests through a browser or something like that. Maybe you have an automatic staging environment. Maybe you have environments beyond that. These are all joined by this idea of the artifact repository, which is a piece of the deployment pipeline that keeps intermediate results of these things as you go along. So because there's no predefined set of stages, it's important to understand why you build this deployment pipeline and why you build stages. Really what you're trying to achieve here is more and more confidence in production readiness, how will this react in production. And so stages in a deployment pipeline become feedback opportunities. So this is primarily what these guys represent for you as an architect is a chance to get feedback at a particular stage along the way of testing our code and putting it through a gauntlet to see if it can get to production. But here's the other really important aspect of continuous delivery and how it impacts the day to day job of an architect. So let's say you have this kind of deployment pipeline set up where commit stage, feedings to acceptance stage, and then you have user acceptance testing, etc. Notice there's one special step here that comes in in the acceptance stage that's not required, but you have to start doing this at some stage along the way. And there's a step here called configure environment. And then the continuous delivery world, this is the first stage where you programmatically build out the environment that your code is going to run on. And so this is the point where you run a puppet script or a chef script to build out the ecosystem the code runs on and then programmatically deploy code to that ecosystem and bootstrap it and see if it's running. And once you started doing that in the deployment pipeline, you do that on every downstream stage because once you've built a certain level of confidence, you don't want to give up any of that confidence. You want to keep building confidence all along the deployment pipeline. But what this means from an architect standpoint is that in traditional, even agile architectures, you didn't really have to worry that much about what this code was going to look like in production about actual machine configurations and memory footprints and all that stuff until very, very late in the process. Because you could run it on test machines, etc. Until you really needed to get to production, you didn't really vet all those things out. Here you've got to vet those things much, much earlier because part of your deployment process is building out that operational infrastructure. And so you can't put that off into the last part of the project anymore, which is a really good thing because this forces the architect to think about the operational aspects of their architecture as eagerly as possible, which is, as we see in continuous delivery, a really good thing to do things as eagerly as possible rather than put them off as long as possible. Because what we really want to be able to do in this world is build a component pipeline. What we really want is a deployment pipeline where if I make a change to a component or service somewhere, it detects that change and automatically runs it against all the different versions that I want to verify this against. So for example, it's quite common in a microservices kind of world to say, okay, I've made a change to this service. Now I want to automatically verify, does this work correctly against the head of my version control and does it still work correctly against the version that's running in production? I want to automate that behavior in a deployment pipeline so that a single change here, let's be vet that that change hasn't had a ripple side effect somewhere else in my ecosystem. So another concept that we're only really coming to grips with in the architecture world, I've captured with this, that yesterday's best practice is tomorrow's anti-pattern. We constantly build architectures that solve outdated problems. So software architecture very often is a mapping between capabilities and constraints and very often it's reactions to constraints. And what happens all the time is we build an architecture around some sort of physical real world constraint and that constraint melts away and all we're left with is an architecture that embodies all those constraints, but now it's just an arbitrary kind of restriction. We see this all the time and I'll show you some examples of this later on. But another example of this is a very common instinct that architects have is to build single sources of truth for things. Data architects love to do this to build the ultimate customer service that encapsulates everything we know about customers. That's just a logical kind of instinct because from a mathematical standpoint you want a single source of truth for things, it's messy to have multiple versions of things. And so that's a common practice in architecture. But let's talk about the impracticalities of that. We have a client who runs an airline and their architects had built the ultimate customer service that has everything we know as a company about customer inside it. And it had built it with the kind of accepted architecture practices with clustered application servers and multiple database servers and all this sort of stuff. And then a volcano blew up in Iceland. Pretty much everybody that had a ticket on this airline called the airline and said, hey, is that volcano going off in Iceland going to affect my flight? And people on the other side of the world who were nowhere near Iceland couldn't board their airplane because boarding does a customer look up. Customer service does a customer look up. And so no matter how much horsepower they had put behind this Uber customer service, when it hit real world kind of constraints, it fell over. Notice that their architects would have been better served if they had split the concept of customer into separate pieces and maybe even had duplicate data between those two pieces. But it would have been their business would have survived this unusual contingency. And so the instincts that you sometimes have as an architect sometimes don't work well when you look at the business constraints in the real world. Let me go deeper into this because as architects we're really good at building boxes and lines. We do those on whiteboards. We even build really pretty versions of this with Visio and OmniGraph all these lines and boxes, which is a useful exercise because it's a snapshot of what the shape, the topology of the architecture is at a certain point in time. This is a good two dimensional representation of an architecture. And for a long time, this was good enough. But what continuous delivery has really made it forced us to realize is that this is not far enough because this doesn't really represent the real world is the abstraction. Now you've got to take those boxes and actually flesh them out with actual things with actual version numbers. This is a 3D version of an architecture. Instead of having a box as an ORM, this is a specific version of an ORM tool that you have to get to work together with all the other stuff and operations. But now this is still not sufficient because now you have to think about what happens when hibernate revs itself in six months. How can I easily make that upgrade without making the entire architecture unstable because too many things rely on a single choke point. This is really a more realistic modern view of architecture, a four dimensional view of architecture that takes into account not only how the pieces fit together, but how to operationalize those pieces and how to evolve that operational architecture over time. That's the really interesting part of architecture right now. And so for example, if you look at a traditional service oriented architecture and look at the constraints that they're working against and the capabilities they're trying to create here, this is very much a shared resources kind of architecture. This is why you have things like a service broker, where you have things like a choreographer and orchestrator, et cetera, you're consolidating all that information into a same place so you can share all those resources and make the most efficient use of them. So one of the goals in this kind of traditional service oriented architecture is to maximize shared resources. But if you look at a microservice architecture, the real goal here is to maximize easy evolution. And so we operationalize each one of these services in a much more encapsulated way in the microservices world, because the real goal here is not to try to maximize shared resources, but basically have resources on demand now. The real goal in this world is to maximize easy evolution to really create these kind of software logos, where you can replace one behavior with another, easily evolve from one behavior to another to create a more evolutionary architecture. But this is a more complex architecture because of it, because you have to have all those operational wrappers around each one of these services. So I think that's one of the reasons that there's so much interest in this microservice style of architecture, because it's the first one where one of the capabilities built into the architecture is to support easy evolutionary change. Microservice style architectures are the first post continuous delivery architecture. It's the first one that kind of fully embraces all the operational concerns of architecture. It won't be the last one. All architectures going forward are going to have to take this into account, because this is an important aspect of architecture we're only now really realizing. And so this is just the first poster child, but believe me, all architectures for now, this will be an important component of them. So last of the concept stuff I want to talk about are some metrics. And in particular, a couple of coupling metrics, afferent and efferent coupling. So for any code artifact that you have, this can be something as low level as a functioner method or as high level as a package or namespace. The afferent coupling for that artifact is the number of incoming connections or references to that thing. And the efferent coupling is the number of outgoing connections or references that it refers to other things. And the easy way to remember this, because these are very similar terms, is that efferent starts with an E, which is also the same first letter of the English word exit. And those are the outgoing connections. So this is the easy way to remember afferent is incoming and efferent are outgoing. This is important to architects because very often you need to understand the structural aspects of your code. That's one of the mentions you need to think about. If you're thinking about, for example, decoupling a monolithic architecture into a services or microservices based architecture, one of the ways you may want to do that is structurally. And you need to understand the structural coupling to be able to do that effectively. And so I want to show you some tools that allow you to visualize the coupling between pieces in a code base. This is very Java centric, but there are tools like this that exist for other platforms. In fact, Smalltalk created a lot of these visualizations and they created a platform called Moose, which is a meta platform for metric stuff. And so for example, if you have C-Sharp, if you can get your C-Sharp code to produce Moose metadata and there are some tools out there that will produce Moose metadata from C-Sharp code, you can pull it into Codecrawler, which is this tool, which is the tool this is inspired by. This is actually a tool in the Java world called Xray, which is an Eclipse plugin that shows you the characteristics of a code base in a slightly different way. This shows you the lines here represent classes and number of lines of code is the length of the box and the width of the box is the number of methods. And so that gives you some ideas about what the structure of the code is like. So that's a real code base. But the really interesting thing about Xray from our standpoint is dependencies because when you look at this chart, this graph, when you click on a particular class, it shows you the afferent and effort coupling for that class. The error heads show you if it's afferent or effort, whether it's incoming or outgoing, and the weight of the line indicates the strength of the coupling between those two things. And so this allows you to look at a class by class basis, how coupled to the is this to the rest of the world. But the more useful view for us is the one that allows you to see this for classes and packages. So here's a package dependency view. And here is a class dependency view for the same project. Now notice that for an architectural standpoint, this represents how classes are coupled to one another within this code base. But if I'm trying to decompose this, let's say this were monolithic architecture, and I wanted to decompose this into let's say four or five services. The first obvious thing for me to do is slice along here because the more bold red lines I slice, the harder my job is going to be because I'm going to have to fix up those coupling points. Those are two things coupled to one another now inside the application architecture. Those are still going to have to work with each other, but now they're separated by network boundary. And so the more of those red lines I cut, the harder my job is going to be. And so structurally, you can look at that and go, well, if I had to decompose this into three services, that'll be one of them. That'll probably be the second one. And this will be the third one. Okay. That's an easy way to kind of slice the whole thing up in a very coarse kind of manner. I'll talk about other ways of decomposing monoliths in a second, but structurally is definitely one of them, and it's nice to be able to see the structural characteristics of your code. Most of the time, though, it's not going to be quite as simple as that. Here's a real project. This is Argo UML, which is an open source UML mapping tool. And this is its class level dependencies. And here it's package dependencies. So this is a very complex monolithic architecture, but this still allows you to see some of those coupling points. Okay. Let's move on then and talk about component-based architectures. The Continuous Delivery Book doesn't say much about architecture. In fact, this is the primary advice that Continuous Delivery Book gives you about architectural concerns is use components to decouple parts of your application that change at different rates. Rate of change is one of the things that may encourage you to split things up into components, but we don't really have just a single kind of component in the software world. We have two kind of components. We have either libraries or we have services. Both of these are conceptually components, but engineering standpoint, they work in different ways. So a library is something that runs within a single process and communicates the language function call mechanisms. These are typically compile time dependencies. So these are JAR files or DLLs or GEMs or something like that. Services on the other hand, run in a separate process and communicate with network communication mechanisms like HTTP or TCP IP and are generally the realm of integration architecture rather than application architecture. These are typically run time dependencies between things. Because these two things are so different, they have different engineering practices associated with them. So let's talk about those in turn and let's talk about some engineering practices around components first. And let's say that this is the way we want to build our application. Rather than building a single monolithic build in our deployment pipeline, we want to use a series of libraries to build this up. We have framework which everything is based on. They have reports, settlement, and pricing engine. And then finally the portfolio management application. And the CDS pricing library is something that maybe comes from a third party, like a JAR file repository, Nexus repository or something like that out in the world. So let's talk about some issues that this introduces. And the first of these is managing dependencies. And most people's first real encounter with this was this fun thing that we used to call DLL hell in Windows. How many people remember DLL hell in Windows? Yep, most people here. The main reason I bring this up is because it's a good example of dependency management. But it's also a great example that yesterday's best practice is tomorrow's anti-pattern. Because the reason that DLLs existed the way they did was when Windows first came out, hard drives were really small and very expensive. And they didn't have enough room to statically link all those applications together. So they built this dynamic link library kind of architecture, which allowed them to save a whole lot of space. That was the constraint they were working against. But of course the space constraint very quickly went away and we were left with the headaches introduced by all this dependency management stuff for a couple of decades before they finally replaced that at the architectural level with the package revolution stuff in the.NET. But now mostly you have two approaches to handling this. The ubiquitous live directory in the project where everybody feels free to add stuff but nobody ever, ever removes anything from this directory because you're afraid you might accidentally wreck the earth if you did that. Or a transitive dependency management tool and every platform ends up here in a transitive dependency management tool because it's just too hard to deal with manually. One of the things you have to deal with when you have libraries like this are cycles, which are circular dependencies between libraries. This is when one component refers to another one, which eventually refers back to the first one. This is particularly bad in ecosystems that have really strong IDEs like Java and.NET because if you're coding along in Java and you reference some class that's conceptually a thousand meters away, what does your IDE do? It pops up a dialog says you only import that for you and you swap that dialog away so fast you don't even see that dialog anymore. It's such a common thing to oh yeah we need to import that. Yeah, yeah, yeah import that, import that. What it really should have is some sort of obnoxious clippy like mechanism that pops up and says should you be importing that library from all the way over there? Are you making a lot of really crazy cycles in your code base? But we don't have that. And so that makes the system really hard to componentize and it makes the lifecycle a lot more complex. It makes it harder to decompose it. There's fortunately a nice little tool out there, open source tool that Curtis Scheld wrote called Draw Analyzer that will allow you to remove some drawer files from your live directory if you want. Because you run this against a library and it'll show you how all those things are connected to one another and who calls what, etc. And it gives you effort, effort coupling metrics, etc. But the other cool thing that Draw Analyzer will do for you is draw the relationship between all those things in your code base. And so for example here's the drawer files and how they're related in struts 1.0. And this is also a good example of what happens if you don't pay attention to this because here's the exact same diagram in struts 2. Yikes, that's terrifying. This is what happens if you don't pay attention to this. In the Java ecosystem you end up with a spider web of dependencies between things, good luck decomposing this and anything without just gutting it and rewriting the whole thing. Fortunately there's help. This is the only commercial tool that I talk about in this talk because it's the only tool that does what this one does as far as I know. A structure 101 goes through and analyzes your code bases just for Java code bases. There's a similar commercial tool in the.NET space called independent that does a similar job not quite as concise as this one but you can glean the same information from it. This analyzes your code base, gives you a to-do list of refactorings that you need to do and this allows developers to untangle cycles within their code base. So the idea here is you structure 101, you go in and untangle things so that you have clean dependencies between the parts of your ecosystem. If you look at a legendarily clean code base from a dependency standpoint, Spring is a really good example of a well organized component based ecosystem and that's not a coincidence. Spring committers all run structure 101 on their laptops and as they make substantive changes to the Spring code base, they run this to make sure they have not accidentally introduced cycles. This is a real problem in the Java ecosystem because the tooling is so powerful it actually hides some deficiencies from you. But what we really like to do in this world is to prevent this from happening. Now one way you can do this is say no developer shall introduce cycles and if you do, there shall be beatings at lunch on Friday. But that never works because you can never force people to think about these little details as they're going about their day job so we're much more fans of building engineering safety nets to catch problems before they manifest into bigger problems and here's a good example of using a tool to do that. This is a thing called J2Pen that's been around for a really long time. This will do analysis of Java code bases between packages to show you after and effort coupling and give you a bunch of metrics but it's written in Java so it understands the Java ecosystem and how packages and things like that work and so you can write a J unit test like the bottom one here that says test all packages. This is analyze all these packages and tell me if any cycles exist. And so what this allows you to do is go in and chase out all the cycles in your code base and then put this unit test in place so that if anybody does accidentally add a cycle because the tooling is being too aggressively friendly then this will fail a unit test before it gets into your code base and starts creating that spider web again. Because J2Pen understands things about how packages work in Java you can also wire in stronger rules from an architectural level because maybe as an architect you want to find some rules that say okay I have this util package it's okay for other things to import from that util package but I don't want it importing from random crap around the world. And so here's the scenario I have EJB web and util and it's okay for EJB to depend upon util and it's okay for web to depend upon util but I never want the reverse to happen. You can set up these rules within J2Pen and then tell it to analyze your code base and tell you if anyone has violated any of those rules or not. This is a good example in the engineering practice is a continuous delivery of a safety net build these little engineering safety nets very often around tests that will flag things that you want to make sure don't happen in your code base rather than relying on people remembering these nitty-gritty details build automatic mechanisms to catch when people make mistakes. Where we really want to get to of course is the ability to build a pipelining library using an deployment pipeline tool like GoCD so that as you make changes to a component it automatically builds all the things that are dependent upon that and then resolves to see if that change has been successful throughout the entire ecosystem. But one of the things you have to worry about in that case are diamond dependencies. So here's the scenario. Let's say that you've updated framework and of course all of its downstream components will now automatically try to update themselves and so reports engine updates himself and he's happy with the change. This looks good. When pricing engine tries to incorporate that change it cannot for some reason and pricing engine now has reds on its test and now the $64,000 question is which version of framework should the portfolio management application rely on? And of course the answer is none of the above. There's no legal version for it to rely on now because two of its children have different dependencies. This is a problem out in the wild, wild world of transitive dependencies on the internet but if you control your ecosystem you can get rid of the diamond dependency problem like this. When you construct your deployment pipeline you need to resolve all dependencies at a certain level before moving on to the next level of dependencies. So in this scenario we build framework and make a change to it. It will trigger a change to pricing, settlement and reports engine and only if all three of those are successful does it promote to the portfolio management application and so now we can make sure that everything resolves at one level before we promote it to the next level and never have to worry about the diamond dependency problem with components. So that's a whole bunch of practices around components. Now let's talk about some practices around services. I want to skip this slide. I'll come back to that in just a second. That's a Conway's law side that I'll get to in just a second. So one of the things that we talk about in the service world is that we tend to prefer choreography to orchestration particularly in the microservice kind of world and let me describe these two things and describe what I'm talking about here. So when you look at the traditional kind of service oriented architecture, enterprise service bus pattern of architectural style and whether this is a relatively simple kind of ESB like a mule or really complex thing like an orchestrator like Ode, Apache Ode or something like that. They have the same kind of characteristics. That's an orchestration style of integration architecture because now if two services need to communicate it between each other they go through this bus to handle things like data transformations and choreography, etc. It's called orchestration because the bus here acts like the conductor of an orchestra. Anytime services need to do anything they need to check with the conductor to make sure that's okay. Contrast that with a more choreography style of integration architecture where there is no third party arbiter and services that want to communicate with one another just get together a service teams and decide which kinds of things they want to pass back and forth between each other. One of the side effects of having an enterprise service bus is that it will accrue a pack of enterprise architects around it like ships grow on the bottom, sorry barnacles grow on the bottom of a ship in the ocean. This is inevitable because of this phenomenon called Conway's Law which I'll talk about in just a second about team structure and organization. Basically Conway's Law says if you have something like an enterprise service bus it will become a layer in your architecture and a communication bottleneck as well. On the choreography side of the world what we're doing here is not involving any kind of third party arbiter but just having the two teams decide what they want to pass back and forth with each other because what we're really trying to support here is to allow them to evolve as independently as possible from one another without having to check with a third party coupling point. But that sounds kind of dangerous because now I have a situation where I'm allowing these services to evolve at different rates and perhaps changing the way they work in an arbitrary way. How do you make sure that things don't just break all the time from an integration standpoint? This again is where continuous delivery relies on engineering practices to build safety nets for this sort of stuff and the common safety net here is something called a consumer driven contract. And here's the idea behind consumer driven contracts. So you have a service provider on the left and three teams on the right that it is providing information for. The idea of a consumer driven contract says that this team here on the right will put together a set of unit and integration tests and hand it to this team. This team not promises to keep that set of tests green every time they make a change to their code base. These guys are going to do the same and so are these and so now the team on the left is running three different sets of unit and integration tests on behalf of these other teams because those tests encapsulate what they need from the service provider. This allows any of these guys to evolve at whatever rate they need to and as long as they don't break those integration tests then we know that they're still can communicate successfully one another. So if this guy on the left changes and it doesn't break any tests then everything's okay. If one of those test changes, if one of those test breaks because of a change this becomes a placeholder for conversation between those two teams again to get together and reestablish the contract in a way that they are both happy with and move on again with the rest of their lives. This is really common particularly in a microservice kind of world where you're doing choreography because in the microservice world you never have any kind of choreographer or enterprise service bus because it's a shared nothing kind of architecture and so choreography is a very common kind of mechanism and consumer-driven contracts are very popular way to implement this. So a bunch of open source tools that do this packed PACT and Pacto, PACTO are both tools that handle consumer-driven contracts. In fact, I should just go ahead and give you, I don't think I have a bed in the slide deck here where there's a fantastic website called DevOpsBookmarks.com which is hosted on Iroku by a bunch of my colleagues in India. What they're trying to do is take all the different open source tools for doing DevOps and continuous delivery and consolidate them on one big reference page and so they have categories there so there's an entire category for service testing and consumer-driven contracts. There's a category there for orchestration tools and provisioning and monitoring, logging, etc. So lots of different tools that enable these kind of engineering practices. And notice too that particularly microservice kind of environments require a certain level of maturity from an engineering standpoint before you can really even go there because if you commonly run around with broken bills or tests that don't are read all the time for days at a time, you can't play in this ecosystem. If you can't guarantee that you can keep tests green and bills up all the time, then there's no way you can handle this kind of dynamic, kind of choreography style of integration. Things will be broken all the time. So it takes a certain level of engineering maturity before you can get to the ability to do this. So let's talk about services and a lot of this encompasses microservices as well because in many ways they are flavors of the same things with a few differences in terms of operational concerns. And in fact this is the real design aesthetic from the microservices world comes from the ideas, particularly one main idea in domain-driven design, which is ostensibly an object modeling kind of technique. You take a big complex domain and decompose it into domain-driven design, these individual domain objects. This book by Vaughn Vernon is a quite good implementing book about domain-driven design. But what has happened in the microservice world is they borrowed this idea from domain-driven design called a bounded context. So in domain-driven design when you identify a key concept within your architecture and part of your domain, you build a bounded context around it, which means within that bounded context you know of implementation details like database schemas, etc. But outside that bounded context no one has any idea of what's going on. You can message into that bounded context and get results back, but you know no implementation details that is purely the business within the bounded context. In domain-driven design this is purely a logical separation, but what we've done in the microservices world is combined this with the engineering practice continuous delivery and made that bounded context a real physical thing. This is the real differentiator between microservices versus other service-based architectures is that every one of these microservices is completely isolated. It forms its own physical bounded context with the rest of the world and shares nothing with the rest of the world, say one thing. Continuous-based architectures promote coupling from application to integration architecture. Here's what I mean by that. When you look at a Model F and it has a whole bunch of modules and classes talking to one another, you don't really concern yourself that much about things like efficiency of method calls between two pieces of your code base because it's all in process. You don't have to worry that much about it. So if you have one method calling another method a thousand times in a loop, it's generally not a big idea, not a bad problem. But when you switch this, let's say you decompose this into a services-based architecture, now you have a different set of problems because now you still have individual little modules inside these services, but now you have coarser grain representations of the way that your application works with each other. This brings a whole host of new problems with it. Most of these are exemplified by this really great thing, Peter Deuches, fallacies of distributed computing. He came up with this at Sun back in the late 80s or early 90s when distributed computing really just became a thing. The fallacies of distributed computing are the really tragic mistakes people make when they shift from application to integration architecture. It's terrible assumptions like the network is reliable and that latency is zero and the bandwidth is infinite and the network is secure and the topology doesn't change ad-hocly and there's only one administrator that you can call when things break and the transport cost is zero and the network is homogeneous. All these things are bad assumptions that people mistakenly make, but this is going to be your world as you switch from a monolithic architecture into a service-based architecture because now you're talking about integration coupling. This makes you a lot more explicit about how things are coupled to one another, particularly the major moving parts of your application, how they send information back and forth between each other. This relies on a lot of engineering safety nets, things like consumer-driven contracts to make sure things are not broken all the time. This encourages a lot of coarser grain coupling. You can't practically make a call a thousand times to this guy now like you could over here because that's going to be a thousand calls over your network and the latency is going to absolutely kill you because the fallacies are distributed computing. So now you have to think about coupling in a lot more explicit way. If you just go about this in a completely undisciplined way, you can create a giant mess. I refer to this as the visual studio problem because it's trivially easy to right-click on a method and say, make me a soap endpoint. You go, oh, hey, I have distributed architecture. Let's go home now. You've built the slowest distributed architecture on Earth because now every function call is now a network call. This creates what is called the spider web architecture anti-pattern. We have lots and lots of services running, but you're not sure which ones are actually being called, but you're afraid to take down a bunch of those things because somebody may be calling them, which is a mess. And now coupling dynamics become an integration issue, and you have to think about those dynamics a lot more diligently in this kind of world. So we talk about monolith versus microservices. Monolithic style architecture is designed this way that you can run multiple modules inside a single container. These are the land of things like application servers, industrial-sync database servers, very much a shared resources kind of architecture. Microservices, on the other hand, are much more around the kind of Linux philosophy of one thing per process. And so these are process-based, not thread-based. One thing per thing, one service per container. When you scale monoliths, you cluster multiple monoliths together and have a clustering protocol between them, whereas in the microservices world, you just spin up new instances of the service. This is a really good example, though, of how ignoring parts of the ecosystem can have you build much more complexity than you need. Because in this monolithic application server world, the way that you get these things to chat with one another is actually build protocols between the application servers and make that part of your architecture of how these things communicate with one another. On-demand scalability is really an operational concern. Why are we building that into our architectural elements? And that makes much more sense over here, that generally on-demand scalability is something an operation takes care of. It's quite common, for example, to have services that have an input queue, and as that input queue starts filling up, you can, on the fly, spin up more versions of that service and then load balance across them so that you can react really quickly to changes that are happening in your ecosystem. And this is just a good example of that greatly simplifies our architecture by letting operations worry about things like on-demand scalability. Here's Conway's law that I mentioned before. We did the first software architecture conference for O'Reilly in Boston this last year, and I was on the program committee. And during the course of the conference, Conway's law was mentioned in so many talks that it became sort of a conference in-joke because everybody was talking about this. Melvin Conway back in 1968 made this observation that any organization whose design system will produce a design whose structure is a copy of that organization's communication structure. This is about the way that people communicate with one another and how that ends up getting represented in things like architecture. And so what that means from our standpoint is if you have UI specialists and middleware specialists and DBAs running around, you're going to end up with those layers in your architecture. It's just a natural kind of follow-on that the way people communicate with one another, you end up building those layers in architecture. And so very typically you have siloed teams like this. This is what we refer to in the continuous delivery world as a human resources department optimized organization. So you've organized yourself to make your human resources department's job as easy as possible because you've all self-selected into little HR silos so that they have a really easy job now keeping everyone sorted out. Maybe that's not your primary goal as an organization. Maybe you'd like to be a better software organization than a human resources organization. And so this is the way that we suggest that you organize things now, building these cross-functional teams. Now there are two names for this phenomenon that we've come up with within ThoughtWorks. One of them was developed by an enterprise architect. I'll give you the two names and you have to guess which one the enterprise architect came up with. One name for this we call this the inverse Conway maneuver. Basically turning Conway's law on its head. The other thing we call this is domain architecture isomorphism. So which one do you think the enterprise architect came up with? Yeah, it's the isomorphism one. But basically the idea is that if you build teams that look like the architecture you want, that architecture will be easier to achieve. That's the idea of the inverse Conway maneuver. Another common thing in the services and particularly microservices world is they focus on products versus projects. Here's the distinction. When you have projects in a big company, you have a team of developers to get together and work on that project and at some point they finish that project and hand it off to someone in operations and they take care of the care and feeding this thing for the rest of his life. And that team then reassemble somewhere else and start working on another project. They will then hand off someone in operations and move on to another project. And of course this poor person in operations can't get things like bug fixes or maintenance releases or things like that done because this team has already moved on. Companies like Amazon have a different philosophy around this. They don't build projects, they build products. They have product teams based on this idea of the inverse Conway maneuver. And so at Amazon you have these cross functional teams which they refer to as two pizza teams. No software development teams shall be larger that can be fed with two large pizzas. This is really a reflection of something Fred Brooks wrote about back in 1975 about communication overhead on projects. And what Amazon has done is we're going to take these small cross functional teams. So these are teams that have developers and DBAs and operations people on it and they build a product. And their philosophy is you build it, you run it because you own this thing forever. And so at Amazon if you're on one of these teams someone on your team is the one that puts it in operation and you own this thing forever. So your product team is responsible for things like enhancements and changes, etc. for this product and it has a product owner who looks after all those things. But this has a bunch of really interesting beneficial side effects as well. Because having these cross functional teams leverages the kind of social aspect that is important to people whether they realize it or not. So for example let's say that you're in the project kind of world up here and you're working on some project and something you worked on two years ago blew up in the middle of the night and some of the operations got paged and had to come in and fix this thing that you wrecked two years ago by accident. You get an email the next morning and it says oh this project you worked on two years ago blew up in the middle of the night and operations. It's like wow I'm glad I'm working on operations here. Let's see if I can code it under disaster today. But if you're on one of these two pizza teams and you wrote some code that blew up in the middle of the night and someone in your team had to get up in the middle of the night and go fix it. The next morning you have to look across the breakfast table at their tired sad eyes. It will make you a better person. Because now it's not some abstract this happened to somebody else. This happened to somebody on your team. And so this forces you to think much more like a team and not this kind of adversarial across silos that you get in big organizations where that's not my problem that's somebody else's problem you make it your problem because it's part of a team. It's also characteristic in this world to have smart endpoints and dumb pipes as deep coupled and cohesive as possible inspired by the way that things like Unix filters and pipes works. Transport in this world is typically either HTTP using something like REST or messaging over a lightweight bus. If you need to go by an area you need performance or something like that. I said before that we prefer the choreography versus the orchestration style of integration architecture here. If you do find yourself with an enterprise service bus but want to build one of these kind of architectures as long as you use your enterprise service bus as nothing but a dumb pipe then we're okay with it. The thing that we don't like about the orchestration style of enterprise integration is that it violates this bounded context idea in microservices because that means that some of the behavior that should be in the bounded context is now smeared out across your integration architecture because part of it resides in this enterprise service bus mechanism. So even if you have one of those if you're just using a transport then we're okay because it doesn't violate that bounded context idea. It's really one of the key ideas in the microservices world that bounded context idea. Another side effect of this world is it tends to be decentralized data management. It's quite easy when you have a monolith to do things like transactional behaviors within the monolith because you're probably talking to a monolithic database as well. But that's much trickier in the microservice world because the last thing you want to do is distribute transactions which are very, very difficult. And so the microservice world, service and microservice world tends to prefer base to acid. So this is really transactions versus eventual consistency. So the microservice and service-based world tends to be more of an eventual consistency kind of world versus a transactional kind of world. Having said that, there are still some cases where you may violate the purity of the architecture and share a context when it's too difficult to decouple those things. And in fact, this turns out to be one of the trickiest things to detangle if you are taking a monolith and decomposing it into services or microservices or the transactional boundaries are very often one of the trickiest things to handle. And in fact, that is one of the decomposition techniques is to look and preserve existing transactional boundaries as you decompose your monolith because those things are harder to deal with. Another side effect of this world is decentralized governance because each of these microservices forms its own bound and context, which means it has its own team. And so let's say that this team is the customer team. And we've realized that we're never going to have more than a couple of thousand customers and we don't need to do any kind of crazy sophisticated querying or anything like that. And we're also, as a team, responsible for spinning up the machinery for our database and the migrations and all that other stuff. And we've made the observation that you can take a raw IP address and get MongoDB running on it in about 90 seconds or two minutes. And I'm pretty sure the first Oracle install dialog won't come up in just 90 seconds. And so you as a team may decide, hey, we don't need Oracle. That's like going rabbit hunting with a bazooka. Let's just use Mongo instead. And six months from now, you realize what a terrible mistake that was. We never should have used Mongo for this. We should use Postgres instead. And nobody else cares because you've made that change within your bound and context. Nobody has any idea of what happens inside your bound and context. And so this has no ripple effect to any other team. This means that governance is much easier in this world because we're freeing up individual teams to make decisions that are right size or the problem they're trying to solve. Now we're not suggesting you should allow this to become the Wild West where everybody picks any technology stack they want. But most organizations make choices to handle the hardest cases. They make choices for tools and infrastructure to handle the industrial strength, the 5% of the cases where we absolutely need to be able to query a million records in sub-second performance time. And they impose that complexity on every single project because you're all sharing the same monolithic architecture and it's overkill for 95% of the things that you're doing, but you have to take on that complexity for the 5% that actually need it. This frees you up to right size the technology choices for the problem you're actually trying to solve. And so a really common thing in this world is to standardize on integration or not platform and grace polyglot solutions where it makes sense to do so. So we don't really care what runs inside the microservices. That's part of the bound and context. We do care that they all integrate successfully one another. So this is the only real coupling point in a microservice architecture is how they integrate one another. So you typically pick something like REST level 2 and say everybody adheres to that. Again, we're not suggesting this becomes the Wild West where everybody picks whatever they want on a team by team basis. But if you look at most large companies and the spectrum of two few languages and platforms and versus too many, most companies fall well on the too few side versus the too many side. My colleague Sam Newman who's here doing a talk right now in another room about microservices has written a book for O'Reilly about this. And here's some of his advice, standardizing the gaps between services and be flexible of what happens inside the boxes. Have one, two, or maybe three ways of integrating but not 20 and pick some sensible conventions and stick with them. Another piece of advice and also common and continuous delivery world is to not make your operations understand all the different shapes of things that you may want to deploy. Rather build a common deployment mechanism so that everything looks the same way. This is Sam's advice as abstract underlying platform differences to perform a uniform deployment mechanism. This can take on several different flavors, probably the most common mechanism for this now are Docker containers because Docker is a really popular thing, a continuous delivery world. If your operations just knows how to put Docker containers into production, then you don't have to worry too much about differences between different platform pieces. But you don't have to go quite that elaborate. My colleague James Lewis has a talk about building a microservice kind of project in Java called Java the Unix way. And his uniform deployment mechanism was he built every one of his microservices as a standalone jar file that had a jetty embedded inside it. And if you call the main method on that jar file, it'll post itself up using jetty, listening on a particular port. And so we could have an entire directory of those jar files and just say, for every one of these jar files, tell them to run themselves. And it would bootstrap the architecture. That's a common deployment mechanism. So let's talk for a second about integration and disintegration and reducing risk of release in this world. So this is typically a continuous delivery, continuous deployment kind of world when you have services, particularly microservices, which sounds really scary. But one of the things that we've done in this world is separated out the things that can break the closure community as this great. So closure, of course, is a functional language in the JVM, which is a really nice thing in its own right. But the creator of closure is also kind of a word of file. He loves old words. And he has resurrected this archaic term, which is absolutely perfect for software called complex, C-O-M-P-L-E-C-T, complex, to complex two things together, to braid or weave them together. And what we've inadvertently done in most of our architectures is completed, deploy, and release, because when you deploy something, you also release it. But if you can separate those things, you can make each piece simpler. And that's exactly what we do here. Because typically in this ecosystem, we deploy components. But we haven't turned on the features yet because we frequently use things like feature toggles or feature flags. This allows us to deploy a component into the ecosystem and make sure it plays nice with everybody else, make sure it's monitoring correctly, and logging correctly, and all the infrastructure pieces are working the way they're supposed to. Now you can turn on features and then monitor to make sure everything's okay. This allows you to deploy a bunch of different services, maybe even some services that do the same thing with slight variations. Because typically in the microservices world, we still haven't impacted users yet because applications consist of routing between services. What this does, so one of the things that you talk about in continuous delivery world is that our blue-green releases, we have identical slices of infrastructure, a blue slice and a green slice. And the idea is you can switch back and forth between these things. In the microservices world, you basically have that at the service level. Because let's say you deploy a service, you release the feature by turning it on, you route to it and it starts misbehaving, you just route back away from it, fix it, route to it again, maybe just saw a small percentage of your users, make sure that's cool, and then gradually more and more people use it. And this is really the basis for evolutionary architecture, which I'll talk about in just a second. So what this suggests is that the more services you have as long as you have good engineering practice drives your risk of release down. Because if you're deploying a monolith, it's all risk. It's one big thing you have to deploy, but if you have a lot of very small services, you're actually deploying smaller and smaller pieces every time. We monitor services in this world, but we also monitor routes and you disintegrate services that no one's using anymore. So this is really the basis for evolutionary architecture. Let's say I have something like a Netflix ecosystem and I have star ratings and someone comes out with a, allows you to do half star ratings. You deploy that in the ecosystem and people start routing to it because they want half star ratings. Over time, everyone is now using half star ratings and they observe that no one is using star ratings anymore and that gets disintegrated out of the ecosystem. We've evolved into that new behavior one tiny bit at a time without disrupting the whole architecture to do that. As I suggested before, you really need a lot of engineering sophistication to be able to pull off something like a microservice architecture because you have to have these engineering practices in place. So for an evolutionary standpoint, when you talk about decomposing monoliths into smaller and smaller pieces, you can partition along natural boundaries. So I talked about structural decomposition using things like afferent and efferent coupling, transactions, another way of looking at this, preserve existing transactional boundaries. Maybe you want to go the full blown inverse Conway maneuver and do by organization or by domain and so let's put things into domain driven design and do domain stuff or maybe you have geological constraints or geographical constraints where you have to be physical locations and you split your architecture along those boundaries. So to conclude all this stuff, what we're really trying to build here is architecture for change and get away from yesterday's best practices tomorrow's anti-pattern, build teams that look like the architecture you want, it becomes easier to build that kind of architecture. I talked about efferent coupling as a code metric before, but you also can have this as a team metric and so you want to strive for a low efferent coupling for your team. Your team shouldn't know everything that's happening in the entire ecosystem. In fact, this is the whole thing kind of wrapped up on one big slide. We have teams with low efferent coupling delivering relatively independently and their common integration pipeline without fearing breaking each other's bills because we have things like consumer under and contracts in place, small cross functional teams sharing information as they need to, sharing a common integration platform that has a deployment pipeline there, verifying that as they push things in that deployment pipeline it hasn't broken things, they're already running in other places and automating a lot of these pains and issues away. That's it. Looks like I'm right up exactly against time so I won't take any questions right now. I'll be around all day if you have any questions you can chase me down but looks like we've hit the break. Thanks very much for coming and hope you enjoy it. Great, thank you. Thanks.
 All right, good morning everyone.  As you've probably guessed, this is the session on continuous delivery for architects.  My name is Neal Ford.  I work for ThoughtWorks.  I'm going to talk about three things in this talk.  First some concepts around the intersection of continuous delivery and architecture.  That's where I'm spending most of my professional time right now is that intersection.  Oh, and keynote just crashed.  It's nice.  So, it's a nice way to start out the talk.  So, let's get that started again.  Sorry about that.  One minute.  Let's try that again, shall we?  So, my agenda for this talk, I'm going to talk about some concepts.  This is one of the tricky things about talking about architecture.  There are all these kind of seemingly peripheral but important concepts that kind of lurk on  the edges of the ideas and software architecture.  I'm going to spend a lot of time talking about components.  And really when you talk about architecture and continuous delivery, there are two kinds  of components you care about.  You care about libraries and you care about services.  And I'll talk about engineering practices for both of those.  And then finally, some evolution strategies because I suspect that many of you are in  this very common situation where you have a monolithic architecture.  The good news is it's so common that it has an industry anti-pattern called the ball of  mud.  The bad news is even though it's so common it has its own name, it still sucks if you  have one.  So, I suspect that many of you are in the process of going from a monolithic architecture  into a services or maybe even microservices style of architecture.  And I'll talk about some evolutionary steps to allow you to do that.  But first let's talk about some concepts.  And of course, if we're going to talk about continuous delivery in architecture, we have  to talk about the concepts behind continuous delivery.  Really this is the same kind of feedback loop that you get with continuous integration.  It's just broader in two really important ways.  So here's a definition of the idea of a deployment pipeline, for example, in continuous delivery.  But it enables you to get fast automated feedback on the production readiness of your application  every time there's a change.  Notice that we're looking for production readiness here, not just I pass some tests somewhere  along the line, which is kind of the bar for continuous integration.  Here we're trying to assess will this react properly in a production like environment.  So that's one important broadening of the ideas of continuous integration.  The other is the triggering mechanism.  Because in the continuous delivery world, we trigger the changes in code just like we  do in continuous integration.  We also trigger any changes in the ecosystem.  So we view software as a complete ecosystem in the continuous delivery world.  It encompasses not just the source code, but also the operating system and the configuration  for the application servers.  All those things that are required to make that architecture operationalized, that's  the entire ecosystem for code.  And anytime something permutates, something changes that ecosystem, we want to react to  that as eagerly as we possibly can.  That's this idea of having a really broad triggering mechanism to try to incorporate change.  One of the key things that you're going to encounter as an architect on a continuous  delivery style project is building a deployment pipeline.  And there's a whole bunch of stuff about building a deployment pipeline.  It can be something as simple as a simple CI server with a bunch of plug-ins and augmentations,  or it could be as sophisticated as the open source Go CD tool.  But this is going to be your responsibility as the architect to construct what this deployment  pipeline looks like.  There's no predefined set of stages.  There's some common stages that people use, but no predefined have to have these stages.  And so it's your job to put these things together.  And so you may have a commit that does the continuous integration job of unit testing,  et cetera.  And then maybe functional testing and more broad user acceptance testing using some sort  of mechanism like Selenium or Sahi or Geb running tests through a browser or something  like that.  Maybe you have an automatic staging environment.  Maybe you have environments beyond that.  These are all joined by this idea of the artifact repository, which is a piece of the deployment  pipeline that keeps intermediate results of these things as you go along.  So because there's no predefined set of stages, it's important to understand why you build  this deployment pipeline and why you build stages.  Really what you're trying to achieve here is more and more confidence in production  readiness, how will this react in production.  And so stages in a deployment pipeline become feedback opportunities.  So this is primarily what these guys represent for you as an architect is a chance to get  feedback at a particular stage along the way of testing our code and putting it through  a gauntlet to see if it can get to production.  But here's the other really important aspect of continuous delivery and how it impacts  the day to day job of an architect.  So let's say you have this kind of deployment pipeline set up where commit stage, feedings  to acceptance stage, and then you have user acceptance testing, etc.  Notice there's one special step here that comes in in the acceptance stage that's not  required, but you have to start doing this at some stage along the way.  And there's a step here called configure environment.  And then the continuous delivery world, this is the first stage where you programmatically  build out the environment that your code is going to run on.  And so this is the point where you run a puppet script or a chef script to build out the ecosystem  the code runs on and then programmatically deploy code to that ecosystem and bootstrap  it and see if it's running.  And once you started doing that in the deployment pipeline, you do that on every downstream stage  because once you've built a certain level of confidence, you don't want to give up  any of that confidence.  You want to keep building confidence all along the deployment pipeline.  But what this means from an architect standpoint is that in traditional, even agile architectures,  you didn't really have to worry that much about what this code was going to look like  in production about actual machine configurations and memory footprints and all that stuff until  very, very late in the process.  Because you could run it on test machines, etc.  Until you really needed to get to production, you didn't really vet all those things out.  Here you've got to vet those things much, much earlier because part of your deployment  process is building out that operational infrastructure.  And so you can't put that off into the last part of the project anymore, which is a really  good thing because this forces the architect to think about the operational aspects of  their architecture as eagerly as possible, which is, as we see in continuous delivery,  a really good thing to do things as eagerly as possible rather than put them off as long  as possible.  Because what we really want to be able to do in this world is build a component pipeline.  What we really want is a deployment pipeline where if I make a change to a component or  service somewhere, it detects that change and automatically runs it against all the different  versions that I want to verify this against.  So for example, it's quite common in a microservices kind of world to say, okay, I've made a change  to this service.  Now I want to automatically verify, does this work correctly against the head of my version  control and does it still work correctly against the version that's running in production?  I want to automate that behavior in a deployment pipeline so that a single change here, let's  be vet that that change hasn't had a ripple side effect somewhere else in my ecosystem.  So another concept that we're only really coming to grips with in the architecture world, I've  captured with this, that yesterday's best practice is tomorrow's anti-pattern.  We constantly build architectures that solve outdated problems.  So software architecture very often is a mapping between capabilities and constraints and very  often it's reactions to constraints.  And what happens all the time is we build an architecture around some sort of physical  real world constraint and that constraint melts away and all we're left with is an architecture  that embodies all those constraints, but now it's just an arbitrary kind of restriction.  We see this all the time and I'll show you some examples of this later on.  But another example of this is a very common instinct that architects have is to build  single sources of truth for things.  Data architects love to do this to build the ultimate customer service that encapsulates  everything we know about customers.  That's just a logical kind of instinct because from a mathematical standpoint you want a single  source of truth for things, it's messy to have multiple versions of things.  And so that's a common practice in architecture.  But let's talk about the impracticalities of that.  We have a client who runs an airline and their architects had built the ultimate customer  service that has everything we know as a company about customer inside it.  And it had built it with the kind of accepted architecture practices with clustered application  servers and multiple database servers and all this sort of stuff.  And then a volcano blew up in Iceland.  Pretty much everybody that had a ticket on this airline called the airline and said,  hey, is that volcano going off in Iceland going to affect my flight?  And people on the other side of the world who were nowhere near Iceland couldn't board  their airplane because boarding does a customer look up.  Customer service does a customer look up.  And so no matter how much horsepower they had put behind this Uber customer service,  when it hit real world kind of constraints, it fell over.  Notice that their architects would have been better served if they had split the concept  of customer into separate pieces and maybe even had duplicate data between those two  pieces.  But it would have been their business would have survived this unusual contingency.  And so the instincts that you sometimes have as an architect sometimes don't work well  when you look at the business constraints in the real world.  Let me go deeper into this because as architects we're really good at building boxes and lines.  We do those on whiteboards.  We even build really pretty versions of this with Visio and OmniGraph all these lines and  boxes, which is a useful exercise because it's a snapshot of what the shape, the topology  of the architecture is at a certain point in time.  This is a good two dimensional representation of an architecture.  And for a long time, this was good enough.  But what continuous delivery has really made it forced us to realize is that this is not  far enough because this doesn't really represent the real world is the abstraction.  Now you've got to take those boxes and actually flesh them out with actual things with actual  version numbers.  This is a 3D version of an architecture.  Instead of having a box as an ORM, this is a specific version of an ORM tool that you  have to get to work together with all the other stuff and operations.  But now this is still not sufficient because now you have to think about what happens when  hibernate revs itself in six months.  How can I easily make that upgrade without making the entire architecture unstable because  too many things rely on a single choke point.  This is really a more realistic modern view of architecture, a four dimensional view of  architecture that takes into account not only how the pieces fit together, but how to operationalize  those pieces and how to evolve that operational architecture over time.  That's the really interesting part of architecture right now.  And so for example, if you look at a traditional service oriented architecture and look at  the constraints that they're working against and the capabilities they're trying to create  here, this is very much a shared resources kind of architecture.  This is why you have things like a service broker, where you have things like a choreographer  and orchestrator, et cetera, you're consolidating all that information into a same place so  you can share all those resources and make the most efficient use of them.  So one of the goals in this kind of traditional service oriented architecture is to maximize  shared resources.  But if you look at a microservice architecture, the real goal here is to maximize easy evolution.  And so we operationalize each one of these services in a much more encapsulated way in  the microservices world, because the real goal here is not to try to maximize shared  resources, but basically have resources on demand now.  The real goal in this world is to maximize easy evolution to really create these kind  of software logos, where you can replace one behavior with another, easily evolve from  one behavior to another to create a more evolutionary architecture.  But this is a more complex architecture because of it, because you have to have all those operational  wrappers around each one of these services.  So I think that's one of the reasons that there's so much interest in this microservice  style of architecture, because it's the first one where one of the capabilities built into  the architecture is to support easy evolutionary change.  Microservice style architectures are the first post continuous delivery architecture.  It's the first one that kind of fully embraces all the operational concerns of architecture.  It won't be the last one.  All architectures going forward are going to have to take this into account, because  this is an important aspect of architecture we're only now really realizing.  And so this is just the first poster child, but believe me, all architectures for now,  this will be an important component of them.  So last of the concept stuff I want to talk about are some metrics.  And in particular, a couple of coupling metrics, afferent and efferent coupling.  So for any code artifact that you have, this can be something as low level as a functioner  method or as high level as a package or namespace.  The afferent coupling for that artifact is the number of incoming connections or references  to that thing.  And the efferent coupling is the number of outgoing connections or references that it  refers to other things.  And the easy way to remember this, because these are very similar terms, is that efferent  starts with an E, which is also the same first letter of the English word exit.  And those are the outgoing connections.  So this is the easy way to remember afferent is incoming and efferent are outgoing.  This is important to architects because very often you need to understand the structural  aspects of your code.  That's one of the mentions you need to think about.  If you're thinking about, for example, decoupling a monolithic architecture into a services  or microservices based architecture, one of the ways you may want to do that is structurally.  And you need to understand the structural coupling to be able to do that effectively.  And so I want to show you some tools that allow you to visualize the coupling between  pieces in a code base.  This is very Java centric, but there are tools like this that exist for other platforms.  In fact, Smalltalk created a lot of these visualizations and they created a platform  called Moose, which is a meta platform for metric stuff.  And so for example, if you have C-Sharp, if you can get your C-Sharp code to produce  Moose metadata and there are some tools out there that will produce Moose metadata from  C-Sharp code, you can pull it into Codecrawler, which is this tool, which is the tool this  is inspired by.  This is actually a tool in the Java world called Xray, which is an Eclipse plugin that  shows you the characteristics of a code base in a slightly different way.  This shows you the lines here represent classes and number of lines of code is the length  of the box and the width of the box is the number of methods.  And so that gives you some ideas about what the structure of the code is like.  So that's a real code base.  But the really interesting thing about Xray from our standpoint is dependencies because  when you look at this chart, this graph, when you click on a particular class, it shows  you the afferent and effort coupling for that class.  The error heads show you if it's afferent or effort, whether it's incoming or outgoing,  and the weight of the line indicates the strength of the coupling between those two things.  And so this allows you to look at a class by class basis, how coupled to the is this  to the rest of the world.  But the more useful view for us is the one that allows you to see this for classes and  packages.  So here's a package dependency view.  And here is a class dependency view for the same project.  Now notice that for an architectural standpoint, this represents how classes are coupled to  one another within this code base.  But if I'm trying to decompose this, let's say this were monolithic architecture, and  I wanted to decompose this into let's say four or five services.  The first obvious thing for me to do is slice along here because the more bold red lines  I slice, the harder my job is going to be because I'm going to have to fix up those  coupling points.  Those are two things coupled to one another now inside the application architecture.  Those are still going to have to work with each other, but now they're separated by network  boundary.  And so the more of those red lines I cut, the harder my job is going to be.  And so structurally, you can look at that and go, well, if I had to decompose this into  three services, that'll be one of them.  That'll probably be the second one.  And this will be the third one.  Okay.  That's an easy way to kind of slice the whole thing up in a very coarse kind of manner.  I'll talk about other ways of decomposing monoliths in a second, but structurally is  definitely one of them, and it's nice to be able to see the structural characteristics  of your code.  Most of the time, though, it's not going to be quite as simple as that.  Here's a real project.  This is Argo UML, which is an open source UML mapping tool.  And this is its class level dependencies.  And here it's package dependencies.  So this is a very complex monolithic architecture, but this still allows you to see some of those  coupling points.  Okay.  Let's move on then and talk about component-based architectures.  The Continuous Delivery Book doesn't say much about architecture.  In fact, this is the primary advice that Continuous Delivery Book gives you about architectural  concerns is use components to decouple parts of your application that change at different  rates.  Rate of change is one of the things that may encourage you to split things up into components,  but we don't really have just a single kind of component in the software world.  We have two kind of components.  We have either libraries or we have services.  Both of these are conceptually components, but engineering standpoint, they work in different  ways.  So a library is something that runs within a single process and communicates the language  function call mechanisms.  These are typically compile time dependencies.  So these are JAR files or DLLs or GEMs or something like that.  Services on the other hand, run in a separate process and communicate with network communication  mechanisms like HTTP or TCP IP and are generally the realm of integration architecture rather  than application architecture.  These are typically run time dependencies between things.  Because these two things are so different, they have different engineering practices  associated with them.  So let's talk about those in turn and let's talk about some engineering practices around  components first.  And let's say that this is the way we want to build our application.  Rather than building a single monolithic build in our deployment pipeline, we want to use  a series of libraries to build this up.  We have framework which everything is based on.  They have reports, settlement, and pricing engine.  And then finally the portfolio management application.  And the CDS pricing library is something that maybe comes from a third party, like a JAR  file repository, Nexus repository or something like that out in the world.  So let's talk about some issues that this introduces.  And the first of these is managing dependencies.  And most people's first real encounter with this was this fun thing that we used to call  DLL hell in Windows.  How many people remember DLL hell in Windows?  Yep, most people here.  The main reason I bring this up is because it's a good example of dependency management.  But it's also a great example that yesterday's best practice is tomorrow's anti-pattern.  Because the reason that DLLs existed the way they did was when Windows first came out,  hard drives were really small and very expensive.  And they didn't have enough room to statically link all those applications together.  So they built this dynamic link library kind of architecture, which allowed them to save  a whole lot of space.  That was the constraint they were working against.  But of course the space constraint very quickly went away and we were left with the headaches  introduced by all this dependency management stuff for a couple of decades before they  finally replaced that at the architectural level with the package revolution stuff in  the.NET.  But now mostly you have two approaches to handling this.  The ubiquitous live directory in the project where everybody feels free to add stuff but  nobody ever, ever removes anything from this directory because you're afraid you might  accidentally wreck the earth if you did that.  Or a transitive dependency management tool and every platform ends up here in a transitive  dependency management tool because it's just too hard to deal with manually.  One of the things you have to deal with when you have libraries like this are cycles, which  are circular dependencies between libraries.  This is when one component refers to another one, which eventually refers back to the first  one.  This is particularly bad in ecosystems that have really strong IDEs like Java and.NET  because if you're coding along in Java and you reference some class that's conceptually  a thousand meters away, what does your IDE do?  It pops up a dialog says you only import that for you and you swap that dialog away so fast  you don't even see that dialog anymore.  It's such a common thing to oh yeah we need to import that.  Yeah, yeah, yeah import that, import that.  What it really should have is some sort of obnoxious clippy like mechanism that pops  up and says should you be importing that library from all the way over there?  Are you making a lot of really crazy cycles in your code base?  But we don't have that.  And so that makes the system really hard to componentize and it makes the lifecycle a  lot more complex.  It makes it harder to decompose it.  There's fortunately a nice little tool out there, open source tool that Curtis Scheld  wrote called Draw Analyzer that will allow you to remove some drawer files from your  live directory if you want.  Because you run this against a library and it'll show you how all those things are connected  to one another and who calls what, etc.  And it gives you effort, effort coupling metrics, etc.  But the other cool thing that Draw Analyzer will do for you is draw the relationship between  all those things in your code base.  And so for example here's the drawer files and how they're related in struts 1.0.  And this is also a good example of what happens if you don't pay attention to this because  here's the exact same diagram in struts 2.  Yikes, that's terrifying.  This is what happens if you don't pay attention to this.  In the Java ecosystem you end up with a spider web of dependencies between things, good luck  decomposing this and anything without just gutting it and rewriting the whole thing.  Fortunately there's help.  This is the only commercial tool that I talk about in this talk because it's the only tool  that does what this one does as far as I know.  A structure 101 goes through and analyzes your code bases just for Java code bases.  There's a similar commercial tool in the.NET space called independent that does a similar  job not quite as concise as this one but you can glean the same information from it.  This analyzes your code base, gives you a to-do list of refactorings that you need to  do and this allows developers to untangle cycles within their code base.  So the idea here is you structure 101, you go in and untangle things so that you have  clean dependencies between the parts of your ecosystem.  If you look at a legendarily clean code base from a dependency standpoint, Spring is a  really good example of a well organized component based ecosystem and that's not a coincidence.  Spring committers all run structure 101 on their laptops and as they make substantive  changes to the Spring code base, they run this to make sure they have not accidentally  introduced cycles.  This is a real problem in the Java ecosystem because the tooling is so powerful it actually  hides some deficiencies from you.  But what we really like to do in this world is to prevent this from happening.  Now one way you can do this is say no developer shall introduce cycles and if you do, there  shall be beatings at lunch on Friday.  But that never works because you can never force people to think about these little details  as they're going about their day job so we're much more fans of building engineering safety  nets to catch problems before they manifest into bigger problems and here's a good example  of using a tool to do that.  This is a thing called J2Pen that's been around for a really long time.  This will do analysis of Java code bases between packages to show you after and effort coupling  and give you a bunch of metrics but it's written in Java so it understands the Java ecosystem  and how packages and things like that work and so you can write a J unit test like the  bottom one here that says test all packages.  This is analyze all these packages and tell me if any cycles exist.  And so what this allows you to do is go in and chase out all the cycles in your code  base and then put this unit test in place so that if anybody does accidentally add a  cycle because the tooling is being too aggressively friendly then this will fail a unit test before  it gets into your code base and starts creating that spider web again.  Because J2Pen understands things about how packages work in Java you can also wire in  stronger rules from an architectural level because maybe as an architect you want to  find some rules that say okay I have this util package it's okay for other things to  import from that util package but I don't want it importing from random crap around the world.  And so here's the scenario I have EJB web and util and it's okay for EJB to depend upon  util and it's okay for web to depend upon util but I never want the reverse to happen.  You can set up these rules within J2Pen and then tell it to analyze your code base and  tell you if anyone has violated any of those rules or not.  This is a good example in the engineering practice is a continuous delivery of a safety  net build these little engineering safety nets very often around tests that will flag  things that you want to make sure don't happen in your code base rather than relying on  people remembering these nitty-gritty details build automatic mechanisms to catch when people  make mistakes.  Where we really want to get to of course is the ability to build a pipelining library  using an deployment pipeline tool like GoCD so that as you make changes to a component  it automatically builds all the things that are dependent upon that and then resolves  to see if that change has been successful throughout the entire ecosystem.  But one of the things you have to worry about in that case are diamond dependencies.  So here's the scenario.  Let's say that you've updated framework and of course all of its downstream components  will now automatically try to update themselves and so reports engine updates himself and  he's happy with the change.  This looks good.  When pricing engine tries to incorporate that change it cannot for some reason and pricing  engine now has reds on its test and now the $64,000 question is which version of framework  should the portfolio management application rely on?  And of course the answer is none of the above.  There's no legal version for it to rely on now because two of its children have different  dependencies.  This is a problem out in the wild, wild world of transitive dependencies on the internet  but if you control your ecosystem you can get rid of the diamond dependency problem  like this.  When you construct your deployment pipeline you need to resolve all dependencies at a  certain level before moving on to the next level of dependencies.  So in this scenario we build framework and make a change to it.  It will trigger a change to pricing, settlement and reports engine and only if all three of  those are successful does it promote to the portfolio management application and so now  we can make sure that everything resolves at one level before we promote it to the next  level and never have to worry about the diamond dependency problem with components.  So that's a whole bunch of practices around components.  Now let's talk about some practices around services.  I want to skip this slide.  I'll come back to that in just a second.  That's a Conway's law side that I'll get to in just a second.  So one of the things that we talk about in the service world is that we tend to prefer  choreography to orchestration particularly in the microservice kind of world and let  me describe these two things and describe what I'm talking about here.  So when you look at the traditional kind of service oriented architecture, enterprise  service bus pattern of architectural style and whether this is a relatively simple kind  of ESB like a mule or really complex thing like an orchestrator like Ode, Apache Ode or  something like that.  They have the same kind of characteristics.  That's an orchestration style of integration architecture because now if two services need  to communicate it between each other they go through this bus to handle things like data  transformations and choreography, etc.  It's called orchestration because the bus here acts like the conductor of an orchestra.  Anytime services need to do anything they need to check with the conductor to make sure  that's okay.  Contrast that with a more choreography style of integration architecture where there is  no third party arbiter and services that want to communicate with one another just get together  a service teams and decide which kinds of things they want to pass back and forth between  each other.  One of the side effects of having an enterprise service bus is that it will accrue a pack  of enterprise architects around it like ships grow on the bottom, sorry barnacles grow on  the bottom of a ship in the ocean.  This is inevitable because of this phenomenon called Conway's Law which I'll talk about  in just a second about team structure and organization.  Basically Conway's Law says if you have something like an enterprise service bus it will become  a layer in your architecture and a communication bottleneck as well.  On the choreography side of the world what we're doing here is not involving any kind  of third party arbiter but just having the two teams decide what they want to pass back  and forth with each other because what we're really trying to support here is to allow  them to evolve as independently as possible from one another without having to check with  a third party coupling point.  But that sounds kind of dangerous because now I have a situation where I'm allowing these  services to evolve at different rates and perhaps changing the way they work in an arbitrary  way.  How do you make sure that things don't just break all the time from an integration standpoint?  This again is where continuous delivery relies on engineering practices to build safety nets  for this sort of stuff and the common safety net here is something called a consumer driven  contract.  And here's the idea behind consumer driven contracts.  So you have a service provider on the left and three teams on the right that it is providing  information for.  The idea of a consumer driven contract says that this team here on the right will put  together a set of unit and integration tests and hand it to this team.  This team not promises to keep that set of tests green every time they make a change  to their code base.  These guys are going to do the same and so are these and so now the team on the left  is running three different sets of unit and integration tests on behalf of these other  teams because those tests encapsulate what they need from the service provider.  This allows any of these guys to evolve at whatever rate they need to and as long as  they don't break those integration tests then we know that they're still can communicate  successfully one another.  So if this guy on the left changes and it doesn't break any tests then everything's  okay.  If one of those test changes, if one of those test breaks because of a change this becomes  a placeholder for conversation between those two teams again to get together and reestablish  the contract in a way that they are both happy with and move on again with the rest of their  lives.  This is really common particularly in a microservice kind of world where you're doing choreography  because in the microservice world you never have any kind of choreographer or enterprise  service bus because it's a shared nothing kind of architecture and so choreography is  a very common kind of mechanism and consumer-driven contracts are very popular way to implement  this.  So a bunch of open source tools that do this packed PACT and Pacto, PACTO are both tools  that handle consumer-driven contracts.  In fact, I should just go ahead and give you, I don't think I have a bed in the slide deck  here where there's a fantastic website called DevOpsBookmarks.com which is hosted on Iroku  by a bunch of my colleagues in India.  What they're trying to do is take all the different open source tools for doing DevOps  and continuous delivery and consolidate them on one big reference page and so they have  categories there so there's an entire category for service testing and consumer-driven contracts.  There's a category there for orchestration tools and provisioning and monitoring, logging,  etc.  So lots of different tools that enable these kind of engineering practices.  And notice too that particularly microservice kind of environments require a certain level  of maturity from an engineering standpoint before you can really even go there because  if you commonly run around with broken bills or tests that don't are read all the time  for days at a time, you can't play in this ecosystem.  If you can't guarantee that you can keep tests green and bills up all the time, then there's  no way you can handle this kind of dynamic, kind of choreography style of integration.  Things will be broken all the time.  So it takes a certain level of engineering maturity before you can get to the ability  to do this.  So let's talk about services and a lot of this encompasses microservices as well because  in many ways they are flavors of the same things with a few differences in terms of operational  concerns.  And in fact this is the real design aesthetic from the microservices world comes from the  ideas, particularly one main idea in domain-driven design, which is ostensibly an object modeling  kind of technique.  You take a big complex domain and decompose it into domain-driven design, these individual  domain objects.  This book by Vaughn Vernon is a quite good implementing book about domain-driven design.  But what has happened in the microservice world is they borrowed this idea from domain-driven  design called a bounded context.  So in domain-driven design when you identify a key concept within your architecture and  part of your domain, you build a bounded context around it, which means within that  bounded context you know of implementation details like database schemas, etc.  But outside that bounded context no one has any idea of what's going on.  You can message into that bounded context and get results back, but you know no implementation  details that is purely the business within the bounded context.  In domain-driven design this is purely a logical separation, but what we've done in the microservices  world is combined this with the engineering practice continuous delivery and made that  bounded context a real physical thing.  This is the real differentiator between microservices versus other service-based architectures is  that every one of these microservices is completely isolated.  It forms its own physical bounded context with the rest of the world and shares nothing  with the rest of the world, say one thing.  Continuous-based architectures promote coupling from application to integration architecture.  Here's what I mean by that.  When you look at a Model F and it has a whole bunch of modules and classes talking to one  another, you don't really concern yourself that much about things like efficiency of  method calls between two pieces of your code base because it's all in process.  You don't have to worry that much about it.  So if you have one method calling another method a thousand times in a loop, it's generally  not a big idea, not a bad problem.  But when you switch this, let's say you decompose this into a services-based architecture, now  you have a different set of problems because now you still have individual little modules  inside these services, but now you have coarser grain representations of the way that your  application works with each other.  This brings a whole host of new problems with it.  Most of these are exemplified by this really great thing, Peter Deuches, fallacies of distributed  computing.  He came up with this at Sun back in the late 80s or early 90s when distributed computing  really just became a thing.  The fallacies of distributed computing are the really tragic mistakes people make when  they shift from application to integration architecture.  It's terrible assumptions like the network is reliable and that latency is zero and  the bandwidth is infinite and the network is secure and the topology doesn't change  ad-hocly and there's only one administrator that you can call when things break and the  transport cost is zero and the network is homogeneous.  All these things are bad assumptions that people mistakenly make, but this is going  to be your world as you switch from a monolithic architecture into a service-based architecture  because now you're talking about integration coupling.  This makes you a lot more explicit about how things are coupled to one another, particularly  the major moving parts of your application, how they send information back and forth between  each other.  This relies on a lot of engineering safety nets, things like consumer-driven contracts  to make sure things are not broken all the time.  This encourages a lot of coarser grain coupling.  You can't practically make a call a thousand times to this guy now like you could over  here because that's going to be a thousand calls over your network and the latency is  going to absolutely kill you because the fallacies are distributed computing.  So now you have to think about coupling in a lot more explicit way.  If you just go about this in a completely undisciplined way, you can create a giant  mess.  I refer to this as the visual studio problem because it's trivially easy to right-click  on a method and say, make me a soap endpoint.  You go, oh, hey, I have distributed architecture.  Let's go home now.  You've built the slowest distributed architecture on Earth because now every function call is  now a network call.  This creates what is called the spider web architecture anti-pattern.  We have lots and lots of services running, but you're not sure which ones are actually  being called, but you're afraid to take down a bunch of those things because somebody may  be calling them, which is a mess.  And now coupling dynamics become an integration issue, and you have to think about those  dynamics a lot more diligently in this kind of world.  So we talk about monolith versus microservices.  Monolithic style architecture is designed this way that you can run multiple modules  inside a single container.  These are the land of things like application servers, industrial-sync database servers,  very much a shared resources kind of architecture.  Microservices, on the other hand, are much more around the kind of Linux philosophy of  one thing per process.  And so these are process-based, not thread-based.  One thing per thing, one service per container.  When you scale monoliths, you cluster multiple monoliths together and have a clustering protocol  between them, whereas in the microservices world, you just spin up new instances of the  service.  This is a really good example, though, of how ignoring parts of the ecosystem can have  you build much more complexity than you need.  Because in this monolithic application server world, the way that you get these things to  chat with one another is actually build protocols between the application servers and make that  part of your architecture of how these things communicate with one another.  On-demand scalability is really an operational concern.  Why are we building that into our architectural elements?  And that makes much more sense over here, that generally on-demand scalability is something  an operation takes care of.  It's quite common, for example, to have services that have an input queue, and as that input  queue starts filling up, you can, on the fly, spin up more versions of that service and  then load balance across them so that you can react really quickly to changes that are  happening in your ecosystem.  And this is just a good example of that greatly simplifies our architecture by letting operations  worry about things like on-demand scalability.  Here's Conway's law that I mentioned before.  We did the first software architecture conference for O'Reilly in Boston this last year, and  I was on the program committee.  And during the course of the conference, Conway's law was mentioned in so many talks that it  became sort of a conference in-joke because everybody was talking about this.  Melvin Conway back in 1968 made this observation that any organization whose design system  will produce a design whose structure is a copy of that organization's communication  structure.  This is about the way that people communicate with one another and how that ends up getting  represented in things like architecture.  And so what that means from our standpoint is if you have UI specialists and middleware  specialists and DBAs running around, you're going to end up with those layers in your  architecture.  It's just a natural kind of follow-on that the way people communicate with one another,  you end up building those layers in architecture.  And so very typically you have siloed teams like this.  This is what we refer to in the continuous delivery world as a human resources department  optimized organization.  So you've organized yourself to make your human resources department's job as easy  as possible because you've all self-selected into little HR silos so that they have a really  easy job now keeping everyone sorted out.  Maybe that's not your primary goal as an organization.  Maybe you'd like to be a better software organization than a human resources organization.  And so this is the way that we suggest that you organize things now, building these cross-functional  teams.  Now there are two names for this phenomenon that we've come up with within ThoughtWorks.  One of them was developed by an enterprise architect.  I'll give you the two names and you have to guess which one the enterprise architect came  up with.  One name for this we call this the inverse Conway maneuver.  Basically turning Conway's law on its head.  The other thing we call this is domain architecture isomorphism.  So which one do you think the enterprise architect came up with?  Yeah, it's the isomorphism one.  But basically the idea is that if you build teams that look like the architecture you  want, that architecture will be easier to achieve.  That's the idea of the inverse Conway maneuver.  Another common thing in the services and particularly microservices world is they focus on products  versus projects.  Here's the distinction.  When you have projects in a big company, you have a team of developers to get together  and work on that project and at some point they finish that project and hand it off to  someone in operations and they take care of the care and feeding this thing for the rest  of his life.  And that team then reassemble somewhere else and start working on another project.  They will then hand off someone in operations and move on to another project.  And of course this poor person in operations can't get things like bug fixes or maintenance  releases or things like that done because this team has already moved on.  Companies like Amazon have a different philosophy around this.  They don't build projects, they build products.  They have product teams based on this idea of the inverse Conway maneuver.  And so at Amazon you have these cross functional teams which they refer to as two pizza teams.  No software development teams shall be larger that can be fed with two large pizzas.  This is really a reflection of something Fred Brooks wrote about back in 1975 about communication  overhead on projects.  And what Amazon has done is we're going to take these small cross functional teams.  So these are teams that have developers and DBAs and operations people on it and they  build a product.  And their philosophy is you build it, you run it because you own this thing forever.  And so at Amazon if you're on one of these teams someone on your team is the one that  puts it in operation and you own this thing forever.  So your product team is responsible for things like enhancements and changes, etc. for this  product and it has a product owner who looks after all those things.  But this has a bunch of really interesting beneficial side effects as well.  Because having these cross functional teams leverages the kind of social aspect that is  important to people whether they realize it or not.  So for example let's say that you're in the project kind of world up here and you're working  on some project and something you worked on two years ago blew up in the middle of the  night and some of the operations got paged and had to come in and fix this thing that  you wrecked two years ago by accident.  You get an email the next morning and it says oh this project you worked on two years ago  blew up in the middle of the night and operations.  It's like wow I'm glad I'm working on operations here.  Let's see if I can code it under disaster today.  But if you're on one of these two pizza teams and you wrote some code that blew up in the  middle of the night and someone in your team had to get up in the middle of the night and  go fix it.  The next morning you have to look across the breakfast table at their tired sad eyes.  It will make you a better person.  Because now it's not some abstract this happened to somebody else.  This happened to somebody on your team.  And so this forces you to think much more like a team and not this kind of adversarial  across silos that you get in big organizations where that's not my problem that's somebody  else's problem you make it your problem because it's part of a team.  It's also characteristic in this world to have smart endpoints and dumb pipes as deep  coupled and cohesive as possible inspired by the way that things like Unix filters and  pipes works.  Transport in this world is typically either HTTP using something like REST or messaging  over a lightweight bus.  If you need to go by an area you need performance or something like that.  I said before that we prefer the choreography versus the orchestration style of integration  architecture here.  If you do find yourself with an enterprise service bus but want to build one of these  kind of architectures as long as you use your enterprise service bus as nothing but  a dumb pipe then we're okay with it.  The thing that we don't like about the orchestration style of enterprise integration is that it  violates this bounded context idea in microservices because that means that some of the behavior  that should be in the bounded context is now smeared out across your integration architecture  because part of it resides in this enterprise service bus mechanism.  So even if you have one of those if you're just using a transport then we're okay because  it doesn't violate that bounded context idea.  It's really one of the key ideas in the microservices world that bounded context idea.  Another side effect of this world is it tends to be decentralized data management.  It's quite easy when you have a monolith to do things like transactional behaviors within  the monolith because you're probably talking to a monolithic database as well.  But that's much trickier in the microservice world because the last thing you want to do  is distribute transactions which are very, very difficult.  And so the microservice world, service and microservice world tends to prefer base to  acid.  So this is really transactions versus eventual consistency.  So the microservice and service-based world tends to be more of an eventual consistency  kind of world versus a transactional kind of world.  Having said that, there are still some cases where you may violate the purity of the architecture  and share a context when it's too difficult to decouple those things.  And in fact, this turns out to be one of the trickiest things to detangle if you are taking  a monolith and decomposing it into services or microservices or the transactional boundaries  are very often one of the trickiest things to handle.  And in fact, that is one of the decomposition techniques is to look and preserve existing  transactional boundaries as you decompose your monolith because those things are harder  to deal with.  Another side effect of this world is decentralized governance because each of these microservices  forms its own bound and context, which means it has its own team.  And so let's say that this team is the customer team.  And we've realized that we're never going to have more than a couple of thousand customers  and we don't need to do any kind of crazy sophisticated querying or anything like that.  And we're also, as a team, responsible for spinning up the machinery for our database  and the migrations and all that other stuff.  And we've made the observation that you can take a raw IP address and get MongoDB running  on it in about 90 seconds or two minutes.  And I'm pretty sure the first Oracle install dialog won't come up in just 90 seconds.  And so you as a team may decide, hey, we don't need Oracle.  That's like going rabbit hunting with a bazooka.  Let's just use Mongo instead.  And six months from now, you realize what a terrible mistake that was.  We never should have used Mongo for this.  We should use Postgres instead.  And nobody else cares because you've made that change within your bound and context.  Nobody has any idea of what happens inside your bound and context.  And so this has no ripple effect to any other team.  This means that governance is much easier in this world because we're freeing up individual  teams to make decisions that are right size or the problem they're trying to solve.  Now we're not suggesting you should allow this to become the Wild West where everybody  picks any technology stack they want.  But most organizations make choices to handle the hardest cases.  They make choices for tools and infrastructure to handle the industrial strength, the 5%  of the cases where we absolutely need to be able to query a million records in sub-second  performance time.  And they impose that complexity on every single project because you're all sharing the same  monolithic architecture and it's overkill for 95% of the things that you're doing, but  you have to take on that complexity for the 5% that actually need it.  This frees you up to right size the technology choices for the problem you're actually trying  to solve.  And so a really common thing in this world is to standardize on integration or not platform  and grace polyglot solutions where it makes sense to do so.  So we don't really care what runs inside the microservices.  That's part of the bound and context.  We do care that they all integrate successfully one another.  So this is the only real coupling point in a microservice architecture is how they integrate  one another.  So you typically pick something like REST level 2 and say everybody adheres to that.  Again, we're not suggesting this becomes the Wild West where everybody picks whatever  they want on a team by team basis.  But if you look at most large companies and the spectrum of two few languages and platforms  and versus too many, most companies fall well on the too few side versus the too many side.  My colleague Sam Newman who's here doing a talk right now in another room about microservices  has written a book for O'Reilly about this.  And here's some of his advice, standardizing the gaps between services and be flexible  of what happens inside the boxes.  Have one, two, or maybe three ways of integrating but not 20 and pick some sensible conventions  and stick with them.  Another piece of advice and also common and continuous delivery world is to not make your  operations understand all the different shapes of things that you may want to deploy.  Rather build a common deployment mechanism so that everything looks the same way.  This is Sam's advice as abstract underlying platform differences to perform a uniform  deployment mechanism.  This can take on several different flavors, probably the most common mechanism for this  now are Docker containers because Docker is a really popular thing, a continuous delivery  world.  If your operations just knows how to put Docker containers into production, then you don't  have to worry too much about differences between different platform pieces.  But you don't have to go quite that elaborate.  My colleague James Lewis has a talk about building a microservice kind of project in  Java called Java the Unix way.  And his uniform deployment mechanism was he built every one of his microservices as a standalone  jar file that had a jetty embedded inside it.  And if you call the main method on that jar file, it'll post itself up using jetty, listening  on a particular port.  And so we could have an entire directory of those jar files and just say, for every one  of these jar files, tell them to run themselves.  And it would bootstrap the architecture.  That's a common deployment mechanism.  So let's talk for a second about integration and disintegration and reducing risk of release  in this world.  So this is typically a continuous delivery, continuous deployment kind of world when you  have services, particularly microservices, which sounds really scary.  But one of the things that we've done in this world is separated out the things that can  break the closure community as this great.  So closure, of course, is a functional language in the JVM, which is a really nice thing in  its own right.  But the creator of closure is also kind of a word of file.  He loves old words.  And he has resurrected this archaic term, which is absolutely perfect for software called  complex, C-O-M-P-L-E-C-T, complex, to complex two things together, to braid or weave them  together.  And what we've inadvertently done in most of our architectures is completed, deploy,  and release, because when you deploy something, you also release it.  But if you can separate those things, you can make each piece simpler.  And that's exactly what we do here.  Because typically in this ecosystem, we deploy components.  But we haven't turned on the features yet because we frequently use things like feature  toggles or feature flags.  This allows us to deploy a component into the ecosystem and make sure it plays nice with  everybody else, make sure it's monitoring correctly, and logging correctly, and all the  infrastructure pieces are working the way they're supposed to.  Now you can turn on features and then monitor to make sure everything's okay.  This allows you to deploy a bunch of different services, maybe even some services that do  the same thing with slight variations.  Because typically in the microservices world, we still haven't impacted users yet because  applications consist of routing between services.  What this does, so one of the things that you talk about in continuous delivery world  is that our blue-green releases, we have identical slices of infrastructure, a blue slice and  a green slice.  And the idea is you can switch back and forth between these things.  In the microservices world, you basically have that at the service level.  Because let's say you deploy a service, you release the feature by turning it on, you  route to it and it starts misbehaving, you just route back away from it, fix it, route  to it again, maybe just saw a small percentage of your users, make sure that's cool, and  then gradually more and more people use it.  And this is really the basis for evolutionary architecture, which I'll talk about in just  a second.  So what this suggests is that the more services you have as long as you have good engineering  practice drives your risk of release down.  Because if you're deploying a monolith, it's all risk.  It's one big thing you have to deploy, but if you have a lot of very small services,  you're actually deploying smaller and smaller pieces every time.  We monitor services in this world, but we also monitor routes and you disintegrate services  that no one's using anymore.  So this is really the basis for evolutionary architecture.  Let's say I have something like a Netflix ecosystem and I have star ratings and someone  comes out with a, allows you to do half star ratings.  You deploy that in the ecosystem and people start routing to it because they want half  star ratings.  Over time, everyone is now using half star ratings and they observe that no one is using  star ratings anymore and that gets disintegrated out of the ecosystem.  We've evolved into that new behavior one tiny bit at a time without disrupting the whole  architecture to do that.  As I suggested before, you really need a lot of engineering sophistication to be able  to pull off something like a microservice architecture because you have to have these engineering  practices in place.  So for an evolutionary standpoint, when you talk about decomposing monoliths into smaller  and smaller pieces, you can partition along natural boundaries.  So I talked about structural decomposition using things like afferent and efferent coupling,  transactions, another way of looking at this, preserve existing transactional boundaries.  Maybe you want to go the full blown inverse Conway maneuver and do by organization or  by domain and so let's put things into domain driven design and do domain stuff or maybe  you have geological constraints or geographical constraints where you have to be physical locations  and you split your architecture along those boundaries.  So to conclude all this stuff, what we're really trying to build here is architecture  for change and get away from yesterday's best practices tomorrow's anti-pattern, build  teams that look like the architecture you want, it becomes easier to build that kind  of architecture.  I talked about efferent coupling as a code metric before, but you also can have this  as a team metric and so you want to strive for a low efferent coupling for your team.  Your team shouldn't know everything that's happening in the entire ecosystem.  In fact, this is the whole thing kind of wrapped up on one big slide.  We have teams with low efferent coupling delivering relatively independently and their common integration  pipeline without fearing breaking each other's bills because we have things like consumer  under and contracts in place, small cross functional teams sharing information as they  need to, sharing a common integration platform that has a deployment pipeline there, verifying  that as they push things in that deployment pipeline it hasn't broken things, they're  already running in other places and automating a lot of these pains and issues away.  That's it.  Looks like I'm right up exactly against time so I won't take any questions right now.  I'll be around all day if you have any questions you can chase me down but looks like we've  hit the break.  Thanks very much for coming and hope you enjoy it.  Great, thank you.  Thanks.
Continuous_Delivery_for_Architects_-_Neal_Ford_0_215.png Continuous_Delivery_for_Architects_-_Neal_Ford_216_995.png Continuous_Delivery_for_Architects_-_Neal_Ford_996_1511.png Continuous_Delivery_for_Architects_-_Neal_Ford_1512_2903.png Continuous_Delivery_for_Architects_-_Neal_Ford_2904_6983.png Continuous_Delivery_for_Architects_-_Neal_Ford_6984_7619.png Continuous_Delivery_for_Architects_-_Neal_Ford_7620_10475.png Continuous_Delivery_for_Architects_-_Neal_Ford_10476_11699.png Continuous_Delivery_for_Architects_-_Neal_Ford_11700_13235.png Continuous_Delivery_for_Architects_-_Neal_Ford_13236_13559.png Continuous_Delivery_for_Architects_-_Neal_Ford_13560_15395.png Continuous_Delivery_for_Architects_-_Neal_Ford_15396_17675.png Continuous_Delivery_for_Architects_-_Neal_Ford_17676_17963.png Continuous_Delivery_for_Architects_-_Neal_Ford_17964_18503.png Continuous_Delivery_for_Architects_-_Neal_Ford_18504_18695.png Continuous_Delivery_for_Architects_-_Neal_Ford_18696_19559.png Continuous_Delivery_for_Architects_-_Neal_Ford_19560_19655.png Continuous_Delivery_for_Architects_-_Neal_Ford_19656_20675.png Continuous_Delivery_for_Architects_-_Neal_Ford_20676_23699.png Continuous_Delivery_for_Architects_-_Neal_Ford_23700_23807.png Continuous_Delivery_for_Architects_-_Neal_Ford_23808_24491.png Continuous_Delivery_for_Architects_-_Neal_Ford_24492_24791.png Continuous_Delivery_for_Architects_-_Neal_Ford_24792_26495.png Continuous_Delivery_for_Architects_-_Neal_Ford_26496_26855.png Continuous_Delivery_for_Architects_-_Neal_Ford_26856_27047.png Continuous_Delivery_for_Architects_-_Neal_Ford_27048_27251.png Continuous_Delivery_for_Architects_-_Neal_Ford_27252_27311.png Continuous_Delivery_for_Architects_-_Neal_Ford_27312_27815.png Continuous_Delivery_for_Architects_-_Neal_Ford_27816_27863.png Continuous_Delivery_for_Architects_-_Neal_Ford_27864_28067.png Continuous_Delivery_for_Architects_-_Neal_Ford_28068_28967.png Continuous_Delivery_for_Architects_-_Neal_Ford_28968_29099.png Continuous_Delivery_for_Architects_-_Neal_Ford_29100_31355.png Continuous_Delivery_for_Architects_-_Neal_Ford_31356_31715.png Continuous_Delivery_for_Architects_-_Neal_Ford_31716_33539.png Continuous_Delivery_for_Architects_-_Neal_Ford_33540_34031.png Continuous_Delivery_for_Architects_-_Neal_Ford_34032_34403.png Continuous_Delivery_for_Architects_-_Neal_Ford_34404_34451.png Continuous_Delivery_for_Architects_-_Neal_Ford_34452_34499.png Continuous_Delivery_for_Architects_-_Neal_Ford_34500_34571.png Continuous_Delivery_for_Architects_-_Neal_Ford_34572_34619.png Continuous_Delivery_for_Architects_-_Neal_Ford_34620_34979.png Continuous_Delivery_for_Architects_-_Neal_Ford_34980_36791.png Continuous_Delivery_for_Architects_-_Neal_Ford_36792_43031.png Continuous_Delivery_for_Architects_-_Neal_Ford_43032_43127.png Continuous_Delivery_for_Architects_-_Neal_Ford_43128_51779.png Continuous_Delivery_for_Architects_-_Neal_Ford_51780_53471.png Continuous_Delivery_for_Architects_-_Neal_Ford_53472_54335.png Continuous_Delivery_for_Architects_-_Neal_Ford_54336_55535.png Continuous_Delivery_for_Architects_-_Neal_Ford_55536_56747.png Continuous_Delivery_for_Architects_-_Neal_Ford_56748_61763.png Continuous_Delivery_for_Architects_-_Neal_Ford_61764_62771.png Continuous_Delivery_for_Architects_-_Neal_Ford_62772_64871.png Continuous_Delivery_for_Architects_-_Neal_Ford_64872_65555.png Continuous_Delivery_for_Architects_-_Neal_Ford_65556_66251.png Continuous_Delivery_for_Architects_-_Neal_Ford_66252_69503.png Continuous_Delivery_for_Architects_-_Neal_Ford_69504_69875.png Continuous_Delivery_for_Architects_-_Neal_Ford_69876_71195.png Continuous_Delivery_for_Architects_-_Neal_Ford_71196_76319.png Continuous_Delivery_for_Architects_-_Neal_Ford_76320_78287.png Continuous_Delivery_for_Architects_-_Neal_Ford_78288_78419.png Continuous_Delivery_for_Architects_-_Neal_Ford_78420_79847.png Continuous_Delivery_for_Architects_-_Neal_Ford_79848_79907.png Continuous_Delivery_for_Architects_-_Neal_Ford_79908_80003.png Continuous_Delivery_for_Architects_-_Neal_Ford_80004_82571.png Continuous_Delivery_for_Architects_-_Neal_Ford_82572_82859.png Continuous_Delivery_for_Architects_-_Neal_Ford_82860_83519.png Continuous_Delivery_for_Architects_-_Neal_Ford_83520_84023.png Continuous_Delivery_for_Architects_-_Neal_Ford_84024_85127.png Continuous_Delivery_for_Architects_-_Neal_Ford_85128_85367.png Continuous_Delivery_for_Architects_-_Neal_Ford_85368_86387.png Continuous_Delivery_for_Architects_-_Neal_Ford_86388_86447.png Continuous_Delivery_for_Architects_-_Neal_Ford_86448_86495.png Continuous_Delivery_for_Architects_-_Neal_Ford_86496_86675.png Continuous_Delivery_for_Architects_-_Neal_Ford_86676_86771.png Continuous_Delivery_for_Architects_-_Neal_Ford_86772_87047.png Continuous_Delivery_for_Architects_-_Neal_Ford_87048_87191.png Continuous_Delivery_for_Architects_-_Neal_Ford_87192_87275.png Continuous_Delivery_for_Architects_-_Neal_Ford_87276_88079.png Continuous_Delivery_for_Architects_-_Neal_Ford_88080_88946.png
All right, good morning everyone. As you've probably guessed, this is the session on continuous delivery for architects. My name is Neal Ford. I work for ThoughtWorks. I'm going to talk about three things in this talk. First some concepts around the intersection of continuous delivery and architecture. That's where I'm spending most of my professional time right now is that intersection. Oh, and keynote just crashed. It's nice. So, it's a nice way to start out the talk. So, let's get that started again. Sorry about that. One minute. Let's try that again, shall we? So, my agenda for this talk, I'm going to talk about some concepts. This is one of the tricky things about talking about architecture. There are all these kind of seemingly peripheral but important concepts that kind of lurk on the edges of the ideas and software architecture. I'm going to spend a lot of time talking about components. And really when you talk about architecture and continuous delivery, there are two kinds of components you care about. You care about libraries and you care about services. And I'll talk about engineering practices for both of those. And then finally, some evolution strategies because I suspect that many of you are in this very common situation where you have a monolithic architecture. The good news is it's so common that it has an industry anti-pattern called the ball of mud. The bad news is even though it's so common it has its own name, it still sucks if you have one. So, I suspect that many of you are in the process of going from a monolithic architecture into a services or maybe even microservices style of architecture. And I'll talk about some evolutionary steps to allow you to do that. But first let's talk about some concepts. And of course, if we're going to talk about continuous delivery in architecture, we have to talk about the concepts behind continuous delivery. Really this is the same kind of feedback loop that you get with continuous integration. It's just broader in two really important ways. So here's a definition of the idea of a deployment pipeline, for example, in continuous delivery. But it enables you to get fast automated feedback on the production readiness of your application every time there's a change. Notice that we're looking for production readiness here, not just I pass some tests somewhere along the line, which is kind of the bar for continuous integration. Here we're trying to assess will this react properly in a production like environment. So that's one important broadening of the ideas of continuous integration. The other is the triggering mechanism. Because in the continuous delivery world, we trigger the changes in code just like we do in continuous integration. We also trigger any changes in the ecosystem. So we view software as a complete ecosystem in the continuous delivery world. It encompasses not just the source code, but also the operating system and the configuration for the application servers. All those things that are required to make that architecture operationalized, that's the entire ecosystem for code. And anytime something permutates, something changes that ecosystem, we want to react to that as eagerly as we possibly can. That's this idea of having a really broad triggering mechanism to try to incorporate change. One of the key things that you're going to encounter as an architect on a continuous delivery style project is building a deployment pipeline. And there's a whole bunch of stuff about building a deployment pipeline. It can be something as simple as a simple CI server with a bunch of plug-ins and augmentations, or it could be as sophisticated as the open source Go CD tool. But this is going to be your responsibility as the architect to construct what this deployment pipeline looks like. There's no predefined set of stages. There's some common stages that people use, but no predefined have to have these stages. And so it's your job to put these things together. And so you may have a commit that does the continuous integration job of unit testing, et cetera. And then maybe functional testing and more broad user acceptance testing using some sort of mechanism like Selenium or Sahi or Geb running tests through a browser or something like that. Maybe you have an automatic staging environment. Maybe you have environments beyond that. These are all joined by this idea of the artifact repository, which is a piece of the deployment pipeline that keeps intermediate results of these things as you go along. So because there's no predefined set of stages, it's important to understand why you build this deployment pipeline and why you build stages. Really what you're trying to achieve here is more and more confidence in production readiness, how will this react in production. And so stages in a deployment pipeline become feedback opportunities. So this is primarily what these guys represent for you as an architect is a chance to get feedback at a particular stage along the way of testing our code and putting it through a gauntlet to see if it can get to production. But here's the other really important aspect of continuous delivery and how it impacts the day to day job of an architect. So let's say you have this kind of deployment pipeline set up where commit stage, feedings to acceptance stage, and then you have user acceptance testing, etc. Notice there's one special step here that comes in in the acceptance stage that's not required, but you have to start doing this at some stage along the way. And there's a step here called configure environment. And then the continuous delivery world, this is the first stage where you programmatically build out the environment that your code is going to run on. And so this is the point where you run a puppet script or a chef script to build out the ecosystem the code runs on and then programmatically deploy code to that ecosystem and bootstrap it and see if it's running. And once you started doing that in the deployment pipeline, you do that on every downstream stage because once you've built a certain level of confidence, you don't want to give up any of that confidence. You want to keep building confidence all along the deployment pipeline. But what this means from an architect standpoint is that in traditional, even agile architectures, you didn't really have to worry that much about what this code was going to look like in production about actual machine configurations and memory footprints and all that stuff until very, very late in the process. Because you could run it on test machines, etc. Until you really needed to get to production, you didn't really vet all those things out. Here you've got to vet those things much, much earlier because part of your deployment process is building out that operational infrastructure. And so you can't put that off into the last part of the project anymore, which is a really good thing because this forces the architect to think about the operational aspects of their architecture as eagerly as possible, which is, as we see in continuous delivery, a really good thing to do things as eagerly as possible rather than put them off as long as possible. Because what we really want to be able to do in this world is build a component pipeline. What we really want is a deployment pipeline where if I make a change to a component or service somewhere, it detects that change and automatically runs it against all the different versions that I want to verify this against. So for example, it's quite common in a microservices kind of world to say, okay, I've made a change to this service. Now I want to automatically verify, does this work correctly against the head of my version control and does it still work correctly against the version that's running in production? I want to automate that behavior in a deployment pipeline so that a single change here, let's be vet that that change hasn't had a ripple side effect somewhere else in my ecosystem. So another concept that we're only really coming to grips with in the architecture world, I've captured with this, that yesterday's best practice is tomorrow's anti-pattern. We constantly build architectures that solve outdated problems. So software architecture very often is a mapping between capabilities and constraints and very often it's reactions to constraints. And what happens all the time is we build an architecture around some sort of physical real world constraint and that constraint melts away and all we're left with is an architecture that embodies all those constraints, but now it's just an arbitrary kind of restriction. We see this all the time and I'll show you some examples of this later on. But another example of this is a very common instinct that architects have is to build single sources of truth for things. Data architects love to do this to build the ultimate customer service that encapsulates everything we know about customers. That's just a logical kind of instinct because from a mathematical standpoint you want a single source of truth for things, it's messy to have multiple versions of things. And so that's a common practice in architecture. But let's talk about the impracticalities of that. We have a client who runs an airline and their architects had built the ultimate customer service that has everything we know as a company about customer inside it. And it had built it with the kind of accepted architecture practices with clustered application servers and multiple database servers and all this sort of stuff. And then a volcano blew up in Iceland. Pretty much everybody that had a ticket on this airline called the airline and said, hey, is that volcano going off in Iceland going to affect my flight? And people on the other side of the world who were nowhere near Iceland couldn't board their airplane because boarding does a customer look up. Customer service does a customer look up. And so no matter how much horsepower they had put behind this Uber customer service, when it hit real world kind of constraints, it fell over. Notice that their architects would have been better served if they had split the concept of customer into separate pieces and maybe even had duplicate data between those two pieces. But it would have been their business would have survived this unusual contingency. And so the instincts that you sometimes have as an architect sometimes don't work well when you look at the business constraints in the real world. Let me go deeper into this because as architects we're really good at building boxes and lines. We do those on whiteboards. We even build really pretty versions of this with Visio and OmniGraph all these lines and boxes, which is a useful exercise because it's a snapshot of what the shape, the topology of the architecture is at a certain point in time. This is a good two dimensional representation of an architecture. And for a long time, this was good enough. But what continuous delivery has really made it forced us to realize is that this is not far enough because this doesn't really represent the real world is the abstraction. Now you've got to take those boxes and actually flesh them out with actual things with actual version numbers. This is a 3D version of an architecture. Instead of having a box as an ORM, this is a specific version of an ORM tool that you have to get to work together with all the other stuff and operations. But now this is still not sufficient because now you have to think about what happens when hibernate revs itself in six months. How can I easily make that upgrade without making the entire architecture unstable because too many things rely on a single choke point. This is really a more realistic modern view of architecture, a four dimensional view of architecture that takes into account not only how the pieces fit together, but how to operationalize those pieces and how to evolve that operational architecture over time. That's the really interesting part of architecture right now. And so for example, if you look at a traditional service oriented architecture and look at the constraints that they're working against and the capabilities they're trying to create here, this is very much a shared resources kind of architecture. This is why you have things like a service broker, where you have things like a choreographer and orchestrator, et cetera, you're consolidating all that information into a same place so you can share all those resources and make the most efficient use of them. So one of the goals in this kind of traditional service oriented architecture is to maximize shared resources. But if you look at a microservice architecture, the real goal here is to maximize easy evolution. And so we operationalize each one of these services in a much more encapsulated way in the microservices world, because the real goal here is not to try to maximize shared resources, but basically have resources on demand now. The real goal in this world is to maximize easy evolution to really create these kind of software logos, where you can replace one behavior with another, easily evolve from one behavior to another to create a more evolutionary architecture. But this is a more complex architecture because of it, because you have to have all those operational wrappers around each one of these services. So I think that's one of the reasons that there's so much interest in this microservice style of architecture, because it's the first one where one of the capabilities built into the architecture is to support easy evolutionary change. Microservice style architectures are the first post continuous delivery architecture. It's the first one that kind of fully embraces all the operational concerns of architecture. It won't be the last one. All architectures going forward are going to have to take this into account, because this is an important aspect of architecture we're only now really realizing. And so this is just the first poster child, but believe me, all architectures for now, this will be an important component of them. So last of the concept stuff I want to talk about are some metrics. And in particular, a couple of coupling metrics, afferent and efferent coupling. So for any code artifact that you have, this can be something as low level as a functioner method or as high level as a package or namespace. The afferent coupling for that artifact is the number of incoming connections or references to that thing. And the efferent coupling is the number of outgoing connections or references that it refers to other things. And the easy way to remember this, because these are very similar terms, is that efferent starts with an E, which is also the same first letter of the English word exit. And those are the outgoing connections. So this is the easy way to remember afferent is incoming and efferent are outgoing. This is important to architects because very often you need to understand the structural aspects of your code. That's one of the mentions you need to think about. If you're thinking about, for example, decoupling a monolithic architecture into a services or microservices based architecture, one of the ways you may want to do that is structurally. And you need to understand the structural coupling to be able to do that effectively. And so I want to show you some tools that allow you to visualize the coupling between pieces in a code base. This is very Java centric, but there are tools like this that exist for other platforms. In fact, Smalltalk created a lot of these visualizations and they created a platform called Moose, which is a meta platform for metric stuff. And so for example, if you have C-Sharp, if you can get your C-Sharp code to produce Moose metadata and there are some tools out there that will produce Moose metadata from C-Sharp code, you can pull it into Codecrawler, which is this tool, which is the tool this is inspired by. This is actually a tool in the Java world called Xray, which is an Eclipse plugin that shows you the characteristics of a code base in a slightly different way. This shows you the lines here represent classes and number of lines of code is the length of the box and the width of the box is the number of methods. And so that gives you some ideas about what the structure of the code is like. So that's a real code base. But the really interesting thing about Xray from our standpoint is dependencies because when you look at this chart, this graph, when you click on a particular class, it shows you the afferent and effort coupling for that class. The error heads show you if it's afferent or effort, whether it's incoming or outgoing, and the weight of the line indicates the strength of the coupling between those two things. And so this allows you to look at a class by class basis, how coupled to the is this to the rest of the world. But the more useful view for us is the one that allows you to see this for classes and packages. So here's a package dependency view. And here is a class dependency view for the same project. Now notice that for an architectural standpoint, this represents how classes are coupled to one another within this code base. But if I'm trying to decompose this, let's say this were monolithic architecture, and I wanted to decompose this into let's say four or five services. The first obvious thing for me to do is slice along here because the more bold red lines I slice, the harder my job is going to be because I'm going to have to fix up those coupling points. Those are two things coupled to one another now inside the application architecture. Those are still going to have to work with each other, but now they're separated by network boundary. And so the more of those red lines I cut, the harder my job is going to be. And so structurally, you can look at that and go, well, if I had to decompose this into three services, that'll be one of them. That'll probably be the second one. And this will be the third one. Okay. That's an easy way to kind of slice the whole thing up in a very coarse kind of manner. I'll talk about other ways of decomposing monoliths in a second, but structurally is definitely one of them, and it's nice to be able to see the structural characteristics of your code. Most of the time, though, it's not going to be quite as simple as that. Here's a real project. This is Argo UML, which is an open source UML mapping tool. And this is its class level dependencies. And here it's package dependencies. So this is a very complex monolithic architecture, but this still allows you to see some of those coupling points. Okay. Let's move on then and talk about component-based architectures. The Continuous Delivery Book doesn't say much about architecture. In fact, this is the primary advice that Continuous Delivery Book gives you about architectural concerns is use components to decouple parts of your application that change at different rates. Rate of change is one of the things that may encourage you to split things up into components, but we don't really have just a single kind of component in the software world. We have two kind of components. We have either libraries or we have services. Both of these are conceptually components, but engineering standpoint, they work in different ways. So a library is something that runs within a single process and communicates the language function call mechanisms. These are typically compile time dependencies. So these are JAR files or DLLs or GEMs or something like that. Services on the other hand, run in a separate process and communicate with network communication mechanisms like HTTP or TCP IP and are generally the realm of integration architecture rather than application architecture. These are typically run time dependencies between things. Because these two things are so different, they have different engineering practices associated with them. So let's talk about those in turn and let's talk about some engineering practices around components first. And let's say that this is the way we want to build our application. Rather than building a single monolithic build in our deployment pipeline, we want to use a series of libraries to build this up. We have framework which everything is based on. They have reports, settlement, and pricing engine. And then finally the portfolio management application. And the CDS pricing library is something that maybe comes from a third party, like a JAR file repository, Nexus repository or something like that out in the world. So let's talk about some issues that this introduces. And the first of these is managing dependencies. And most people's first real encounter with this was this fun thing that we used to call DLL hell in Windows. How many people remember DLL hell in Windows? Yep, most people here. The main reason I bring this up is because it's a good example of dependency management. But it's also a great example that yesterday's best practice is tomorrow's anti-pattern. Because the reason that DLLs existed the way they did was when Windows first came out, hard drives were really small and very expensive. And they didn't have enough room to statically link all those applications together. So they built this dynamic link library kind of architecture, which allowed them to save a whole lot of space. That was the constraint they were working against. But of course the space constraint very quickly went away and we were left with the headaches introduced by all this dependency management stuff for a couple of decades before they finally replaced that at the architectural level with the package revolution stuff in the.NET. But now mostly you have two approaches to handling this. The ubiquitous live directory in the project where everybody feels free to add stuff but nobody ever, ever removes anything from this directory because you're afraid you might accidentally wreck the earth if you did that. Or a transitive dependency management tool and every platform ends up here in a transitive dependency management tool because it's just too hard to deal with manually. One of the things you have to deal with when you have libraries like this are cycles, which are circular dependencies between libraries. This is when one component refers to another one, which eventually refers back to the first one. This is particularly bad in ecosystems that have really strong IDEs like Java and.NET because if you're coding along in Java and you reference some class that's conceptually a thousand meters away, what does your IDE do? It pops up a dialog says you only import that for you and you swap that dialog away so fast you don't even see that dialog anymore. It's such a common thing to oh yeah we need to import that. Yeah, yeah, yeah import that, import that. What it really should have is some sort of obnoxious clippy like mechanism that pops up and says should you be importing that library from all the way over there? Are you making a lot of really crazy cycles in your code base? But we don't have that. And so that makes the system really hard to componentize and it makes the lifecycle a lot more complex. It makes it harder to decompose it. There's fortunately a nice little tool out there, open source tool that Curtis Scheld wrote called Draw Analyzer that will allow you to remove some drawer files from your live directory if you want. Because you run this against a library and it'll show you how all those things are connected to one another and who calls what, etc. And it gives you effort, effort coupling metrics, etc. But the other cool thing that Draw Analyzer will do for you is draw the relationship between all those things in your code base. And so for example here's the drawer files and how they're related in struts 1.0. And this is also a good example of what happens if you don't pay attention to this because here's the exact same diagram in struts 2. Yikes, that's terrifying. This is what happens if you don't pay attention to this. In the Java ecosystem you end up with a spider web of dependencies between things, good luck decomposing this and anything without just gutting it and rewriting the whole thing. Fortunately there's help. This is the only commercial tool that I talk about in this talk because it's the only tool that does what this one does as far as I know. A structure 101 goes through and analyzes your code bases just for Java code bases. There's a similar commercial tool in the.NET space called independent that does a similar job not quite as concise as this one but you can glean the same information from it. This analyzes your code base, gives you a to-do list of refactorings that you need to do and this allows developers to untangle cycles within their code base. So the idea here is you structure 101, you go in and untangle things so that you have clean dependencies between the parts of your ecosystem. If you look at a legendarily clean code base from a dependency standpoint, Spring is a really good example of a well organized component based ecosystem and that's not a coincidence. Spring committers all run structure 101 on their laptops and as they make substantive changes to the Spring code base, they run this to make sure they have not accidentally introduced cycles. This is a real problem in the Java ecosystem because the tooling is so powerful it actually hides some deficiencies from you. But what we really like to do in this world is to prevent this from happening. Now one way you can do this is say no developer shall introduce cycles and if you do, there shall be beatings at lunch on Friday. But that never works because you can never force people to think about these little details as they're going about their day job so we're much more fans of building engineering safety nets to catch problems before they manifest into bigger problems and here's a good example of using a tool to do that. This is a thing called J2Pen that's been around for a really long time. This will do analysis of Java code bases between packages to show you after and effort coupling and give you a bunch of metrics but it's written in Java so it understands the Java ecosystem and how packages and things like that work and so you can write a J unit test like the bottom one here that says test all packages. This is analyze all these packages and tell me if any cycles exist. And so what this allows you to do is go in and chase out all the cycles in your code base and then put this unit test in place so that if anybody does accidentally add a cycle because the tooling is being too aggressively friendly then this will fail a unit test before it gets into your code base and starts creating that spider web again. Because J2Pen understands things about how packages work in Java you can also wire in stronger rules from an architectural level because maybe as an architect you want to find some rules that say okay I have this util package it's okay for other things to import from that util package but I don't want it importing from random crap around the world. And so here's the scenario I have EJB web and util and it's okay for EJB to depend upon util and it's okay for web to depend upon util but I never want the reverse to happen. You can set up these rules within J2Pen and then tell it to analyze your code base and tell you if anyone has violated any of those rules or not. This is a good example in the engineering practice is a continuous delivery of a safety net build these little engineering safety nets very often around tests that will flag things that you want to make sure don't happen in your code base rather than relying on people remembering these nitty-gritty details build automatic mechanisms to catch when people make mistakes. Where we really want to get to of course is the ability to build a pipelining library using an deployment pipeline tool like GoCD so that as you make changes to a component it automatically builds all the things that are dependent upon that and then resolves to see if that change has been successful throughout the entire ecosystem. But one of the things you have to worry about in that case are diamond dependencies. So here's the scenario. Let's say that you've updated framework and of course all of its downstream components will now automatically try to update themselves and so reports engine updates himself and he's happy with the change. This looks good. When pricing engine tries to incorporate that change it cannot for some reason and pricing engine now has reds on its test and now the $64,000 question is which version of framework should the portfolio management application rely on? And of course the answer is none of the above. There's no legal version for it to rely on now because two of its children have different dependencies. This is a problem out in the wild, wild world of transitive dependencies on the internet but if you control your ecosystem you can get rid of the diamond dependency problem like this. When you construct your deployment pipeline you need to resolve all dependencies at a certain level before moving on to the next level of dependencies. So in this scenario we build framework and make a change to it. It will trigger a change to pricing, settlement and reports engine and only if all three of those are successful does it promote to the portfolio management application and so now we can make sure that everything resolves at one level before we promote it to the next level and never have to worry about the diamond dependency problem with components. So that's a whole bunch of practices around components. Now let's talk about some practices around services. I want to skip this slide. I'll come back to that in just a second. That's a Conway's law side that I'll get to in just a second. So one of the things that we talk about in the service world is that we tend to prefer choreography to orchestration particularly in the microservice kind of world and let me describe these two things and describe what I'm talking about here. So when you look at the traditional kind of service oriented architecture, enterprise service bus pattern of architectural style and whether this is a relatively simple kind of ESB like a mule or really complex thing like an orchestrator like Ode, Apache Ode or something like that. They have the same kind of characteristics. That's an orchestration style of integration architecture because now if two services need to communicate it between each other they go through this bus to handle things like data transformations and choreography, etc. It's called orchestration because the bus here acts like the conductor of an orchestra. Anytime services need to do anything they need to check with the conductor to make sure that's okay. Contrast that with a more choreography style of integration architecture where there is no third party arbiter and services that want to communicate with one another just get together a service teams and decide which kinds of things they want to pass back and forth between each other. One of the side effects of having an enterprise service bus is that it will accrue a pack of enterprise architects around it like ships grow on the bottom, sorry barnacles grow on the bottom of a ship in the ocean. This is inevitable because of this phenomenon called Conway's Law which I'll talk about in just a second about team structure and organization. Basically Conway's Law says if you have something like an enterprise service bus it will become a layer in your architecture and a communication bottleneck as well. On the choreography side of the world what we're doing here is not involving any kind of third party arbiter but just having the two teams decide what they want to pass back and forth with each other because what we're really trying to support here is to allow them to evolve as independently as possible from one another without having to check with a third party coupling point. But that sounds kind of dangerous because now I have a situation where I'm allowing these services to evolve at different rates and perhaps changing the way they work in an arbitrary way. How do you make sure that things don't just break all the time from an integration standpoint? This again is where continuous delivery relies on engineering practices to build safety nets for this sort of stuff and the common safety net here is something called a consumer driven contract. And here's the idea behind consumer driven contracts. So you have a service provider on the left and three teams on the right that it is providing information for. The idea of a consumer driven contract says that this team here on the right will put together a set of unit and integration tests and hand it to this team. This team not promises to keep that set of tests green every time they make a change to their code base. These guys are going to do the same and so are these and so now the team on the left is running three different sets of unit and integration tests on behalf of these other teams because those tests encapsulate what they need from the service provider. This allows any of these guys to evolve at whatever rate they need to and as long as they don't break those integration tests then we know that they're still can communicate successfully one another. So if this guy on the left changes and it doesn't break any tests then everything's okay. If one of those test changes, if one of those test breaks because of a change this becomes a placeholder for conversation between those two teams again to get together and reestablish the contract in a way that they are both happy with and move on again with the rest of their lives. This is really common particularly in a microservice kind of world where you're doing choreography because in the microservice world you never have any kind of choreographer or enterprise service bus because it's a shared nothing kind of architecture and so choreography is a very common kind of mechanism and consumer-driven contracts are very popular way to implement this. So a bunch of open source tools that do this packed PACT and Pacto, PACTO are both tools that handle consumer-driven contracts. In fact, I should just go ahead and give you, I don't think I have a bed in the slide deck here where there's a fantastic website called DevOpsBookmarks.com which is hosted on Iroku by a bunch of my colleagues in India. What they're trying to do is take all the different open source tools for doing DevOps and continuous delivery and consolidate them on one big reference page and so they have categories there so there's an entire category for service testing and consumer-driven contracts. There's a category there for orchestration tools and provisioning and monitoring, logging, etc. So lots of different tools that enable these kind of engineering practices. And notice too that particularly microservice kind of environments require a certain level of maturity from an engineering standpoint before you can really even go there because if you commonly run around with broken bills or tests that don't are read all the time for days at a time, you can't play in this ecosystem. If you can't guarantee that you can keep tests green and bills up all the time, then there's no way you can handle this kind of dynamic, kind of choreography style of integration. Things will be broken all the time. So it takes a certain level of engineering maturity before you can get to the ability to do this. So let's talk about services and a lot of this encompasses microservices as well because in many ways they are flavors of the same things with a few differences in terms of operational concerns. And in fact this is the real design aesthetic from the microservices world comes from the ideas, particularly one main idea in domain-driven design, which is ostensibly an object modeling kind of technique. You take a big complex domain and decompose it into domain-driven design, these individual domain objects. This book by Vaughn Vernon is a quite good implementing book about domain-driven design. But what has happened in the microservice world is they borrowed this idea from domain-driven design called a bounded context. So in domain-driven design when you identify a key concept within your architecture and part of your domain, you build a bounded context around it, which means within that bounded context you know of implementation details like database schemas, etc. But outside that bounded context no one has any idea of what's going on. You can message into that bounded context and get results back, but you know no implementation details that is purely the business within the bounded context. In domain-driven design this is purely a logical separation, but what we've done in the microservices world is combined this with the engineering practice continuous delivery and made that bounded context a real physical thing. This is the real differentiator between microservices versus other service-based architectures is that every one of these microservices is completely isolated. It forms its own physical bounded context with the rest of the world and shares nothing with the rest of the world, say one thing. Continuous-based architectures promote coupling from application to integration architecture. Here's what I mean by that. When you look at a Model F and it has a whole bunch of modules and classes talking to one another, you don't really concern yourself that much about things like efficiency of method calls between two pieces of your code base because it's all in process. You don't have to worry that much about it. So if you have one method calling another method a thousand times in a loop, it's generally not a big idea, not a bad problem. But when you switch this, let's say you decompose this into a services-based architecture, now you have a different set of problems because now you still have individual little modules inside these services, but now you have coarser grain representations of the way that your application works with each other. This brings a whole host of new problems with it. Most of these are exemplified by this really great thing, Peter Deuches, fallacies of distributed computing. He came up with this at Sun back in the late 80s or early 90s when distributed computing really just became a thing. The fallacies of distributed computing are the really tragic mistakes people make when they shift from application to integration architecture. It's terrible assumptions like the network is reliable and that latency is zero and the bandwidth is infinite and the network is secure and the topology doesn't change ad-hocly and there's only one administrator that you can call when things break and the transport cost is zero and the network is homogeneous. All these things are bad assumptions that people mistakenly make, but this is going to be your world as you switch from a monolithic architecture into a service-based architecture because now you're talking about integration coupling. This makes you a lot more explicit about how things are coupled to one another, particularly the major moving parts of your application, how they send information back and forth between each other. This relies on a lot of engineering safety nets, things like consumer-driven contracts to make sure things are not broken all the time. This encourages a lot of coarser grain coupling. You can't practically make a call a thousand times to this guy now like you could over here because that's going to be a thousand calls over your network and the latency is going to absolutely kill you because the fallacies are distributed computing. So now you have to think about coupling in a lot more explicit way. If you just go about this in a completely undisciplined way, you can create a giant mess. I refer to this as the visual studio problem because it's trivially easy to right-click on a method and say, make me a soap endpoint. You go, oh, hey, I have distributed architecture. Let's go home now. You've built the slowest distributed architecture on Earth because now every function call is now a network call. This creates what is called the spider web architecture anti-pattern. We have lots and lots of services running, but you're not sure which ones are actually being called, but you're afraid to take down a bunch of those things because somebody may be calling them, which is a mess. And now coupling dynamics become an integration issue, and you have to think about those dynamics a lot more diligently in this kind of world. So we talk about monolith versus microservices. Monolithic style architecture is designed this way that you can run multiple modules inside a single container. These are the land of things like application servers, industrial-sync database servers, very much a shared resources kind of architecture. Microservices, on the other hand, are much more around the kind of Linux philosophy of one thing per process. And so these are process-based, not thread-based. One thing per thing, one service per container. When you scale monoliths, you cluster multiple monoliths together and have a clustering protocol between them, whereas in the microservices world, you just spin up new instances of the service. This is a really good example, though, of how ignoring parts of the ecosystem can have you build much more complexity than you need. Because in this monolithic application server world, the way that you get these things to chat with one another is actually build protocols between the application servers and make that part of your architecture of how these things communicate with one another. On-demand scalability is really an operational concern. Why are we building that into our architectural elements? And that makes much more sense over here, that generally on-demand scalability is something an operation takes care of. It's quite common, for example, to have services that have an input queue, and as that input queue starts filling up, you can, on the fly, spin up more versions of that service and then load balance across them so that you can react really quickly to changes that are happening in your ecosystem. And this is just a good example of that greatly simplifies our architecture by letting operations worry about things like on-demand scalability. Here's Conway's law that I mentioned before. We did the first software architecture conference for O'Reilly in Boston this last year, and I was on the program committee. And during the course of the conference, Conway's law was mentioned in so many talks that it became sort of a conference in-joke because everybody was talking about this. Melvin Conway back in 1968 made this observation that any organization whose design system will produce a design whose structure is a copy of that organization's communication structure. This is about the way that people communicate with one another and how that ends up getting represented in things like architecture. And so what that means from our standpoint is if you have UI specialists and middleware specialists and DBAs running around, you're going to end up with those layers in your architecture. It's just a natural kind of follow-on that the way people communicate with one another, you end up building those layers in architecture. And so very typically you have siloed teams like this. This is what we refer to in the continuous delivery world as a human resources department optimized organization. So you've organized yourself to make your human resources department's job as easy as possible because you've all self-selected into little HR silos so that they have a really easy job now keeping everyone sorted out. Maybe that's not your primary goal as an organization. Maybe you'd like to be a better software organization than a human resources organization. And so this is the way that we suggest that you organize things now, building these cross-functional teams. Now there are two names for this phenomenon that we've come up with within ThoughtWorks. One of them was developed by an enterprise architect. I'll give you the two names and you have to guess which one the enterprise architect came up with. One name for this we call this the inverse Conway maneuver. Basically turning Conway's law on its head. The other thing we call this is domain architecture isomorphism. So which one do you think the enterprise architect came up with? Yeah, it's the isomorphism one. But basically the idea is that if you build teams that look like the architecture you want, that architecture will be easier to achieve. That's the idea of the inverse Conway maneuver. Another common thing in the services and particularly microservices world is they focus on products versus projects. Here's the distinction. When you have projects in a big company, you have a team of developers to get together and work on that project and at some point they finish that project and hand it off to someone in operations and they take care of the care and feeding this thing for the rest of his life. And that team then reassemble somewhere else and start working on another project. They will then hand off someone in operations and move on to another project. And of course this poor person in operations can't get things like bug fixes or maintenance releases or things like that done because this team has already moved on. Companies like Amazon have a different philosophy around this. They don't build projects, they build products. They have product teams based on this idea of the inverse Conway maneuver. And so at Amazon you have these cross functional teams which they refer to as two pizza teams. No software development teams shall be larger that can be fed with two large pizzas. This is really a reflection of something Fred Brooks wrote about back in 1975 about communication overhead on projects. And what Amazon has done is we're going to take these small cross functional teams. So these are teams that have developers and DBAs and operations people on it and they build a product. And their philosophy is you build it, you run it because you own this thing forever. And so at Amazon if you're on one of these teams someone on your team is the one that puts it in operation and you own this thing forever. So your product team is responsible for things like enhancements and changes, etc. for this product and it has a product owner who looks after all those things. But this has a bunch of really interesting beneficial side effects as well. Because having these cross functional teams leverages the kind of social aspect that is important to people whether they realize it or not. So for example let's say that you're in the project kind of world up here and you're working on some project and something you worked on two years ago blew up in the middle of the night and some of the operations got paged and had to come in and fix this thing that you wrecked two years ago by accident. You get an email the next morning and it says oh this project you worked on two years ago blew up in the middle of the night and operations. It's like wow I'm glad I'm working on operations here. Let's see if I can code it under disaster today. But if you're on one of these two pizza teams and you wrote some code that blew up in the middle of the night and someone in your team had to get up in the middle of the night and go fix it. The next morning you have to look across the breakfast table at their tired sad eyes. It will make you a better person. Because now it's not some abstract this happened to somebody else. This happened to somebody on your team. And so this forces you to think much more like a team and not this kind of adversarial across silos that you get in big organizations where that's not my problem that's somebody else's problem you make it your problem because it's part of a team. It's also characteristic in this world to have smart endpoints and dumb pipes as deep coupled and cohesive as possible inspired by the way that things like Unix filters and pipes works. Transport in this world is typically either HTTP using something like REST or messaging over a lightweight bus. If you need to go by an area you need performance or something like that. I said before that we prefer the choreography versus the orchestration style of integration architecture here. If you do find yourself with an enterprise service bus but want to build one of these kind of architectures as long as you use your enterprise service bus as nothing but a dumb pipe then we're okay with it. The thing that we don't like about the orchestration style of enterprise integration is that it violates this bounded context idea in microservices because that means that some of the behavior that should be in the bounded context is now smeared out across your integration architecture because part of it resides in this enterprise service bus mechanism. So even if you have one of those if you're just using a transport then we're okay because it doesn't violate that bounded context idea. It's really one of the key ideas in the microservices world that bounded context idea. Another side effect of this world is it tends to be decentralized data management. It's quite easy when you have a monolith to do things like transactional behaviors within the monolith because you're probably talking to a monolithic database as well. But that's much trickier in the microservice world because the last thing you want to do is distribute transactions which are very, very difficult. And so the microservice world, service and microservice world tends to prefer base to acid. So this is really transactions versus eventual consistency. So the microservice and service-based world tends to be more of an eventual consistency kind of world versus a transactional kind of world. Having said that, there are still some cases where you may violate the purity of the architecture and share a context when it's too difficult to decouple those things. And in fact, this turns out to be one of the trickiest things to detangle if you are taking a monolith and decomposing it into services or microservices or the transactional boundaries are very often one of the trickiest things to handle. And in fact, that is one of the decomposition techniques is to look and preserve existing transactional boundaries as you decompose your monolith because those things are harder to deal with. Another side effect of this world is decentralized governance because each of these microservices forms its own bound and context, which means it has its own team. And so let's say that this team is the customer team. And we've realized that we're never going to have more than a couple of thousand customers and we don't need to do any kind of crazy sophisticated querying or anything like that. And we're also, as a team, responsible for spinning up the machinery for our database and the migrations and all that other stuff. And we've made the observation that you can take a raw IP address and get MongoDB running on it in about 90 seconds or two minutes. And I'm pretty sure the first Oracle install dialog won't come up in just 90 seconds. And so you as a team may decide, hey, we don't need Oracle. That's like going rabbit hunting with a bazooka. Let's just use Mongo instead. And six months from now, you realize what a terrible mistake that was. We never should have used Mongo for this. We should use Postgres instead. And nobody else cares because you've made that change within your bound and context. Nobody has any idea of what happens inside your bound and context. And so this has no ripple effect to any other team. This means that governance is much easier in this world because we're freeing up individual teams to make decisions that are right size or the problem they're trying to solve. Now we're not suggesting you should allow this to become the Wild West where everybody picks any technology stack they want. But most organizations make choices to handle the hardest cases. They make choices for tools and infrastructure to handle the industrial strength, the 5% of the cases where we absolutely need to be able to query a million records in sub-second performance time. And they impose that complexity on every single project because you're all sharing the same monolithic architecture and it's overkill for 95% of the things that you're doing, but you have to take on that complexity for the 5% that actually need it. This frees you up to right size the technology choices for the problem you're actually trying to solve. And so a really common thing in this world is to standardize on integration or not platform and grace polyglot solutions where it makes sense to do so. So we don't really care what runs inside the microservices. That's part of the bound and context. We do care that they all integrate successfully one another. So this is the only real coupling point in a microservice architecture is how they integrate one another. So you typically pick something like REST level 2 and say everybody adheres to that. Again, we're not suggesting this becomes the Wild West where everybody picks whatever they want on a team by team basis. But if you look at most large companies and the spectrum of two few languages and platforms and versus too many, most companies fall well on the too few side versus the too many side. My colleague Sam Newman who's here doing a talk right now in another room about microservices has written a book for O'Reilly about this. And here's some of his advice, standardizing the gaps between services and be flexible of what happens inside the boxes. Have one, two, or maybe three ways of integrating but not 20 and pick some sensible conventions and stick with them. Another piece of advice and also common and continuous delivery world is to not make your operations understand all the different shapes of things that you may want to deploy. Rather build a common deployment mechanism so that everything looks the same way. This is Sam's advice as abstract underlying platform differences to perform a uniform deployment mechanism. This can take on several different flavors, probably the most common mechanism for this now are Docker containers because Docker is a really popular thing, a continuous delivery world. If your operations just knows how to put Docker containers into production, then you don't have to worry too much about differences between different platform pieces. But you don't have to go quite that elaborate. My colleague James Lewis has a talk about building a microservice kind of project in Java called Java the Unix way. And his uniform deployment mechanism was he built every one of his microservices as a standalone jar file that had a jetty embedded inside it. And if you call the main method on that jar file, it'll post itself up using jetty, listening on a particular port. And so we could have an entire directory of those jar files and just say, for every one of these jar files, tell them to run themselves. And it would bootstrap the architecture. That's a common deployment mechanism. So let's talk for a second about integration and disintegration and reducing risk of release in this world. So this is typically a continuous delivery, continuous deployment kind of world when you have services, particularly microservices, which sounds really scary. But one of the things that we've done in this world is separated out the things that can break the closure community as this great. So closure, of course, is a functional language in the JVM, which is a really nice thing in its own right. But the creator of closure is also kind of a word of file. He loves old words. And he has resurrected this archaic term, which is absolutely perfect for software called complex, C-O-M-P-L-E-C-T, complex, to complex two things together, to braid or weave them together. And what we've inadvertently done in most of our architectures is completed, deploy, and release, because when you deploy something, you also release it. But if you can separate those things, you can make each piece simpler. And that's exactly what we do here. Because typically in this ecosystem, we deploy components. But we haven't turned on the features yet because we frequently use things like feature toggles or feature flags. This allows us to deploy a component into the ecosystem and make sure it plays nice with everybody else, make sure it's monitoring correctly, and logging correctly, and all the infrastructure pieces are working the way they're supposed to. Now you can turn on features and then monitor to make sure everything's okay. This allows you to deploy a bunch of different services, maybe even some services that do the same thing with slight variations. Because typically in the microservices world, we still haven't impacted users yet because applications consist of routing between services. What this does, so one of the things that you talk about in continuous delivery world is that our blue-green releases, we have identical slices of infrastructure, a blue slice and a green slice. And the idea is you can switch back and forth between these things. In the microservices world, you basically have that at the service level. Because let's say you deploy a service, you release the feature by turning it on, you route to it and it starts misbehaving, you just route back away from it, fix it, route to it again, maybe just saw a small percentage of your users, make sure that's cool, and then gradually more and more people use it. And this is really the basis for evolutionary architecture, which I'll talk about in just a second. So what this suggests is that the more services you have as long as you have good engineering practice drives your risk of release down. Because if you're deploying a monolith, it's all risk. It's one big thing you have to deploy, but if you have a lot of very small services, you're actually deploying smaller and smaller pieces every time. We monitor services in this world, but we also monitor routes and you disintegrate services that no one's using anymore. So this is really the basis for evolutionary architecture. Let's say I have something like a Netflix ecosystem and I have star ratings and someone comes out with a, allows you to do half star ratings. You deploy that in the ecosystem and people start routing to it because they want half star ratings. Over time, everyone is now using half star ratings and they observe that no one is using star ratings anymore and that gets disintegrated out of the ecosystem. We've evolved into that new behavior one tiny bit at a time without disrupting the whole architecture to do that. As I suggested before, you really need a lot of engineering sophistication to be able to pull off something like a microservice architecture because you have to have these engineering practices in place. So for an evolutionary standpoint, when you talk about decomposing monoliths into smaller and smaller pieces, you can partition along natural boundaries. So I talked about structural decomposition using things like afferent and efferent coupling, transactions, another way of looking at this, preserve existing transactional boundaries. Maybe you want to go the full blown inverse Conway maneuver and do by organization or by domain and so let's put things into domain driven design and do domain stuff or maybe you have geological constraints or geographical constraints where you have to be physical locations and you split your architecture along those boundaries. So to conclude all this stuff, what we're really trying to build here is architecture for change and get away from yesterday's best practices tomorrow's anti-pattern, build teams that look like the architecture you want, it becomes easier to build that kind of architecture. I talked about efferent coupling as a code metric before, but you also can have this as a team metric and so you want to strive for a low efferent coupling for your team. Your team shouldn't know everything that's happening in the entire ecosystem. In fact, this is the whole thing kind of wrapped up on one big slide. We have teams with low efferent coupling delivering relatively independently and their common integration pipeline without fearing breaking each other's bills because we have things like consumer under and contracts in place, small cross functional teams sharing information as they need to, sharing a common integration platform that has a deployment pipeline there, verifying that as they push things in that deployment pipeline it hasn't broken things, they're already running in other places and automating a lot of these pains and issues away. That's it. Looks like I'm right up exactly against time so I won't take any questions right now. I'll be around all day if you have any questions you can chase me down but looks like we've hit the break. Thanks very much for coming and hope you enjoy it. Great, thank you. Thanks.
concepts around the intersection of continuous production readiness of your application every the configuration for the application servers. as the architect to construct what this stages, it's important to understand why you best practice is tomorrow's anti-pattern. We the first one where one of the capabilities built into the architecture is to support easy the coupling between pieces in a code base. This this that exist for other platforms. In fact, architectures. The Continuous Delivery Book and give you a bunch of metrics but it's written architectural style and whether this is a every time they make a change to their code base. So it takes a certain level of engineering the network is secure and the topology doesn't application, how they send information back and services or microservices or the transactional architecture to do that. As I suggested before, to have these engineering practices in place. So