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