Modular Monoliths in .NET with Steve Smith - podcast episode cover

Modular Monoliths in .NET with Steve Smith

Mar 07, 202451 min
--:--
--:--
Download Metacast podcast app
Listen to this episode in Metacast mobile app
Don't just listen to podcasts. Learn from them with transcripts, summaries, and chapters for every episode. Skim, search, and bookmark insights. Learn more

Episode description

Modular Monoliths strike the middle ground between monoliths and microservices! Carl and Richard talk to Steve Smith about his work striking a balance between the simplicity of a monolithic set of services and the complexity of breaking everything into microservices. Steve discusses the performance and simplicity advantages of monoliths and only breaking out services with specific needs into separate services. .NET has excellent tooling to help you evaluate, test, and manage your modular monoliths!

Transcript

How'd you like to listen to dot net rocks with no ads? Easy? Become a patron for just five dollars a month. You get access to a private RSS feed where all the shows have no ads. Twenty dollars a month. We'll get you that and a special dot net Rocks patron mug. Sign up now at Patreon dot dot NetRocks dot com. Hey, welcome back to dot net rocks. This is Carl Franklin and it's Richard Campbell. Steve Smith is with us. We'll be talking to him in a minute. But hey

man, how are you doing. I haven't talked to you in a while. Uh, you know, we had a burst of shows and now we've you know, caught back up, so it's time to get back to work again. And I happen to be in Mexico. So okay, coming coming to you from the Grand look at the Vedanta Resort. How's your bandwidth good enough? You know, everybodybody else is at the pool, you know, because they're on vacation, right, so hopefully it holds together. But I'm

recording locally. We'll be okay. All right, good, Well, let's start things off the right way with better no framework all right, all right, well Google is at it again, Yes they are. They now have this deep you know, Google Deep Mind, their AI thing, Yeah, the original, the original AI guys, the reason that Open AI was made. Yeah. So they have this Genie team, and they came out with Genie, which is a generative interactive environment creator. It's so no wishes,

yeah yeah, and you can't wish for more wishes. So we introduced Genie, a foundation world model trained from Internet videos that can generate an endless variety of playable action controllable worlds from synthetic images, photographs, and even sketches. So the idea is that you can sketch some things, or find some things, or just say, give me something that looks like this, and you can make side scrolling games, you know, like Mario Brothers kind of thing

awesome from them automatically. At least that's what I think it is. I haven't done it, and it looks like the Really the only application is sort of controlling and animating sprites and a background in a two D scrolling world. Perhaps, yeah, but to do it with regular text just means a whole lot of other people think they can be video games. Now. Yeah, well I'm not really sure if it's well, it's a text image generation model,

so you're right there. Yeah, but I don't know. I'm not really that much of a video game guy to think that this is something I want to look at now. But I also like the idea of just generating animations. Of course, we just recently had the announcement of Open AI Sorrow, which was more like thirty second generated video. Clearly we're on a path of exploring more capabilities with generative AI. Yes, we are fun fun So anyway, that's what I got know and learned it loves He was talking to

us Richard Campbell. Hey, I grabbed a comment off a show eighteen thirty one, the one we did with Steve back in February of last year twenty three, when we talked about clean architecture, because he's a clean kind of eye, and Ken had this comment by a year ago. He said, this is a great episode, but what about new Get Hell, I love they of putting things into new Get packages, but I can see it will

get out of hand as well. You know, only if you update them, Ken, Right, as long as you just leave it with the original bugs, everything will be fine. An example is asp asp dot version ing. It's a great asp dot net versioning package. But the new get libraries have changed, so now the developers could be making a bunch of changes to the new new get packages, but they did two months ago, and then

other developers would never get the new changes. Nothing against new Get. But it seems like anything you do in this monster programming world is not perfect. Yeah. True, it's just a question how difficult, right, And in the area of testing, because we talked about testing on that show too,

the world changes and developers still need to learn on the fly. Who is testing my Cobald world that I was running back in ninety four or inherited DELFI from in nineteen ninety or that four point six dot two And he says in two thousand, which you know was in two thousand, It was like twenty fourteen, twenty fifteen. What about the C plus plus code the nineties? What testing framework should I use? X unit? What about Java? You

know? Testing frameworks for everything? Ken case in point in the enterprise world. None of the programming world is perfect. I would include programming training as that as well, But without you guys doing this show, I'd be way more lost so thanks. Wow. Cool, that's very kind. Yeah, it's very kind, Thanks, Ken, miel No. I think it's an interesting problem. And you know, often these tools become an issue primarily because they've been successful. You know, if nobody was using new Get, it

were great. I remember in the early days of NEWGAT there was such a thing as new Get hell quite literally, and it was very hard to manage, just as it was to manage without Newgat. But then they quickly fixed things up and ever since it's been really great. I think. Yeah, I think Newgat's amazing. Packet managers always have their challenges, like that's not going to go away, especially with visual studio tooling. You know, you can just update everything, which can be a problem also, you know,

but at least you'll know which ones are the problem. Well, inevitably you'll know the most important thing, which is it is your fault. Yeah,

of course, yeah, yeah, I blame you all right. Ken, Thanks for thanks for your comment, and a copy of music Coba is on its way to you, and if you'd like a copy of music co buy, I write a comment on the website at don at Ross dot comma on the facebooks you publish every show there and if you comment there and a reading on the show, we'll send your copy of music Coba and you can follow us on the twitters or the exes or whatever the hell is today. But

that's all cool. But we've been there for a long time. The cool kids are hanging out on Macedon. I'm at Carl Franklin at tech Hubsocial and I'm Rich Campbell at macedon dot social and send us a two and for all the ways you can attact me anyway, you can find that at Carlfranklin dot com. All right, let's get into this conversation with Steve Smith. Will bring him back. I probably don't need to introduce him, but I will

anyway. Steve, otherwise known as our Dallas on all the social networks, is an entrepreneur and software developer where they passion for building quality software as effectively as possible. He provides mentoring and training workshops for teams with the desire to improve. Steve has been recognized as a Microsoft MVP for over ten consecutive years and as a frequent speaker at software developer conferences and events. He enjoys helping

others write maintainable, testable applications using Microsoft's developer tools. Steve has just published a zero to hero course on modular monoliths at dometrain dot com, and you can connect him with him at Steve at our Dallas dot com. Welcome back, See hey Carl, he Richard. How's it going all as well? Friend? Well, I'm not in Mexico, so I don't know where you are, Steve. But Richard and I were just talking that it's the same

temperature in Mexico and Ohio. It's twenty eight degrees right, Ah, okay, you know one celsius and one is appearan something like that. I like mine better. Yeah, just saying right. So we did recently did a show on the you know, the monolith, the modular monolith. Yeah, Leila Porter but yeah, that's right with Leila. But it was not really dot net centric, and we thought we'd bring you back to, you know,

give us the dot net developers perspective on modular monoliths. So what you been thinking about, Buddy, Well, the focus of the industry for the last five or maybe ten years even has been on micro services and how micro services are the end all be all. And what I've found is that a lot of teams take their existing monolithic code that's that usually doesn't have a lot

of modularity to it. You know, generally everything is is kind of in a big ball of mud, and they don't know what to do to fix that, and it keeps getting worse over time, and so you know, micro services is right, there is this shiny new toy that if nothing else, will improve their resume. And they're like, you know, if we had these separate micro services, they couldn't possibly be tightly coupled with one another

because they're supposed to be independent. So they convince their their their boss, their their job, whatever, that that's the way to go as a means of you know, following the buzz and getting the other benefits of micro services, like you know, independence and you know, separate scalability of individual services. So I got a question, how does giant ball of mud one talk to giant ball of mud two that because that seems to be the fundamental problem,

doesn't it that that can be an issue between micro services? Yes, but it's like this this fundamental thing where the teams I've seen, not MYI it's necessarily but just like social media and folks I talk to a conference is like almost two of every one of them. They are, you know, thinking that moving to the micro service approach solves the problem of lack of modularity in their monolith, right, And if you do it right, it certainly

does. But it introduces a whole lot of additional problems because now you're dealing with a distributed application, and you know, rather than trying to figure out how to introduce modularity into your code and become experts at you know, building and operating a distributed application, like, maybe you could just do those one step at a time, Yeah, and avoid the possibility of building a distributed monolith, which is what you get, Carl, if you have, you

know, these these two different things that are actually talking to each other as if they were still in process, right, but now they're distributed. Yeah, exactly. And it seems a little sarcastic. I'm just saying I had a problem. I used microservices, and now I have multiple problems that talk to each that can't talk to each other. Yeah. Yeah, there's there's an image out there, a meme that, you know, the Pooh emoji. As like before I had my big monolith at a giant Pooh emogi and

now I've got micro services a dozen pooh emojis. It just multiplied. Yeah, but this seems like, you know, once upon a time it was service oriented architectures, right, I think that microservices was going to fix Like, are we just going through an oscillation here? Yeah? Yeah, microservices grew grew out of that. The thing is is it's not a bad pattern, right, I mean too big basically a single responsibility idea among different silos.

But then you know, you can take that, you can do that all within a single project and still have separation and still only update one DLL at a time, if you know, just if you're using DLLs, but one little bit of it at a time, and still get all the benefits of that, but without the complexity of this huge distributed mess. That's right, that a lot of people don't understand. There's a bunch of reasons why folks move toward micro services, and some of it's because they want that independent

scalability. Some of it's because they see that, you know, the Amazons and Netflixes and whatever are using it, and and folks say, hey, if that big successful company is using this pattern, I have to use that pattern so I can become big and successful It's like, that's not really how it works. And you ask him, how many customers do you have, oh, one hundred two hundred yeah, ok, yeah, do you need infinite scale on your you know, one feature of your of your application?

Maybe not? Yeah, So you know there's there's that issue. And distributed applications are much harder, right, Like Martin Fowler's got an article from like twenty fourteen that basically says, if you're trying to build a micro services application, instead of building micro services, first, build a monolith. First, figure out how the design works, and then you know, split off individual micro services as and when and if it makes sense to do so. Right,

that's much less risky. There's fewer dragons. He's got an image with dragons. Sounds exactly like the usual scaling issues, right, It's like, we've got to build the site scalable. It's like, well, what parts need to be scaled? Right? Yeah? And sometimes for you know, medium sized to large organizations, part of what they need to scale is their

teams. Right. They've got an application that's so big that they're trying to put multiple teams working on it, and they're running into a Conway's Law problem and they're hoping to fix that with micro services. But you can build modular

monoliths and have multiple teams collaborating just fine. Also, it's just a matter of how you structure your solution and break those things up when I think that's something that Lailah brought up as well, which is like Conway's loss certainly applies to micro services and the idea being that all software reflects the team that's built it. So it's like, if you're building an app with three different teams, you're gonna have three feature sets, right, So you know, whatever

points was. Unless you've got a team that large, why would you bother with micro services because they really come down to granular elements that can be worked on simultaneously hopefully. So if it's only if it's only six people work on the thing in the first place, you're really creating a lot of plumbing for

no good reason. Yeah, it does. If you're building this modular monolith and you do determine that you know there is a bottleneck in one of your projects or you know one of your silos, you should probably know how to be ready to carve that off into its own service and communicate with it, not in process, but you know, through some other mechanism, whether it's

APIs or gRPC or however. So it's it's beneficial to you to figure that out and be at the ready to either generate the code around that or be able to do that and have experience with it before it becomes a problem, you think for sure. Yeah, and and like so in my course that I just finished, the starting point for most monoliths is a single project. If I'll do whatever console, ESPNT core, and that you almost always have

to start with a monolith in anything you're building. And in a typical you know, just monolithic application, it just never splits from there, right, it just grows and grows and grows. And you know, whether you're using MVC or raisor pages or whatever it might be in the dot net world, like you just keep adding them to that same project, and it just keeps

getting bigger. And if you have separation, like if you're following clean architecture and you have multiple projects, they aren't split vertically, they're not split per feature, they're split per technical concern. Right. I love clean architecture. We've talked about it here before. It's a great way to keep your domain

model from becoming tightly coupled to your database. But when you only have you know, primary projects of user interface, all your infrastructure concerns, and your domain model, you don't have any type of separation vertically between, like here's the the product's feature and here's the order's feature, and here's the customer's feature, right, and then all those things can talk to each other, and

so they do. And that's what makes it a tangled mess. At the domain model level, at the UI level, and all the way into the data model. It becomes very difficult to carve those out into a separate service that you'd want to split out for for whatever reason, because of performance or maybe security or data isolation, all kinds of reasons why you might want to split part of that out, And it's hard to do that if you don't have a plan for that going in. Ree've all Lowe talking about areas of

resonance. You know, basically the idea is that if I make a change here, does the whole app resonate with the change, like you have to go check for impacts everywhere, or if I make a change in this particular spot, there is everything directly related that the only thing that resonates. You know, if you're messing with payment systems, only payment system stuff is affected.

Right. Yeah. I was in the military, so I use the term blast radius, And you know when I break this, what all is into blast radius that I'm gonna have to say blast I usually measure the quality by meals that way. But I think that was here joke originally Richard deference to you. No, No, I think I think the ex military guy using blast radius has a whole other impact than I do. But yeah, the idea obviously is to limit the blast radius of certain types of changes.

Right. If it's something that should only affect, like how orders are processed, then you would hope that making that change doesn't require you to redeploy everything that has to do with you know, customers or you know, the search engine of the site or whatever it might be. Well, I'm just thinking in terms of merge conflicts, man, Like, yeah, okay, he was busy working over on payments here, and then somebody went and made some

changes to product, and now I have a merged conflict. Really like that that shouldn't happen, right, But you also have the problem of inner activity between all your projects, right, so one project might have references to two or three or four other projects. So now if that one project needs to go into a micro service, what do you do with the other ones? Are you? Are you now committed to splitting everything up and that just increases

complexity? Right? Yeah, well, even adding the modularity increases complexity of the whole solution. But the point of it, or one of the points of it, especially if you have a large team you're hoping that you can have different teams take on different modules, is that things become simpler in that module. So if you look at the whole solution, yeah, like your four project solution now has fifteen projects because you've broken it up into four modules.

But when you're working on just the order processing module, you still only care about two projects and you don't care about all the other modules. So your actual area of concern on a day to day basis is simpler. True, everybody has that shared project, right where all the things go, like models and all of those things. Yeah, oftentimes yes, and it might be shared or it might be a per module. You'll probably have both. You'll have some that are global and some that are per module. But like,

this is just a pattern like the modular monolith is a pattern. It's not a totally prescriptive thing. But the way I have built it and the way I show it to do in my course, is to have a single entry point, host, process or project. And so that's my ASPNT core project that enters in and it literally has nothing in it except program dot c s and appsettings dot Jason, and its job is to load the modules from

the other projects. And then a given module in the solution is basically just a solution folder, because we don't have better artifacts for that in dot NetWorld, at least at the moment. And inside of that solution folder, there's there's two or three additional projects. Right, there's the actual code for the module, which includes all of its UI and all of the domain model logic and however talks to a database, and then all the logic for it is

in there, and they're separated just in folders. Right, there's not you know, it's not a clean architecture thing with with separate projects in there. You know, all those different pieces are there, but they're just separated by folders. And the reason is that I want them all to be internal. I don't want other modules to be able to access those of compile times. I'm using the internal keyword heavily anywhere I can to keep that module locked down

and encapsulated. And then another project it'll have as tests because I like tests. Now, how the tests work against that project, Well, we can use the internals visible to attribute on the assembly to make it so the tests at least can get to those files. We encourage everybody listening to pause and rewind and listen at half speed because you just unloaded a whole bunch of pile

of wisdom there, Steve. Yeah, yeah, sorry, you might want to you might want to listen to a little slower, but but by all means continue at this pace because I think it's great. That's a consequence of listening to YouTube and podcasts at one and a half speed, as I think, like this is how people are supposed to talk, is like this fast. Yeah, yeah, yeah, but I mean just a whole bunch of stuff. You just you just gave us advice to do, you know,

using internal and the way that projects are scoped and solutions are scoped. So yeah, there's a lot to it, and it's a lot as we're obviously figuring out right now. It's a lot more complex than people think, even in a monolith, to be prepared, to be prepared to go, yeah, I mean to give it the initial structure. There is a little bit more complex, a little bit more work. It's really not that bad.

And probably like I've done with clean Architecture, I've published a template that you can install off of new get that's on getthub and you can just do a you know, dot that new clean arc and it gives you the solution all set up. I'll probably do something similar for modular monoliths. I just haven't gotten there yet. But once you have it set up, like adding another module is pretty straightforward. It's like add a solution folder, add these two

or three projects, and you know you're off and running. The third project that's typically in that module that I haven't mentioned is a contracts project, and the whole idea of the contracts project is that's where the shared stuff goes. That's where the DTOs or the messages or things that you need in order to communicate with that model from another module where those would live. That's great, Yeah, very important. It just really quick. I don't mean to change

the subject because we've got to get back to this. But what's dome Train and why haven't I heard about it? Dome Train is Nick Chapsis's training company, and so Nick Chapsis is a real popular YouTuber talks about dot net a couple of times a week, and so he has initially published his own courses, but in the last year or so, he's brought in a bunch of additional authors on there, and so you'll find my modular Monolith course there as

well as a bunch of other courses. And I still have a relationship with plural Site, and I have a bunch of courses on plural site as well. But I'm trying dome Train out for the modular Monolith topic. Cool because I think that, you know, people are like, Okay, you've convinced me, I want to go check out this this workshop here, great stuff.

Yeah. I don't know if it'll still be good when people listen to this show, because I know that could be in the far future, but at least for now, if they use our Dallas when they check out one of those courses, they get twenty percent off. Very good. Uh So you're when you were talking about contracts, you're not talking about contracts as in something that's a part of the domain for this business, but contracts, as

in the contracts between elements of the application interfaces, et cetera. Exactly. Yes, not not contracts like legal contracts, but the the public messages, they're they're classes, their records, they're they're dt os. They could be

queries, they could be events, they could be commands. Those are typically the three types of messages that your application will use, and then you will have dt os that represent the actual things in your domain, right, Yeah, And so that and that's just basically a way to maintain that reliability from update to update. The old DTOs are still supported, so that I mean, we did a lot of this with the old in service bus approaches just

because I had so many different teams working and in different languages. So you know, there's no way you're going to get everybody to move to V two. Like it just wasn't a thing, right you, backward compatibility. Yeah, the bigger celebration was when did you get to retire account if ever? Yeah, And the other key reason why that separate project exists is to touch on what Carl was mentioning, which is, you know, what if these two things need to talk to each other, right, not just one not

just in one direction. Right. So in dot net, if you as soon as you split out two things into two different projects. Let's say we've got customers and orders, right, and so I want to go and get a customer with all their orders for this page I need to show. Okay, Well, then I guess customer needs to have a reference to orders so it can get all the order stuff. All right. Well now I'm like, I'm on an order, but I want to show all the customer details

with it, right. Well, okay, well, now that order endpoint needs to have some way to go call customer. Well, as soon as you try and add a project reference in both directions and visual studio, it's it's not going to let you. Circular references aren't allowed. But you could certainly have the customer's module depend on order dot contracts, and you can have the orders module depend on customer dot contracts, and that's perfectly fine, and

then you can use those messages to communicate with one another. So you know, one of the byproducts of splitting up all these silos into individual things when when they're distributed is it's almost like the sequel join problem right right, when you have when you follow doctor cod and everything's in like all these fully normalized tables, and then just to pull one set of data out of the database

requires fourteen points. I mean, you have the same kind of thing here, right with microservices if they're too complex and so walking that line between you know where how what's the granularity that we need? Right? And that is tough and if you get it wrong with micro services, it is fairly expensive,

but mostly in terms of time and effort. Sometimes there's money to refactor a distributed application in order to fix something like that, where like these two concepts really should have been together, but we split them and now everything is harder. Yeah. Yeah, now now we're being punished for it. I mean, we've got to have a whole conversation just about debugging micro services in the first place, because that's hard to Yeah. The beauty of the modular

monolith approach is that you're not distributed. All these communications that we're talking about, they're all in process right right. You can use a tool like mediator and the mediator pattern to make it so that one module can talk to another. Just by using those contracts, you can new up a command and say, you know, mediator dot send this command, and some other module that

knows about that command is the one that's going to process the work. And if you're stepping through in a debugger, you just step right from module to module. Everything just works in process. It's fast. Right, there's not a distributed message bust or anything involved unless you need one. But just you know, by default, your monolith, which is now a modulith if you will, a modular modelith module, is still what it was before. Right, It's still simple to deploy, simple to debug, all runs in one

process. Just all we've done is logically separate things into these different modules. But Steve, what about Kubernetes. You never have to worry about it with this approach. That's the beauty of it. I think. I think Kubernetes is a way for cloud vendors to make more money. Well, it's working, but I mean, it's just an interesting point about this that the deployment

or the implementation and the architecture are separate things. You certainly can can push out a model if in a contater, just as well as you can push it a push out as out of microservice. As a good table we have a friend who listens to the show, and he knows who he is if he's listening, who I'm friends with, and I've been friends with him for

a long time. And his boss, you know, at his company, is sold on you know, Kubernetes and micro services and all these things and the you know, domain driven design and all the things that go with it. And you know, when you talk to them, it's like they only have a handful of customers. But so it doesn't make sense and he can't talk and any sense into his boss in terms of you know, trying to simplify this and going monolithically modular, and it's just painful. It's very painful.

And you know, I guess, as you said, I think it might be a little bit hubrious, like, oh, well, we need to anticipate the day, right, when are you know, when we suddenly have millions of customers and blah blah blah. But you really need to ask yourself, is is that going to happen? And can we prepare for it now and serve those five hundred thousand, ten thousand customers, serve them well and be ready for the next for one hundred thousand customers? Right And it's

there are challenges even with this architecture. Right. What is one of the nicest, easiest things you get out of a monolithic architecture is that typically you have a single database and anybody can querry that database for anything they want at any time, from anywhere, right, And that's a blessing and a curse.

Right later on, if you do decide to try and split this up into different modules or micro services like that is usually one of the hardest things to do because you look at your database and you're like, hey, let's let's create an enerity relationship diagram and see all the foreign keys, and it's just tangled web. It's like, well, everything is related to everything, how do I start? And it's easier to just write a query with a

bunch of joints in that scenario. If you move to micro services, every

micro service should have its own database. If you've moved to a modular monolith, the same is true, although typically you can just use schema, not the whole sequel schema, but the schema type in SQL server or database, so that every table is prefixed by the schema, so you'll have you know, orders dot order and orders dot order, item for example, and then you just make it a rule that you follow as a team that when I'm in the orders module, I only work with things that are in the orders

schema. I don't go reach out and find other, you know, things that are in the database. Right, But you know you can if you want to. And that's that's one nice thing is you've got that escape out if you need it. But there are other patterns that you can use when you need data aggregation, Like I really want to run this report and I'd like to be able to join across the orders and the customers and the addresses

and the products. And you know that is difficult to do in a micro services scenario where you've got four different separate databases that might even be running on different database technologies. But there are patterns that you can use to make that happen, and I show how to do that in my course. Also, guys, let's take a break. We'll be right back after these very important messages, and we're back. You're listening to dot net rox. I'm Carl

Franklin. That's my friend Richard Campbell in Mexico, somewhere where it's nice and warm and sunny, goddamn it, nice and warm and full of palm trees. Yes, And that's Steve Smith. And we're talking about modular monoliths. And Richard made a joke, but what about Kubernetes. And you know, it's kind of bittersweet because a lot of people use it, and a lot of people are very good at it. But eventually, you know, if

your monolith, your modular monolith does become a set of microservices. It's not that Kubernetes is going away, right, It's just that, you know, we don't want to start with it, right, And I mean the main thing you get with Kubernetes is managing all these different services in a way that allows for independence and independent scale. And in your monolith initially you can still scale that, right if you're just using a simple app service or you're hosting

your own VMS or whatever. Right, you can always have more instances of that and scale, you know, horizontally that way, not to mention vertically. I mean, you can add more horsepower to that instance for quite a while, especially if you're playing in cloud Land. Yeah, you know, the cloud Land machines are just getting more and more powerful, so you don't

have to distribute across multiple instances. Yeah, you just spin up the dial and say, well I need ten of these if need be for horizontal, or you spin up the dial and say well I need an E or an F or whatever labels they have for the higher. Uh, there'll be a Q one of these days. Yeah, that'll be the quantum computers. There

you go. The stack Overflow is not using micro services, right, I mean, if you ever read anything about their architecture, they just have some really powerful servers that run the entire site, and most of our apps were building don't have anywhere near the traffic of stack overflow, or the response time for that matter. Right. Yeah, So, I mean there is some

software side of this. They What I appreciate about your hater is not just that mechanism scaling and they're relatively small, but it's also a unit of update like you get. The containers give you a habit of treating software like cattle, not pets, where you don't modify anything, you just make a new one. Tendency listeners just shuddered in horror when you call them cattle, because

those are sacred. What do you mean cattle? I didn't say what kind of animal yeah, yeah, that's a good metaphor for the point being that you tend not to update and create unique states that you you design. The update is a new manifest. The manifest creates new instances of containers if you want to management Kubernetes, to knock yourself out, whatever makes you happy. And then you shift workloads over to the new implementation and the old ones can

be shut down. That that's that's the magic of cloud right that that you don't have to update servers anymore. You just make new ones and kill the old ones. Right and and the beautia ASP do a core. It works

with Linux, it works across platforms. So you could certainly take this modular monolith deployable you know the DLLs that you're going to deploy, uh and and send that into a doctor image and then host that container and then as part of your c I c D pipeline, publish a new container, push that up there, have a blue green deployment or you know, whatever you want to do, uh and and you know when it when you vetted it and verify that's good to go. You know, replace the existing one with that

one or with ten of that one. If if that's how you want to scale, yeah, uh, and you don't necessarily need to have micro services. But let's say you do. Right, Let's say that you've got this modular monolith that you've built, and it's you know, been easier to build along the way because you didn't have to deal with Kubernetes yet, you didn't have all the you know, distributed application effort yet. And now you realize this piece, this one module, really needs to be separate for reasons because,

yeah, it's it's a bottleneck in some way. It's a performance bottle neck or a feature bottle neck, like what is it that? Yeah, it could be any of those things, right, it could be a bottleneck, could be there's a different team that's in a different time zone that you want to work on it. It could be h you know, there's GDPR requirements that the data can't leave the you know, Germany, so you need

to host it somewhere else, any any number of reasons. Right, Well, if it's been built as a module, it's fairly easy for you to pull that out and put it in a separate process. Right, And now you know that can be you know, you know, you're not necessarily on a micro services architecture, but you do have you know, now one module that's separate from the rest of your modules that are all bundled together. And so you take the logical separation that you already have and you turn it into

physical separation on a case by case basis. You don't have to, you know, do all of it at once. But this isn't free either. You're adding an authentication layer there, then in a transport layer because you're not part of the same thing for sure. Yeah, there's a host of things that you'll have to figure out, at least for that first one, like how are you going to communicate it with it now that it's out of process.

And the nice thing about the modular monolith approach is if you're using you know, messages like I've described as contracts approach, is those messages all have handlers that in a monolith can just do the work right in the handler, it goes and makes a database call and gets the stuff it needs and returns

back your dto and that's that. Right Now, you suddenly say, well, actually you're you're across the wire from me, You're somewhere else, and so you can't just do that anymore, right now you've got to transport it over a message queu or a message bus. You've got in service bus in between, or there's an a layer between, and we have to have you know, token based security flow all the way through. Like all of those

things can still be done just in that handler. Now you're going to add that additional work, probably as a decorator, as another handler that sits in front of that one, so that the original one doesn't even necessarily have to change, but you'll add that new responsibility in its own class that sits in front of the existing one. Okay, yeah, that makes sense. But I also appreciate the idea of like, you only do this because you need

to. You're adding complexity and overhead and impacting performance, I would think to a little to some degree. Yes, but you know, as a guy who's done a lot of scaling over the years, is like, I'm going to reduce the single use performance so the multi use performance stays consistent. That's not necessarily fast per se, but at least is as the number of instances

go up, it doesn't change. Because that's the only thing that makes people sad is that this one took five minutes where the other one took four seconds.

Yeah, right, right, Yeah, just trading for scalability will almost always make individual performance worse, right, because if you just have your entire application on one box and either it doesn't have a database, or that database is also on that box, right, then all of your calls are on the same box, right, there is no network hop, and so you're going to come back in you know, milliseconds, you know, very very

small milliseconds on every request. But how do you scale that? Well, that's the trick, right, And so as soon as you start scaling it and you have multiple servers involved in network hops, everything is orders of magnitude slower, but still generally fast enough. And now it scales you know, linearly at least up to some point. Yeah, yeah, there's always there's nothing's for forever, but it should be enough at least, right, And

an architecture, everything is a trade off. So it's just a question of what is the right architecture for your application for today and for the next you know, whatever period of time you anticipate in media, Yeah, for fishent amount of time. All right, Steve, here's this scenario for you. So people are listening to this and they're about to embark on a new project and realizing that they're going to get in over their heads the upfront architecture if

they're going to make this right. Maybe they've watched your your your workshop, here your course and they want to hire a consultant, right, So they bring in these consultants. And as we know consultants, uh, many of them can talk a great talk and you want to they're on the lookout for smells, right, So what smells should we be looking out for when we're hiring consultant. Then they sit down and they say, all right, here's what we think I think you should do. Blah blah blah. What are

the smells that say Nope, this guy is not does not understand. Well, first you should just call nimble Pros because that's us, uh and we can help you. So go to nimblepros dot com. You know plug that

you set me up for. Sorry, but no. If you're looking for things to watch out for in your modular model, well in your monolith or in your architecture, the biggest thing if you're if you're hoping to have modularity, right, whether it's micro services or modules within a monolith, the thing that will kill modularity is things that will kill independence, right, things that add tight coupling between modules. So, if it's micro services or modules,

if they're sharing the same database, that's a red flag. That's a code spill. If and I mean the actual tables in that data so they have separate schema then and they're on the same database server, that's that's fine. You know, you can always break that apart later. But if they're literally just sharing one data model between multiple modules or micro services, then that's going

to make them tightly coupled and you're going to lose that. So if the consultant says, so here's module one, it's going to talk to our central database, and module two and three are also going to talk to our central database, you say, there's the door. You ask them a question of you know, hey, doesn't that make them less independent from one another? And then you hope they have a good answer. Maybe there's a good reason why they don't want to split the data model. That is complicated, or

it does add complexity to split the data mode. And there is such a thing as we know as too much separation. Sure, yeah, so I guess yeah, right, Like Michelle, my wife and partner at Nimblepros is a veterinarian by by education, and and they kind of have a thing where they don't talk badly about how another veterinarian diagnose something. Right if somebody comes in and they took it to another clinic and then they bring it to you, like, you don't know what that that saw. You don't know what

the animal was doing at that time. So I'm not going to talk badly about some consultant or or architect or whatever that makes certain decisions because I don't know what they were thinking, what what what what they were seeing at that moment and how the you know, requirements were given to them. I will only assess it based on the information I get at the point in time where I am introduced to the problem. So maybe if I could throw in an

answer here. If you hear them say always or never, you know only as Seth speaks an ye, try and be practical and remember that everything is is a trade off. Is always saying it depends gets old too. It's true. It only is helpful to say it depends if you immediately follow that with what it depends on and how your decision will be different based on that again in a healthcare field, if you're diagnosing something and you say, you know what's the treatment going to be, and you say, well, it

depends. Everybody is waiting on what on your test results. It depends on the test results, and then you know, based on that we'll do X or y like that depends should sure, all right? So anything else that I mean that the type of other flags. Other red flags for sure would be direct calls between modules, right, and direct I mean that they are. You know, on a modular monolith, you can get away with synchronous communication using the mediator pattern and I show that in my course and it works

fantastic. And the reason why that is allowed in my opinion, why that works in a modular monoth and it doesn't work in micro services. And what I'm what I'm describing is in micro services, if you have a direct synchronous call from micro service A to microservice be using RPC or web APIs or whatever you want, that means that they both have to be up at the same time. And so now they have a dependency that you know, they are not independent. You know, if one goes down, the other goes down.

And so if you want to have availability of these services even when one of them is down, one of them is being updated, or one of them crashed or whatever. Right, then you can't have those direct synchronous dependencies between them, so you want to use some kind of message queue or service bus or something like that. Yeah, exactly, exactly right. So for commands you can usually get away with just throwing a command on a queue and then when that other service gets around to it, it does the work.

But for queries you usually have a conundrum, a different problem, like I need this data from that other service, how do I get it? And so for that the easiest approach is data duplication. Right, you have a cash and that's called the materialized view pattern, and I cover that in my course also, But the general idea is that instead of you asking service B for its data with a query over the network, you just get the data out of your own local copy of service b's data, and Service B is

updating that copy constantly with events. Right, so every time there's a new record added or removed or updated, an event is fired and you update your cash. And so if that other service is down or communication between you is down, you always still have your cash to work from data might be a whole idea, right, but the data might not be up to date exactly,

So it's a cap theorem your training consistency for availability. Right. And what about CQRS that comes to mind, where you have a separate pathway for querying than you do for writing data, right, And it's exactly this type of thing I just described that. It's one of the reasons why you want to have that separation of commands and queries. So CQRS, if you don't know, the acronym is command query responsibility segregation and the benefit of it.

There's a bunch of benefits, but one of them is that you can use different patterns and different architectural approaches for your commands versus your query's. So, like I was saying, you could throw a command on a queue and forget about it, you can't do that with a query, right. You can't just throw it on a queue and continue on because you need that data and

so you have other patterns that you use to respond to those. And so in a modular architecture, whether it's going to turn into micro services or remain a modular monolith, it does make sense for you to define your messages in terms of queries and commands and events. Those are the three messages you should have explicitly defined and then use those as your mechanism for communication, and then

put those in the contracts project for each module. And just to illustrate how complex these things are, I saw a great tweet by Greg Young, who was the first one to do CQRS. I think he might even coin the term in the pattern, but that he was turned down at a job offer because they said he didn't know enough about CQRS. You don't know anything about CQRS. It's like saying Steve Smith, you don't know anything about nimble pros.

Go, yeah, Like did you even google it? You know, yeah, google that phrase and you know his name, right, So what have we missed? Is there anything else that people should be on the lookout for? Maybe maybe when investigating and existing architecture, right, and you're you obviously things that are tightly coupled. But how does one begin to take a monolith that might not be modular and modularize it. There's a few different ways

that you can start. Like one of them is you look at the data model or the object model and you try and figure out where there's some isolation, there's some things that could stand alone. And it might be that your your hand is forced. It might be that there are constraints like this is the one that's not performing well enough, or this is the one that needs to be in a separate region, and so you have to start there.

But if you're not forced, it's usually best if you can pick something that's low hanging fruit, that is, you know, sort of the Hello World, of of the of the various modules, right, something easy and so you know, sometimes it's something like how we send emails, right, take all the email sending functions and put them in a module and figure out a way to send communication to that module to say, hey, here's everything you need to send this email, and then it can do that work right,

And that could also be spun off as a micro service if you want it. I've I've done that many times for clients as their first micro service. Like here's your micro service that just sends emails. Like it's it's really small, it's micro, it's only got one thing it has to worry about, and you do it from all over the place inside your various applications. So like it makes a good first micro service, and then likewise is an easy thing to pull out, you know, some type of thing like that.

It could be an easy thing to pull out for a module in a modulate model. The reason for it is that once you've done something simple and easy like that, you've you've figured out where all the dragons are, you figured out what all the problems are. It's a nice easy vertical slice that you know, you have to answer all those questions like well, how do I communicate with it? And how do I you know, separate it, and

how do I deploy it separately? If it's a micro service, all those questions have to be answered, but you're not, you know, bogged down by the This is this huge, massive, complicated thing that's tied into everything else. Like no, do a simple thing that you can solve all the distributed problems or all the modularity problems. And then once you have that as an example, now you can just take that example and use that same approach

for the next one that's more challenging. Do we have to know DDD in order to do this? Do I have to take a course on demand driven design? You don't have to, but it probably helps because of some of the patterns that are involved. Right, Each one of these modules or each micro service should be its own bounded context. Right, And if you have never heard of that, then that's add a little bit about DDU would probably

go a long way, right. Okay, So you know, I'm basically hearing of voices of the listeners out there going all right, you guys are sort of pooping on micro services. But does that mean all these other technologies and patterns and strategies that we use are are invalid? And you know the answer over and over again is no. It's just that the modules exist in a single problem first, right, Yeah, if there's a good reason to go to micro services, by all means you. I'm not saying don't do

that. I'm just saying don't do it without a good reason, right, And don't necessarily do it out of the gate like you're if you're building a brand new application, you will go orders of magnitude faster building a modular monolith. Then you will if you're having to try and have a bunch of different services that all communicate to each other like debugging and deploying, and you know, reckoning with that and then changing that design later. Yeah, that's the

thing you be most likely to get defensive. Yeah. I mean the only place I've seen this makes sense, and you know we addressed this before, is oh, we have one hundred people working on this, and they're actually breaking it into these pieces and creating all the communication layers because it allows everybody to work at once and hopefully and you've got a contract team that's sitting over top of that that's making sure that the APIs are consistent and nobody gets surprised.

Like, so you're already paying the overhead to make that many people productive, right, I just don't know how many folks are in that situation, right, Like really, you know, there's an upside to Conways law, which is if the app is architectured to the size of the team, and the team generally has their hands around it, like they know what they're looking

at, right. Yeah, and this subsequent you know, break breaking a part of things because of performance or other constraints is more reflective of how the software is being used rather than the initial architecture. Yeah. And why do

you have one hundred people working on this? Usually it's because you want to achieve some level of velocity, right, Well, I would argue that you could have half as many people working on it, and you know, build it as a single repository modular monolith, and you would go faster than having one hundred people working on it in a dozen different repositories and all trying to figure it out, with a separate team responsible for contracts, and another one

responsible for making sure everybody does everything right, and two more teams responsible for figuring out how to deploy it all. Well, Steve, is there anything else besides here? Of course you want to pitch or talk about or do we miss anything before we sign off? Probably mentioned since we've been talking about micro services and monoliths that I do have another course coming. I think it'll

be ready first of April or so on. From micro services to modular monoliths, which is the backward direction from most of the books in literature that's been rud for the last ten years. But if you've found yourself in a mess with your micro services and you want to get back to a monolith but still keep your modularity that you've worked so hard to get, that's what this course will cover. Very cool, Steve, I can't thank you enough for being

with us. It's always enlightening to talk to you, and we always learned something and take the course. Get out there, check it out. Thanks again, Steve, Thanks Carl Richard. All right, always Bud. We'll see you next time on dot net rocks. Dot net rocks is brought to you by Franklin's Net and produced by Pop Studios, a full service audio, video and post production facility located physically in New London, Connecticut, and of

course in the cloud online at pwop dot com. Visit our website at d O T N E t R O c k S dot com for RSS feeds, downloads, mobile apps, comments, and access to the full archives going back to show number one recorded in September two thousand and two. And make sure you check out our sponsors. They keep us in business. Now go write some code, See you next time. You got Jamtlevans and

Transcript source: Provided by creator in RSS feed: download file
For the best experience, listen in Metacast app for iOS or Android