Coding Blocks - Clean Architecture – What is the Humble Object Pattern?
Episode Date: March 7, 2018It's time for another deep dive into Robert C. Martin's Clean Architecture as Joe puts us on the spot, Allen has a new mission, and Michael shares his Easter eggs....
Transcript
Discussion (0)
You're listening to Coding Blocks, episode 76.
Subscribe to us and leave us a review on iTunes, Stitcher, and more
using your favorite podcast app. And check us out at CodingBlocks.net
where you can find show notes, examples, discussion, and a lot more. Send your feedback
questions and rants to comments at CodingBlocks, follow us on Twitter at CodingBlocks
or head to www.CodingBlocks.net and find all
our social links there at the top of the page.
With that, I'm Alan Underwood.
I'm Joe Zeck.
I like what you did there.
I'm Michael Outlaw.
It was nice and fast.
Small business owners, it's time to be honest
about how you feel when dealing with your day-to-day admin work.
Admit it, you can't stand it.
It's a total grind. The truth is over 5 million small
business owners felt exactly the same way until they discovered FreshBooks. FreshBooks is the
dead simple cloud accounting software that's transforming how small business owners handle
their paperwork. Invoicing, using FreshBooks to create and send an invoice literally takes about
30 seconds. There's no formulas or formatting, just perfectly crafted invoices every time.
How about online payments? Your clients can pay you online, which often means you'll end up getting
paid a lot faster. Project deposits? No problem. There's a super handy deposit feature so you can
invoice for a payment upfront when you're kicking off that new project.
How about insights? FreshBooks can even show you whether or not a client has even looked at the invoice you've sent.
This is only a fraction of what FreshBooks can do for you. You owe it to yourself to feel the full effect of FreshBooks on you and your small business. For a free 30-day trial, just go
to freshbooks.com slash coding, that's C-O-D-I-N-G, and enter CodingBlocks in the How Did You Hear
About Us section. All right, here we go. We're going to kick off a little bit of podcast news.
This one's going to be short and sweet today. So, Jay-Z, what you got for us? All right, I got a couple iTunes reviews here. First one from
S. Rolson. And actually, that's it.
So, a couple equal one. Yeah, that's a good one. Thank you.
Yes, thank you. Yeah, and for Stitcher, we were lucky to even
get this one in because we were having problems even getting Stitcher to load.
They would only show that
yes, you were visiting www.stitcher.com
and that was it.
That was all you would get.
It was nice.
Thank you to
Jack of all Pythons
for writing in your review.
Love that name. The clarity.
Yep.
I saw this article
and I thought, oh, this would be an interesting thing to bring up
In this section here
Tech Republic posted a article
On the five worst
Programming languages to learn in 2018
So if you have
If you
Want to spend some free time
Learning some languages
What might you think would be
In that top five
i don't know what they would have put here honestly top five worst top five worst
and uh i i was kind of worried about this i saw this one um when i was like waiting for my food
five guys or something in this article i was like i don't know if i would read it i think i'm going to be offended
um and i was i was definitely surprised by some of these i guess we should probably talk about
what they are huh yeah number one on the list is dart huh okay don't bother wasting your time right
yep google language developed in 2011 but uh this came from low engagement across GitHub, Stack Overflow,
Freenode, Reddit, Twitter, Facebook.
Number two is, I find interesting, Objective-C.
Oh, wow.
Yeah.
Yeah, and that's where I was surprised.
Okay, Google has a history
of kind of abandoning things you know luckily goes done really well so i wasn't surprised to
see dart here objective c though it's like that's still really used i think is the is the reason
they're doing that yeah i mean yeah apple apple was pushing heavy for swift yeah and and everything's
a lot easier in swift than it is in objective c right um i was just proud to see it just because
it is such on such a prominent platform right but hey all right number three coffee script
i feel like we talked about that one.
I think that felt like that one came up recently
or well, recently as in like the last six months.
If that's recent.
Bye, Felicia.
All right.
Number four, I haven't heard of,
so I'm going to mispronounce this one,
but Lua.
This one really surprised me. It's used a lot for game scripting engines yeah yeah it's just a nice little
scripting language i see it used a lot for like mods and games and and things like that so i'm
really surprised like there's still some really popular game frameworks that are built on it so
i had a hard time with this but uh i guess i guess other tools have kind of grown up and
being used more often like unity is really popular in the game space, so maybe that's what it is.
Now, I feel like number five is going to hurt some feelings.
You ready for this one?
I think.
Number five, Erlang.
Ooh.
It's not going to hurt us.
John, he's always been a big fan.
John just hung up on the podcast.
Yeah, that one
I mean I don't want to say that it doesn't make sense that it's not that it's on the list but
at the same time it's like oh yeah that one there's a little salt on the wound for that one
well if you ever try to use it it's it's truly a miserable experience
I could say um what was the book?
It was like the seven languages in seven weeks or something book that was the only time I've ever messed with.
So, like, that's not a real, you know, experience.
So, I really can't say anything.
Sorry to anyone who uses Erlang or is a fan of it.
But I just, it definitely, and the reason it was in the book to begin with is because it's a different programming kind of paradigm.
It's a very different way of thinking.
It's functional language.
Yeah, it's functional and it's especially weird
it's painful i love that i love that yeah i want to do like that erling is
i guess that means that haskell is going to win out for all things functional then
i think so or f sharp f shar F sharp, sir. Um, okay.
Well,
no,
no,
probably,
probably not.
If you're,
if you're in a Microsoft ecosystem,
if you're a,
I guess if you're in Java ecosystem,
what like is closure like reigning Supreme or,
I mean,
I don't know.
Let us know.
Like if you're,
if you're working with a functional language that we're neglecting,
you should tell us about it.
Yep.
And if you are a developer of one of those five languages,
also let us know.
And in fact,
in fact,
you can comment on this episode for a chance to win a copy of clean
architecture.
Yeah.
With whatever your comment is,
but that'd be a great topic right there.
So I'll tell you too.
I was once heavily invested in a language
that people started talking about um being dead and it became a little joke like every year people
would say it was dead let me tell you it's dead now which one uh colfusion that's right i knew
he's gonna say it's no longer a joke oh yeah so i mean yeah i mean it's a it's a small fraction of
of its popularity and so i like now whenever someone says, like, a language is dying,
like, I kind of believe it.
Yeah, you're like, no.
People said Silverlight was dying.
People said Flash is dying.
Like, yeah, it probably is.
Abandoned chip.
There was just a user stat that came out recently.
Or not a user stat, but a stat that came out that Flash,
I think it was in Chrome.
Flash use in Chrome has dropped like 80 since 2014
like massive right like the ipad killed it apple apple killed flash but anyways all right so what
you got up next joe well now i feel bad i'm talking about bad about cold fusion it's not
dead it's still doing great things it still serves serves a great purpose, but it's definitely changed a lot
over the years.
It's the best way to serve up all your flash sites.
Moving along.
Hey, CodingBlocks is sponsoring
Orlando CodeCamp this year. So that means
if you're going to Orlando CodeCamp, which is either
a free or nearly free event, I forget, it might cost five
bucks this year, but there's
going to be stickers in the bag.
So free stickers just for going to the event and you can go check out my talk.
It's going to be at 10 AM and hopefully you guys will enjoy it.
And I'll have a little link to the show notes.
If you live around central Florida,
you should definitely come check it out and come kick me in the shins or
something.
I'll give you a high five.
Okay.
Right.
So you're,
you're actually asking people to kick you.
Okay.
Yeah.
Yeah.
And you'll never be,
I'll be wearing a coding box shirt,
probably MS dev hat.
And I'll be walking around kicking people's shins.
And he'll have a kick me sign on his back.
Yeah.
Joe's not a small dude.
Like you'll be like,
okay,
I'll kick that dude.
Wait,
no,
I'm not
doing that yeah in fairness i'm also really awkward so it'll probably be on accident
oh that's awesome all right well i already mentioned that uh if you want to leave a
comment on this episode for a chance to win a copy of clean architecture please do so
but if you'd like to help us out in other ways, you can head to www.codingblocks.net
slash resources.
And there you can find links to various affiliates
where if you were going to buy something anyways,
buy a copy of a book or something like that anyways,
then why not go through that and help us out too?
Yeah, Pluralsight in particular has a great affiliate program.
So if you want to help us out and you're a fan of Pluralsight like we are,
then if you use our link, we will really appreciate that.
Yep.
All right.
And so let's get into the meat of this episode,
which is basically kind of bringing everything to,
we're wrapping it up on clean architecture, right?
So it's been a few months in the making and uh let's go ahead and jump on into it so in this one we're going to talk
starting off at least about presenters and humble objects so what's a humble object guys is that
is that one that's just not too full of itself i'd never heard this term before reading this
chapter and once i read i was, that's a really cool idea.
That's a cool thing to have a word for.
There should be a word for that.
Yeah, I'd never heard of this pattern.
I agree with you there.
It says it's the design pattern.
It was originally identified as a way to help unit testers
separate behaviors that are hard to test
from the behaviors that are easy to test.
And the pattern itself was called the humble object pattern.
So yeah, I'd never heard of it.
And this was really cool.
I mean, the harder to test stuff were things like the UI,
which I think we all know, right?
Like the UI changes so much to trying to unit test that it's impossible.
You're just constantly chasing your tail.
Yeah, and so the
humble object is it's all that dirty stuff right it's when we talk about pushing things to the
edges pushing those dependencies out pushing your integrations with 30 third parties out to the
edges like these are the edges these are where we put that code that needs to deal with other
things that we you know like at some point you can't mock anymore you can't put any more interfaces
in place you just have to touch the other stuff and so the idea is that you lump that code into particular objects like in these humble objects
and they're the ones that do all the dirty work yep and i thought what was interesting here is
i'd never heard it called this way before the presenter object that basically gets the data
from the application tier and then hands it off to a view model that then goes to the view i'd never
heard of it done that way or or or called that way i should say but i mean you typically call
the controller right yeah yeah your controller is what is going to go get the data to then give to
your view model and then your view model is going to be what you use by the view to populate the page right so yeah it was just a different approach i don't know but this was also i want to be a
little clear here because i don't did we maybe we said this but in case we didn't i want to make
sure this is called out because this kind of threw me for a loop because the humble object is the
thing that's hard to test right right yep and it that felt counterintuitive when
i heard the the name humble object pattern and they just in that first description that i gave
of it right i was like oh i guess the things that are humble are the things that are easy to test
but no those are the things that are hard to test they mentioned yeah go ahead they mentioned later
though like they they wrapped it up and and i should find the reference while you
guys talk about this but they wrapped it up at the end of that section that defined why they called
it the humble object because it does sound counterintuitive right it sounds like the
humble object would be hey yeah you test me out that's fine but it was the inverse yeah well the
code that i write that deals with third parties is like not, I would never describe as humble. It's brazen. It's bold.
It's not humble.
Right.
Well, and that's why I was thinking that the humble, the object that is humble would be
the one that's easy to test.
Right.
But yeah, I was totally wrong about that.
Um, yeah, there was another thing in here that like totally threw me to, uh, you know,
Alan, you were talking about the views and the view models.
And, um, you know, as he was going through this section about the presenters
and views and he says that there's nothing you know you should have nothing in your view except
for the presentation of the data period and that's it right right no logic whatsoever none no logic
just presentation period now okay before you go on with that that's
where this wrapped up so basically what you just said the view shouldn't do anything nothing is
left for the view to do other than to load the data from the view model into the screen thus
the view is humble so the view is not doing anything but it's also the hardest thing to test
because it can change so much so okay all
right okay so that's that's why they that's why they put it that way all right now okay sorry i
i get that now um but so so the view is doing nothing other than presenting data now
i ask you this because we're all aware of templates, right? So does this mean that you cannot have any conditionals in your templates for your view presentation?
You shouldn't, honestly.
Right, according to this, you shouldn't. So like, I guess the way I approach it typically is like, if you see something in the UI
to where you're making some sort of decision based off,
hey, if this value is this, then show this or what.
I try and pass that down from the server layer anyways,
because the problem is if that data
that's going to be coming back to you
somehow has to be validated against it,
I want to be the server or the place that's sending and getting that data to be the source to you somehow has to be validated against it. I want to be the server
or the place that's sending and getting that data to be the source of truth, right?
So let me rephrase this in a different way then. Okay. Let's say that you are writing your new
Angular component and you've got, you're just writing out the, you know, I'm calling it a template, but the HTML-like part of the code, right?
And you want to say, hey, there's going to be a list of usernames.
And for every username, print out a div.
And in that div, there'll be a span for the username and things like that.
So for each user, for each user,
print this out. Right. But if there's zero users, right, then that thing is,
it's conditionally deciding like, Oh, don't display anything that there's nothing to display
there. Right. Now that's just an example that you could technically in those same type of templates,
whether it be a view JS or angular or react or
whatever templating method you, you know, uh, framework you're using, you could do other things
like, Hey, if the, if this has, if this array has some data, then go through that for loop.
Like I said, otherwise, maybe I print something else out to the screen that says there is nothing so it kind of made it sound like hey your your template should have
zero logic yeah that's that that's walking the line right like i i feel like what you just said
is just typical view you're not building business logic into it you're literally just trying to make
sure the ui looks nice looks nice and is descriptive.
So I don't know that that falls.
I think the term business logic, though, can be, yeah.
It's one of those things like we kind of had joked about this last time with the,
I think when we made some joke about the, depending on who you're talking to, right?
Like that's kind of, terms like that can be relative to who your your target audience is right
it's true and if you're if you're the ui guy if you're focused on or gal and you're just focused
on that then you know you're gonna be like hey my business rule is like when there is this data
this div gets populated with these spans or yeah that that's a tough one i do think that probably i think the the more relevant part
that they were talking about was if you have to format data in a particular way right don't make
your view do that there should be whatever is populating that view model or no the view model
itself wait the view is all about presentation so it's all about format no no
no so what they were saying is like if you needed to like imagine you have some sort of accounting
page right you have a balance sheet or something if you needed something to be formatted in a
particular currency the view should not be doing that that data should be formatted provided to
the view model and then the view model is passed the view just grabs it out of the view model right and if you needed that thing to be read so another way to say this then would
be like if you wanted something in a local currency or or local locality whatever that is right then
you might let you know the i think you were saying the presenter object would make that decision
yep of like okay let me translate this into the local currency formats
or local, you know, decimal formats or whatever. And the view doesn't do that. That's fine.
Right.
I just wanted to clear because like, I mean, the view is all about like,
hey, this is going to be formatted, you know, we're going to uppercase all of this lettering,
right?
But that shouldn't be done by the view.
If you're getting into CSS land, right?
And that's the crazy part.
Like when you really start thinking about it,
that, so I see Joe shaking his head too,
that shouldn't be made at the view level, right?
Because then, because at that point.
That's what we're saying, right?
Right, it should not be.
And the interesting thing to bring in here too
is if you've worked in the MVVM patterns
where you have a view model,
they're also saying that every single thing on that page that could be in that view page form, whatever it is, right?
There should be a corresponding view model property for it, right?
So if you have a button, if you have fields, if you have whatever, the view model should be what is populating that entire
thing like that view supposed to be completely stupid so to your point css yeah if you want to
add a class you know is the server supposed to return the class name to the view that seems wrong
but what if you had maybe the div for the normal and the div for the red and both of them kind of
properties and then you have like a you know a hidden property or whatever they'll show or hide or will include or not include well see that brings
up a very important thing that you just said you were talking about divs and and show hide and all
that and this is where things sort of fall apart is in by the way if you are somebody that returns
html from a database like you have some sort of product that says,
oh, I want this thing to be a red span.
You are absolutely not doing it right.
And the reason is, is because now you assume
that your only consumer or only client of that data
is a browser of some sort.
Something that can read HTML.
That is not how you treat data, right?
Like you should not be doing that.
So that's where it's kind of interesting, right?
So if you were to code everything, let's say, into your UI and you're doing an Angular app,
right, and you want this thing to be red over here, is that just because that particular
client should see it red?
Or if you have a mobile app,
should it also be read there? Are you going to be recoding all these type of these transformations
on every single platform you're doing? Or if you have a presenter object, does it make it easier?
I mean, it does make it an interesting case. I mean, I guess what was kind of like, um,
a little bit, you know, mind opening opening for me and this is why i brought
this up was because i i'm okay with like when we were talking about like locale uh type decisions
being made in the presenter you know controller whatever you want to call it like server side
and you're deciding like oh i should return back the english version of this because you're in
in the united states or oh you're in spain i'm going to return back the spanish version of this because you're in the United States or, oh, you're in Spain. I'm
going to return back the Spanish version of the text, or I'm going to format things into pounds
because you're in the UK or something, you know, like those kinds of things that makes sense that
you wouldn't do that in the view, but in the view layer, like it was kind of a little bit
mind blowing to me because I'm like, well, no, if I want something, uh, this text is all going to be uppercased.
You know, that's a, that's a view decision.
Like on the server side, you shouldn't care how I want to present it.
If you, if you returned back the name, Alan Underwood, right.
Then, you know, from the data side, return it back in its proper, you know, uppercase
a and uppercase u you know kind of
format but if on my particular view presentation i'm deciding i want it to be all uppercase because
that's what this particular view wants then i think that that decision belongs there not
and i'll say too you know with the formatting like if you're a wordpress and you've got a
table for posts and that each
post has rich formatting and that's
part of the requirement. I want to be able to bold stuff or
I want to be able to have line breaks or whatever. You kind of
got to return that.
What's the alternative? I'm not talking about
when you actually put a blob of HTML
in the database because it's
expected output it is. I'm saying
you have some sort of stored procedure
that
you need to return a numerator and a denominator, right?
And you wanted to shortcut it and do, you know, here's numerator, BR tag, denominator.
Like, no, that's not what you do, right?
You return the two data pieces together and then whatever's consuming it, use it. In the case of like a WordPress blog post or something to where you actually embedded HTML in that because that's what you want to look like.
That's different, right?
I'm giving you the content that I want to get back out.
I'm generating you some HTML because this is what the output calls for.
But yeah, man, here's the thing i i'm with you if if i'm doing something in a ui like an angular
type thing yeah i'm gonna do it in css and i'm gonna do it i'm gonna do it that way but i probably
would use something to format the locale and i probably would use something to do those various
different things but yeah i mean the look of it. Well, I mean, that's definitely extreme.
Right.
I mean, because like to me, like the view is all about the look.
The look, right.
But, you know, kind of taking a step backwards there,
going back to the logic within your template,
whatever that template may be, like, you know,
doing ifs or fors or whatever inside of that.
I mean, to me, that seems like a perfectly valid thing inside of your view but it is a type of logic that he's saying that
my interpretation of what he was saying was like no you shouldn't be doing that which would just
felt weird yeah i i think that if you wanted to take it to that level where you were saying like
if there's zero records then maybe in your view model,
you have an empty message type thing. You know what I'm saying? So,
so for instance, maybe you have an empty message property.
And then if that empty message property is filled in,
then it shows that empty message, right? Or something like that.
So I think you can still,
you can still accomplish it and not having your,
your UI make a bunch of decisions for you. Yeah. I mean, it just gets weird though,
because now, now you've just moved the decision to the, to the server side. And now the server
side is going to be like that for all use cases. And maybe that's okay. But let's say you wanted
to have something like, um, a banking application and you're like, hey, here's an API endpoint
that will return back all of the transactions for the current calendar year.
Okay.
And, you know, so you're going to get back an array of these transactions.
Well, if there were zero transactions, I expect an array of zero, right?
Not an array of one that has a string that says, Hey, there were none.
Oh no, it would be a separate property though.
I think is what I'm getting at.
Yeah.
Like a show none message kind of property.
Yes.
Yes.
So you'd have, you'd have your, your standard array that come back with a collection of
whatever, if it had stuff or not.
And then you'd have another one.
It's like, here's empty results message, right?
So it'd be two separate properties on it.
And I think that's, I think that's how you accomplish what he's talking about in this whole view thing, right?
To where really the view can kind of be dumb.
I'm not going to decline that pull request because you had a loop or a condition on there.
Right. No, same here.
Dang it, that's what I was going for.
Starting to deny it.
All right, well, let's get into testing and architecture.
Yep.
Testing is pretty much,
unit testing is pretty much impossible
without good architecture.
And that's what they say.
So there was this great thing in here,
which I found,
he says that the separation of these behaviors
into those that can be tested
into those that can't i like when we're trying to break up our things into humble objects and
those that aren't humble objects that is often a boundary an architectural boundary itself
yep yep and a lot of people say like why should i write my test first so well you ever tried
to test afterwards and so it's really hard.
And so I think that that's a good test case.
And it's like, if you can't write tests for your code
or if it's really difficult,
that's a good sign that you've got architectural problems.
It's a shame.
Hey, better know.
Yeah, it's a shame they put this here though,
because they go into it in more detail in a little while.
And I really like some of the points that they bring up.
But it was because, but I mean, the reason why was because the Humble Object
was all about separating the behaviors. So once you separate those behaviors,
then you've identified boundaries. Yeah, good point.
You can test just about everything up to that Humble Bundle.
That Humble Object. If you don't know about
those, you get some good deals
on video games, right?
Or books.
Or books.
So the next
one is database gateways.
Our favorite conversation.
We've got a little bit of debate
coming up here in a moment.
So this
is where they say that it contains
all the interfaces for your CRUD operations to be implemented.
So you create reads.
Okay.
You know, we a lot of times throw out acronyms, create, read, update, delete, CRUD.
So your typical storage type things.
Yeah, these gateways will sit between the use cases and the database.
And this is where the debate comes in.
So I think probably all of us had to read this section a couple times.
So my takeaway was no SQL lives in the database gateway area.
And I'll go back to like bullet point one here because it says it contains all the interfaces
for the CRUD operations.
And what they said is,
these interfaces are to be implemented by the appropriate classes.
So your database implementations,
whether that's an RDBMS,
a relational database,
or whether it's a DocumentDB or something like that,
those implementations are over there,
but these are the interfaces.
These database gateways are the
interfaces that everybody has to sort of adhere to yeah and this is where like i totally misread
this part because um yes he says that we don't allow sql in the use case layer but uh he says
that we use the gateway interfaces to have the appropriate method so i'm
i misread that as like oh well okay fine we're putting our sequel in these gateways but as i
understand it from alan's take on it that instead the gateway is an interface and you might have a
mess and a method on it like I made that financial one.
Get all transactions.
Get all transactions for current year.
So you might have an interface that defines a method called
get all transactions for current year,
but there's no implementation behind that.
That implementation would be in the database layer,
and it would implement that method that method and so it would
have that's where the sequel that was my now understanding after you having said that you
didn't agree with my take on the sequel living where it should we actually do talk before the
show sometimes um yeah i, here's the thing.
The one huge takeaway for me, and we're going to talk about this a little bit more here in just a few minutes.
The one major takeaway for this whole clean architecture setup is tons of interfaces.
Yes.
Going back to Joe's, I have this solid application that does nothing, but I've got five million interfaces.
Like, when you start talking about these layers and they talk about these boundaries, it's almost like if you think about there's the left side, there's a layer, and then there's the right side layer.
So you got your database and you have your application.
There's this thing in the middle that are all your interfaces, right? That both of those sides have to adhere to. And that's really what the clean
architecture is, is literally these abstractions, whether they're interfaces, and I take this back,
it could be interfaces, it could be abstract classes, it could be any of that kind of stuff.
But it's this thing in the middle that has no implementation that everything has
to adhere to. And that's what this database gateway is. It's another one of these do nothing
tiers. So let's make this a little bit more concrete. You would have your database. So you
might have a SQL server or an Oracle. And then on top of that, you're going to have some kind of ORM typically so you might have an entity framework or a hibernate and then above that this is where kind of coming back to our DDD
conversation right this is where you're going to have this database gateway yep that implements
the interfaces so that you're not letting your entity framework implementation or usage or detail
leak out into the rest of your application. You'd have this database gateway there sitting above
the ORM that is, you know, get all financial transactions for the last year, right? And then you have your use cases above that layer, above the database
gateway. And so when your use case for, you know, getting transactions for a timeframe, or, you know,
for a current year, it's going to call a method on that interface, right? It only knows of the
interface, it doesn't know anything about any other implementation, whatever.
You could swap it out with a version that reads off of a file.
You could swap it out with an Invent Hibernate version or a Java Hibernate version or Entity Framework, whatever.
That's where the benefit of having that layer of abstraction between the use case and the orm buys
you right so what about an orm list world or a world with a less of an orm like you know i think
about a dapper expando i was trying to sort of lightweight framework that lets you easily query
a proc or pass a query and get some sort of dynamic object back so we've got our database still does
that mean we have this
little light layer that all it does is have like a little query and an object that it returns yeah
man just it's just exactly the same right so your database layer so here's your database your actual
you know infrastructure then your dapper let's call it layer right there and then your gateway
interface like there's no reason it really has to be much
anything else i mean all right oh go ahead oh go ahead well i was gonna say with your um
you know when you referred to it as a little lightweight uh orm like all that's really
saying is like you're just going to sprinkle all your um sql dependency and implementation
out throughout your code well that's right unless we
have the layer and that's where i was kind of going with is like well with dapper or you're
some sort of lightweight framework right just kind of it's real thin layer between my object
that's coming out of it and the sql um what ends up happening is a you end up creating classes that
get returned or get mapped to on the output right and so you're kind of hand creating your rm and putting them somewhere presumably in that same layer or you're
returning dynamic objects and like we talked about last object last uh the last episode i believe it
was we talked about the the dangers of returning dynamic objects because you're letting your
database which is implementation detail drive these core objects of your, you know, it's life without a main model, right?
Right.
And if you really boil it down to what it is, you could, when you think about that database
layer, it doesn't really matter how you do it, right?
Like you could mix all these technologies.
You could put entity framework in there.
You could have a version of Hibernate running in there as well.
You could also have Dapper in there.
Like it doesn't really matter because ultimately if you're implementing this database gateway that sits on top of it, it doesn't care about what you do, right?
Like if you wanted to get some object one way but but another object different way, it doesn't matter as long as whatever comes out of that thing adheres to that
contract.
Hey man,
do what you want.
Right.
So.
And like a hybrid date will generate the sequel for you.
So like link to sequel,
things like that.
Dapper is not,
but either way,
whether you're handcrafting that sequel,
or if you're having something generated for it,
either way,
you're going to want a separate layer there.
And that means that you're going to want an outer layer too, that kind of defines that
interface.
And that's what the other areas of your application will deal with.
And it'll be this, this data layer behind it.
And, and the interesting thing for me is a lot of times, like this is the one part of
this book that is kind of
frustrating is they're very light on examples in terms of like, what's,
what does the code look like? Like they draw tons of pictures and they put,
you know, dashed lines around things and all that.
But if,
if you're going to look at this in terms of like a dot net project in C sharp,
right? Like I totally can see you have the database layer,
let's call it, as a project, right?
It is something that can be compiled into an assembly.
That is your project.
The interfaces for this thing
could totally be a separate project, right?
Like you could literally have a database gateway project
that would compile into its own assembly
and it would just be a list of interfaces and abstract classes or whatever else, right?
And then the use cases could be a totally separate project, right? It might even be
multiple projects that all, but the key is, is the use cases are going to reference that database
gateway project. And then the database layer itself is also going to reference that database gateway project so that they can all implement and then cross those boundaries, right?
So I think that was that literally was the one thing that was kind of frustrating about this
book is I really would have loved to have seen some more examples of not just not just simple
code, but hey, how does how does your actual project component breakdown look inside a
solution or inside you know intelliJ or or Visual Studio or something like that you know but well
hopefully layers can be kind of unpopular with programmers right because they think about
redundancy they think about I have to make this change over here and I've got to go plumb this
thing all the way down to the database I had a column i had a column database i do it in the gateway now i'm in my use case but uh you know
i'm kind of on two of two minds like one hand it's like it's just typing like get over it
on the other hand like you know it's redundancy it's a place for mistakes more code you know more
mistakes um but on third hand i kind of wanted to like if you're just like adding something in three four or five
layers like paste paste paste paste like are you does that mean that you've plumbed that use case
to that database you know like what's the reason that you're having to do this plumbing i don't
know if that's the problem there if that's indicative but something to think about well
we talked about that in a little while too so all right yeah that that one's that one's kind
of interesting so i'm looking at these uh these excellent charts that uh outlaw pasted in the uh
in the show notes last episode it was episode 75 i'm looking at the cone of shame here
oh right yeah that that was uh i had fun trying to draw that just to make it
match what was the previous previously drawn there.
He did a great job of it.
Yeah.
I loved it.
So,
uh,
what we got up next.
So data mappers.
Yeah.
Who wants to kick this one off?
Well,
he says there's no such things as ORMs.
I love this.
I absolutely love this.
Did you read this part,
Joe?
No,
man.
Okay. I think there's going to be some people people that are gonna take offense to that statement though man it but does
he make a good case i mean i guess they're all a good case because this whole thing this whole
book makes me feel dumb because i'm like no that's wrong wait no no you can totally have
conditionals in your view what are you talking about oh i shouldn't do that and then you tell me all the reasons so
yeah man like what he says and what he states here is i mean okay let's let's first off say
splitting hairs right but whatever objects are not data structures from the user's point of view. That's okay. All right.
What does that even mean? The users can only see the exposed behavior. So if you're a developer,
you're the user of that object. You only get to see if you're doing it properly, whatever was
exposed in the interface, which is typically behavior. It's not data properties, right? It's
not all the properties on an object. So then what he says is
a data structure has no implied behavior, which is what an ORM creates is a data structure because
you do have access to the properties on it, right? It's typically nothing more than a DTO. You have
an object with a ton of properties and you can read them, you can set them, you can do whatever
you want. Is that true though? Cause like, I mean, let's pick on our boy here.
Any framework.
I mean, there's definitely tons of behavior.
Outside of CRUD?
Not really.
No.
Well, okay, fine.
Define outside of CRUD because like if you could do reads of like,
hey, give me all of the
associated objects to this one that's just a relationship that's a data structure still though
it is but that's not a behavior because remember behavior is acting on the data somehow so you know
so we're saying behavior in this in this case is defined as business logic. Yeah, yeah. Not as in read logic.
Right, not read.
This is literally,
and that's kind of what he's saying here,
is what you get out of an ORM
is a data structure.
It's literally the record from a database
or the record from some sort of storage thing
just basically shoved into an object, right?
So it's a bag of properties essentially.
Okay.
It has no behavior.
But that doesn't mean it's not an object.
That's where I kind of,
the distinction I had all our time with,
it's like,
what do you mean it's not an object?
Like in Java,
the number 13 is an object.
So it's just a matter of how we're kind of defining things here.
Yeah.
I mean,
I get what he's saying though.
Yeah.
He's splitting hairs.
Right.
Like I said,
it's when you, when you boil it down to it he's basically throughout the book and even in other
books an object has behavior in in domain driven design when we talked about things you know things
that you interact with have behavior you shouldn't be thinking about them as you know the various
different states that you're doing that's that's the job of something else it's kind of like it's kind of like the same it reminds me of the same splitting hairs
conversations that we've had before about like you know a dto versus a poco or a pojo right
you know like a dto just has the data there's no kind of functionality on at all whereas a plain
old class might have some methods on it that are simple right but it's it's more
than just the data you couldn't you you're not just representing it as like a simple struck
of data right right and and that's kind of what this sounds like so i mean it you know really
honestly it's not all that relevant like who cares what the ORM is called? But I thought it was a fun little section to just get people's ire up, I guess.
A little clickbait sentence.
Yeah, it really was.
So, yeah, whatever.
Well, he does say that,
going back to our humble object, though,
that these are a type of boundary
between the gateway interface and the database.
Right? So, going back i guess
that's how i i kind of picked you um stated you know a few minutes ago back then i said you know
you might have sql server and and or uh oracle and then on top of that you would have entity
framework or in hibernate and then on top of of that, you'd have your interfaces. So yeah, it's the boundary.
The humble boundary.
Yes.
All right.
So the next one that we have up are service listeners.
And they also can implement the humble object pattern.
And the way that I interpreted this and wrote it down to sort of i guess simplify
it in my mind was you basically have this data transformation that proxy classes set
to take data from the application format it and pass it over to the external service
so so that's that's basically what they're talking about, right?
Like just another layer that takes data
massages
it and then throws it across the way.
Word, serverless,
it's the future.
So I guess it might be
in like common
web apps today, then,
you could definitely say that that service listener would be like your C Sharp or Java layer.
You have your JavaScript on the client side,
you have something running on the server side,
then you have some kind of storage on the back end, at a minimum, right?
And the service listener would be in that middle tier.
In a middle, middle tier, I would think, right?
So if you think of like C Sharp or Node.js or anything, right,
that's going to take a request from your client, right?
That's the service from your, as far as your JavaScript part is concerned, right?
It's calling that other
service which is you know node as you get pointed out or c sharp or java but then but then the whole
humble thing though was once that hits that service it's going to take that data and transform it in a
way and send it to whatever the next tier is right right? And that's kind of what the... Right, it might take that request.
So give me all the financial transactions for Alan.
So my client side might pass in the ID that I'm looking to get the data for,
which would be Alan's ID.
And then that call is eventually going to work its way back to some kind of database query.
Proxied somehow and massaged all the way through.
It got transformed through many different layers before it got to that database.
And then that data is then going to get massaged back out again
as it filters its way back up through it.
Yes.
Yeah.
All right.
Well, so I guess then at each one of these boundaries, we're likely to find a humble object.
That's what it sounds like, or that's what it should be, right? Is what it sounds like.
And then...
Yeah, he says that the use of this pattern at these boundaries will increase your testability.
Yeah, we can test everything up to that humble but humble object so have them at the edge
the the crust of your planet i like that the crust the crust of your application that's good
we're going to make our own we like to eat here so we're going to have a pie now right who wants
the onion architecture we have the pie that's right oh man all right so the the next piece that we're going to talk about
is partial boundaries and this is where things start to make a little bit more sense in terms of
you know how am i going to write my application without generating five gazillion lines of code
right so the first thing he points out is full-blown boundary architecture is expensive.
It makes sense.
Like, I mean, how many inputs and outputs and all that garbage do you have to write
for every single layer that they've talked about so far?
What's a boundary, though? I forget.
Come on, man. Are you serious?
Well, I mean, just for our listeners, right?
I read the book in a couple of weeks, you know?
Like, what's an example of a simple boundary for them?
Oh, man.
So, let's rewind then.
And like your input, right?
You have something that takes inputs and then it needs to output them.
Your boundaries are how it's going to communicate those things, right?
Like, so translating those inputs into something that the next class up, the dependencies as
they go up every layer, you're going to have these things that translate it.
Because we said, well, you're not going to have an object down here as an input, and
it's going to pass up through five layers.
Because as soon as you do that, if that object definition ever changes, you've got to change all five layers of classes.
Bless you.
So at each one of those layers, you're going to have these boundaries
so that you have clean ways to pass data to and from,
so it isolates them from change.
Okay, so what's a partial boundary then?
So, okay, if we talked about this as like there was three tiers
like in that example that i just gave right like if you only and he made fun of like the three-tier
thing not being an architecture right all right but if you said okay fine there's a there's a
database there's a web server and then there's a front end client, let's call it.
And we talked about, you know, that you might have interfaces in between each of those,
in either of those levels, right?
If I recall right, we said that there'd be like, there was going to be six, I felt like was what was the number, right?
Because you're going to have two at each one.
Am I thinking of that right?
Well, no. You'd have at least one boundary in between each, right? Because you're going to have two at each one. Am I thinking of that right? Well, you'd have at least one boundary
in between each, right? So you'd have five total layers.
There'd be a boundary between the client and the server, and a boundary between
the server and the database. And so at each one of those boundaries,
you would have an interface for each of those,
but then an implementation of it on either side.
Right.
Right?
So that's, you know, two interfaces, but four implementations.
Not necessarily going to be implementations on either side.
There'd be one side to implement,
but then the other side has to know how to go use that implementation.
So it's going to usually be some sort of inversion of control but but yes well let's say no no let's say that
there was though because this is where i was getting this is where in my mind how i was
visualizing the partial that was that like you know your your client side has its own implementation
of the interface so that it's not bound to the server side's implementation but they're both
using maybe the same interface okay right if Right? If you're going full implementation, right?
But the partial would be like,
hey, we're going to have the one interface
with one implementation that could be shared.
Well, they do multiple ways of this,
but the interesting thing is instead of...
I guess that wouldn't work what I was saying.
Instead of having this...
So what they called it in this was reciprocating.
So let's back up real quick on this. So when you have the full blown and they have what they call
their polymorphic interfaces both ways, which means that whatever's on the left side and the
right side both have to implement this thing that's in the middle, right? Or they have to
reference this thing in the middle. One's going to fulfill that contract. The other one's going to get the fulfillment from that contract, but they both
adhere to that particular contract, right? And so that's really expensive because you're talking
about your client side has to program to use this interface and this other side has to program to
use the interface. And then you have all these inputs and outputs. So your request and response
objects that are going to be, you know, coming in
and out of both sides of these things. So it's a lot of code and it's a lot to maintain. So
you also have your dependency management on both sides of these things. So rather than do that,
what they talked about with the partial boundary, and this was kind of interesting,
is instead of having this middle tier that is all your interfaces and
everything and here to just bundle it with whatever the component is right so bundle your interface
with um maybe your database tier and then and then that way when you go call it if everybody's
diligent about it they use that interface and and they use their dependency injection to fulfill
whatever's going to do that interface.
The problem that you run into is, and they showed it in one of the pictures and I don't
remember what page it was on, but you have this interface and if everybody's just good
about it and they're a good Samaritan, they're going to use that interface to get to whatever the object is right the problem is though is you could easily
if you're just somebody who's trying to get it done you can just go right by it and you can go
straight to the concrete implementation right so another way to say this then is if it was a full
blown if you had full-blown boundaries then everything would be deployed independent of the other. Correct. So one thing can't talk to another
because it's not together.
It's not there.
It's not, yeah.
But to skip that and go with the partial boundary,
then you let the,
what was the thing that he called it?
Not the dependency rule.
Dang it. Or maybe it was the dependency rule about, about how you leave your code. Cause that's kind of what you were saying, right?
About the flow of your dependencies. Um, if you use the dependency rule principle,
then, um, you could deploy it all in one jar file or DLL or executable whatever but um you're you're you are relying on everyone to be
um consistent about their usage of it and diligent right and diligent about their usage of it right
and so you know it's kind of like the onus is on the developer that you know you're trusting that
they won't uh break that because since they
would have direct access to the object and instead of instead of for example instead of going through
a factory to get the object which would return back an implementation of an interface instead
they're like you know what i'm just going to go and create this i'm going to new up this object
myself right that would be an example of how you could break that right you can totally bypass the interface and the the reason
this partial boundary came up is because the first thing you live with is it's expensive right because
there's a ton of code to make all this happen but you think about the code but then this bundling
into one thing like you just said one dll or one jar file This is huge because when you can do that, what does that buy you?
You have a simpler build pipeline. You don't have version numbering to track to make sure that these
components are interoperable now because you bundled those interfaces and those inputs and
output classes with that particular component. So you know it's going to work with it. You don't
have to worry about that. And consistent with a lot of what this book has
been about, you're deferring the decision of whether or not and when you should break that
thing out into its own thing. And like, what does that even look like? Yep. Right. So yeah, I mean,
it feels like definitely partial boundary is your starting point. Yeah. And that's a lot of the
cases. All right, Joe, what you doing over there?
Well, it's just it's easy to cheat the boundary, right?
And so it's easy for things to get dirty
and then it gets hard to split them up later.
So I know in prior chapters,
they kind of talked about like kind of treating things
that are even in the same component as separate.
So I think you can still maintain good discipline,
especially if you're doing like a test-first approach
where you have to maintain that discipline. And I think that that really helps you kind of maintain partial
boundaries and kind of get around some of those downsides. But I just think it's dangerous. Like
I know for me, like anytime, like I kind of try to achieve something like that, like I end up
slipping dependencies and get my arrows going on the wrong directions. Well, yeah. And that's
exactly what they said right so there were a
couple of ways that they did it so they had it with the did i where did i put this well okay
the implementations are down a little bit further so we'll get to that in a second um he even
mentioned in fitness which he's used throughout this book in terms of you know the application
that that he wrote that he used a lot of these principles for,
is when they initially created that thing,
they wanted to make sure that they only had to deploy one thing, right?
One component, one jar.
But when they talked about this, he said, you know,
we wanted to keep the web server separate from the actual code.
And he said, and so we tried to do that, but we wanted
it to be bundled all together. And he said, the problem is over time they found out, okay, well,
we don't really need a different web server to be pluggable. And so then what happened is exactly
what we were talking about before the dependency started getting more tightly coupled to it. And,
and so that whole decoupling became weaker right and that's what happens
that's naturally what you're going to see if you if you do these and you cheat these things
but well another way to phrase that is we started leveraging the power of the web server or whatever
in in higher layers and it allows us to get things done quicker that's exactly what happens right
and so you you traded off your decoupling for efficiency and creating it initially
right it's a trade-off like none of this stuff is black and white right like you're not going
to go write software and be like it's going to be absolutely perfect because if you do that you're
never going to write any software yeah we wouldn't have spent like tons of hours reading and talking
about this book if it was just black and white and they could just go google the answers right exactly that's a great point um so we said that the the full-on
implementation requires two-way reciprocation that's all good so this is where they got into
where they had the picture with the little dotted line and it's the strategy pattern which we've
talked about before which is selecting the algorithm you want to use at runtime.
And this is all good, but you can bypass it.
Right.
You know, Weekly Dev Tips just did their weekly episode on the strategy pattern.
Oh, nice.
It's actually up next to my podcast, whatever it's called, Podcatcher.
Very cool. to my podcast uh whatever it's called podcatcher very cool yeah so he mentions that another
alternative to the strategy pattern here to solve this would be to use the facade pattern
right where this the facade calls the necessary services when you make that uh that request
right but there were a couple downsides of this.
Well, I guess similarly, you always have that possibility
if you could go around it.
But you're also dependent on it.
If any one of those facade implementations change,
then everything is going to have to be recompiled as a result.
But I feel like that was still true even with the strategy pattern.
No, it doesn't have to be.
Because it's all still in one component.
No, it doesn't have to be because, well, I mean, I guess if it was all in one component.
Yeah, because this is all partial.
Well, I think the difference was is if you do the strategy pattern you could literally like
hot load an assembly type thing to do it right the the thing was because they were bundling the
interface in with the other one i think that's how they could do it but with the facade pattern
you actually have a transient dependency all the way from the client to whatever it's using
because it's just it's straight up it's just straight up, it's hooked in.
Yeah, I guess I just misunderstood then because I was thinking that a lot of what we were talking about here
in this partial boundary section was...
Should be bundled.
You were bundling things as a lazy way of doing it
because you were trying to get around
having to version these things and manage that.
Separate them, yeah.
But yeah, it could just be combining chapters too.
That's easy enough to do.
So then there's layers and boundaries.
Yeah, this chapter was a lot more code focused, right?
If I remember right, or maybe it was
the next one. No, well, I mean, I don't know
about code focus, but definitely a use
case example, because he goes through
talking
about the game Hunt the Wampus
as the
use of it, and how
it starts out simple, where maybe you want
to have your game rules
collected together in one circle.
And then another layer might be the languages that you want to support.
And then it gets a little bit more complicated because it's like, well, okay, you're going to need another layer.
That's going to be how you're going to persist the results of the game,
uh, or the current steps. Right. Yeah. And, and then,
and then it just starts building on there because then it's like, okay,
you know, like you, you mentioned player health, uh,
there's the mapping data and then it's like, Oh, what about multiplayer?
So then you need network layers um
yeah yeah i mean we don't want to dive too deep into this particular one because it was a lot of
diagrams right like this one was a ton of diagrams drawing lines all that kind of stuff showing you
how you could break these things out but the key the key takeaway on this one was the architectural
boundaries are all over the place right like it
started out super simple but as you started expanding it like they were everywhere um
yeah and that these boundaries are expensive to implement but if you ignore them they're
very expensive to add after the fact, even if he makes the case,
even if you do have a good set of use cases of test cases around these,
um,
these boundaries,
they're still,
it's still hard to go back in and break that apart.
And you know,
the crazy part about when they say when they're ignored, I think that's if you just completely aren't using any kind of thoughts when
you're doing your components,
right?
Like you can put in the partial boundaries and you might've set yourself up
so that it wouldn't be so bad.
But if you literally are just coding it and you're not thinking about some of
these,
these decisions as you go,
yeah.
Coming back and trying to plug those things in later could be
a real pain. It's really tough. Yeah.
So here's the thing. You're trying to be a good architect.
What are you to do in this
situation? Nothing.
Guess wisely. But I do think that
you know, like we talked about earlier, like if you can get
the test going, I think that's a good way of kind of
reinforcing the right behaviors.
And if you do decide to
refactor later down the line,
I think that tests kind of help you give you that confidence that you need to do that refactoring.
And so, they don't mention it in the book, but just based on what I'm hearing, kind of
reading here in the background, I think that testing seems like a pretty good strategy for
at least kind of keeping those options open. But I mean, ultimately, you know, it just
comes down to kind of guessing or trying to make your, your, um, best guesstimate. It's funny though. You say the testing's a good way.
We'll find out in a little while. There's some pitfalls to that too. Yeah. Well, I mean, like,
let's explore that for a moment though, because I mean, conventional kind of, you know, wisdom
and conversations kind of follow along with what Joe said and and what and what uncle bob says here in this
in this part of the book is going against that because he's saying that like hey even if you do
have the unit test that it's still going to be very expensive so you know an example might be
like if you have some object that you're using and everywhere you're just directly newing it up
everywhere you're not you don't have an interface for it you're passing it around you're um you know
at by the class name you're directly newing it up so there's no layer of like a factory
pattern in between it or anything like that builder pattern or nothing um you know then uh
you when it does come time to you decide like like, Oh, I now want, you know, something else
that's very similar to this thing, but kind of different. So maybe I want to have both of these
things implemented in interface. Now you've got to go back after the fact and change the first one
to now implement that interface that also meets whatever desire you have for the second version
of that thing too. And you got to go back and change all the use cases, all the other places, all the touch points
where that first one was being used to pass in the interface, all the places where it was being
newed up by, you know, just, you know, newing it up directly, you know, you're going to want to go
back and change all that and then refactor, you the test cases appropriately that's a lot of you know that that's an expensive and risky change to go back after the
fact which is kind of his point here yep yes so generally you just don't do it and you code
additively and you keep adding to the pile right yeah that's what we're trying to avoid that is
what you're trying to avoid but that's why why he said, you know, what does an
architect do? You said it, you guess. But the other thing too is you do, you try to at least
be intelligent about what you're doing and you constantly iterate on it. It's not a one and done
thing, right? It's not, hey, we built it this way. It's done. It's as it evolves.
Yeah, you're first going to try to figure out where these boundaries are in the beginning.
You're going to decide, okay, which of these boundaries can I ignore?
Which of them do I need to partially implement, fully implement?
And then you're going to keep doing that.
Like you said, this is a rinse and repeat.
This is not a one-time decision.
You're going to keep looking for the friction where these, uh, and then where these boundaries don't exist and
then reevaluate. Right. And your goal here is to implement these boundaries that, you know,
once the cost to implement them is less than the cost to ignore, then that's when you're going to,
you're going to implement it. And you're going to keep doing that throughout the life cycle of the system.
Yep.
And don't fire your arrows until you smell the wumpus.
Yeah, I didn't know that, but I somehow survived.
Words of wisdom from Joe Zach.
Deep thoughts by Joe Zach.
You must smell the wumpus first.
So if you don't know what I'm talking about, you should google hunt the wumpus and like play it in your browser or you should code implementation uh for
fun there you go there you go so this next chapter for me honestly is kind of what was the glue for
the entire book like it was very code heavy in trying to describe where some of the things happen.
So it's called the main component and it's basically the entry point of your application.
It's the overseer of everything.
And he even dubs it the ultimate detail.
I like that name for it.
He says that this is the lowest level policy.
And this is where it all comes together, right?
Yeah, it is.
And there's only one thing that depends on it, the OS.
Whatever's running it is the only thing that cares about it.
And this is the reason why I like this one so much is
we've talked about dependency inversion.
We've talked about dependency injection.
We've talked about DI frameworks. We've talked about ioc containers and all this kind of stuff and none
of it's really kind of come together anywhere yet right this is where the rubber met the road
if you want to know where dependency injection and inversion and all that stuff happens
the way that it was shown and described in this chapter was is basically all in this main
this main class and this main method where they basically put all the crap from the entire thing
there so all your string constants all the um newing up of the game board for the uh hunt the
wumpus and like literally everything was created in this main
thing and then supposed to be passed along.
Yeah.
Would you say it's the humblest of objects?
Yeah.
The dirtiest,
the absolutely the thing that you would not test because you couldn't,
there's,
there's too many implementation details here that are all kind of decided.
It says,
this is where you should create all the factories,
the strategies,
the global facilities,
all that.
This is,
that's why they actually mentioned that you might want to have another kind of
version of this main and use it as a test,
like a big integration test or something,
or,
you know,
you could kind of develop little slices.
I think about unity,
like you can create different scenes.
So like one thing I might do is like just create a new blank scene,
throw my character in there while I'm working on something you know kind of mess around
make sure it's working and then kind of take it back to my scene and actually work in it where
you might have to get to a tricky area or something or navigate through the game to
actually see in action but just easier to kind of new up a like a kind of a quick test environment
to work on yes so this is your outermost circle it does all of it it says it does all the dirty work
i mean i didn't see talking about any um sorry go ahead no no you're good go ahead
oh see i didn't see anything about dependency injection here and like that's one thing i kind
of thought about like when i set up like a bindings file or something if i'm messing with
dependency injection framework.
That's somewhere where I'll usually say, hey, this interface gets you this concrete thing. And sometimes it's an XML, so notice it's in class.
But I think of that a lot of times as being this kind of central point that touches everything dirty.
And that's outside the main, but it's still pretty dang dirty.
Well, I guess it's going to depend on your dependency injection framework too, though, right?
Yeah.
I mean, honestly, I'm thinking structure map as an example.
I haven't actually used that one.
I mean, Joe and I were talking about this probably a few weeks back.
Like I was getting really frustrated because I wanted to do some DI in a library.
And it just it doesn't work very well because there's not a a given entry point
right with main it is your entry point so if you're trying to do dependency injection you
know what you need to set up there so your ioc container if you're going to do it it would be
in that main even even if you're calling off to something to do it for you, but the goal is that main is going to be what sets that stuff up.
They didn't show a DI framework,
but they did show dependency injection in this.
Because I think they had factories that newed up like the,
I want to say it was like even the map, right?
In this main method.
So they do dependency injection,
but they weren't using a DI framework for this kind of thing i think a lot of those like at least my experiments with the di frameworks
and like unity and stuff like once i start getting the injection train really rolling i end up with
less and less arguments past methods because those things are now specified the class level
and then now the class is um is you know kind of modeled more around behavior rather than data which is how i tend to typically program just
because of years of of uh questionable habits but i do think that when i kind of start with
di or when i go back and kind of add it i keep feeling like the code that i'm writing
is closer and closer to what the code i'm reading about is supposed to look like.
So real quick on this one, only because I was looking at like one of the things that they showed is in one of their factories, they didn't, the factory, it wasn't your standard call the factory and it returns you an object they pass the name of the
class to the factory and what that does is what we've talked about before like how you loosely
couple things that's literally going to load up a java class that may not have been there right like
the dependency might not have even been in that particular jar. It's injected whenever you build or compile or whatever, when you bring all this stuff
together.
And if you wanted to do something like that in.NET, there's actually a load assembly
that you can call that will do something similar to that.
So when we talk about decoupling these things, it can literally be, hey, this class isn't
something that you actually have
available right now you're going to tell it what you want to load up and it's going to go try and
find that assembly somewhere and use it right yeah he referred to main as saying it was basically a
plug-in that you could have multiple versions of this thing you might have a version for
development you might have a version for production maybe you have a test version but that feels so i get the i get the plug-in statement i'm okay i'm on board with
that part because you know if you think about like okay well you're just plugging in all the
dependencies and everything but i don't like the idea of saying to have multiple versions of it i
don't want to continue that that thought i don't want to like i don of it. I don't want to continue that thought.
I don't want to encourage anyone to do that. It goes against
our 12-factor app.
Like having multiple entry points? Having different versions of the app.
Like the dev version should be
on parity with the prod version.
Right.
So the,
I mean,
that,
that was like one of the tenants of the 12 factor app.
So I kind of didn't like that part of it though.
Yeah.
You get something working in tests and you don't realize that there's
something,
cause it kind of implies that you're only working on tests and you're not
messing with the production.
Yeah.
That's something I'd rather,
rather configured. I'm okay with calling it a plugin since like you know you are kind of quote
plugging in all the dependencies right right but i don't want to encourage people to have
different versions of this thing hey my dev version works great nobody's ever heard that
before right like it works on my machine yeah that that's what i don't like i was kind of
thinking like um you know powershell's got that
that what if convention so if you pass like dash what if it'll tell you like what will change
and it's supposed to be a safe way in linux it would be dash dash dry run yeah um that makes
yes i don't i don't know i've never seen that linux in bash well i mean yeah there's it's in
like i know a lot of git commands that have that but
i'm trying to think of some other uh bash commands that would have that or you know just shell
commands that would have that yeah that's pretty cool uh but yeah the idea is um you know i could
potentially have i almost treat like a kind of a state machine or something where it's like
hey if you're doing the what if rather than me having a bunch of like kind of inner functions
that each take the like you know am i in what if mode what if mode if mode doing that plumbing i might have two different kind of higher
level points that sort of act like a main here so i might have like the what if main and the
regular main and both of them all use the same parts to just arrange slightly differently
or i could just you know pass the what if flag to any relevant inner functions
so yeah yeah i guess now i've kind of talked myself out of it
because it's kind of weird to have this like,
well, here's the main that you call
and it's going to decide to call one of these other mains.
It's like, well, at that point, now we're talking three mains.
And yeah.
I just kind of view that what if would be before the transaction.
Like you're either going to commit it and do the action or you're not, right?
Well, if you're doing like a file level stuff or something that'd be not necessarily be a transaction that you can apply well the transaction might be like a rename or a delete
yeah right
all right there's like there's no oh new at like the operating system level
or at least not one I want to rely on.
Hmm.
I don't know. Doesn't matter.
Alright, well,
with that said,
if you haven't left us
a review already, we would
greatly appreciate it if you would.
You can head to what sorry
oh man i'm tired guys i'm tired i had a brilliant idea the other day okay and it deals with reviews
oh okay i was thinking like we really appreciate the reviews so much and it means a lot to us and
really appreciate everyone who does it, everyone who's
ever done it. And so I thought, wouldn't it be cool if we sent stickers to everyone who writes
a review? And the problem is that anyone historically, like the 500 people or whatever
have written them before, like, well, what about that? I thought, hey, if you screen cap, link,
or just write us and tell us you sent a review i would be happy to send you stickers
now unfortunately i didn't talk about this with you guys ahead of time so it's a little awkward
now to say like hey perhaps we should volunteer to send a crap ton of stickers uh out to people
for free but i don't know what guys think? I'm fine with it.
I wrote nay just because I feel like someone had to.
No, I'm just kidding. I'm all for it.
Alright, so let's do it.
If you write a review
or if you've ever written a review and you send us
an email about it or let us
know about it and
an address, I will send you out
stickers for free international too
because what the heck it's late i don't care yeah that's what we do we give here so yes
the the point of all that is we really do appreciate it and you know yeah i don't i
don't care we could have we could literally have a babillion reviews.
And as soon as we get that next new review,
it's like the first one all over again.
It really is, man.
We really do appreciate it.
It really does put a smile on our face.
It means a lot to us.
And we really do appreciate that you take the time out of your day to write that.
You can head to www.codingblocks.net
slash review where you can find some little
shortcut links there for you to some of the platforms or maybe
you know of one that we missed and you want to leave your review there.
By all means, please do. And hey, by the way, let us know where you
left some of those reviews
you know in case if we need to modify our list right um so with that let's head into
my favorite portion of the show survey says and with that last episode in the spirit of valentine's day we asked have you ever made
a mix tape and your choices were does the playlist count oh it doesn't then no i haven't
or man i got my technique down and everything.
I know exactly when to play Bon Jovi's five words.
Yes, I have.
All right.
So, Alan, let's go you first.
Which one do you think is the popular vote with a percentage?
Man, I'm going to be hopeful here that we have we have some just
awesome people and i'm gonna go man i got my technique down and everything all right i know
exactly when that we're gonna go with 65 65 i like that i dig the optimism i I like that. All right. Joe?
Well, I'm checking online right now to see if you can.
Yes, you can.
There is a company out there.
They will create a mixtape.
Yeah, they'll create a mixtape.
Oh, no, wait.
You know what?
It looks like a tape, but it's actually a USB drive.
Okay, so that doesn't count.
All right, so I'm going to say heck no.
What? And I'm gonna say uh playlist count i'm gonna say uh 62 man 62 uh for not everybody is romeo romeo you gotta be ourselves you know 62 no they haven't made a mixtape because playlists don't count and 65
yes they've made a playlist well so we're both wrong by the price is right rules you're both
wrong on the percentage i'll tell you that you were both like very optimistic, uh, which is, you know, that's awesome.
Congrats for you.
But,
uh,
Joe won the popular.
Oh man,
come on.
Since a playlist doesn't count,
then no mixtape.
I have a new mission in life.
I'm going to get you people like you gotta,
you gotta be suave or if you know,
no,
nowadays everybody like, here's my Spotify playlist. Go, know no nowadays everybody like here's my spotify
playlist go go listen here's my itunes playlist yeah i guess sitting around listening for the
radio song to come on for hours doesn't really exist no man that that's those days are long gone
that was an art you gotta take time for romance
not anymore now it's now with these
subscription services you got now man you got access to all the music ever made joe you gotta
take time i i pay for spotify so i don't have to romance things you know sometimes i put like
little references in here and i'm not sure if... I wonder sometimes if people get my sense of humor or anything,
or if you even get it.
Did anyone happen to catch the...
Consider...
Let me just tell you, there are multiple Easter eggs
in some of the things that I throw out there
in the show notes or the conversation or whatnot.
Who's Ben Javie?
Ben Javie.avi yeah that was one no but like any reference to like the
man i got my technique down and everything that sounds familiar like friday or so i
though no no guess joe i'm terrible with references to anything.
When I wrote that, I was thinking of Samuel L. Jackson from Pulp Fiction.
Oh, man.
I've never seen it.
What?
Yeah, I don't know why.
Oh, my God.
Yeah.
Alan.
Yeah, I don't know why.
Jeez.
Okay.
We're going to need to do a Coding Blocks Blocks episode one of these days where we just, I don't know, maybe we take it offline.
We kind of discuss some of these things. Bring Alan up to speed on the ways of the world.
Yeah, we're going to have to table this for now, but yeah, we're going to help you.
We keep saying that we're going to do like a yes-yes-no with him.
We never have.
It'll be hilarious, though.
It's not going to be fun.
Well, that's the point.
That's the point.
It's supposed to be no. It'll be hilarious, though. It's not going to be fun. Well, that's the point. That's the point. It's supposed to start off.
The whole point of a yes, yes, no is that you're supposed to bring something to us.
Like, what does woke mean?
What does it mean to be woke?
And then we're going to say, okay, you don't know, so you're a no.
Joe knows, I know, so we're yeses.
And then we've got to explain it from there.
That's the whole point.
But I feel like it'll always be me saying what's
this right yes no no no that's reply all has recently done some sports yes yet well yes no
no's and they've been quite entertaining as well i can win those all right you would definitely win
those i would win those all right so for this's survey, we asked, and this was sent in to us by Joe Recursion Joe.
This was themed off of one of his ideas that he had, which was, hey, when you're not coding,
be it for school or work, but whatever your quote professional version of that would be,
in your free time, do you eat, sleep, code, repeat?
Coding is all that matters.
Or do you got to be well-rounded, get outside, ride a bike,
climb a mountain, hike a trail?
Or do you just sit back and watch Netflix, binge watch everything?
Or if you're like spoons,
Rocket League or insert favorite video game title here.
Yeah.
And you know what?
If we didn't list one of the options you like,
you can always drop a comment and tell us what you do like to do.
And you might win a book out of it.
Yep.
Codingblocks.net slash episode 76.
Freelancers and small business owners,
I feel for you. Tax season is here and there's a good chance that many of you are trying to dig your way out from underneath a pile of receipts and spreadsheets. Do yourself a huge favor and
stop digging. Before you completely disappear under that abyss of paperwork, go and check out
FreshBooks cloud accounting software. Not only is it going to save you a ton of time and stress, it might actually change the way you feel about dealing
with your taxes. Need to send your accountant a quick summary on the amount of tax you collected
last year? How about pulling together a profit and loss summary? FreshBooks can generate these
reports in seconds instead of the hours it would take you to do them manually. You can even set up
FreshBooks to import expenses directly from your bank accounts,
which means next time you use your debit card for the meal, tank of gas, or new computer,
boom, the purchase is recorded directly in FreshBooks.
All this and FreshBooks is ridiculously easy to use.
It's made especially for people who don't like dealing with numbers and their taxes.
Right now, FreshBooks is offering a 30-day unrestricted free trial to our listeners.
To claim it, just go to freshbooks.com slash coding and enter coding space blocks in the how did you hear about us section. And we're back. And we just happened to look at the clock
and realize just how long we've gone. So we know that we told you that this is going to be our last episode on clean architecture.
But in order to make a better listening experience for you guys and get to bed at a manageable time,
we're going to cut this one a little bit short and skip ahead to our resources.
And we'll have a part two of this guy coming out pretty soon here
so thanks for sticking with us and uh on to resources we like which will be simple it'll be
obviously clean architecture which has been pretty much the resource we like for
this entire series yeah it's been what like three months two months it's been a little
i don't want to quantify it at all but i do want to say um
we're not like so we're capping our discussion on this book uh you know after the the next episode
but there's actually a ton more to it the appendix is really good there's a lot of different sections
on here that dive into more specific examples there's more code in there which is really nice
and in fact there's a whole big section of the book called details that really kind of dives
into those some of those tough questions that we've kind of argued back and forth so definitely worth
picking up highly recommend it love this book well yeah and i don't even want to say that we
might not come back to it though we might good want to come back to it we just want to take a
break yeah we are we are going to to kick back a little so that, this is my favorite part of the show.
It's the tip of the week.
So what you got, Joe?
Yes. So Friday,
like five o'clock last week,
I was trying to figure out
this weird bug that just started
happening on something I hadn't even touched
recently, right?
JavaScript error, it just wasn't working.
I knew it would work a few days earlier.
I'm looking at the stack trace. It's like a mile long. I'm trying to figure out what I did.
Eventually, I started looking at the file history. Nothing, not seeing anything that should have
mattered at all. I'm blaming the framework right now. I'm convinced like this is a bug. And at
some point, I didn't even realize that I had done this because i know this is a terrible anti-pattern i know like it's kind of a programmer cliche to do
but at some point my bug hunt went from trying to figure out what was wrong and it changed into
trying to prove that my framework was wrong so that i could show somebody to be like look
doesn't make sense right here.
And I was so desperate for this that I kind of lost sight of the actual bug.
And anyway, by the time I figured out, I'd finally looked through enough history. And I looked at some files I didn't think mattered because everything was obviously correct because I had typed it all myself.
It's from my files.
It turned out that I'd reused a variable.
So I had a variable above my JavaScript method
and I had a closure,
which took an argument in that was the same variable name.
So in the closure,
I was thinking I was referencing the outer item.
I was actually referencing the inner.
And it just so happened,
the framework,
I would have expected it to be the same value anyway.
But in this case, it wasn't. It it was slightly different it was actually like a shallow copy that was just
missing some stuff that i hadn't expected i wouldn't have guessed based on looking at the error
anyway long story still long
use tools uh i had been griping about this in the javascript channel on the slack
and uh what i finally said came back you know on monday and said okay friday night saturday
monday i figured it out i'm an idiot here's what it was everyone's like well uh you know no doy
webstorm highlights that for you and i was like well i've got time to open up a second ide i mean
come on like what you got friday night you got saturday you got sunday or monday morning
to look into this thing i was like well that's a really good point there's actually really good
tools for this sort of thing and so i don don't know exactly at what point you should cut over to using more advanced tools.
And obviously I didn't get this one right,
but I have that available to me.
So I just want to kind of, it's a reminder out there,
like when you're bashing your head against the wall,
trying to figure out what's wrong,
sometimes it's good to kind of take a step back
and think about different approaches.
And so WebStorm is an example here.
I'm sure there are really great plugins
for Visual Studio Code or Visual Studio that would have helped me out here too.
And so I could have spent five minutes downloading that and opening that and would have found the problem a lot quicker.
That's my tip. Don't be like me.
Yeah, the funny part about that is like a month ago, I committed some code into one of these JavaScript files
that I know that Joe's heavily working in, right?
And I committed it locally.
I didn't push it up or anything,
but I went ahead and just introduced this new variable name
in the outer enclosure.
And then Friday afternoon, I'm like, okay, i'm ready to drop this bug right so i went ahead
and just pushed that in but because i didn't rebase or anything it was like way back in the
history of the git log so that he'd never find this thing right yeah so it's hilarious that all
weekend he was like i can't figure out why this is broken you know what's funny there is um the
deal was i i had this closure from the get-go and I was
only using one variable. It was something that passed from the framework. So I just
had to find that one variable. And then at some point I realized, oh, you know what? I want to
make use of the third variable that's passed to this closure. So I went in to the docs and said,
okay, here's the three argument names that they've got. Copy to paste it into my argument list.
And it just so happened that that second variable,
the one I wasn't even using,
the one I didn't care about at all,
was the one that had overlapped
because I had used kind of a generic term
for my data store.
And that's what did it.
And I didn't realize at the time
because I was so focused on testing
the one thing I was working on there.
It was in the UI.
It wasn't something easy to catch.
And it wasn't until much later that I realized
that something really strange was happening. Man's not fun nope all right i could
have been playing into the breach so uh i've got a couple of them for you so the first one
is just kind of like like this duh why didn't I already think about this kind of moment that I had?
But, you know, every one of us on this show,
we've talked about the show notes that we put out there for each episode.
And so if you haven't already checked it out,
you're really doing yourself a disservice. So like for this episode,
head to www.codingbox.net slash episode 76, and you'll be able to find all of the show notes
as it relates to this episode, right? But then what never dawned on me is that part of the way we
publish our episodes, those show notes are included with the episode.
So you can literally follow along with what we're saying as you're listening to us saying it all in
your podcast player, whatever app you're using, right? So you can see and click around and whatnot
and follow along with what we're saying.
And for some reason, that just never dawned on me before.
I don't know why, but it finally did.
And I was like, oh, man, this should definitely be a tip of the week.
So there's my why didn't I think of that sooner tip of the week.
And then this other one that I was like, oh, my God, I didn't realize you could do that. Was that in Visual Studio Code, I knew that you could highlight something and do it F12
and go to the definition of it.
What I didn't know is that you could control click that thing and go to the definition
of it.
Control click?
Yes.
Really? and go to the definition of it. And I was like, yes, when you click the, when you press control,
uh, it'll, if it's a fully named thing, you know, it'll underline it to let you know that it's
clickable. And you're like, Oh wait, what does that do? And you click it and boom, there you
are in the definition. So if you have like some kind of class name or something like that, um,
and you, then you could, you could go to the definition of that, that class name or something like that um and you then you could you could go to the definition
of that that class or maybe like in your um object you might have a dot property on it and you could
go to the definition of that so i'll include a link to microsoft's documentation for it but
because they talk about multiple ways to go to the definition, but control click has definitely become like my new favorite.
Awesome.
I love visual studio code.
All right.
So mine,
I've got a few here again,
because it's always stream of consciousness and I can never really remember
any of this stuff.
And even if I mark it down,
I somehow forget where they are.
So the first one is I sent a tweet out about that, this particular
one earlier this week, and it's named arguments in C sharp. And it's been available since version
four, not of the like the C sharp language version four, right. And really, all it is,
is this, if you've got a method that you're calling that has a super long parameter list,
which we've talked about is sort of a code smell,
but there are some times that you just can't get around it.
It's kind of frustrating when you look at it.
You see a string and you see true, true, false, you know, a number.
And you're like, I have no idea what this is.
And if you're not in an IDE, then it's really even more of a pain
because now you can't even go look, right?
Like if you're just browsing your code on git or whatever you don't even know well you can do named arguments which
would literally put the name of the parameter colon and then whatever the value is so if you
are looking in something like you know your vsts repo or github or whatever you can actually see
there oh this is the name of the parameter And here's the argument value that goes along with it. So it's a really nice way of being able to see
directly what you're passing to a method. So, you know, that's, that's really great for optional
arguments, too. So if you've got like one argument that's required and say that, you know, you want
to use the fifth one and everything between there isn't you can just do first argument comma then the name of the one you want to specify and then
that one oh that's a great point yeah you don't even have to put all five or six arguments in
there you just do the two that you want yeah excellent yeah and this isn't just uh a c-sharp
thing i mean like plenty of other languages have the same feature right right right yeah i think uh
you see this in python all the time that's what what I was going to say. One of the guys
actually was like, oh man, I use this in Python all
the time. I didn't know it was in C Sharp because he
was doing Unity development.
Does Java have it? I don't
know if Java does or not.
I wonder if I can Google that.
Java named arguments.
Let's see.
I see a Google feud in our future,
Joe. Brace yourself. The java idiom i've seen
for simulating keyword arguments and instructors is the builder pattern so no it does not look like
they do yeah i see how like spring does it with annotations and some other things but man
oh wait that was asked a long time ago, though. Maybe there are. Anyways. Yeah.
Let us know.
I take that back.
Maybe win a book.
I have no idea.
Oh, no, they do know.
It looks.
No, I don't know.
Anyway, I take it back.
All my rambling is gone.
All right.
So the next one I have is.
Okay.
So if you think the long parameter lists are code smell and we've mentioned that they are in the past, I've got a link here for refactoring.guru smells long parameter
lists.
And they have a few ways that you can get rid of it and the reasons why you might do
it and the reasons why you might not.
So that's just an external link for anybody that's interested.
And then because we've been talking about architecture.
So my buddy Ryan showed me
this today and I found this by going to GitHub and looking at trending. So you can go to github.com
slash trending. And if you're interested in a particular language, you can choose that language
over on the right hand side of the page and it'll show you all the hot trending things on GitHub, right? So I went and looked for C Sharp.
And there is one in here called eShop on containers that Microsoft has basically put together
their entire list of best practices for doing like a microservices architecture in containers,
in Azure, in whatever, like it's amazing. So if you ever want to see how to write a very
complex distributed application that can scale, they've got like their best practice thing up
here that all uses Docker and it'll run on windows. It'll run on Linux. Like you can,
you can literally set this thing up and get it running.
You can clone the repo and do it all. But I highly recommend it. Mixed in here, they've got things
such as the domain-driven design patterns on some of these things. They've got some nice little
diagrams that even show you what they did in various different places, their microservices,
their MVC app, all that. So highly highly recommend this thing it's cool to look at
if you're trying to learn about you know how you can set up these complicated and complex
architectures so i just went to the docs director here just to see you know how nice that was
uh they've got whole ebooks in here yeah in english and Spanish and Chinese. What?
Dude, this thing is so good.
They've even got, so check this out.
They've even got at the bottom,
orchestrators, Kubernetes and service fabric in Azure.
Like seriously?
Like, I mean, look, you could literally go do this thing
and learn how to set up and deploy
a multifaceted application.
Like really, really cool stuff here.
Yeah, even outside of Microsoft, this is just great general advice.
Like I'm looking at introduction to containers in Docker right now.
It's in one of the eBooks in the docs.
It's incredible.
Yeah, man.
It's all tailored.
The books look like they're heavily tailored towards this kind of setup and stuff. So it looks like it'll save you some time. Just like read here and then go click, click, man. It's all tailored. The books look like they're heavily tailored towards this kind of setup and stuff.
So it looks like it'll save you some time.
Just like to read here and then go click, click, boom, and see what they're talking about.
Yep.
So I was curious about your named parameter list.
And the top answer on Stack Overflow as of February of 2017 is a no.
On Java?
For Java, yeah.
And there's actually aipedia page for named parameter
and it lists uh all of the well it's a non-exhaustive list of languages but java is not
in that list interesting and i also looked up i was curious i was like does java even have
does it have uh optional arguments so i I looked and the answers are pretty fun.
It's like, no, but here's how you can do it.
You can define a variable called, you know, default argument one and just pass it right there.
You could do, create multiple methods that have different sets of arguments.
Like, man, that's not, that's not the question.
It's not the same.
Right.
I mean, I have been doing more Java development lately because, yeah.
So I've been doing more.
There are probably great reasons for it.
It's been catching up a little bit, though.
Like they now have anonymous methods that are similar to like link type stuff.
Right.
So there's definitely, they're catching back up with C Sharp.
I mean, obviously they were kind of what. Man, there's going to be some back up with C Sharp. I mean, obviously, they were kind of what...
Man, there's going to be some Java developers mad at you.
I mean,
there's just so many nice syntactic
sugar things in C Sharp that feel
very verbose in Java, but
it's definitely gotten better since
I last messed with it heavily.
Yeah, look, I'll put it out there. Give me VAR,
give me death.
I was thinking, though, that there's a lot in the Java community there where
they're way ahead.
Oh,
definitely.
Definitely.
If you go outside of Java and you do something like groovy,
even they're probably way further along than,
than what other languages are.
So,
I mean,
you know,
not picking on them,
but it,
it does feel like for me who is used used to C sharp, that it's actually,
it's gotten friendlier.
Yeah.
I mean,
so many concepts come out of the Java community.
It's incredible.
So I think,
um,
Java,
the language,
you know,
compared to C sharp,
you know,
whatever,
but Java developers,
top notch.
Uh,
uh,
uh,
uh,
a few octaves went up there.
That's awesome.
All right.
So that's a good lord, guys.
All right.
So yeah, we did some talking about humble object, layers and boundaries, main components, database gateways.
We remind you that there's no such thing as an ORM.
And we're really sorry for cutting this one short, guys.
Yeah.
We hate doing that.
Yeah, so we will continue this conversation one last time.
But until then, should you be listening to us
because a friend happened to point you to the website
or you're listening on their device,
or they just said, hey, they opened up your own device and said, hey, listen to this.
You can find us on iTunes, Stitcher, and more using your favorite podcast app
so that you can subscribe to us.
And leave us a review if you haven't already by heading to www.codingblocks.net
slash review.
And while you're up there,
check out our show notes,
examples,
discussions,
and more.
And we've got a fantastic Slack community.
So if you've got feedback,
questions or rants,
then you can take it there and talk to people that are much smarter than I am
about it.
And make sure to follow us on Twitter at CodingBlocks
or head over to CodingBlocks.net.
And remember, comment on the blog post for a book
or send us a review and send us an email with an address
and we'll hook you up with free stickers.
It's a limited time offer, you know, in case it goes terribly.
So send it quick.
And by the way, for the Slack thing,
go to CodingBlocks.net slash Slack if you want to join.
Yep, you can invite yourself.
Yep.
All right, guys.
That's a wrap.