 Good afternoon, everyone. So I tend to walk a lot on stage. So if I'm not allowing you guys to see anything that you're interested in, just tell me, and I'll move out of the way. OK. So my name is Sebastian. I'm Sebas Oga in Twitter, GitHub, and everywhere, probably. I work for a company called Ride. And I came from Colombia, which is that small country that's like darker there on the world. So Colombia has, like a city country, has a lot of particularities in our culture. And some of them are related to our geographical location. So Colombia is in South America, on top of South America. You know, in South America, we have the Andes that go from the South to the North. They basically, Andes basically ends where Colombia starts. And then it divides into three, like chains of mountains. So we have a lot of valleys between those chains of mountains, and really high mountains, too. We only have snow on some of them, although we don't have winter. We don't have even seasons in Colombia. So one of these weird cultural things I mentioned in Colombia we have in Colombia comes as related to this geography. I mean, not geography, but the way Colombia is influenced by these mountains we have. So at least two of the biggest cities in Colombia are world built on top of some of those mountains. And that meant that a couple centuries ago, when those regions of the country were being colonized, the only means that people had to transport really heavy stuff, such as construction material and food or even other people were basically donkeys. So that is like a big part of our culture. And it has evolved to some things that are, I mean, it has evolved in a funnier way. And I'll just go ahead and tell you why. We have something called avuroteca. And avuroteca is something like this. So it's like a donkey plus a discotheque. So you can imagine like a donkey on a rave or something like that playing music. So all of this was kind of born because of donkeys transporting stuff to remote places where there were no roads, no cars, of course, no trains, boats, or any other means of transportation. And someone thought that it was a good idea to also put speakers in a monkey and take the party everywhere. So later on when we had roads and someone decided to import like chassis, car chassis, and engine, they kind of put something together. And that ended up being called a chiva. And a chiva, like nowadays, looks like this. I mean, they still exist. We don't use them as well as avurotecas. That's something that we don't use anymore. Like it's not something we do on a normal basis. So chivas were basically like the first means of transportation. I mean, the first cars basically that we had in Colombia that went to remote places, the ones I was talking to you about in the mountains, which are really hard to reach. And on those chivas, there were a lot of people in there. I mean, people transported their food. And you could even see chickens there alive. And it was like the way that people got stuff to the remote places where they lived. So with a chiva happened something similar to what happened to the burro, to the donkey. Someone invented the chivateca. So you can imagine what that is. That's a chiva with a discotech. So the chiva was no longer used to transport people and food. It was just used to party. I've actually been on those twice, and I don't like them. It's there's like too much going on. It's a car moving, and there's also people dancing, and you're also trying to drink. If you don't spill it before you drink it. So it's kind of odd, and it actually feels kind of dangerous. So I'm talking about this because a lot of times, it happens to our applications, to the systems we work on. They start with an intention, and they start with a really defined clear objective. And then at the same passes, things degrade. And sometimes when you're working on them, when you're working on an application, you feel like it's dangerous to make any change, even in small changes. So today, we're going to talk about a system architecture pattern, if we can call it like that, that's based on services. And I personally prefer services. I think that they taste better in small disposable cups. We're going to talk a little bit more about what that means. So let's start talking about a monolith application or what a monolithic application is. Because I think the word monolith or monolithic has been given a bad meaning, a meaning that's not up to what the word really means. Because a monolith doesn't have to be a bad thing. A monolith is different from a big couple monster application. And I think a lot of people, including myself, I don't know. Maybe I'm just the only one, and you guys don't. But I ended up thinking about the monolith applications being a bad thing just by definition. And that's not the case. The problem is that a lot of monolithic applications have bad object-oriented design. And that does means that an application is going to be a big coupled monstrosity. So I wanted to touch base about this before going forward. Because talking about services and microservices, it's like trained. It's what everyone knows about. A lot of people are trying to do. It's supposed to be the solution to the monolith application problem. And it's not or not necessarily. And it won't solve your application design problems. So on a talk that was recently gave, I'm sorry I forgot what conference was that, a guy called Simon Brown said, if you can build a structure monolith, what makes you think microservices is the answer? And he's totally right. Thinking about services versus monolith applications, it's not like the holy grail. It's not something that's going to fix all of your problems. It's just another approach to solving a problem. So the first problem, when we talk about microservices or service-oriented solutions and monolith applications, the first problem we have to solve is something I like to call the boundary problem. And that basically means that if we have a monolith and because of any reason, we can discuss the version later, you decide that you want to refactor your application or change it or redesign it towards a microservice architecture, you won't be able to do it unless you have successfully fixed the boundary problem. And what's that? That's basically defining clear boundaries in your system and defining components in your system. And that can be done in a Rails application, in a Sinatra application, or in an application in any other language using any framework. So in order to fix this problem or to do this to architecture our applications the right way, there are a couple, I mean, there are three principles I'm only going to mention the two that I think are useful for this case that are called package cohesion principles. So the first one is called the common closure principle and this basically says that all classes that change together should be part of the same package. So basically if we go back to object oriented, I mean, to principles of the object level, object design level, such as solid, we have the serial responsibility principle which says that a class should have one and only one reason to change. So this principle goes like a level higher to the package level and says that all classes that change because of the same reasons should be put together or should be part of the same package. And this is really important because if you want to have services or move towards a microservice architecture, you should really give this a lot of thought. You really want to put the correct classes together because if not, you're going to still have the boundary problem even though you don't have a monolithic application anymore. And the second principle is called the common reuse principle and this basically means that you should also put together in the same package the classes that get reused together. So this goes like a level of granularity down, I mean, goes a level of granularity deeper. And this means that even if a group of classes changes because of the same reason, they should only be put together if they are reused together. If not, there's no need to put them together because then people working in your system will tend to try to avoid reusing a big service that does more than you really need to. So my point with presenting this principle to you is to explain that in order to move from a monolith to a microservice architecture, sorry, the first thing you have to solve is the boundary problem. And basically, to create a new service, you just take a package or a model that's already existing that follows the two principles that we set. And this allows you to easily start creating, to start migrating from the monolith to a microservice-oriented architecture. So sometimes this is not that easy. And a lot of the times you are not migrating from a monolith to a microservice architecture. Sometimes you want to start from scratch with this type of architecture. So this type of principles might be useful, but might not be the best guide when you're starting because you still don't know the reasons that a class will change or will need to change. So there are some other ideas or principles that you can use in order to know what things to put together and how to create those boundaries between your services. So another one is just to think about logical divisions of the problem domain that you're working on. So on a talk, he gave, even Phoenix mentioned that if someone asks you to divide a problem in modules or packages, and you start writing on a whiteboard, probably the first approach you have to doing that is the more natural, is the more obvious approach, way to do it. And it's the way that you should try to start. Because this means that it's intuitive the way you're trying to separate things. And it might, I mean, it's not a golden rule. It doesn't guarantee that it's going to work, but it's probably a really good starting point. And it's important to know that perfect is the enemy of good. And although this last principle I just mentioned doesn't guarantee that everything is going to work, it shouldn't constrain you from starting, and you shouldn't be afraid of iterating. You shouldn't be afraid of not getting it right the first time. Because it's hard to do it. It's hard to adopt this type of architecture when starting from scratch on a project. So there are some things that work like adopting this architecture for projects that are greenfield or for projects that were monolithic applications before, I've seen that should try to avoid. And the first one is to never share active record models between services. You should never do that. It will lead to a lot of headaches. Even if you try to be really disciplined about maintaining the state of the model in equaling all of the services, there's going to be a point where all services are going to have so much in specific different needs that's going to be impossible to maintain. And you're going to end up having a lot of problems because of it. So the best thing to do with models is to only have each model in one service and that's it. If you're migrating from a monolith to a microservice architecture, if you're starting from scratch, always have each model in only one of your services. Another important thing that I've seen while working with microservice architecture is that sometimes people try to share stuff such as this active record models or other code that's common to more than one service via libraries. And this is normally a bad idea because it goes against one of the good things that microservice, that this type of architecture brings to you and is that if there's a change on a specific module or package or there's a change in a specific business rule, you should only be worried about deploying one specific package or module. If you share code through libraries, that means that you'll have to basically redeploy all the services that use that library. So you will be losing a lot of independence. And another thing you definitely need to avoid is something that's called the common waste law. And basically the common waste law says that if you're working in an organization that's generating a system, the system you're generating will try to emulate or imitate the same structure that the organization has. And this is why we have systems where we have, for example, like three layers of, I mean, yeah, three different layers, for example, the database, the part like a middleware and the front end. And that might be because organization has a team of DVAs, a team of backend developers and a team of front end developers. So a lot of the times the way we end up structuring our microservices or service-oriented systems are guided or decided because of our organization structure and not because it's actually the best way to organize our code. So the key here is that, I mean, like the key property is that of a component is the notion of independence, replacement and upgradability. So basically this means that the best way to know if a component has, is well-defined and has the correct boundaries that it should have is to think about what would happen if I could, if I needed to completely replace this component for another one, completely rewrite it. Will something, I mean, will the system break? Will it be easy to deploy? Will it be easy to deploy it again? Will it be easy to deploy the new implementation? Will it be easy to upgrade this service? Will it be easy to deploy bug fixes, new features? So as I was mentioning before, services, like service-oriented systems or architectures, not only talk about microservices, which are the ones I've mentioned the most, I think, like this type of principles apply to services of any size. There can be a couple of really big services, a bunch of microservices, a lot of services that are medium-sized, I don't know if that even exists. But the point is, what I want to show with this is that it doesn't matter what size the service you're deploying is, it is important to have these boundary problems solved or fixed, because if not, like adopting this architecture will really help. And also because there's a lot of discussion about what's actually considered a microservice and what's not, a lot of people just talk about like abstract concepts, some other people go on to more concrete things, like counting lines of code, and that's not really the most important point here. You can call them whatever you want. The important thing is that if you're building your system with this type of architecture, you should really have a clear way to know where to place the boundaries in it. So that's why, talking about this, that's why I'm gonna talk, sorry, about why I think services taste better in small disposable cups, or why you should try to design your services in such a way that you could call them microservices. So here's like, I don't know, like the best definition I think we could, we can find on the internet right now about the term microservices. And as Martin Follers wrote, he has sprung over the last few years to describe a particular way of designing software applications as sweet, often-deplendent, deployable services. So basically, this has a bunch of benefits after a bunch of benefits, basically, other than just helping you define in a better way the boundaries on your systems, of your systems. And one of them is that you can use multiple languages. So each service, sorry, you might be reading a different language. Also that all code bases are isolate, one from the other. And having services kind of, having those boundaries, kind of put boundaries on by design. So if a service is by design, well, that's a shame, but the good thing is that it's contained. I mean, like the bad design won't affect all the system or won't rot all the system, it will just affect that specific service of your system. And another good thing is that services will end up being easy to replace. So this means that, all of this means that even if you try really hard, it's really difficult to find a way to couple all of the different systems are part of the big application. So basically, if you think about it, when you have a bunch of microservices, they act as UNIX programs because like they basically receive some input, process it and pass it as you can do on UNIX with pipes to the next program or next service. And basically that's how it works. That's the good thing about having, I mean, if you think about it, that's why UNIX model or idea of having really small programs that do really specific things is good. And if you can take it to a bigger scale, you'll gain a lot of those benefits. So this sounds really good. This has a lot of benefits and that's all we've seen so far, but it's not all unicorns and rainbows and it has some pitfalls. So one of the pitfalls, although this doesn't sound bad, one of the pitfalls is that in order for this to really work good, you have to automate the deployment. But not just the deployment of one specific service, sorry, application as you could do with a monolithic app, this means that you have to orchestrate, sorry, the deployment of a bunch of services and you have to find the best way to do it and you have to automate it even if they are reading different languages. And this means that you have a lot of work to do. Also you can have a lot of degradation issues and inter-service communication problems and these are hard to track when you have a lot of services running at the same time. When you have only one application, it's really easy and you can notice it really quickly, really fast, but when you have a bunch of services, it's hard. So you have to implement, you have to be really good at monitoring every one of the services, monitoring the communication between them and responding fast when something fails. Another problem is that since you have a lot of small applications or services, each one of them has a log. So when something goes wrong and you don't know exactly where it's going wrong, you could spend countless hours going into each one of the logs of these services trying to find where the problem is. So you also have to work to have a unified log for all of the applications or all of the microservices in one place so that you can find all the logs even when a service is gone, even if you deprecated it. So another pitfall is when you have to trace or troubleshoot a bug or an issue that your system is having and the issue is happening across a bunch of microservices. So this can get to be really hard. If you don't have a way to identify when I request pass through each one of the microservices. So this is way to do this. It's just like probably to add a unique identifier to each one of the requests or yeah, the request your system process so that you can trace it down each one of the microservices you have. So when do you know if the application you have, the system you're working on is a candidate to using this type of architecture? So even Phoenix came up with this concept which he called the human cognitive mass and it basically talks about how much each one of us can understand how a system works and how can that, I mean, how much information we can retain and still understand everything that's going on. So he came up with a few rules. So the first one says that no single app can be larger than the human cognitive mass and every app that crosses that limit should be broken up or just should get its size reduced. And if you think about it, this is, although like it's a really relative concept, it makes a lot of sense because once a system or an application is too big for any developer that takes a look at it or works on it to understand it, it's important that they have a chance to, sorry, it's moment to split that application into smaller ones that are easier to understand and to maintain. He also said that every sufficiently complex domain will require an app larger than the human cognitive mass. So basically this means that for a lot of the problems we're solving, we're gonna need to build probably more than one application. Any problem that's considered, I mean, that's considerably big will probably benefit from adopting this type of architecture. And also other than this, you have to take into consideration that adopting this type of architecture is gonna have a lot of operational cost. So you have to keep in mind that your team or the team that's working on the system has to be prepared for it. So you have to be good at rapid provisioning a servers to deploy new services or redeploy new versions of systems. Also you have to be good at monitoring all of your services and at being able to rapidly deploy a service if something fails or if you need to just roll out a new feature. So to recap, what we were talking about, microservices architecture won't fix your object-oriented design problems. It will, at a level, it will force like your components to be the couple but that's just because they are different code bases, not because they're gonna fix your design problems. And if you adopt this architecture it will allow you to deploy components individually which at the same time it will allow you to replace them really easily. If something goes wrong, when you deploy a new feature and you need to roll back, it's really easy to do it. Also, if for some reason, I know you have a memory issue on the server, you can just redeploy your, the same service story and just kill the old one. And it will also allow you to use different programming languages which can be really useful because depending on what type of problem you're trying to solve, there might be some programming languages that are more fit or a better tool to fix one problem than the other. So it's important to know that like microservices architecture is no free launch. It comes with a big operational cost and you should adopt it when the benefits of adopting it overweigh the costs of adopting it. Thank you very much. Thank you.