 So hello. My name is Sebastian. I live in Bogota. That's the capital of Columbia in South America. You can find me at Sevastoga in Twitter and GitHub. I work for a startup called Ride. We are reinventing the way people commute to work, so you should definitely check us out. Today we're going to talk about microservices. So I want to give a lecture about microservices. There's a bunch of them out there. They're really good. You should check them out if you haven't. Today I want to talk about why I think sometimes microservices are a bad idea, and not sometimes, like a lot of the times. So let's start by defining what microservices are. So microservices are like a particular way of designing software, basically. By designing software, we are creating, like, a lot of small applications that can be independently deployed. So a lot of people have discussed, like, is a microservice is just a service-oriented architecture, and it kind of is. Microservices are just like a subset of service-oriented architecture. It's just like with a set of, it's just a piece of it with a set of really well-defined rules. And you could say that microservices are a service-oriented architecture. What, like, scrum is too agile, basically. And microservices are not just, like, a new thing that hipster developers like to talk about. There's probably people that have been doing microservices for 10 years. It's just like a name that was given to the subset of rules in the service-oriented architecture, like cloud or definition. So there has been a lot of controversy to how big a microservice should be. So the problem with that is that microservices have a failure by design. And that failure, it's in its name. It includes the size of the service in its name. And it's kind of confusing because, like, micro says that they should be really small. And the size here is not the most important thing. It's just part of what microservices are. But they could have probably been given a better name. So a lot of people like to say that microservices, I mean, that a service can be considered a microservice depending on how much line of code it has. That's, I don't know, that can be confusing. It changes a lot depending on the language you're using probably. Some people say that you can consider a service a microservice based on the size of the team that's building that microservice. For example, in Amazon they have, like, the two-pizza rule. And that makes sense, but I don't really like those approaches. There's another type of approach, which are, like, really arbitrary defined rules. For example, Chad Fowler likes to say that microservices have to be this big. And this big being, like, basically, like, how big your hand is on your screen. So if it's bigger, if the code you wrote is bigger than that, it's not a microservice. That's kind of arbitrary. I don't know. I don't really like that definition. So to present the definition, I think that we should all, like, have in mind when talking about microservices, also talk a little bit about cognitive psychology. So there's a concept in cognitive psychology called cognitive load, which refers to the amount of information a person is trying to process at any given time. And there's another concept I want to introduce that's called cognitive limit, which refers to the maximum number of chunks of information a person can process in working memory at any given time. So these are really related. So basically, I think that you can say that a service is a microservice if the cognitive load that microservice represents is lower than the cognitive limit. So let's talk a little bit more about the cognitive limit. So basically, the cognitive limit refers to how much information you can hold in your head at a given point in time. So if you're able to completely wrap your mind around a service, totally understand what it's doing without the need to look into code or documentation, you could call that service a microservice. But you have to keep something in mind. And it's that when talking about a group of people, cognitive limit tends to decrease as the team grows. So basically, the bigger the team, the lower the cognitive limit is. This is a totally made-up graph, so don't look for numbers or X and Y limits. But it's basically, I think, really explains what I'm trying to say. So before we go into more details about microservice-related stuff, I want to tell you a personal story. So that personal story will give us a little bit of context. So the story is about the first job I had. And that job was at Babel Stadium. My job consisted on selling hot dogs on game days, and it turned out I was good at it. So my manager asked me to also sell phone fingers. So it went okay. But when my manager asked me to make some public announcements, I mean between innings, it sounded a little crazy. But okay, I now had to also do that somehow. Weirdly enough, I was able to do all of that. So my manager asked me to moan the law before each game. So I was basically doing that also too before each game. Surprisingly, my manager lost an employee. So he asked me to help him accommodate people on their seats after moaning the law and what people was like getting into the stadium for the game. By the way, I'm sorry I couldn't find like a better image of a ticket in the Internet and I had to use one that's like for one direction. So because things weren't bad enough already, one direction showed up for the game and I had to accommodate them. That was definitely my last day of the job. I had to quit. Okay, that's the story. I don't know, but probably by this point you already realize that this is not a true story. I'm just trying to make a point here. So in that order of thoughts, I want to ask questions to everyone. Please raise your hand. If you have a system that's probably going over your team cognitive load and you want to break it up, break it down into other systems. Okay, cool. Thanks. So this is not uncommon and this happens a lot. We're going into this situation when we have a monolithic application. So the HH talked about this earlier today. And I kind of disagree with his concept of what a monolithic application is. So let's look at it a little bit. Let's look at it basically. So I think that like a single-rails application, like having a system basically that's a single-rails application doesn't make that system or doesn't make that application a monolithic application. So what makes a single-rails application a monolithic application is basically poor object-oriented design. So let's like separate those concepts. Given the fact that your system is only composed but one Rails app doesn't make that Rails app a monolithic. A single-rails app can be like well-designed and well-built. And there's actually like a talk that was given recently, I think on moving your nails, but Akira Matsuda, where he gave a really, I mean, which was really interesting and he talked about how Cookpad, which I think is a Japanese company, what's probably the world-largest Rails application. He gives, on the talk, he gives like really good insight of how he achieved it and like the amount of traffic they can handle with one Rails application that's like running on, I don't, I might be lying, but I think it's like 300 servers. So if you have an application, so although like I think they probably like do too much to keep their system being like a single-rails application and I don't know if I will go to that extent, you could do it. And if that's the way you like to roll, that's fine. And that doesn't mean that your application is a monolith. So you can call the integrated systems you want. That's fine. You can give it the name you want to them. But let's be honest, a monolith doesn't look like this. What's that? A monolith really looks like this. That makes more sense. That's how a monolith looks. That's how you feel when you're working with a monolithic application. When you're working with a monolithic application, you probably, you normally like can't reuse a part of your system without basically like reusing the whole system. Or you can like easily change the flow without having to do shotgun surgery, which is really bad. So now like, that we know like the difference between what's really a monolithic application and what's not, when should you go for microservices? I don't know. Let's think a little bit about it. It's an interesting topic. So should you go for a monolith? I mean, should you go for microservices when you realize that you have like a monolith? That your single rails app is no longer a well-defined app, but it's like monolith? Well, I would say no. This is a fallacy that a lot of people believe in. When you have, I mean, everyone knows that when you have a banana and you smash it, you just get a bunch of little bananas. That's all you get. So the fact that you have a monolithic application doesn't mean that you have to go for microservices. I found this on Twitter, which is something I really like, and basically says that if you can't correctly design a single application, you won't be able to like design a microservice, or assist in that space based on a microservice architecture. And I totally agree with that. You first need to be able to nail a single rails application before thinking about even going for microservices. So when should you really like use microservices? I mean, it's clear why not to, but so when should you do it? So one good reason to go into that direction is when you have a part of your system that needs to be escalated differently from the rest of the system. So this has happened to us on RIDE where we started with a kind of like a brain application that was coordinating a lot of things, and we realized that some parts of that system needed to have a better performance. So we had to deal with the decision of do we want to scale the whole like brain application, which is wonderful for microservices? Or can we like just extract this and escalate it differently because that's a specific need for this? So this is a really good reason to go towards microservices. Another one, it's when a part of your system needs to be easily replaceable. So what happens when you have monoliths and what has happened, like in a lot of really big companies that have been producing software for a lot of years is that some systems are like 20 years old or 10 years old, are built on languages that probably no one in the team at a given time knows how to write code in, and it's running on a server that hasn't been touched for a lot of years, and no one wants to change because they're really scared about breaking stuff. So when you have stuff, I mean, when you have like your business logic basically spread in different small microservices, this is really difficult for this to happen because if you have a microservice that it's failing, it's not scaling as it should, it has a bug or whatever, and it's not technology on a server that no one in the team understands, you can easily replace it. Just building in whatever language you want, in whatever you think is best, and replace it. And you don't have to replace it right away. You can do it gradually and testing and every step that the new service will really be able to replace the old one. And this is really cool. This is great because you don't need to do a big rewrite. You don't have to throw the 20-year-old service to the garbage and start from scratch and probably create all the bugs that were already fixed on a huge application. Okay, so let's talk about another reason, like when you should think about going for microservices. And this is when you want to be able to deploy some parts of your system more often than others. And this is really common. Like when we have a big Rails app, you notice that there's some tools that actually allow you to check this. And you notice that there are some parts that have a greater churn. That you're changing all the time, probably because business logic is changing a lot, probably because it's harder to understand. So there are a lot of bugs on the specific part. It can be also because, I don't know, there's a lot of reasons. But sometimes you have to change parts of your system more often than others. And when you have a big single app, this means that you have to deploy your app every time you change a small part of your system. And this costs a lot. And also, the bigger the app, the more you're afraid to deploy it to production. So you tend to accumulate more changes for each deploy. And then when you accumulate a lot of changes for each deploy, there's a lot of more possibilities of a deployment to go bad than when you just deploy constantly smaller changes. So when this happens to you, it's also a good idea to think about microservices. Okay. So another reason why you should look at microservices is when you don't want to use the same technology stack for every part of your system, you have to be aware that this can be taken to an extreme. So there's a blog post out there by some cloud, I think, where they explain that when they moved to a microservice architecture, they allowed anyone to write a new microservice and any language they wanted to. And this ended up being a huge problem for them because there were microservices on basically any living language out there, any language that was still under development. Everyone wanted to learn a new language, so they basically created a new microservice on that language, which can be really cool, but can be also really hard to handle. So, for example, at Ride, what we do is when we need to create a new service, whoever is going to work on it or whoever is going to be responsible for it, basically creates like a proposal and says, okay, I'm going to create new microservices. This is like a contract, it's responsibilities, and I want to use this stack stack to build it. And then we open it for proposals, sorry for comments. So we do an RFC, a request for comments. Basically, everyone in the engineering team has a period of time when they can give feedback on that proposal. And that feedback is on design, too. It has to do with the business value that each microservice adds to the whole problem we're solving, but it's also around the technology stack we're going to use because the whole team is going to be responsible for maintaining that new microservice that's going to be created. So we probably want it to be bringing something that makes sense for the problem we're fixing, but also something that we want to maintain, something that we think makes sense and that it's not like a new crazy language, something someone just wants to learn and experiment with. So that's called technology heterogeneity. I know that word's confusing to me. So last but not least, the most important thing is that the team that's working on building your system has to be ready to support this type of architecture. And it's key. I mean, this is really important and it's what a lot of people moving towards microservices miss. The skill set of your team has to be ready to support what moving to microservices means, which we'll talk about a little bit further during this talk. And also, the team has to be big enough to be able to work on different services on a distributed, basically on a distributed system. And sometimes people overload a really small team with this type of architecture and that's when they start to see a lot of problems with it. So you have to be really aware of this. So how do you know if your team is ready to go towards some microservice architecture? There's basically three things that are key. The first thing is that you have to be able to easily provision new servers whenever you need to. The second one is that you need to be able to set up basic monitoring for every new microservice you create and the existing ones. And also, you need to be able to respond to failures that are monitoring the use set up decks. And last, as you mentioned, is that you need to be able to rapidly deploy new applications. So if you have a new microservice that you need to get into production, the team should be able to get it into production in a few minutes, not a few hours, not a few days, not a few weeks. So that's really important. If your team is not there yet, you're probably better off not going towards microservice architecture. So now that we, let's say that your team is ready to handle all of this, which is great. You could say, okay, I'm ready. Let's go for microservices. I really love the idea of it. I think we give it a really long time and discuss about it. So let's do it. But you have to consider the downsides of it. And they're not trivial. So let's get to, let's see what like the most common downsides of microservices are. So first of it is that DevOps intensive. So as I mentioned before, teams need to be good DevOps, need to be ready to support a lot of services running all the time. And this can kind of be mitigated by using a platform service, which will probably do a lot of the work for you. And that's good. If that's the way you say to go, I think that's fine. Another downside of, I mean, more than the downside, that's like something you need to be aware of. But let's talk about this. So you will have log files for every service that's running. And this can make really, I mean this can make debugging really complicated and hard. So you need to have a centralized logs for your whole system so that you can like watch what's going on there. And also something that's really important is that you probably want to have unique identifiers for every request that's going throughout your system so that if something goes wrong, you can easily trace it and figure out when word thinks are going wrong and how to fix them. This is really important, believe me. So another downside of microservices is that you have to be prepared for failure. So I know, I mean this is not, this is something that you shouldn't only worry about when you have microservices. Like you should also be prepared for failure when you have like a single app, if it's Rails or not, it doesn't matter. But the thing is that when you have microservices, this is harder to manage. You need to have a lot of more stuff into consideration to be prepared for failure. So let's look at what are the most common failures when you are dealing with a microservice architecture. So the first one is network practices. So this is something that will inevitably, you, I mean, sorry, this is something that you will inevitably have to deal with when working with distributed systems even if they're not microservices. So this is really important because there's no such thing as a network that doesn't fail or services that never goes down. We all know that sometimes, like, sometimes these things fail. So we need to be prepared for it. So for example, let's say we have a system that looks like this. And let's say that communication between node or service A and B goes down. And then we get a request on node A. So node A has to decide between basically two options. Node A can respond to the client telling them, like, hey, there's, like, something wrong going on. I can't really process your request right now. Or node A can also say, okay, I'm going to deal with this. I'm going to respond to you something. And then I will internally deal with the consequences that having null communication to node T will bring to the system. So this is something that's not trivial and something that you need to plan ahead of. Okay. So the thing is that this is not the only problem. You can also have services that are sometimes unavailable. So even if you have the perfect network that never goes down, services will eventually be unavailable. So there's a formula for this. It says that basically, like, the probability of a failure occurring on your system is equal to one minus the probability of a node or service not failing forward to how many of those are. This is, like, wow. I don't know. It's complicated. When I first saw this, it was really, like, hard to get my head around. So let's just see an example. Let's say you have a bunch of microservices, all of them have an uptime of 99.9%, which is great. But you have 40 microservices. This means that your system, applying this formula we just saw, yeah, this one. The system will have an availability of 96.1%, which in other words means that you will have around 4%. I mean, like, most of the time you have a probability of a 4% of something going wrong in your system. And this is only considering, like, that if a node fails or a service fails, only that service will fail. But depending on how you design your system, if a node fails, a lot of other related fails can fail, too. So this can get really bad. You need to be prepared to handle this type of failures. So let's look at another one. That inconsistencies. So when the network is partitioned or a service is unavailable, they will most probably, this will most probably cause data to be inconsistent. And this requires planning. You need to know how you're going to deal with this so that data is eventually consistent. Or if you don't care about consistency, like maybe even, like, how to deal with this, how to deal with data not being consistent in your system. And this is not trivial because it can really, it can really make your system, like, not work as it should. Okay? And, like, these two problems we just talked about are basically part of something that's called the CAP theorem or CAP theorem, which talks about, like, dealing with this type of failures in distributed systems and really explains, like, not only how they can affect your system but also probably how you can deal with them depending on your business requirements. That's the most important thing. So basically, CAP stands for consistency, availability, and partition tolerance. And when you have distributed systems such as a microservice architecture, you have to deal with partition tolerance because your system is partitioned. It's not something you can choose off. But you have to balance how to be available and also, like, have consistency with data at the same time. So this is really important if you're thinking about microservices. If you haven't heard about the CAP theorem before, you should really read about. I really recommend it to you. It's really interesting. But this is a topic big enough to do another talk about it. So let's talk a little bit about, like, what to do, like, when you want to build microservices. Let's say your team is ready. You can deal with all the downsides of it. You're ready for it. So how to start? So first of all, when you're trying to break a big application into small services, use the bounded context pattern, which basically deals with large models by giving them the ability to have specific behavior based on their context or the context they're on. So like in this image, you see that we have the customer model and the product model in two different contexts. One of them is, like, the sales context and the support context. Depending on the context, each of these models is, they will probably have a different behavior and you'll probably want to have access to different data that's related to it. Check it out. It's really useful. So also, something you really need to do that I found is really useful, it's having a specification for each microservice and being able to run that specification as an executable test. So one of the, like, it could be a pain in the ass basically to do testing with microservices. So one way you can handle this and make it easier to work with is by having specs that you can run as an executable contract. So that when you test each microservice, you can test it again, that executable contract and make sure that when everything's running together, when everything's deployed, it will work fine together. And you won't, like, only realize you have bugs until you go to production, which is really bad. And this doesn't mind if you're using, like, HTTP RESTful API or if you're using, like, for communicating, you're using a message broker or RPC. This is something you really need to do that will save you a lot of headaches. So you should also be aware that you should go for a synchronous communication over synchronous communication whenever you can. This will make you make it easier to deal with any type of failure, the type of failures we just saw the cap theory and talk about. And another thing that I found really useful and that we've learned in Bride is that you should use schema-based formats over schema-less ones. So there's, so, like, to give you a little bit of context, for example, like, a schema-less format is JSON. And a schema-based format can be protocol buffers or Captain Proto or, I don't know, there's probably a bunch of them outside, out there. So the good thing about this is that schema-based formats allows you to extend data that you pass between systems as you need to as your system grows and changes. And it's also, I mean, it also has some validations and will also allow you to be backward compatible as you grow. And this is something that's really important and we'll talk about something called the golden rule of microservices in a few minutes. So what should you do? Just start. Create a new microservice when you need it. Be aware that the perfect is the enemy of the good. So you don't need to have the perfect design before going to microservices. Just start and you'll be afraid to reiterate on your solution. So what shouldn't you do now that we know how to do it? So it's really important that you don't share databases between microservices. Sharing databases is like calling another object private methods. That's really bad. Something you don't want to do is solely ranking encapsulation. So don't do this. There's a lot of ways around this. And if you're doing it, it's probably because you don't want to think hard enough how to fix the problem. And if you see yourself in a situation when you temporarily, hopefully, have to deal with this, just make one microservice in charge of writing to the database and the rest of them just reading from it. But still, you'll have a lot of coupling because if the schema changes, all of these microservices that start reading from it will have to change too. When you share a database, you'll feel like this. You'll feel like you're moving on dangerous grounds. So something we saw before today is to avoid being biased by Conway's law. And this is basically... This law was coined by something that Marvin Conway coined at a point, say, in 1968. He said that organizations produce systems whose design is a copy of the structure of the organization. So you should be really aware of this and not try to just replicate the way your organization works into how your system works, because that's probably going to... that's probably going to have you creating microservices you shouldn't or designing them the way you shouldn't. Most importantly, don't break... I've mentioned it before, don't break the golden rule of microservices. And this basically says that you need to be able to deploy any service anytime without changing any other service. And this is not trivial to achieve. Because if you fail to achieve this, you're losing most of microservices' benefits. If you find yourself in a position where you are doing lockstep deployment, when you have to deploy more than one service at a time so that the system doesn't break, it doesn't really make sense to have microservices. It doesn't really make sense to have things that you should be able to deploy independently, change as much as you want without the rest of the system knowing. So be aware of that. If you find yourself in this situation, you have to fix it real quick or maybe think about going back to a single big application. So to rub everything I've been saying up, I would like to bring two quotes by Michael Feathers. And the first one says that he strongly believes that there's a lot of complexity conservation software, which means that, for example, in microservices, we need to be aware that when we go towards that direction, we're pushing complexity into the interaction of our services. And we need to be prepared to deal with that. So my recommendation is go for microservices if they allow you to better manage the complexity of the system that you are building. That's all I've got for today. Thanks a lot.