Modular Monoliths: Goldilocks Architecture? | Steve Smith (Ardalis) & Eric Fleming | .NET Day 2026
Read full transcript 35 segments
-
With us are Steve Smith and With us are Steve Smith and Eric Fleming. Hello to Eric Fleming. Hello to Eric Fleming. Hello to you both. I hope you both. I hope you both. I hope you are all well, how are you are all well, how are you are all well, how are you? You will you? You will you? You will talk about talk about talk about modular monoliths, modular monoliths, modular monoliths, the architecture of " the architecture of " Goldilocks". " Goldilocks". " Goldilocks"? Goldilocks"? Goldilocks"? Never heard of it, is this a Never heard of it, is this a Never heard of it, is this a term I should term I should term I should know? know? It's a story that It's a story that many people heard as many people heard as many people heard as children, at least children, at least children, at least in the United States. I in the United States. I don't know how it's don't know how it's perceived in other perceived in other perceived in other countries, but there countries, but there countries, but there a girl walks through the a girl walks through the a girl walks through the forest, comes across a forest, comes across a forest, comes across a house where house where house where bears live, and tastes three bears live, and tastes three bears live, and tastes three different bowls of porridge: different bowls of porridge: different bowls of porridge: one too hot, one too hot, one too hot, one too cold, and one too cold, and one too cold, and one just right one just right one just right . And she sleeps . And she sleeps . And she sleeps in different beds, some in different beds, some in different beds, some too hard, some too too hard, some too too hard, some too soft, and some just right soft, and some just right soft, and some just right . And the point is . And the point is . And the point is that there is a certain that there is a certain that there is a certain middle ground middle ground middle ground that is the perfect that is the perfect that is the perfect balance—that's what balance—that's what balance—that's what the metaphor is. the metaphor is. Okay, then that makes Okay, then that makes sense. Then I had already sense. Then I had already sense. Then I had already learned something. learned something. learned something. Good. Can we Good. Can we Good. Can we start? The slides start? The slides start? The slides have been added, so please give me the have been added, so please give me the have been added, so please give me the floor. Good luck with your floor. Good luck with your floor. Good luck with your presentation, thank you.
-
presentation, thank you. presentation, thank you. OK. Thank you. Hello OK. Thank you. Hello OK. Thank you. Hello everyone. My name is Steve everyone. My name is Steve everyone. My name is Steve Smith, also known Smith, also known Smith, also known as Ardalis. I work at as Ardalis. I work at as Ardalis. I work at NimblePros with Eric, NimblePros with Eric, NimblePros with Eric, and today we're going to and today we're going to and today we're going to talk to you about talk to you about modular monolith architecture. Eric? Eric? Yes, and I'm Eric Fleming, Yes, and I'm Eric Fleming, Yes, and I'm Eric Fleming, Chief Architect Chief Architect Chief Architect at NimblePros. Excited at NimblePros. Excited at NimblePros. Excited to dive into this. Are you to dive into this. Are you to dive into this. Are you ready, Steve? ready, Steve? ready, Steve? Yes. We have a lot to Yes. We have a lot to Yes. We have a lot to cover, because cover, because cover, because it's usually a it's usually a it's usually a presentation of at least presentation of at least presentation of at least an hour, so we'll an hour, so we'll an hour, so we'll be talking really be talking really be talking really fast, and you fast, and you fast, and you can always watch can always watch can always watch it on YouTube and it on YouTube and it on YouTube and slow it down if you slow it down if you slow it down if you need to. So let's begin need to. So let's begin . OK. The first thing . OK. The first thing . OK. The first thing I want to say is: if I want to say is: if I want to say is: if you want to learn you want to learn you want to learn more about modular more about modular more about modular monoliths, you monoliths, you monoliths, you can always go to can always go to can always go to modularmonolith.com, there you modularmonolith.com, there you modularmonolith.com, there you will find a bunch of will find a bunch of will find a bunch of resources, articles, resources, articles, resources, articles, videos, etc. Now let's videos, etc. Now let's videos, etc. Now let's quickly quickly quickly go over the go over the go over the definitions. So, definitions. So, definitions. So, first of all, this is the first first of all, this is the first first of all, this is the first law of software architecture law of software architecture from a from a great book on the great book on the great book on the basics of this basics of this basics of this discipline. And this discipline. And this discipline. And this first law is that first law is that first law is that everything is a everything is a everything is a compromise.
-
compromise. compromise. Software architecture is all Software architecture is all Software architecture is all about compromises. There about compromises. There about compromises. There is no one is no one is no one right right right architecture for architecture for architecture for everything. So when we everything. So when we everything. So when we talk about talk about talk about monoliths, monolithic monoliths, monolithic monoliths, monolithic architecture means architecture means architecture means that the application that the application that the application is deployed as a is deployed as a is deployed as a single process. single process. Monolith, you know, " mono" comes from mono" comes from mono" comes from Greek. Uh, "mono," Greek. Uh, "mono," Greek. Uh, "mono," which I'm probably pronouncing which I'm probably pronouncing which I'm probably pronouncing wrong, generally, wrong, generally, wrong, generally, as far as I understand, as far as I understand, as far as I understand, means one, sole, means one, sole, means one, sole, or lonely. So, or lonely. So, or lonely. So, when we talk about a when we talk about a when we talk about a monolithic monolithic monolithic architecture or architecture or architecture or application, it simply application, it simply application, it simply means that we means that we means that we deploy only deploy only deploy only one thing. We don't one thing. We don't one thing. We don't need to manage need to manage need to manage a bunch of different a bunch of different a bunch of different independent processes, independent processes, independent processes, services, or services, or services, or containers to make this containers to make this containers to make this architecture architecture architecture work. And work. And work. And actually, even with actually, even with actually, even with most monoliths, most monoliths, most monoliths, that's not exactly the case, because that's not exactly the case, because that's not exactly the case, because you probably also have a you probably also have a you probably also have a separate database. separate database. separate database. So there are probably So there are probably at least two at least two components involved in the process. But, components involved in the process. But, components involved in the process. But, aside from the database, the aside from the database, the aside from the database, the monolith is your monolith is your monolith is your code. Now code. Now code. Now many people perceive " many people perceive " monolith" as a monolith" as a monolith" as a kind of pejorative, as kind of pejorative, as kind of pejorative, as some kind of bad word.
-
some kind of bad word. But that's actually not But that's actually not entirely fair. entirely fair. entirely fair. The thing about monoliths is The thing about monoliths is The thing about monoliths is that if you that if you that if you deploy just deploy just deploy just one object, and your one object, and your one object, and your application gets application gets application gets bigger and more bigger and more bigger and more complex over time, and you don't complex over time, and you don't complex over time, and you don't care about its care about its care about its design, eventually design, eventually design, eventually it can end up looking like this it can end up looking like this it can end up looking like this . This is something that . This is something that . This is something that many teams many teams many teams have encountered over the have encountered over the have encountered over the years: you build and years: you build and years: you build and build and build, and build and build, and build and build, and it turns into a it turns into a it turns into a giant giant giant tangled mess, tangled mess, tangled mess, or what is known as " or what is known as " big big big ball of mud architecture." So the ball of mud architecture." So the ball of mud architecture." So the real problem is not that real problem is not that real problem is not that you are you are you are deploying only deploying only deploying only one object. The problem one object. The problem one object. The problem is that you is that you is that you let it become let it become let it become this tangled this tangled this tangled mess, right? mess, right? mess, right? Monolith is not a Monolith is not a Monolith is not a problem. The problem problem. The problem is the complete lack of is the complete lack of is the complete lack of structure in the code structure in the code structure in the code base. And over the base. And over the base. And over the years of software development, years of software development, many many different architectural different architectural different architectural patterns have emerged to patterns have emerged to patterns have emerged to try to try to try to combat this. This is by no means a combat this. This is by no means a combat this. This is by no means a new problem. And new problem. And new problem. And the one that almost the one that almost the one that almost every developer every developer every developer encounters first is a encounters first is a fairly simple fairly simple fairly simple approach called approach called approach called multi-tier multi-tier multi-tier architecture. Isn't that right architecture. Isn't that right architecture. Isn't that right ? A typical ? A typical ? A typical multi-tier multi-tier multi-tier architecture separates architecture separates architecture separates everything along technical everything along technical everything along technical lines: the lines: the lines: the user interface in one user interface in one user interface in one tier, all the business tier, all the business logic, hopefully, logic, hopefully, logic, hopefully, in another, in another, in another, data access as a third data access as a third data access as a third tier, and there tier, and there tier, and there may be others as well, such may be others as well, such as workflows. And the as workflows. And the as workflows. And the multi-tiered multi-tiered multi-tiered architecture really architecture really architecture really helps a lot. So, helps a lot. So, helps a lot. So, with a multi-tiered with a multi-tiered with a multi-tiered architecture, for a architecture, for a architecture, for a typical typical typical e-commerce site
-
e-commerce site e-commerce site you might have something you might have something you might have something like this. Maybe like this. Maybe like this. Maybe you have users with you have users with you have users with shopping carts who shopping carts who shopping carts who later place later place later place orders, and you orders, and you orders, and you need to work with need to work with need to work with inventory and then inventory and then inventory and then ship the product to ship the product to ship the product to the user. This the user. This the user. This works great, and you works great, and you works great, and you have rules where have rules where have rules where maybe the maybe the maybe the top level can top level can top level can only interact with the only interact with the only interact with the level directly level directly level directly below it. You don't have to below it. You don't have to below it. You don't have to resort to resort to resort to tricks and, you know, tricks and, you know, tricks and, you know, skip levels or skip levels or skip levels or do anything like that. do anything like that. do anything like that. Of course, lower Of course, lower Of course, lower levels should not levels should not levels should not communicate with communicate with communicate with higher ones. And you higher ones. And you higher ones. And you get code that, get code that, get code that, you know, looks like this you know, looks like this you know, looks like this , nice and clean. , nice and clean. , nice and clean. All user All user All user levels at the top have levels at the top have levels at the top have corresponding elements corresponding elements corresponding elements they they they interact with below them, interact with below them, interact with below them, and so on up to the and so on up to the and so on up to the next level. This is next level. This is next level. This is great. However, great. However, great. However, the problem with such a the problem with such a the problem with such a multi-tiered multi-tiered multi-tiered architecture is that architecture is that architecture is that it is useful, but it is useful, but it is useful, but it is not enough. it is not enough. it is not enough. Because nothing Because nothing Because nothing prevents her from looking like this prevents her from looking like this prevents her from looking like this . And once . And once . And once you start you start you start making all the different making all the different making all the different parts of your parts of your parts of your application application application talk to talk to talk to every other every other every other part, and nothing, part, and nothing, part, and nothing, you know, is you know, is you know, is stopping that. Now you stopping that. Now you stopping that. Now you start to get start to get start to get this kind of spaghetti this kind of spaghetti code where, you know, everything is code where, you know, everything is code where, you know, everything is interacting everywhere, and it interacting everywhere, and it interacting everywhere, and it becomes very difficult becomes very difficult becomes very difficult to separate things to to separate things to to separate things to determine what are the determine what are the determine what are the main parts of main parts of main parts of just one function of the just one function of the just one function of the application. And this application. And this application. And this leads to the leads to the leads to the code inevitably becoming code inevitably becoming code inevitably becoming more difficult to more difficult to more difficult to maintain, often maintain, often maintain, often harder to harder to harder to test depending test depending test depending on how on how on how tightly coupled the tightly coupled the tightly coupled the components are, especially components are, especially components are, especially to the infrastructure.
-
to the infrastructure. to the infrastructure. So spaghetti code is what So spaghetti code is what So spaghetti code is what you're you're you're trying to avoid trying to avoid , what leads to that , what leads to that , what leads to that confusing "big confusing "big confusing "big pile of dirt" in a pile of dirt" in a pile of dirt" in a diagram or diagram or diagram or architecture that architecture that architecture that we don't want to we don't want to we don't want to end up in, because it's very end up in, because it's very end up in, because it's very expensive to get out expensive to get out expensive to get out of there once you've of there once you've of there once you've reached that point. reached that point. reached that point. Now, continuing this Now, continuing this Now, continuing this metaphor with food and metaphor with food and metaphor with food and pasta, I know pasta, I know pasta, I know many of you have many of you have many of you have just had lunch, and just had lunch, and just had lunch, and some may some may some may just be having breakfast. Um, just be having breakfast. Um, just be having breakfast. Um, if it's not spaghetti if it's not spaghetti code, it's because we code, it's because we code, it's because we used used used levels, right? It may be levels, right? It may be levels, right? It may be lasagna code now, lasagna code now, lasagna code now, but it's still not as but it's still not as but it's still not as good as we'd good as we'd good as we'd like it to be, right? There are like it to be, right? There are like it to be, right? There are still a lot of things still a lot of things still a lot of things mixed up there, and nothing mixed up there, and nothing mixed up there, and nothing separates them from the separates them from the separates them from the cross- cross- cross- connection within connection within connection within each level. So what each level. So what each level. So what we really we really we really want is ravioli. want is ravioli. Ravioli are individually Ravioli are individually wrapped pieces of wrapped pieces of wrapped pieces of dough, and if you want, dough, and if you want, dough, and if you want, each one can have its own each one can have its own each one can have its own separate filling. I don't separate filling. I don't separate filling. I don't think most think most think most people who eat people who eat people who eat ravioli usually ravioli usually ravioli usually do that. So the do that. So the do that. So the cooking metaphor cooking metaphor cooking metaphor may not work, may not work, may not work, but in our but in our but in our real code, each real code, each real code, each of these standalone of these standalone of these standalone modules may have modules may have modules may have its own implementation, its its own implementation, its its own implementation, its own templates that own templates that own templates that it uses, or it uses, or it uses, or it may be it may be it may be responsible for a different responsible for a different responsible for a different team. This opens up team. This opens up team. This opens up many possibilities.
-
many possibilities. So, when you have So, when you have true modularity true modularity true modularity in your in your software architecture, it software architecture, it means that each means that each means that each individual module has individual module has individual module has some kind of encapsulation, some kind of encapsulation, some kind of encapsulation, making it making it making it integrate neatly with integrate neatly with integrate neatly with other modules other modules other modules using certain using certain using certain well-known patterns and well-known patterns and well-known patterns and interfaces. The idea behind interfaces. The idea behind interfaces. The idea behind encapsulation is encapsulation is encapsulation is that you that you that you only offer a only offer a only offer a set of public set of public set of public interfaces through interfaces through interfaces through which which which elements interact, and other elements interact, and other elements interact, and other modules or parts of the modules or parts of the modules or parts of the program cannot program cannot program cannot simply interfere with the simply interfere with the simply interfere with the internal processes internal processes internal processes you you you use. They use. They use. They can't, you know, can't, you know, can't, you know, intervene and change the intervene and change the intervene and change the global data that global data that global data that you're working with, you're working with, you're working with, for example. Another for example. Another for example. Another point is point is that the focus that the focus that the focus is on is on functionality, not functionality, not just technical just technical just technical levels. So it's levels. So it's levels. So it's more of a more of a domain-driven design approach domain-driven design approach . And this helps to ensure . And this helps to ensure . And this helps to ensure that all the that all the that all the subject-matter rules subject-matter rules subject-matter rules for a particular for a particular for a particular function are function are function are encapsulated in a encapsulated in a encapsulated in a single module, rather than single module, rather than single module, rather than scattered across scattered across scattered across many different many different many different places. I can't even places. I can't even places. I can't even tell you how many tell you how many tell you how many applications I've seen applications I've seen applications I've seen where business rules where business rules where business rules for something like for something like for something like calculating tax, calculating tax, calculating tax, checking a checking a checking a customer discount, or customer discount, or customer discount, or whatever are scattered whatever are scattered whatever are scattered between JavaScript code in the between JavaScript code in the between JavaScript code in the browser and other browser and other browser and other code in different code in different code in different controllers or controllers or controllers or endpoints. And then endpoints. And then endpoints. And then there are parts in there are parts in there are parts in libraries and in libraries and in libraries and in stored stored stored procedures, and it's procedures, and it's procedures, and it's just a mess when just a mess when just a mess when any of that any of that any of that changes or needs to changes or needs to changes or needs to evolve, and you evolve, and you evolve, and you need to find all
-
need to find all need to find all these places and these places and these places and change them correctly in a timely manner, change them correctly in a timely manner, change them correctly in a timely manner, ensuring ensuring ensuring appropriate appropriate appropriate versioning. So versioning. So versioning. So with this level of with this level of with this level of encapsulation, you encapsulation, you encapsulation, you make it so that there's make it so that there's make it so that there's only one place where only one place where only one place where this type of business this type of business rule lives, and everything else rule lives, and everything else rule lives, and everything else interacts with it through a interacts with it through a interacts with it through a well-known public well-known public well-known public set of interfaces. And set of interfaces. And set of interfaces. And ideally, each module is ideally, each module is not just a not just a not just a class library with class library with class library with certain logic. It certain logic. It certain logic. It also has a also has a also has a user interface. He user interface. He user interface. He also has data. It also has data. It also has data. It contains all contains all contains all the components it the components it the components it needs as a complete needs as a complete needs as a complete piece. OK. So piece. OK. So piece. OK. So if we look at the if we look at the if we look at the multi-tier multi-tier multi-tier architecture, it architecture, it architecture, it seems to stay the seems to stay the seems to stay the same, but same, but same, but now we're going to add some now we're going to add some now we're going to add some boundaries between each of these boundaries between each of these boundaries between each of these functions to make functions to make functions to make them more modular. them more modular. So, if we So, if we look at it from look at it from look at it from another perspective, we another perspective, we another perspective, we get a concept get a concept get a concept similar to this, where we have similar to this, where we have similar to this, where we have separate logically separate logically separate logically separated modules that will separated modules that will make up our make up our application. Okay, application. Okay, application. Okay, so is that enough so is that enough ? Can we just, ? Can we just, ? Can we just, you know, logically you know, logically you know, logically divide? Or divide? Or divide? Or can we can we can we argue that we argue that we —and by “we” I —and by “we” I —and by “we” I mean, first and foremost, mean, first and foremost, mean, first and foremost, my resume—also my resume—also my resume—also need physical need physical need physical separation because I would separation because I would separation because I would really like to add really like to add really like to add more microservices more microservices more microservices to my experience?
-
to my experience? to my experience? I think it would help I think it would help I think it would help me find a better me find a better me find a better job and job and job and value my time more. And value my time more. And value my time more. And this is a common thing that this is a common thing that teams resort to, especially those teams resort to, especially those dealing with that dealing with that dealing with that same "big same "big same "big ball of dirt"—the ball of dirt"—the monolith. They often monolith. They often monolith. They often say, “The only say, “The only say, “The only way to untangle this is way to untangle this is to split everything into to split everything into to split everything into different applications, so that different applications, so that different applications, so that each one performs each one performs each one performs only one function.” Is only one function.” Is n't that right? Of course, n't that right? Of course, microservices are an microservices are an microservices are an option, and a fairly option, and a fairly option, and a fairly popular one that has been popular one that has been popular one that has been actively actively actively used used used over the last over the last over the last decade. But dragons decade. But dragons decade. But dragons are waiting for us there are waiting for us there are waiting for us there . . . I borrowed these dragons from I borrowed these dragons from I borrowed these dragons from Martin Fowler's article; They're Martin Fowler's article; They're Martin Fowler's article; They're cute, I cute, I cute, I like them, that's why I like them, that's why I like them, that's why I added them to this slide. added them to this slide. added them to this slide. If we had more If we had more If we had more time, I would ask you to time, I would ask you to time, I would ask you to imagine another 20 minutes of imagine another 20 minutes of imagine another 20 minutes of me talking about me talking about why you probably why you probably why you probably don't need a don't need a microservices-based architecture from the microservices-based architecture from the start. But start. But start. But today we simply today we simply today we simply don't have time for that. So don't have time for that. So don't have time for that. So we'll skip that we'll skip that we'll skip that part and move part and move part and move on to the graph, where on the on to the graph, where on the on to the graph, where on the vertical axis we vertical axis we vertical axis we see the number of see the number of see the number of modules—how modules—how modules—how modular modular modular the application is, and on the the application is, and on the the application is, and on the horizontal axis— horizontal axis— the number of the number of the number of deployed services deployed services . Of course? So, . Of course? So, . Of course? So, on the left you deploy on the left you deploy on the left you deploy only one unit—it's a only one unit—it's a only one unit—it's a monolith, and on the right you deploy monolith, and on the right you deploy more than one.
-
more than one. more than one. It could be It could be It could be microservices or microservices or microservices or something else. If you something else. If you something else. If you do everything right, you will do everything right, you will do everything right, you will end up in the upper end up in the upper end up in the upper right quadrant, where right quadrant, where right quadrant, where you will achieve a proper you will achieve a proper microservices architecture, where everything microservices architecture, where everything is completely independent, is completely independent, is completely independent, cohesive, and cohesive, and cohesive, and works great. However, if you do works great. However, if you do works great. However, if you do n't do everything n't do everything n't do everything right, if you right, if you right, if you don't don't don't set boundaries properly, if you share set boundaries properly, if you share set boundaries properly, if you share things you things you things you shouldn't, or if you shouldn't, or if you shouldn't, or if you communicate in communicate in communicate in inappropriate ways inappropriate ways , you can easily end up in the , you can easily end up in the , you can easily end up in the bottom right bottom right bottom right quadrant—the " quadrant—the " distributed distributed distributed mess," which is the mess," which is the mess," which is the worst place to be worst place to be worst place to be because because because you now have all you now have all you now have all the problems of a monolith and the problems of a monolith and the problems of a monolith and all the challenges of a all the challenges of a all the challenges of a distributed distributed distributed architecture architecture architecture at the same time. So at the same time. So at the same time. So moving there moving there moving there won't improve your won't improve your won't improve your life at all. Um, it's much life at all. Um, it's much life at all. Um, it's much easier to move in only easier to move in only easier to move in only one direction at a one direction at a one direction at a time, and it's much time, and it's much time, and it's much easier to move to easier to move to easier to move to microservices if you've microservices if you've microservices if you've already defined where the already defined where the already defined where the boundaries should be. And I boundaries should be. And I boundaries should be. And I believe this means believe this means believe this means that you should move that you should move that you should move to a modular to a modular to a modular monolith with logical monolith with logical monolith with logical modules before modules before modules before trying to move trying to move trying to move to physically to physically to physically separated and separated and separated and isolated isolated isolated microservices. Good.
-
microservices. Good. microservices. Good. So, let's So, let's So, let's talk about talk about talk about modular monoliths. Um modular monoliths. Um , I'm using the , I'm using the Goldilocks architecture metaphor. If Goldilocks architecture metaphor. If you are not familiar with you are not familiar with you are not familiar with the tale of the three the tale of the three the tale of the three bears, you can bears, you can bears, you can google it. But the point is google it. But the point is google it. But the point is that a girl that a girl that a girl named Goldilocks named Goldilocks named Goldilocks wanders through the forest, wanders through the forest, wanders through the forest, finds a house where finds a house where finds a house where bears live, and bears live, and bears live, and decides to eat their decides to eat their decides to eat their breakfast. She breakfast. She breakfast. She finds three bowls finds three bowls finds three bowls of porridge, tastes each one: of porridge, tastes each one: of porridge, tastes each one: the first is too hot, the the first is too hot, the the first is too hot, the second is too second is too second is too cold, so she cold, so she cold, so she doesn't eat them, and the third is just right doesn't eat them, and the third is just right doesn't eat them, and the third is just right , and she , and she , and she decides to eat it all. decides to eat it all. So the idea here is that So the idea here is that you have options: you have options: you have options: either no modules at all either no modules at all either no modules at all , a sort of , a sort of , a sort of "as-is "as-is " architecture in a monolith, which can " architecture in a monolith, which can " architecture in a monolith, which can lead to a "big lead to a "big lead to a "big pile of dirt"; or on pile of dirt"; or on pile of dirt"; or on the other hand, the other hand, the other hand, microservices, where we microservices, where we microservices, where we break absolutely break absolutely break absolutely everything into separate everything into separate everything into separate applications, applications, applications, deploy them deploy them deploy them separately, and communicate, separately, and communicate, separately, and communicate, you know, through you know, through you know, through asynchronous means or asynchronous means or asynchronous means or at least over the at least over the at least over the network. Um, and that's another network. Um, and that's another network. Um, and that's another option. And in the middle option. And in the middle — what if we — what if we — what if we only made a logical division, only made a logical division, only made a logical division, but still but still but still deployed it as a deployed it as a deployed it as a single unit? Um, and I'd single unit? Um, and I'd single unit? Um, and I'd argue that this is argue that this is argue that this is probably a good probably a good probably a good compromise for compromise for compromise for many applications many applications . Good. So, a . Good. So, a modular monolith architecture will modular monolith architecture will basically have a basically have a basically have a host. If you host. If you host. If you 're using something 're using something 're using something like ASP.NET or like ASP.NET or like ASP.NET or ASP.NET Core ASP.NET Core ASP.NET Core web applications, it web applications, it web applications, it will be a true ASP.NET Core will be a true ASP.NET Core will be a true ASP.NET Core web application. And it should web application. And it should web application. And it should be quite be quite be quite minimal. There minimal. There minimal. There should be should be should be nothing superfluous in it. And nothing superfluous in it. And nothing superfluous in it. And then each module then each module then each module will be a separate
-
will be a separate will be a separate project that the host project that the host project that the host integrates with and integrates with and integrates with and loads. When loads. When loads. When we look at each we look at each we look at each of these modules, they of these modules, they of these modules, they must have certain must have certain must have certain characteristics for characteristics for characteristics for this architecture this architecture this architecture to work. So, to work. So, to work. So, each of them must be each of them must be each of them must be independent. What does this independent. What does this independent. What does this mean? Well, if these mean? Well, if these mean? Well, if these were microservices, that would were microservices, that would were microservices, that would mean that mean that mean that the team the team the team responsible for that responsible for that responsible for that microservice could microservice could microservice could deploy it at any deploy it at any time without coordinating time without coordinating time without coordinating its actions with other its actions with other its actions with other microservices microservices microservices around it. Um, in the case of a around it. Um, in the case of a around it. Um, in the case of a module within a module within a module within a monolith, the entire monolith, the entire monolith, the entire monolith should be monolith should be monolith should be deployed deployed deployed at the same time, but each at the same time, but each at the same time, but each team, if they are team, if they are team, if they are separate teams separate teams separate teams working on a separate working on a separate working on a separate module, should be able to module, should be able to module, should be able to make make make changes to it. And as long as changes to it. And as long as changes to it. And as long as they don't violate they don't violate they don't violate their public their public their public contract, they don't contract, they don't contract, they don't need to need to need to coordinate with coordinate with coordinate with other teams or other teams or other teams or other modules, other modules, other modules, right? Their internal right? Their internal right? Their internal changes must be changes must be changes must be independent. Um, and they independent. Um, and they independent. Um, and they don't need to, you know, don't need to, you know, don't need to, you know, do that kind of do that kind of do that kind of coordination to coordination to coordination to work. They work. They work. They should be logically should be logically should be logically separated. And so separated. And so separated. And so in our source in our source in our source code, that means code, that means code, that means they should have their they should have their they should have their own namespace.
-
own namespace. own namespace. They should have They should have They should have their own their own their own folder structure. They must folder structure. They must folder structure. They must have their own domain have their own domain have their own domain model. So they don't model. So they don't model. So they don't rely on a rely on a rely on a common set of types common set of types common set of types because, again, that would because, again, that would because, again, that would make it harder for them to be make it harder for them to be make it harder for them to be independent. If independent. If independent. If they change something in a they change something in a they change something in a shared model, it shared model, it shared model, it could break another could break another could break another module that module that module that uses that uses that uses that same shared same shared same shared module. Or a model. module. Or a model. module. Or a model. Typically you want Typically you want Typically you want them to be them to be them to be functionally functionally functionally oriented. So oriented. So oriented. So instead of instead of instead of having things that having things that having things that maybe deal with maybe deal with maybe deal with technical aspects technical aspects technical aspects or cross-cutting or cross-cutting or cross-cutting issues, you wouldn't want to issues, you wouldn't want to issues, you wouldn't want to have a module that is the have a module that is the user interface and another user interface and another module that is the module that is the module that is the data layer, right? These are data layer, right? These are data layer, right? These are levels, not modules. levels, not modules. levels, not modules. But you can of course But you can of course But you can of course have things for, have things for, have things for, say, say, say, order fulfillment, order fulfillment, order fulfillment, cart processing, or cart processing, or cart processing, or reporting, or anything reporting, or anything reporting, or anything that's that's that's functionality in functionality in functionality in your app. But your app. But your app. But they should generally they should generally they should generally correspond correspond correspond to what the user to what the user to what the user perceives as different perceives as different perceives as different user user user stories, paths or stories, paths or stories, paths or features they features they features they use, etc. use, etc. use, etc. Inside a module, you Inside a module, you Inside a module, you want all of its want all of its want all of its elements and all of its elements and all of its elements and all of its source code to be source code to be source code to be cohesive. And cohesive. And cohesive. And cohesion cohesion cohesion means they're all means they're all means they're all connected, connected, connected, right? They right? They right? They work together, they work together, they work together, they refer to each refer to each refer to each other. And so if other. And so if other. And so if you look at the code you look at the code you look at the code and structure it, and structure it, and structure it, you'll see that all the you'll see that all the you'll see that all the code in that module code in that module code in that module usually works usually works usually works together to achieve the together to achieve the together to achieve the same goal. What if same goal. What if same goal. What if instead you instead you instead you look and look and look and see that all this see that all this see that all this code is working towards one code is working towards one code is working towards one goal, but this code goal, but this code goal, but this code here is doing something here is doing something here is doing something completely different, right? Well, completely different, right? Well, completely different, right? Well, it wouldn't be it wouldn't be it wouldn't be cohesive because cohesive because cohesive because these completely different things these completely different things these completely different things might belong in a might belong in a might belong in a different module. For different module. For different module. For example. If you are example. If you are example. If you are familiar with object- familiar with object- oriented
-
oriented oriented design, you design, you design, you should consider should consider should consider each module as a each module as a each module as a separate bounded separate bounded separate bounded context. Isn't that right? And context. Isn't that right? And context. Isn't that right? And "limited" is an "limited" is an "limited" is an important part of important part of important part of this term, or this term, or this term, or at least as at least as at least as important as " important as " context." This is context." This is context." This is about about about encapsulation. True? encapsulation. True? encapsulation. True? It must have boundaries It must have boundaries so that other modules and the so that other modules and the so that other modules and the program itself program itself program itself cannot simply cannot simply cannot simply interfere with its interfere with its interfere with its inner workings. inner workings. inner workings. Interaction must Interaction must Interaction must occur through the occur through the occur through the published published published interface provided by interface provided by interface provided by this module. And " this module. And " context" means that context" means that context" means that each module has each module has each module has its own environment, its own environment, its own environment, its own rules, its own rules, its own rules, its own internal its own internal its own internal abstractions and methods of abstractions and methods of abstractions and methods of operation. Thanks to operation. Thanks to operation. Thanks to all this, all this, all this, since they are since they are since they are independent and have their independent and have their independent and have their own context, they own context, they own context, they can be shared between can be shared between can be shared between teams. What I teams. What I teams. What I mean: In large mean: In large mean: In large organizations, many organizations, many organizations, many companies companies companies justify justify justify moving to moving to moving to microservices by saying, microservices by saying, microservices by saying, "We have, let's say, 100 "We have, let's say, 100 "We have, let's say, 100 engineers and we engineers and we engineers and we need them to need them to need them to work on this work on this work on this application, but they can't application, but they can't application, but they can't work on work on work on one big one big one big solution because it's too solution because it's too solution because it's too complex." They complex." They complex." They constantly interfere with constantly interfere with constantly interfere with each other. If you each other. If you each other. If you move to a move to a move to a modular architecture modular architecture , even within a , even within a , even within a single deployment, single deployment, single deployment, different teams different teams different teams can be responsible can be responsible can be responsible for different modules within for different modules within for different modules within that monolith, that monolith, that monolith, allowing a large allowing a large allowing a large number of engineers number of engineers number of engineers to work to work to work on the application in a cohesive manner. Each on the application in a cohesive manner. Each on the application in a cohesive manner. Each module must have module must have module must have its own data storage.
-
its own data storage. its own data storage. This again This again This again emphasizes their emphasizes their emphasizes their independence. This is independence. This is independence. This is also true for also true for also true for microservices. A very microservices. A very microservices. A very common common common anti-pattern in anti-pattern in anti-pattern in microservices is the microservices is the microservices is the use of a use of a use of a shared database. shared database. shared database. This is one of those things This is one of those things This is one of those things that leads to the that leads to the that leads to the creation of a " creation of a " distributed tangle of distributed tangle of distributed tangle of clutter." Don't do clutter." Don't do clutter." Don't do this. In your this. In your this. In your modular monolith, modular monolith, modular monolith, each module each module each module should also have its own should also have its own data storage system. And each of them data storage system. And each of them can be can be can be organized organized organized according to its according to its according to its complexity. If complexity. If complexity. If you have a very simple you have a very simple you have a very simple module, it may module, it may module, it may not need complex not need complex not need complex internal internal internal organization. Maybe organization. Maybe organization. Maybe he doesn't need a he doesn't need a he doesn't need a lot of abstraction or a lot of abstraction or a clean clean architecture style of organization. Maybe architecture style of organization. Maybe architecture style of organization. Maybe it's just CRUD operations it's just CRUD operations —create, read, —create, read, —create, read, update, delete— update, delete— update, delete— that need to be in that need to be in that need to be in one place. You one place. You one place. You can make it can make it can make it very simple. But very simple. But very simple. But maybe you have another maybe you have another maybe you have another module that is business-critical and module that is business-critical and has a lot of has a lot of complexity, and complexity, and complexity, and you want to you want to you want to use a different use a different use a different template for it. You have the template for it. You have the template for it. You have the opportunity to do this. opportunity to do this. opportunity to do this. They don't have to They don't have to They don't have to look the same look the same look the same because each of them because each of them is a separate context. is a separate context. So, to achieve So, to achieve this modularity, this modularity, this modularity, you should you should you should follow follow follow a few simple a few simple a few simple rules. Um, the first rules. Um, the first rules. Um, the first rule is rule is rule is that for each that for each that for each module you should module you should module you should create a separate create a separate create a separate project and project and project and use the use the use the C#internal keyword, C#internal keyword, C#internal keyword, which makes sure that which makes sure that which makes sure that external projects don't external projects don't external projects don't have access to these have access to these have access to these types. You should types. You should types. You should use a use a use a separate schema or separate schema or separate schema or perhaps a separate perhaps a separate perhaps a separate database for each database for each database for each module. Again, module. Again, module. Again, they should have they should have they should have their own their own their own data retention strategy.
-
data retention strategy. data retention strategy. They also don't They also don't They also don't necessarily have to necessarily have to necessarily have to use the use the use the same database, same database, same database, right? They don't right? They don't right? They don't have to have to have to use Entity use Entity use Entity Framework, SQL Server, or Postgres. Framework, SQL Server, or Postgres. Framework, SQL Server, or Postgres. For example, some of For example, some of For example, some of them may them may them may use a NoSQL use a NoSQL use a NoSQL database. You can database. You can database. You can have, say, MongoDB have, say, MongoDB have, say, MongoDB for one module, SQL for one module, SQL for one module, SQL Server for another, and SQLite Server for another, and SQLite Server for another, and SQLite for a third. And it for a third. And it for a third. And it will will will work great. This gives you work great. This gives you work great. This gives you some flexibility in some flexibility in some flexibility in choosing the right choosing the right choosing the right data store for the data store for the data store for the tasks tasks tasks this this this module focuses on. Next, it's worth module focuses on. Next, it's worth module focuses on. Next, it's worth defining your defining your defining your public contracts in a public contracts in a public contracts in a separate project so that separate project so that separate project so that any other any other any other module can module can module can interact through these interact through these interact through these public types. It is also public types. It is also public types. It is also worth considering worth considering worth considering using a using a using a messaging tool messaging tool messaging tool , , , such as a mediator, such as a mediator, such as a mediator, instead of directly instead of directly instead of directly calling services, calling services, calling services, as this provides as this provides as this provides benefits in the form of benefits in the form of benefits in the form of middleware pipelines middleware pipelines middleware pipelines for solving for solving for solving end-to-end and end-to-end and end-to-end and operational tasks, operational tasks, operational tasks, such as logging, such as logging, such as logging, validation, etc. So validation, etc. So validation, etc. So why not just why not just why not just define the contracts define the contracts define the contracts inside the inside the inside the module itself? Why is a module itself? Why is a module itself? Why is a separate project needed? separate project needed? separate project needed? The biggest problem, The biggest problem, The biggest problem, which is easier which is easier which is easier to show with an example, to show with an example, to show with an example, is that is that is that if you have two if you have two if you have two projects, module A and projects, module A and projects, module A and module B, and module A module B, and module A module B, and module A calls something in calls something in calls something in module B, it has a module B, it has a module B, it has a reference to the project.
-
reference to the project. reference to the project. But later on, module B But later on, module B But later on, module B will need something from will need something from will need something from module A, and you won't module A, and you won't module A, and you won't be able to do that, be able to do that, be able to do that, right? A right? A right? A cyclical dependence arises. cyclical dependence arises. cyclical dependence arises. Therefore, simply having Therefore, simply having Therefore, simply having public contracts in public contracts in public contracts in every every every module project will not work. But module project will not work. But module project will not work. But once you add a once you add a once you add a separate project for separate project for separate project for contracts, any contracts, any contracts, any module can module can module can reference reference another module's public contracts project and another module's public contracts project and make calls, make calls, for example using a mediator for example using a mediator to send an event to send an event to send an event or command that a or command that a or command that a handler in the other handler in the other handler in the other module will then module will then module will then pick up. pick up. Yes. And Steve, you don't Yes. And Steve, you don't have to have to have to use a use a use a mediator for this. mediator for this. mediator for this. You don't need to You don't need to You don't need to use an use an use an external library. external library. external library. You could just You could just You could just use regular use regular use regular service interfaces service interfaces service interfaces for this. for this. for this. Yes, that's true. Um, Yes, that's true. Um, Yes, that's true. Um, I like I like I like using the using the using the mediator library mediator library mediator library for, like I said, for, like I said, for, like I said, creating a pipeline of creating a pipeline of creating a pipeline of end-to-end tasks, end-to-end tasks, end-to-end tasks, but if you don't but if you don't but if you don't need that need that need that resource cost, because it resource cost, because it resource cost, because it can slow down can slow down can slow down performance, or performance, or performance, or you don't want the extra you don't want the extra you don't want the extra complexity, you can complexity, you can complexity, you can just just just use use use interfaces. Let interfaces. Let interfaces. Let module A reference module A reference module A reference an interface an interface an interface defined in defined in module B's public contract project, and module B's public contract project, and the implementation of that the implementation of that the implementation of that interface be interface be interface be inside module B— inside module B— that that that would work fine too. So, what does would work fine too. So, what does would work fine too. So, what does this look like in code?
-
this look like in code? If we If we use the use the use the mediator approach, it mediator approach, it mediator approach, it might look might look might look something like this: something like this: something like this: inside the inside the inside the cart module, I create a cart module, I create a cart module, I create a create create create order command, since order command, since order command, since I place an order I place an order I place an order in the cart, and this command in the cart, and this command in the cart, and this command is defined in the is defined in the is defined in the public contracts project of the public contracts project of the public contracts project of the orders module, and orders module, and orders module, and then I just then I just then I just send this command send this command send this command through the mediator. We didn't through the mediator. We didn't through the mediator. We didn't have time to consider a have time to consider a have time to consider a full comparison full comparison full comparison of microservices. Here is a of microservices. Here is a of microservices. Here is a quick summary of quick summary of quick summary of the differences between the differences between the differences between logically separated logically separated logically separated modules in a monolith modules in a monolith modules in a monolith and microservices. and microservices. Again, these are all Again, these are all trade-offs, so you trade-offs, so you trade-offs, so you are making some choices when are making some choices when are making some choices when making this decision, making this decision, making this decision, and you can see and you can see and you can see them here. But I want them here. But I want them here. But I want you to remember that we're you to remember that we're you to remember that we're comparing an comparing an comparing an architecture where architecture where architecture where everything is everything is everything is based on based on based on microservices from the start to an microservices from the start to an microservices from the start to an architecture where everything is architecture where everything is architecture where everything is based on modules, based on modules, based on modules, and there's no reason and there's no reason why you can't why you can't why you can't have a modular have a modular have a modular monolith. And then, when monolith. And then, when monolith. And then, when you realize that this you realize that this you realize that this particular module particular module particular module makes sense to move to a makes sense to move to a makes sense to move to a microservice, you microservice, you microservice, you can always can always can always do it later do it later do it later by configuring by configuring by configuring the interaction of other the interaction of other the interaction of other modules with this modules with this modules with this microservice via microservice via microservice via public contracts— public contracts— and everything will work.
-
and everything will work. So when we So when we suggest suggest suggest using using using modules first, we are not saying modules first, we are not saying modules first, we are not saying that microservices that microservices that microservices cannot be used at all cannot be used at all cannot be used at all . It's . It's . It's just that the transition to just that the transition to just that the transition to microservices becomes microservices becomes microservices becomes easier when you already easier when you already easier when you already have modularity. Okay, have modularity. Okay, have modularity. Okay, let's look let's look let's look at the structure of the solution. at the structure of the solution. at the structure of the solution. Here is an example of a project Here is an example of a project Here is an example of a project called River Books, called River Books, called River Books, which I covered in which I covered in which I covered in my course on my course on my course on modular monoliths on modular monoliths on modular monoliths on Dome Train. It has five Dome Train. It has five Dome Train. It has five modules located in modules located in modules located in solution folders. If solution folders. If solution folders. If you look at you look at you look at the web project, you can the web project, you can the web project, you can see that it is very see that it is very see that it is very thin. There is thin. There is thin. There is practically practically practically nothing in it. There's only program.cs nothing in it. There's only program.cs nothing in it. There's only program.cs and some middleware and some middleware and some middleware for example. Oh, and it's for example. Oh, and it's for example. Oh, and it's just just just used to used to used to load other load other load other modules. By " modules. By " loading" I loading" I loading" I mean the code that mean the code that mean the code that runs when the runs when the runs when the web application starts web application starts web application starts to connect and to connect and to connect and register everything register everything register everything needed for needed for needed for each module. Um, and each module. Um, and each module. Um, and each module owns each module owns each module owns this code, right? So, this code, right? So, this code, right? So, it does its own it does its own it does its own loading. Um, and loading. Um, and loading. Um, and everything inside the everything inside the everything inside the books module is mostly books module is mostly books module is mostly internal, but that internal, but that internal, but that public public public contracts project contains the contracts project contains the contracts project contains the public interface public interface public interface that is that is that is used.
-
used. So, at this point, I'll So, at this point, I'll hand it over to Eric, hand it over to Eric, hand it over to Eric, and we'll show and we'll show and we'll show him his screen for a moment. him his screen for a moment. Yes. So, along with the Yes. So, along with the modular monolith, modular monolith, modular monolith, Rider gives us really Rider gives us really Rider gives us really useful tools useful tools useful tools to explore the to explore the to explore the modular monolith modular monolith modular monolith and how its boundaries and how its boundaries and how its boundaries work in practice. work in practice. work in practice. Um, one of them is the Um, one of them is the Um, one of them is the built-in built-in built-in representation of representation of representation of the architecture. Um, in Rider you the architecture. Um, in Rider you the architecture. Um, in Rider you can find it in the can find it in the can find it in the main menu: " main menu: " tools", " tools", " architecture", and then architecture", and then architecture", and then select "show select "show project dependency diagram". By project dependency diagram". By default, this default, this default, this shows dependencies shows dependencies shows dependencies for the entire solution, for the entire solution, for the entire solution, but for a smaller but for a smaller but for a smaller example, we'll narrow example, we'll narrow example, we'll narrow this down to the books module and the this down to the books module and the this down to the books module and the users module. So I can users module. So I can users module. So I can just uncheck that just uncheck that just uncheck that box. Select the box. Select the box. Select the books implementation, the books implementation, the books implementation, the books contracts, and then the books contracts, and then the books contracts, and then the users implementation. So, right users implementation. So, right users implementation. So, right now Rider first now Rider first now Rider first groups these projects by groups these projects by groups these projects by solution folders, so solution folders, so solution folders, so we only see an overview we only see an overview we only see an overview at the module level. And what at the module level. And what at the module level. And what Rider allows you to do is Rider allows you to do is Rider allows you to do is double-click on these double-click on these double-click on these blocks to see the blocks to see the blocks to see the individual projects and individual projects and individual projects and see exactly where see exactly where see exactly where these dependencies go.
-
these dependencies go. So I can double- So I can double- click on them, and we click on them, and we click on them, and we can see that the can see that the can see that the users implementation from the users module users implementation from the users module users implementation from the users module only references the only references the only references the books contracts. It does not books contracts. It does not books contracts. It does not reference reference reference the implementation of books. This is the the implementation of books. This is the the implementation of books. This is the encapsulation that encapsulation that encapsulation that Steve was just talking about, Steve was just talking about, Steve was just talking about, at the module level. So, at the module level. So, at the module level. So, users knows what to users knows what to users knows what to ask books, ask books, ask books, while books hides the while books hides the while books hides the implementation details behind a implementation details behind a implementation details behind a contract. contract. This is really useful, This is really useful, but can we but can we but can we see exactly where we are see exactly where we are see exactly where we are referencing things from the referencing things from the referencing things from the calling module? calling module? calling module? Yes, actually in Rider, Yes, actually in Rider, Yes, actually in Rider, in this diagram, you can in this diagram, you can in this diagram, you can right-click right-click right-click on one on one on one of the modules and select of the modules and select of the modules and select "enable "enable "enable connectivity analysis." This will connectivity analysis." This will connectivity analysis." This will allow us to just allow us to just allow us to just click on this click on this click on this arrow, and it will show arrow, and it will show arrow, and it will show where where where these these these dependencies actually occur. That is, from dependencies actually occur. That is, from dependencies actually occur. That is, from the implementation of users to the implementation of users to the implementation of users to the contracts of books, where the contracts of books, where the contracts of books, where they are consumed. You they are consumed. You they are consumed. You can see in this can see in this can see in this example that we example that we example that we are in the are in the are in the users module, and it is referenced users module, and it is referenced users module, and it is referenced in in in this this this add to add to add to cart handler. So, this cart handler. So, this cart handler. So, this uses mediator.
-
uses mediator. uses mediator. So, for the So, for the So, for the user module to be able user module to be able user module to be able to add an item to the cart, it to add an item to the cart, it to add an item to the cart, it needs details needs details needs details about the book, right? So, it about the book, right? So, it about the book, right? So, it needs a name needs a name needs a name and a price. So it and a price. So it and a price. So it uses this uses this uses this request for the book details request for the book details request for the book details and then uses and then uses and then uses the response to the response to the response to populate the item in populate the item in populate the item in the cart. So, this the cart. So, this the cart. So, this uses mediator. As uses mediator. As uses mediator. As we said before, we said before, we said before, you don't have to you don't have to you don't have to use mediator use mediator . It could be, you know, . It could be, you know, . It could be, you know, some kind of service and some kind of service and some kind of service and interfaces. So if interfaces. So if interfaces. So if you notice, this doesn't you notice, this doesn't you notice, this doesn't access the access the access the book database or book database or book database or use the use the use the internal entity of the internal entity of the internal entity of the book. This goes book. This goes book. This goes through contracts. To through contracts. To through contracts. To see this a little see this a little see this a little better, we can better, we can better, we can review the essence of the review the essence of the review the essence of the book. You'll notice that book. You'll notice that book. You'll notice that Steve mentioned Steve mentioned Steve mentioned using using using inner classes. This is the inner classes. This is the inner classes. This is the books module, this is the books module, this is the books module, this is the inner class of inner class of inner class of this module, and this is the this module, and this is the this module, and this is the database entity. database entity. We can We can review the review the review the usage of the usage of the usage of the book entity to book entity to book entity to confirm that confirm that confirm that it is the one it is the one it is the one being used for the being used for the being used for the database and database and database and remains remains remains within the books module only. The within the books module only. The within the books module only. The test project has test project has test project has access to it so we access to it so we access to it so we can write tests, can write tests, can write tests, but it remains but it remains but it remains only within the only within the only within the books module. We see that books module. We see that books module. We see that the dependency diagram the dependency diagram the dependency diagram shows these shows these shows these module boundaries, and the module boundaries, and the module boundaries, and the usage view allows us usage view allows us usage view allows us to drill down into these boundaries to drill down into these boundaries . Another cool thing about . Another cool thing about . Another cool thing about Rider for modular Rider for modular Rider for modular monoliths is the monoliths is the monoliths is the creation of so-called creation of so-called creation of so-called solution filters.
-
solution filters. Imagine that the application Imagine that the application has grown, we have dozens of has grown, we have dozens of has grown, we have dozens of modules, different modules, different modules, different teams are responsible teams are responsible teams are responsible for different areas. for different areas. for different areas. Let's stay with the Let's stay with the Let's stay with the same example: my same example: my same example: my team is responsible team is responsible team is responsible for the books module and the for the books module and the for the books module and the users module. users module. So I'm going to So I'm going to unload all unload all unload all the projects in the solution, the projects in the solution, the projects in the solution, since I'll remove since I'll remove since I'll remove more than I'll leave, and more than I'll leave, and more than I'll leave, and then add only the then add only the then add only the modules and projects modules and projects modules and projects that I need. that I need. So, the implementation of books , book contracts, and I , book contracts, and I , book contracts, and I know that for this know that for this know that for this example, the users module example, the users module needs a reference needs a reference to the contract. So I to the contract. So I to the contract. So I only add contracts only add contracts only add contracts from these other modules. I am from these other modules. I am from these other modules. I am not adding their not adding their not adding their implementations. We implementations. We implementations. We don't need a don't need a don't need a reporting module for reporting module for reporting module for our work at all. I'm adding a our work at all. I'm adding a our work at all. I'm adding a user module user module user module and a shared kernel. And I'll and a shared kernel. And I'll and a shared kernel. And I'll just upload these just upload these just upload these projects back. When projects back. When projects back. When they are loaded, you they are loaded, you they are loaded, you see 16 projects, see 16 projects, see 16 projects, nine are unloaded.
-
nine are unloaded. nine are unloaded. I'll just keep this I'll just keep this I'll just keep this as a solution filter. as a solution filter. as a solution filter. So, we can So, we can So, we can click "Save" click "Save" . You will be asked if . You will be asked if . You will be asked if you want to open you want to open you want to open it immediately. Of course, it immediately. Of course, it immediately. Of course, why not? So this is a why not? So this is a why not? So this is a filtered filtered filtered solution, and you see solution, and you see solution, and you see here: 16 projects, 9 here: 16 projects, 9 here: 16 projects, 9 filtered. We filtered. We filtered. We can expand this can expand this can expand this and see that Rider and see that Rider and see that Rider shows us useful shows us useful shows us useful information: in these information: in these information: in these modules we modules we modules we skipped some skipped some skipped some projects because projects because we don't we don't necessarily need them for our daily work. necessarily need them for our daily work. You will also notice that You will also notice that we did we did we did not need to connect the reporting module at all not need to connect the reporting module at all not need to connect the reporting module at all . So . So . So it is completely it is completely it is completely filtered. These filtered. These filtered. These solution filters are very solution filters are very solution filters are very convenient because they convenient because they convenient because they simply create an simply create an simply create an SLNF file. You can SLNF file. You can SLNF file. You can add them to your add them to your add them to your version control system and your version control system and your version control system and your team can team can team can use them without any use them without any use them without any problems. You can problems. You can problems. You can create many create many create many different combinations. different combinations. different combinations. I find them very I find them very I find them very useful because I can useful because I can useful because I can limit my work limit my work limit my work to only what to only what to only what interests me, and the main interests me, and the main interests me, and the main solution can be solution can be solution can be kept open in kept open in kept open in another window if you another window if you another window if you want to run the want to run the want to run the full web application full web application full web application to perform to perform to perform end-to-end tests with end-to-end tests with end-to-end tests with all loaded all loaded all loaded modules. You modules. You modules. You can also just can also just can also just open the CLI, open the CLI, open the CLI, start Aspire from the start Aspire from the start Aspire from the command line, and command line, and command line, and get going. Rider get going. Rider get going. Rider gives us some really gives us some really gives us some really cool tools cool tools cool tools that work great with that work great with that work great with modular modular modular monoliths.
-
monoliths. monoliths. The architectural The architectural The architectural diagram helps diagram helps diagram helps you understand the boundaries of you understand the boundaries of you understand the boundaries of the modules, and the the modules, and the the modules, and the usage finder usage finder usage finder lets you drill down lets you drill down lets you drill down and see and see how everything interacts from a how everything interacts from a how everything interacts from a code perspective. And code perspective. And code perspective. And solution filters solution filters solution filters allow you allow you allow you to focus your to focus your to focus your workspace on only the workspace on only the workspace on only the parts that matter parts that matter parts that matter to you in a large to you in a large to you in a large modular monolith. modular monolith. modular monolith. Perfectly. Well, let's Perfectly. Well, let's Perfectly. Well, let's sum up. sum up. sum up. Can we quickly Can we quickly Can we quickly go back to go back to go back to the slides? We're almost the slides? We're almost the slides? We're almost out of time. If out of time. If out of time. If you want to learn you want to learn you want to learn more about RiverBooks, you more about RiverBooks, you more about RiverBooks, you can find it at can find it at can find it at riverbooks.ardalis.com. There is riverbooks.ardalis.com. There is riverbooks.ardalis.com. There is documentation and a documentation and a documentation and a link to GitHub. link to GitHub. link to GitHub. Brief summary: Brief summary: Brief summary: monoliths often monoliths often monoliths often lack logical lack logical lack logical separation. You separation. You separation. You get "huge get "huge get "huge piles of dirt" and piles of dirt" and piles of dirt" and spaghetti code. Layers spaghetti code. Layers are a good start, are a good start, are a good start, but they are not enough, and but they are not enough, and but they are not enough, and microservices can microservices can microservices can be overkill. So be overkill. So be overkill. So using something using something using something in between in between in between provides a more provides a more provides a more balanced, so- balanced, so- balanced, so- called "golden" called "golden" called "golden" solution. If you solution. If you solution. If you want to learn want to learn want to learn more in a more in a more in a course format, I have a course format, I have a course format, I have a selection of selection of selection of modular monolith courses modular monolith courses modular monolith courses on Don't Train and you can on Don't Train and you can on Don't Train and you can get 20% off get 20% off get 20% off if you use the if you use the if you use the code Ardalis. And, of course, code Ardalis. And, of course, code Ardalis. And, of course, NimblePros, our company, NimblePros, our company, NimblePros, our company, constantly provides constantly provides constantly provides a lot of training and a lot of training and a lot of training and helps customers helps customers helps customers transition to this and transition to this and transition to this and other architectures. So other architectures. So other architectures. So reach out if you reach out if you reach out if you need help. That's all we have need help. That's all we have need help. That's all we have .
-
. . Let's see if there are any Let's see if there are any Let's see if there are any questions. questions. questions. I would really like I would really like I would really like you to have a full hour you to have a full hour , friends. , friends. , friends. Me too. Me too. Me too. So, the only question So, the only question So, the only question we're we're we're going to ask now is, you know, going to ask now is, you know, going to ask now is, you know, why are microservices why are microservices why are microservices so bad, and we'll let so bad, and we'll let so bad, and we'll let you fill the rest of the you fill the rest of the you fill the rest of the time with the answer to time with the answer to time with the answer to that. But no, it's a great that. But no, it's a great that. But no, it's a great topic. Thank you very much. You topic. Thank you very much. You used the used the Rider toolkit very well. Rider toolkit very well. Rider toolkit very well. Actually, I wouldn't Actually, I wouldn't Actually, I wouldn't necessarily necessarily necessarily have guessed to have guessed to have guessed to do that, although it's a do that, although it's a do that, although it's a really good really good really good use case for the use case for the use case for the solution, the filters are solution, the filters are solution, the filters are great there. And great there. And great there. And yes, yes, yes, project dependency diagrams are really project dependency diagrams are really project dependency diagrams are really cool. cool. cool. This is another feature that This is another feature that This is another feature that someone mentioned, someone mentioned, someone mentioned, there's just so much going on there's just so much going on there's just so much going on that you forget about it that you forget about it that you forget about it . . . Honestly, I don't even Honestly, I don't even Honestly, I don't even remember the remember the remember the last time last time last time I used a I used a project dependency diagram. project dependency diagram. Yes, no, it's really Yes, no, it's really Yes, no, it's really nice. nice. nice. Yes, and it can be Yes, and it can be Yes, and it can be useful for finding useful for finding useful for finding dependencies that dependencies that dependencies that you may not have known about you may not have known about you may not have known about and that shouldn't and that shouldn't and that shouldn't be there. And this will help be there. And this will help be there. And this will help organize everything to organize everything to organize everything to get rid of unnecessary get rid of unnecessary get rid of unnecessary dependencies. dependencies. dependencies. Yes, that's right. So, Yes, that's right. So, Yes, that's right. So, again, it's a slightly again, it's a slightly again, it's a slightly different way of different way of different way of using using using tools than you tools than you tools than you normally would, but it normally would, but it normally would, but it actually helps actually helps actually helps you stick to you stick to you stick to the architecture and the architecture and the architecture and make sure make sure make sure it's appropriate.
-
it's appropriate. it's appropriate. I also had a I also had a I also had a question about this. question about this. question about this. Something like this Something like this . You mentioned the . You mentioned the . You mentioned the division into teams. And it division into teams. And it division into teams. And it got me got me got me thinking about how much thinking about how much thinking about how much architecture is architecture is architecture is related to processes related to processes related to processes and working with your and working with your and working with your teams. So if teams. So if teams. So if you want something to be you want something to be you want something to be able to be able to be able to be shared across shared across shared across teams, you want teams, you want teams, you want the team to not only the team to not only the team to not only understand the architecture understand the architecture , but also adhere to it , but also adhere to it , but also adhere to it and conform to it. and conform to it. So, do they So, do they ultimately shape each other? ultimately shape each other? I think so. This works I think so. This works better if there is better if there is better if there is a monorepository, for a monorepository, for a monorepository, for obvious reasons, when obvious reasons, when obvious reasons, when working with a monolith. And that working with a monolith. And that working with a monolith. And that 's why all teams 's why all teams 's why all teams usually commit to the same usually commit to the same usually commit to the same Git Git repository. And with that, repository. And with that, repository. And with that, you know, if you you know, if you you know, if you can set up can set up can set up continuous continuous continuous deployment and deployment and deployment and continuous delivery continuous delivery , that helps. And as a , that helps. And as a , that helps. And as a prerequisite for this, it's prerequisite for this, it's prerequisite for this, it's usually a good idea to have usually a good idea to have usually a good idea to have some type of some type of feature flags so that you can feature flags so that you can commit and commit and commit and push changes frequently, even push changes frequently, even push changes frequently, even if they're not yet if they're not yet if they're not yet complete. And then of complete. And then of complete. And then of course in your course in your course in your CI process you CI process you CI process you need to need to need to make sure make sure make sure you have lots of you have lots of you have lots of automated automated automated tests so that nothing tests so that nothing tests so that nothing goes into goes into goes into production if it production if it production if it breaks something. So, all of breaks something. So, all of breaks something. So, all of this points to a this points to a this points to a process you'll process you'll process you'll have to have to have to set up, set up, set up, right? That is, there must be a right? That is, there must be a right? That is, there must be a certain level of certain level of certain level of maturity not only in maturity not only in maturity not only in development, but also in DevOps and development, but also in DevOps and development, but also in DevOps and in the way the in the way the in the way the team works, for team works, for team works, for all of this to really all of this to really all of this to really work at full work at full work at full capacity. But you capacity. But you capacity. But you can get can get can get benefits even if benefits even if benefits even if your team your team your team consists of one consists of one consists of one person and you just person and you just person and you just want to
-
want to want to organize your organize your organize your code a little better, some of these code a little better, some of these code a little better, some of these principles principles principles will still be useful. will still be useful. will still be useful. Mhm. Yes, that's how I Mhm. Yes, that's how I Mhm. Yes, that's how I usually think of usually think of usually think of architecture, as architecture, as architecture, as working with code, but it working with code, but it working with code, but it strikes me that it strikes me that it strikes me that it also impacts how also impacts how also impacts how teams work and teams work and teams work and interact with each interact with each interact with each other. Especially if other. Especially if other. Especially if you, as the module owner, you, as the module owner, you, as the module owner, want to refer to want to refer to want to refer to another module. another module. For example, you have to For example, you have to implement it, but implement it, but implement it, but organize organize organize communication with another communication with another communication with another team. team. team. The contracts are already there, you The contracts are already there, you The contracts are already there, you can can can use them. If use them. If use them. If you need a you need a you need a contract that doesn't yet contract that doesn't yet contract that doesn't yet exist, then you will exist, then you will exist, then you will have to have to have to coordinate your coordinate your coordinate your actions with another team. Just like actions with another team. Just like actions with another team. Just like if you were if you were if you were using using using microservices, you would need to microservices, you would need to coordinate everything with coordinate everything with the team that owns the team that owns the team that owns that microservice and that microservice and that microservice and say, "Hey, we say, "Hey, we say, "Hey, we need a way need a way need a way to do this." You know, to do this." You know, to do this." You know, can you provide that for us can you provide that for us can you provide that for us ? ? ? Mhm. Yes. Yes. I have an Mhm. Yes. Yes. I have an interesting interesting question from the chat from question from the chat from question from the chat from Daniel. The name Daniel. The name Daniel. The name looks familiar. looks familiar. looks familiar. Assuming my Assuming my Assuming my modules need to modules need to modules need to exchange data exchange data exchange data with each other, what with each other, what with each other, what patterns would you recommend patterns would you recommend patterns would you recommend to ensure to ensure to ensure consistency? This consistency? This consistency? This applies, applies, applies, for example, for example, for example, to database transactions to database transactions to database transactions .
-
. Yes, ideally, if Yes, ideally, if you need you need you need atomic transactions, atomic transactions, atomic transactions, they should they should they should be be be inside a single inside a single inside a single module. And if you module. And if you module. And if you can live with can live with can live with finite finite finite consistency, then you consistency, then you consistency, then you can have can have can have intermodule intermodule intermodule communication, communication, communication, right? If you want to right? If you want to right? If you want to make sure, make sure, make sure, for example, that your for example, that your for example, that your module remains module remains module remains operational operational operational even if a dependent even if a dependent even if a dependent module is somehow module is somehow module is somehow unavailable—which is not unavailable—which is not unavailable—which is not often the case often the case often the case in a modular in a modular in a modular monolith, as monolith, as monolith, as usually if something usually if something usually if something goes wrong, the goes wrong, the goes wrong, the entire monolith goes down— entire monolith goes down— you can still you can still you can still achieve this achieve this achieve this using various using various using various patterns, such as a patterns, such as a patterns, such as a materialized materialized materialized view. This view. This view. This can also help can also help can also help with performance with performance with performance when your module has when your module has when your module has its own copy of the data its own copy of the data its own copy of the data it constantly it constantly it constantly needs. So instead of needs. So instead of needs. So instead of constantly constantly constantly accessing another accessing another accessing another module for some module for some module for some piece of data, it piece of data, it piece of data, it simply uses simply uses simply uses its internal its internal its internal version. And the patterns that version. And the patterns that version. And the patterns that you would use you would use you would use in microservices, in microservices, like materialized like materialized like materialized views, views, views, asynchronous asynchronous asynchronous communication, the communication, the outbox pattern, things like that, you outbox pattern, things like that, you can can can use them in a use them in a use them in a modular monolith.
-
modular monolith. modular monolith. And I show all these And I show all these And I show all these things in my things in my things in my Domain Driven Design courses as well. Domain Driven Design courses as well. No, I'm not showing all No, I'm not showing all the templates, but I'm the templates, but I'm the templates, but I'm showing the ones I showing the ones I showing the ones I just mentioned in the just mentioned in the just mentioned in the Domain Driven Design course. Domain Driven Design course. Domain Driven Design course. Yes. Um, I was Yes. Um, I was Yes. Um, I was wondering about the wondering about the wondering about the mediator mediator mediator you were talking about: what exactly do you were talking about: what exactly do you were talking about: what exactly do you use as you use as you use as this this this mediator? mediator? mediator? Uh, what kind of Uh, what kind of Uh, what kind of implementation? implementation? implementation? Yes. Yes. Yes. It could be your It could be your It could be your own development, it own development, it own development, it could be the could be the could be the MediatR library from Jimmy MediatR library from Jimmy MediatR library from Jimmy Bogard, which is now Bogard, which is now Bogard, which is now commercial, or it could commercial, or it could commercial, or it could be another be another be another generated generated generated library library library called Mediator, written called Mediator, written called Mediator, written exactly as you exactly as you exactly as you expect. And, you know, expect. And, you know, expect. And, you know, each of them has its each of them has its each of them has its pros and cons. They have pros and cons. They have pros and cons. They have slightly different functions and slightly different functions and slightly different functions and characteristics, but characteristics, but characteristics, but it's simply a means to it's simply a means to it's simply a means to allow you allow you allow you to depend on the to depend on the to depend on the mediator library mediator library mediator library and message types and message types and message types rather than directly on rather than directly on rather than directly on another another another module's service. What I like most about module's service. What I like most about module's service. What I like most about this approach is this approach is this approach is that, as that, as that, as I mentioned, you I mentioned, you I mentioned, you can configure a can configure a middleware pipeline for it.
-
middleware pipeline for it. So every time I So every time I So every time I call mediator.send command, call mediator.send command, call mediator.send command, I will validate that I will validate that I will validate that command. I'll wrap it command. I'll wrap it command. I'll wrap it in a try-catch block. I will add in a try-catch block. I will add in a try-catch block. I will add logging. If logging. If logging. If an exception occurs, I an exception occurs, I an exception occurs, I will write the details of will write the details of will write the details of the exception to the log. And so the exception to the log. And so the exception to the log. And so much of the boilerplate much of the boilerplate much of the boilerplate code that could be code that could be code that could be in a service method or a in a service method or a message handler— validation checking validation checking , start , start , start and end logging, and end logging, and end logging, execution time measurements, execution time measurements, execution time measurements, OpenTelemetry setup, OpenTelemetry setup, OpenTelemetry setup, and other things—is all being and other things—is all being and other things—is all being simplified. All of this is simplified. All of this is simplified. All of this is being ported to being ported to being ported to individual middleware elements individual middleware elements that are that are now now now standardized across the standardized across the standardized across the entire application. entire application. Um, yes, yes. I didn't Um, yes, yes. I didn't quite understand what quite understand what quite understand what exactly you exactly you exactly you used for used for used for the implementation, whether it was a the implementation, whether it was a the implementation, whether it was a mediator, well, you know, mediator, well, you know, mediator, well, you know, as you say, a as you say, a as you say, a specific package, or whether specific package, or whether specific package, or whether it was something it was something it was something like a like a like a conceptual conceptual conceptual mediator. mediator. mediator. This, this is whatever you want This, this is whatever you want This, this is whatever you want . . . Yes. This, this is cool. Yes. This, this is cool. Yes. This, this is cool. Matthias, do you have any more Matthias, do you have any more Matthias, do you have any more questions? questions? questions? Um, I, I just want to Um, I, I just want to Um, I, I just want to say, well, say, well, say, well, I have a question. Me, I'm I have a question. Me, I'm I have a question. Me, I'm pretty far from that pretty far from that pretty far from that kind of software development kind of software development . I . I was doing this about 15 years was doing this about 15 years was doing this about 15 years ago, and I really wish I had ago, and I really wish I had ago, and I really wish I had seen seen seen it when I was working at it when I was working at it when I was working at that company at the that company at the that company at the time. But, just time. But, just time. But, just off the top of my head, I'd be off the top of my head, I'd be off the top of my head, I'd be really interested really interested really interested to know how many to know how many to know how many examples of each of examples of each of examples of each of these you've seen, these you've seen, these you've seen, like like microservices architecture, and microservices architecture, and how many times has it how many times has it how many times has it actually worked? And actually worked? And actually worked? And how many times have you how many times have you how many times have you used this used this used this modular architecture modular architecture ?
-
? This is mostly my default choice for default choice for new applications that new applications that new applications that will be quite will be quite will be quite complex and complex and complex and require require require multiple modules. And multiple modules. And multiple modules. And also for legacy also for legacy also for legacy systems that we're systems that we're systems that we're trying to trying to trying to migrate, like migrate, like migrate, like from .NET framework or to the cloud from .NET framework or to the cloud from .NET framework or to the cloud or, you know, something like that. or, you know, something like that. I've seen teams that go straight to microservices, and Eric and I were on a and Eric and I were on a and Eric and I were on a big big big project together about project together about project together about five to seven years ago, and it didn't five to seven years ago, and it didn't five to seven years ago, and it didn't end very end very end very well. This, this was well. This, this was well. This, this was n't really n't really n't really successful. So, there successful. So, there successful. So, there can certainly be can certainly be can certainly be problems problems problems when trying to when trying to when trying to implement implement implement microservices for microservices for microservices for everything from the everything from the everything from the beginning. Now, when beginning. Now, when beginning. Now, when you have certain you have certain you have certain modules, I've definitely modules, I've definitely modules, I've definitely seen many times seen many times seen many times where you can take a module where you can take a module where you can take a module and say, "This should and say, "This should and say, "This should be a microservice be a microservice be a microservice because, well, for certain because, well, for certain because, well, for certain reasons, because it reasons, because it reasons, because it needs to needs to needs to scale scale scale independently or independently or independently or something." And it's relatively something." And it's relatively something." And it's relatively easy to separate that out easy to separate that out easy to separate that out when it's already a when it's already a when it's already a module. So, as for module. So, as for module. So, as for the numbers, I, I don't know.
-
the numbers, I, I don't know. Personally, for me, these are Personally, for me, these are single-digit numbers for single-digit numbers for single-digit numbers for each option, but each option, but each option, but I have definitely seen a higher I have definitely seen a higher I have definitely seen a higher level of success with this level of success with this level of success with this approach than just a approach than just a approach than just a full migration to full migration to full migration to microservices from a microservices from a microservices from a legacy application. legacy application. Yes, the initial stage, Yes, the initial stage, especially if you're especially if you're especially if you're starting a new starting a new starting a new project from scratch and project from scratch and project from scratch and trying to trying to trying to implement implement implement microservices right away, as microservices right away, as microservices right away, as we did in recent we did in recent we did in recent examples at Nimble Pros, it's examples at Nimble Pros, it's examples at Nimble Pros, it's much easier much easier much easier to start with a modular to start with a modular to start with a modular monolith and then, as monolith and then, as monolith and then, as Steve said, Steve said, Steve said, break it down break it down break it down later if later if later if needed. I don't needed. I don't needed. I don't think we've ever had a think we've ever had a think we've ever had a case where there was a case where there was a case where there was a real real real need to share need to share need to share such a project. So, such a project. So, such a project. So, of course, it can be of course, it can be of course, it can be done, but the done, but the done, but the performance gain will be performance gain will be performance gain will be minimal. But minimal. But minimal. But by starting as a by starting as a by starting as a modular monolith, you modular monolith, you modular monolith, you don't spend a ton of don't spend a ton of don't spend a ton of time fixing time fixing time fixing bugs in bugs in bugs in microservices. You don't microservices. You don't microservices. You don't have to have to have to redo everything redo everything redo everything , and in a , and in a , and in a modular monolith it's modular monolith it's modular monolith it's much easier much easier much easier to build the architecture to build the architecture to build the architecture from scratch. from scratch.
-
Ugh. For me, the most Ugh. For me, the most interesting thing, what I interesting thing, what I interesting thing, what I really liked really liked really liked and what I think is a great and what I think is a great and what I think is a great opportunity, is what opportunity, is what opportunity, is what Steve said about Steve said about Steve said about having separate having separate having separate databases for databases for databases for each module. each module. Yes. Yes. That sounds really That sounds really That sounds really interesting. Ugh. interesting. Ugh. interesting. Ugh. Yes. Yes. Yes. This used to be This used to be This used to be much more difficult much more difficult much more difficult to implement 10 to implement 10 to implement 10 or 15 years ago, when or 15 years ago, when or 15 years ago, when most most most organizations had organizations had organizations had only one database only one database only one database for the entire company, which was the for the entire company, which was the for the entire company, which was the responsibility of a responsibility of a responsibility of a separate team or separate team or separate team or person. But now it's person. But now it's person. But now it's much easier to much easier to much easier to deploy deploy deploy databases for each databases for each databases for each individual task, and individual task, and individual task, and we have we have we have tools like Aspire tools like Aspire tools like Aspire where you can run where you can run where you can run any database any database any database or even multiple or even multiple or even multiple databases in containers databases in containers databases in containers right on your right on your right on your desktop. desktop. desktop. Building Building Building these types of these types of these types of applications is much applications is much applications is much easier today than it was 10 or 15 easier today than it was 10 or 15 easier today than it was 10 or 15 years ago, that's for sure. years ago, that's for sure. Yes. Steeply. Well, Yes. Steeply. Well, thank you for your thank you for your thank you for your session. Our time is almost session. Our time is almost session. Our time is almost up. up. up. Thank you very much. Very interesting, Thank you very much. Very interesting, Thank you very much. Very interesting, as they say: "Aspire all the as they say: "Aspire all the as they say: "Aspire all the things." Yes, I think that's exactly what things." Yes, I think that's exactly what things." Yes, I think that's exactly what we need to we need to we need to do. Yes, do. Yes, do. Yes, thank you very much for your session thank you very much for your session . There was a lot of very . There was a lot of very . There was a lot of very useful information there, useful information there, useful information there, and I think there's a lot to and I think there's a lot to and I think there's a lot to think about.
-
think about. think about. Thank you very much and Thank you very much and Thank you very much and we hope we hope we hope to see you again soon to see you again soon to see you again soon . . . Okay, thank you. Okay, thank you. Okay, thank you. Thank you.
No summary available yet.
View original episode ↗