 One of the most complex it's a pretty simple thing actually. So we heard from Francesco He talked about OTP a little bit on OTP behaviors OTP applications is another behavior that comes bundled with the beam so they're relying VM and The idea of an OTP application is that you have these different Processes running and there's a supervision tree And that's all packaged in a bundle that you can then send to other Other beams and that it will just run to deploy that that's just a convention of how to bundle applications umbrella apps are Nothing more really than Another convention of how to have multiple applications inside of a bigger bundle. That's your umbrella That's gonna wrap them all together Now, what's the the advantage you might ask of having an umbrella app versus just having many apps? It's really just about the convention. I think so there that your tooling is gonna be aware of this. So for instance mix Peter was talking about mix the the tool very important tool if you're doing elixir if you run tests You can run the test for all the applications together When so that's a big thing for dependencies as well If you run mix depths get on the top app, it will get the dependencies for all the applications That's cool. That's cool. If you're using Phoenix, which is the one of the main web frameworks for elixir It's also aware of what a Braille apps are and if you create a new Phoenix app inside of the umbrella The generators will behave a little bit differently Distillery which is a deployment Library also is aware of umbrella apps and even allows you to deploy as a single app or you can specify How you want each different app to behave when you're deploying? So it's just really a convention and a nice convention to have these different apps that are all If you want to call them services, they're all part of this bigger bundle The ways you start or you create a new umbrella app is really just using mix new same thing as your when you're creating a Regular elixir app, but you have the dash dash umbrella at the end. That's an option So this will create these files particularly interesting is this apps directory instead of a lib directory And these apps directory is gonna be empty at first. So there's really no Application code because this is just a bag for you to put your applications And then it's as easy as really see CDing into these apps directory and doing mix new and creating apps inside of there And that's it as simple as that So that's about it about umbrella apps that I wanted to talk talk to you about the technicals of it It's really this simple the part that really excites me and really got me into Umbrella apps and how they could be used is more about how to build a maintainable application or what I think Could be a ways to to build them a more maintainable application And then so I want to talk about a little bit about this and then how to apply this to two umbrella apps So right now there's a lot of frameworks out there and I'm not gonna focus specifically on web But that's mostly what I do. So If something doesn't make sense, maybe I'm just talking about web frameworks But there's a lot of frameworks that make it easy to build an app But not necessarily a maintainable one. So very famously rails a few years back had the 15 minute blog And yeah, that's cool. I can make a blog in 15 minutes But if that blog grows to be like a major thing will the same patterns still still hold true For a bigger team and for a different scalability Problems that I might have some symptoms that I I've seen in my experience starting to express themselves when You start having these issues of the framework not really being maintainable and not scaling with with a team and the and the project is Something that happens is you can start to have these very large files as your app grows Because a lot of things just keep going to the same files and that just just became become this bucket of Behavior that is really hard to understand which leads to a slower pace and getting stuff out the door And this is obviously the the biggest issue actually This is also do my opinion to a High coupling between your components, which means you start having these different classes or modules or whatever Packages and they're all very coupled to each other They all try to get a behavior and communicate with each other when sometimes they really shouldn't there's just a Level of abstraction or some abstractions that you're doing that. They're not really correct Another thing that you start seeing is low cohesion Which means that inside of these classes or these modules you start to have a lot of behavior that doesn't really Match with the rest of the behavior on the class a very common Example of this is for instance in a web app The user class or the user model where you can start you have like behavior for like authentication or Something like that and then you start adding things more specific to your app to the to that user model as well and Then you're now really conflating these Concepts that shouldn't be together and that leads to these large files and sort of place and all of that so this is some of the Symptoms that I that I see and I believe they all come from this overarching problem Which is not really thinking about how to model your domain and that's a little what I really wanted to talk about to you today so for me and This is debatable an ideal application With all the trade-offs that come with this is one that's easy to understand and easy to change That's something that that's what I really focus on when I'm developing or thinking about how to Structure an application is about just mainly these two main things Because I really want for it to be Easy to understand by new team members for instance that that's an important thing so Smaller methods or smaller functions smaller modules. That's usually Helpful easy to change As a trade-off again here because if you have a lot of these small modules then knowing which models are being called and what the The function path is going to look like for a simple process can be hard so trade-offs here a Really thing the thing that's very important to have in mind and a quote that I really like Is this one that the system is the asset? The code is really a liability. So what I mean here is that With all I'm going to be talking about if I was able to have my system and have a product that works and Really with zero lines of code that would be ideal for me and that's kind of Contradictory to the geek within us all right like we like to write code, but on Professional setting that's not really what you're being paid to do most of the times you're being paid to solve a problem Not really write code code is just the way you solve that problem so a way that I like and of Thinking about how to solve these problems is the main driven design. So that's Something that we're gonna talk about now the main driven design, which I'll be calling ddd from now on because it's just shorter is More or less like a theoretical it has some actual patterns and stuff that you're gonna use I'm gonna talk about some of the more Theoretical ideas about the main modeling So you have your problem and then how are you gonna structure your code to be able to Achieve the separation of context and all of that The first thing the thing that I I wanted to stress because again in my experience This is something that most people don't even talk about and don't even think about when building applications Are sub domains sub domains represent something on your problem space and that's the the real difference and Because we're mostly working and thinking about our solution space So how are you gonna solve things and we don't really talk about? The problem space a lot. So here I have an example of two different sub domains, which are sales and support So these are things that exist for our product we have a sales team and sales part of the product and a support part of the product and some of the mains can have Different types. I here have an example of two of them. There are three So first of all, there's our core domain We have to think of what is the main thing that our problem is solving. What is our core competency as a as a company and So that's it's gonna be a part of the product that you really gonna focus on I You have supports of domains So support is something that you're building yourself still it's important to the company But it's not really the core thing you want to do and then you have generics of the mains as I have there for support Which still is something that you need But it's probably something that you can get off the shelf a good example of supporting sub generics of the main Something like a payment system. You can just use stripe or brain tree or the wall or whatever you're using You have a small adapter layer and that just works You can switch them off and as long as it takes a token and an amount to get a payment then that's fine So those are sub domains Now when you move to the solution space in in thinking about these things You come you come to the bounded context bounded context Can have a one-to-one relationship and do have a one-to-one relationship a lot of times of sub domains But they're not necessarily the same thing But here we have our sub domains and we have a different context for each for each of the sub domains And the way it's called context is because really what bounded context are about is Defining a boundary between parts of the system that have different languages that they speak, okay? An example a good analogy I think to think about sub domains versus bounded context and what the different is is if you think of a floor Like you have a room like these you have a floor and you have a carpet Okay, so your sub domain is going to be the floor And you're gonna you want to walk on a on the floor and you you can put a carpet and if it's cut Exactly to the size of the the floor then you have a one-to-one Mapping between the floor and the carpet so that's your sub domain and your bounded context But and to show like how a solution space is different than a problem space You can have a floor and imagine he has some holes in it Now your bounded context can be you can still be the carpet But if I'm walking through a hole I might trip so a better solution might be to fill the hole and then put the carpet on top So continuing the analogy the floor is still the The problem space is still a sub domain But the feeling of the holes plus the carpet is now your solution so there's two things to your solution Okay, so that's why there's these are different things to solving this problem Now going a little bit Deeper into bounded the bounded context the ones we were talking about here sales and support You can see here the different entities that we are using inside of each of these different contexts You have for sales like opportunity Pipeline and support has ticket and defect and some other stuff The the more interesting ones for me are customer and product because you can see them. They are in both so what this means is They have the same name, but they are in different contexts. That's what I'm talking about the language This is a language We call it a ubiquitous language. So that means that the sales team From top to down of the whole organization that that means The domain experts or your sales team developments when they talk about a customer within the sales context Then that's like a sales customer. You might be not even a paying customer yet Something that you're something that you're trying to sell to within the support context. That's probably already a paying customer That has some issue. So they are slightly different and you want to model them as different things And here just making the parallel to umbrella apps a little bit Here's where I would separate each context into a different application okay, so it'll be like a different service and Each model will be represented in each of these applications because they represent different things And now you're not conflating those contexts as I was talking about like in the user model Because user if you think about it is really a bad name Because user can represent so many things it can be an account. It can be a customer. It could be an author There's so many names for what a user can do and that's why they are Often called behavior magnets because if you just say user that's so generic that everything is gonna want to go in there and so thinking about This Thinking about it in this way helps with that especially one very important thing about this that I kind of not really said yet is This is all about communication what I'm talking about here coming up with these names this terminology separating of context This is all about talking with the main experts talking with the stakeholders getting everyone together and having this shared glossary of information and another Benefit of this is then now as I said these applications if you implement them as application can be deployed separately They can be scaled separately. So if we need we have a higher Needs in terms of users for sales. Let's say or for support We can have 10 support servers and servers and just one for sales. They can really they're completely independent That's the whole idea Again to kind of drive this point through If you think about tomatoes Tomatoes like it's a simple thing. You think about it but in Culinary so in cooking a tomato is seen as a vegetable in the botanic world is seen as a fruit in theater or movies It's like feedback like from the rotten tomatoes thing and even a lot of another one If you think of the Pomodoro technique For productivity productivity a Pomodoro is a tomato. That's you're counting units of productivity So just for a simple thing as a tomato we can see four completely different Things that it can mean in different contexts. So that's kind of the idea of what bounded context mean is thinking about where the same concepts or different concepts but The the the ones that have the same name are the more interesting ones what they slightly differences they have when talking about it in different contexts and the The reason it's important to think about this context and separate them is That having a domain model that models everything is pretty much impossible So that's why you want to break break it into different contexts and have the separation again, because I know this thinking about this if you never Seen a domain model this way. It's it's not easy. At least it wasn't for me at first So I want to give another example We're having we have sales and now we have shipping instead of support and we added our course of domain Which is manufacturing and here we see an example of manufacturing has a manufacturing context That's a one-to-one shipping has a shipping context. That's a one-to-one But sales has two contexts Okay, we have sale the sales context with if you think about it as an application That's an application on our side that we implemented ourselves But then we have an external context with a CRM that the sales team uses. So that's something that we want to represent here and It's part of the sales context like on the CRM the terminology that we use is going to be the terminal Terminology that we use within the sales context So for instance a customer or a product is going to represent the exact same thing that we're talking about in our sales context, okay? Now the opposite of this is if you think of an app in the Straight for I'm going to call it straightforward MVC where you have models views and controllers and everything needs to fit into one of these buckets Then what you really have so the problem doesn't really change you still have the same set of domains Like the problem is the same, but your solution is different. You now just have one app. That's one big context So everything like you have a customer Everything is going to go into that customer or you start adding prefixes like sales customer or support customer or stuff like that But everything is within the these app context So you you have your solution space is now covering or going over all of the the difference of the mains within the problem space and This is really something that I've definitely done a lot in the apps that I've built and Once you start growing your app this is where all the problems I think come from or a lot of them actually and The god models that I was talking about the behavior magnets. That's I think this is a big culprit of that and Of course all of that will eventually Slow the pace of your of your team because everything is in the same context now You're trying to the main to model your entire domain into the same thing and and it's not always easy okay, so that was about it for so the mains and bounded context and The last concept that I want to talk about in terms of the DDD theory is the concept of aggregates So we're now inside of a bounded context This is the example of the sales bounded context and we have these different entities which are the boxes And we have this almost circles which are the aggregates A lot of the aggregates can just have one entity. They're not super interesting But an aggregate can have more than one entity and what that that means is That if you have if you have an aggregate with let's say these two entities customer and address It should really be treated as a whole thing. So that's the point of the aggregates It's it's one thing and it serves as a way to uphold The main invariance for instance you have this business rule that there cannot be more than one customer per address the way that's going to be handled is There's gonna be an aggregate route That's the the customer here. That's the aggregate route That's where the outside of the aggregate communicates to it all all the calls come through the aggregate route and it's its job to know the its internal state and manage That internal state and uphold that domain invariant. So it's a consistency and transactional boundary for the rest of the system You can you can think of it for the rest of the system There's only like the customer, but internally the customer has a separate thing. That's an address So this is an aggregate. That's an aggregate route. Usually We name the aggregate after the aggregate aggregate route. So in this case would call this the customer aggregate And now again the parallel to umbrella apps or in elixir I Said bounded context we are usually do that with different apps Different aggregates are usually mapped very well to different actors. So different processes It could be very well that this is a gen server if you use that so a generic server that holds its own state and The way then the outside world and talks to it is as we've seen in the other talks You have a process ID you send messages to that and then he has its internal state and managers all of this So it maps really well to the to this actor model Okay, at this point some of you might be thinking This is Duff we call so it is a lot of big design up front We need to think about all of these things and it's not I want to really stress that The idea is not to achieve the perfect the main modeling because that's not gonna happen The idea is think about this a little bit communicate within the team Reach the main model that didn't command query responsibility segregation. Sorry what this means is First before CQRS we had CQS which stands for command query separation principle and it's actually a simple but powerful principle it states that This is for a function or a method or whatever you want to call it if you have a return value You cannot mutate state and I'm gonna change this a little bit for languages like elixir or Ruby Which always have a return value. You cannot really return void So if you have a return value you care about you cannot mutate state But if you mutate state then you cannot care about the return type So the idea is you have commands that mutate state Somehow you can be an internal state doesn't matter if or create a new state in case of a elixir or any language they use as a immutable types or and So that's commands and then you have queries that Where you just do a query and you get a return value back, but the query cannot change anything on the state So that's CQS the difference here is that CQS This is exactly just what it says so you can have a class or a module that has these commands and queries all together CQRS takes CQS and adds an extra layer that says that each Responsibility so commands and queries need to be on separate models. These need to be separate classes or modules So what this gives you is something like this Where you have a command model that you can send commands to it will for instance persist data to the database And you have a query model you do queries on In this example that I have here. They're both on the same application, but that's not even necessarily true they can be in different applications and That will give you some powerful things to work on The idea behind CQRS is that it's it's not possible to create an optional optimal solution for every situation Using just a single model This this thing builds then on top of the next thing I want to or the next thing builds on top of this And what I want to talk about now again very very briefly is event sourcing. I didn't know if you guys heard about it, but Event sourcing is very coupled with CQRS. They both are very evangelized by Greg Young Which is the the guy that came up with the terms event sourcing and Now we're gonna put all of these I've been talking about you're gonna put it together so we're gonna now look at CQRS with DDD and It kind of comes into event sourcing the idea is that you have your bounded context It's a green box here You got a command that command will go to an aggregate root and the aggregate root knows knows how to translate a Command into an event. So event sourcing it works all with events. That's just That's what why the name is event sourcing Takes a command transforms that into an event or events can be more than one and persists the event into an event store The event story can be a data relational database. It could be something else. It doesn't really matter and the other thing the aggregate root does is Manages its own internal state and publishes the event Somehow again have their message buzz doesn't really matter how this is not important for event sourcing how this happens But you will broadcast the message the event to every Listener that it has subscribed to to that particular event then and So this is the command model then you have your read model over there That gets the queries and this is listening to the events that that are coming depending can listen to One or other event depending on what he cares about Reads the event and persists the data that he gets from the event It can massage that data a little bit however you want and persists that again I have a relational database, but it can be in memory. It doesn't really matter The point here and the thing that that's very powerful because these are separate things So this does not do not have to be the same database they don't even have to be on the same machine and So what means is that you get these events with all the data that you can use and you can then construct the For instance, let's assume that's a relational database. You can construct your tables the exact way you need them for your reads so Potentially that means you can just get rid of joints all together You can just have a table or a database view Materialized view like whatever your solution is, but it can be optimized for the exact situation You you want for the queries in this case the in the case of event sourcing this read model is called the projection And the cool thing about it as it's have one here in this example But for the same events I can have any number of different projections So I can have one optimized for reporting one optimized for logging one optimized for analytics I can have these different things. They can scale differently. They can because this is all independent. There's no coupling between these things so it's a Simple I think model, but a very powerful one and You see this is all coming together in terms of a ddd separation of concerns and all this Okay, so that's it with theory I'm not gonna bore you anymore with here. You're gonna look at some code of how to Actually implement this into elixir with umbrella apps and I give you an example of that The library I'm gonna be using for my examples is called commanded You can totally roll your own event sourcing system in elixir. There's other solutions other than commanded I've been using commanded and I really like it So if you want to try out CQRS and event sourcing in elixir, I really recommend this library. It's pretty cool So here's what we're gonna be building basically We have going back to our same example that we're using we have our sales context and our shipping context They're very similar here. So we have at the very beginning Not really a command, but we have our public API. That's hiding the dispatching of the command Just to make it simpler for the users. We have on our sales module a place order That's a function. It takes a map with the attributes needed to place an order That goes to the sale context as a command then you see that place order That's the command it goes to a router and the router is the place that knows Where to which aggregate route to send each of the commands? So we know that place order will go to the order aggregate route for instance And then the other aggregate route knows to translate the place order command into the order placed event So that's what the aggregate route is doing changes its internal state and then Sends that event to all the event handlers that are listening I Have here in this example two event handlers one inside of the bounded context and one outside Just to represent that it doesn't really matter what it is on your system As long as the events are getting there the event handlers should work because Basically, you can have any sort of queuing system in in here and to send the events and it should be very Distributable One thing to have in mind here is when doing something like this you should mostly be okay with having an eventual consistent system because There even with commanded there's you can Require strong consistency for some events, but it's not really great If you can go with an eventual consistency Which means that you just send the events you hope someone will catch them and that will eventually catch up on the query models on the read models And for shipping is the same thing the examples I have are actually just for sales because this is really the the same thing, but the shipping has just a different command It's cheap order and there's I just have both because there's a particularity that I want to talk about Between integrating this just to context Okay, so looking at the code Here's the main sales module For this is a elixir code if you're not familiar familiar. I hope it's simple enough that you can read it There's a function called place order takes all the properties that we need to place an order and then You have the place order Command that's a struct That hasn't been talked yet here, but as a struct is just like a value object you create this map with this It's basically a map with properties, but has a name So that's a place order with all the properties and then we use the pipe that Sorry, Peter talked about that Takes the the place order the command sends it as an argument to the router dispatch and that will send it to the router The one thing to have in mind here because I'll talk about it in just a second is that we're generating a uuid here And we're sending the uuid as part of the command So looking at the router is very simple. It's a using Commanded commanded behavior for the router That's why this creates this kind of a DSL for the router But it and abstracts a lot of what the router is doing So that's a reason to use libraries, so you don't have to really do this yourself if you don't want to And you can see that this patch takes the Narray with our list with all the commands. He wants to map to a certain aggregate route And in this case you just have one place order that goes to order the important thing here is this identity part It's really important important. What we're saying here is that this Entity so this order is gonna be represented or what's gonna? Identify this order is that attribute is the uid uuid the one we just generated before And this is important particularly to communicate between contexts So what we're saying is that there's always gonna be uuid on the order that's gonna uniquely identify it So that when there's a projection that's gonna get an event on some other context It will know that it we're talking about the same order because of that uuid So They now can talk together and say like now we have place order But we can have now ship order and we send the uuid and we're talking about the same thing importantly and Might be wondering about this is We what this means is that we no longer have or we can no longer really rely on database Enforced IDs, okay, we have to manage on the application level our own IDs Because as I said we can be using totally different databases or a system might not be using a database at all So we cannot rely on the database to give us IDs And what that also means is we kind of cannot really rely on foreign key constraints as well We have to manage that on the application level So that's a cost we are at a trade-off that we are willing to make in order to have this Very distributable and scalable system Okay, the router just to recap the router takes the command It knows to send that command to the to the ordered aggregate route the aggregate route is Here again, it's a struct and It does two things in commanded these are this is a bit particular to command it the concept is not but the names are so we have execute Execute is where we take the command and we translate that to an event or events You can see that the execute Function takes two arguments. The first one is the current internal state of the aggregate which is an order and We can do stuff with it and then it takes the command and it returns an event Here we're Importantly pattern matching on the current state to make sure that the UID of the current state is nil Or no nil is the null for elixir And what why this matters is we can only place an order for an order if an order does not exist yet So this means is that there's gonna be a different struct a different instance If you want to call it of this entity order for every different order and that's gonna base gonna be based on the UID Okay, so that's execute and then we have apply apply is the how we tell it how to apply This event to the internal state So again, we take the internal state as the first argument and then we take the event as a second argument and then we tell it how to apply the the state like the event or whatever information we want from the event to the state and here if you're not familiar is just a Syntax from elixir to update Basically a map so it's we have the state you can think of as a key value map and we want to update certain keys of that map Okay, so this will then We don't see it here because it's handled by commandant, but it will broadcast the event and Then you have some event handler which in this case is a projection so it is gonna represent our query model our queries or our read model and this handler has You can have more but in this case has one handle Function and the handle function will pattern match on the events So any event that does not match despite pattern matching or any other that we have on our handle Handle functions will just be disregarded by this event handler. So here. We're saying we're interested in Order the order placed Event as some meta information. We don't care about I abstracted this persist order. This is just implementation details of starting that the event into Relational database so nothing too fancy there and then return the okay atom to say okay We process the event correctly. We could also return an error and say like we could not process the event for some reason Again, we are using the commandant behaviors for the handler and the interesting thing there like he has a name that's not super interesting, but you have that start from origin and The reason that's there and there's you can start from other things is that In these examples the way I showed it you create or instantiate This is a projection as soon like as soon as you have the first the system the first time So every event will be broadcasted and come here at the time But that's not necessarily true for every situation You can have the system running for a while and then creating a new projection. So what do you do there in? In this scenario what I'm doing is say okay start from the origin of all the events and Send them over so it's gonna go through the list of events because that's event sourcing I didn't really Say this but that event store is basically you can think about it as an append only List of the events so it will go through all the events and we'll replay them and we'll do the handle thing For all the events and then we'll eventually Hopefully catch up and then it will start working from there okay, so This is how you then have your your projection with Here I'm doing persist order to persist to the database, but you can very well persist to the database and also persist to a server in memory and You can have at the same time a database persistence and a caching layer all built based on these events that that come That's pretty easy to do and something that you can very well do Okay in conclusion Building maintainable apps that scale is not easy. That's a premise Or an assumption I'm making But that being said I think that the from and I I've been doing rails for the past five years now So straightforward MVC is basically what I do, but I think it is flawed And I even for prototypes I think because postponing any sort of a conversation between the main experts and the dev team or design team or whoever's involved It is it's not very good You need to start talking about what you're gonna build and what how are you gonna call things? As soon as possible if not what usually happens you leave you leave that to the developers to come up with Random names a lot of times because we don't have to be experts in all the domains that we are coding for And again communication with the main experts keeps your abstractions in check and in general makes it for better apps I think So the last thing I want to say is I want to give you some homework for after the conference is Think about the app you're currently working on whatever it is and try to draw a diagram of the subdomains and the bounded Context you currently have in your app and see how those matches all those match and then think If any of these techniques I just told you about any of these even if not the event sourcing implementations Just the domain modeling if it could help into separating and some concept We could do some of these concepts and contexts are even coming up with concepts that you didn't even know that we're there As a bonus you can try implementing this with umbrella apps and commanded and let me know how that goes if you do it That's it. I'm Zemeth pretty much everywhere online if you want to subscribe to my Soon-to-be newsletter it doesn't exist yet. You can go there I want to just thank my company paying for me to be here and allow me to be here and that's about it I think because of all the issues I took all the time So I'm gonna be here for the next two days. If you have any questions on this, let me know I'm very happy to talk to you about this So thanks. We have a break now