00:00:01.640
okay I think it's good so whenever you're
00:00:07.320
ready hi everyone H I'm just getting sorted but I'm really excited to give
00:00:14.040
this talk uh it's called so writing tests feel painful what now uh and I I
00:00:19.520
did give it a couple of weeks ago at RSC in Detroit but I'm really excited to be
00:00:24.599
able to give it to to folks here all right just going to get started
00:00:31.480
um I learned recently about something called the stages of change model uh
00:00:37.079
which describes how people navigate making a significant decision or change
00:00:42.440
in behavior in their lives uh and I suspect that my talk
00:00:48.520
maybe intrigued you um because you are somewhere around here in this blob when
00:00:53.719
it comes to testing so in the contemplation stage uh you are considering making a change but you
00:01:00.359
might not know how you'll go about it uh in the determination stage you are ready to take an action U maybe starting with
00:01:06.920
some small approachable steps and if you are indeed somewhere you know um in these stages that is very great for me
00:01:14.799
uh because that means that I have the best possible opportunity today to help you move forward from where you're
00:01:23.079
at um so I know a lot of people struggle with
00:01:28.360
testing and they are not really sure uh what to do about it um as a consultant I
00:01:34.720
embed in client teams dealing with complexity in their day-to-day work uh
00:01:39.920
and it shows in their tests the following might sound familiar you try to read or write a test and then get
00:01:46.680
lost along the way um you find yourself bogged down brute forcing a test to Green um first of all that makes sense
00:01:54.320
that it's painful um especially if you work in a large and complicated code base and if already a pro at this um
00:02:01.920
this talk can still be for you U I think we would all be wise to understand and
00:02:07.560
empathize with the experiences of our fellow colleagues so what if I told you that
00:02:14.680
you already have a tool for determining the next step when you have some testing
00:02:20.800
struggle our instincts are very wise and we would do well to become more skilled
00:02:27.160
in listening to them so my goal for this talk is not to provide prescriptions but to teach you
00:02:35.560
how you can explore your own process for approaching a tricky test uh and today we'll work through an example realistic
00:02:42.599
to many modern rails apps that I've seen um we'll articulate some reactions
00:02:47.760
provoked by code learn how to adapt to them and then make space to experiment
00:02:53.000
with change so I would like us to imagine
00:02:58.560
that we're building an app called patreon it's like patreon but for pets
00:03:03.920
and it's a platform for people to financially support their favorite pets in exchange for various membership
00:03:10.720
perks this is my dog Hickory he has a page on patreon to cultivate a community
00:03:17.760
of people who want to give him love affection and
00:03:23.760
treats um you can join the Hickory fan club on a certain tier Each of which has
00:03:29.080
different membership benefits reasonable $5 a month gives you access to exclusive
00:03:35.040
album of cute pictures of him uh or you can go wild on the $100 tier and I will
00:03:41.040
personally cook him a steak dinner uh and let you FaceTime him monthly because why not and since I clearly know what
00:03:48.280
the users want um I've also you know built some functionality to let uh Hickory fans to try out benefits before
00:03:55.319
committing uh you can upgrade cheers on a trial basis
00:04:03.040
so this happens um via a class called tier with trial upgrader um which
00:04:09.599
accepts a membership and a tier in its initializer uh and it has one public
00:04:16.400
instance method called upgrade which starts the trial and updates the membership tier there's also some
00:04:22.720
conditional logic so let's say uh if the membership was already on a subscription based billing model uh it would update
00:04:30.320
the subscription with the trial information as well and this is perfectly serviceable code if you catch
00:04:37.120
my drift uh in many reals apps I've seen classes like these often orchestrate procedural work maybe it logs an event
00:04:44.479
or Ines some additional work uh in a background job so just business logic as
00:04:50.000
some may call it um but later it turns out that subscription based members are upset
00:04:56.919
because they didn't receive proper notification about their trial um they want to know when they'll be build next
00:05:04.080
so we find ourselves looking at this condition for if they have a paid subscription and you know let's say we
00:05:10.000
have already implemented some other class called subscription Notifier uh which has a class method named notify
00:05:15.680
trial started and it takes in a subscription which we can presume was
00:05:20.840
defined elsewhere in the file and um we have access to that trial variable from
00:05:26.160
earlier in the method
00:05:31.600
and since we introduced new Behavior we'd like to write a test for it um for this talk we are using rspec rails and
00:05:37.880
Factory bot as part of our testing toolkit so we navigate to the spec file
00:05:43.120
and hooray there's an existing test for this upgrade method uh and even the
00:05:48.240
particular condition that we are targeting uh except it looks like this
00:05:55.039
and I find it pretty overwhelming so I don't even want you to bother making too much sense of
00:06:01.840
slide so let me tell you um what I experienced when I look at that code
00:06:07.039
first I want to make a noise like ah because I don't know what to focus on um
00:06:12.880
I'm surprised to see some like class names of collaborators that we didn't uh
00:06:18.639
notice at first clance in the application code that we were looking at earlier and there's also some arbitrary
00:06:25.960
values in test data that I'm confused whether that's important or not
00:06:32.240
so I enumerate these feelings because once I do I tend to be able to observe them with less attachment uh I'm able to
00:06:40.280
step into a bit more curiosity about what's going on rather than kind of fill around in my
00:06:45.440
grievances um because I've certainly been there uh and and if you've heard of code smells you know there are hints
00:06:51.440
that something may be off about the design of our code regardless of the code working or even passing a test um
00:06:58.919
and I would that developing a nose for code smells takes practice uh but the
00:07:05.400
cool thing is that we already have an instrument to pay attention to which is our own state of
00:07:11.440
being so do remember my surprise about seeing additional collaborators it turns
00:07:17.000
out that these two methods that I've highlighted um actually obscure some implicit
00:07:24.240
dependencies um subscription is a memorized instance of the class stripes
00:07:29.520
subscription which takes in the membership uh and then when we call this update subscription method um we are
00:07:37.599
calling this update method on the subscription itself which takes in all these other arguments um including the
00:07:44.919
tiers that it's moving to and from as well as the end date of the trial and
00:07:50.720
you know I don't know why but this is just kind of what we're dealing with um anyone who works with Legacy or existing
00:07:58.319
code kind of knows that just like why is this like this
00:08:07.440
feeling so we can presume um we also sorry we are also
00:08:13.400
want to look at this uh start trial method and uh we find out that we call
00:08:21.039
the start class method on the trial model which we presume returns an instance of the trial that was started
00:08:31.120
so what now um our goal was to test the new behavior that we added um for that
00:08:36.200
Notifier but the existing test was so difficult to read and I imagine difficult to write um and we had to dip
00:08:43.120
into details of private methods to understand what was
00:08:49.360
happening when you write a test you are interacting with the code as a
00:08:54.480
user it said that if testing feels painful uh we might want to reconsider
00:09:00.200
the design of our code and to me that begs the question what are tests for so
00:09:05.959
you know we often know them as verifying behavior and catching bugs but if they give us grief and we don't know why I
00:09:12.680
think there is a bit of a mindset shift in order uh and I'm of the opinion that we should write tests for ourselves and
00:09:19.760
for each other not just for a green check mark um a good test tells you how
00:09:25.360
the system works how to use methods available to you what to put in and expect out and potentially any side
00:09:32.920
effects that happen along the way so I like to think of it as leaving a torch in a dark tunnel um we pay it forward
00:09:40.120
when we write tests with the intention that others will rely on them including our future
00:09:45.880
selves so we find ourselves a little bit lost in this dark tunnel in the tier
00:09:51.160
with trial upgrader class um we're a bit uncertain and that's okay uh it's not
00:09:56.320
anyone's fault and what matters is kind of what we choose to do next and how we find our
00:10:03.200
foot so the main feeling I want to resolve is that
00:10:08.640
overwhelm uh and I kind of start asking myself like what would help to ground myself in this test file and maybe I
00:10:15.959
might start reorganizing um information in the test so I could collocate
00:10:21.079
Behavior by inlining some references or definitions that are defined kind of far
00:10:27.120
away um either like in another file file or just at the top of the file in some
00:10:32.800
let blocks or maybe at the bottom um if it's like a helper method in the test file uh I maybe will flatten or Nest
00:10:40.920
some like context blocks depending if I need to just like situate the context
00:10:47.279
around the different conditions being tested um so that I'm able to see everything in front of me but in this
00:10:53.000
case I actually want to start with a clean slate and write the test from scratch even though there's already an
00:10:59.000
exist test for this code path um this helps me not be biased by what was
00:11:04.399
written previously um because you know it's our test now and we can do whatever we'd like with
00:11:12.920
it you may feel nervous to write a totally new test for existing code and
00:11:19.959
that's okay that could mean that you need some more information before getting started you know Common Sense
00:11:25.720
tells us to get directions um before heading off into the unknown so I suggest asking yourself a couple of
00:11:33.480
questions um to get that guidance so do you know what you're testing do you know
00:11:39.680
how to set up the object method under test do you know how to get into the
00:11:44.959
appropriate code path uh if not you know maybe there's a bit more work ahead of you but once I've gotten my bearings I
00:11:52.480
follow the arrange act assert pattern for organizing my tests which helps me keep track of where we've been and what
00:11:58.480
we still need to do uh and sometimes I begin at the end with the assertion because that's information
00:12:04.399
we have at hand um since we already wrote it in the test description so because I would like to
00:12:10.839
verify the behavior of notifying here um since it's a side effect and we don't really have an accessible state to
00:12:16.600
assert on um we mock subscription Notifier and expect it to have received
00:12:21.920
our method notify trial started uh and next we want to fill in
00:12:29.279
the ACT part of our pattern so we construct the instance of a tier with upgrader trial to call the upgrade
00:12:35.320
method on and it needs a membership in a tier which we don't have yet so we
00:12:40.600
provide those two arguments by setting them up with Factory bot uh and since we want to enter that condition for when a
00:12:47.120
membership has a subscription we set the has paid subscription attribute to
00:12:52.920
True uh lately I've also been finding it helpful to think about necessary versus
00:12:58.160
unnecessary coupling in test so uh coupling is the degree to which things
00:13:03.880
need to change together um and if you've heard about it you might have heard that it's something to avoid um because it's
00:13:10.959
kind of said that Loosely coupled modular software is easier to work with and change um but I do want to point out
00:13:18.040
that some amount of coupling is expected in test code uh because we need some entry point into our system right so
00:13:25.000
considering the minimum dependencies required for a test kind of primes me to notice when that coupling starts to
00:13:31.240
spiral a bit and we are kind of dealing with more things than uh we think we might need
00:13:40.320
to and I think we would benefit from kind of taking a look at where we're at now with our
00:13:45.440
coupling so first of all um we are coupled to the class and Method under
00:13:52.079
test and luckily upgrade doesn't accept uh any other arguments so we don't have
00:13:57.160
to worry about creating uh additional objects there um but we do have
00:14:03.920
to uh know about the arguments to new up that class and any details for configuring
00:14:10.759
them and then lastly um the class responsible for the side effect because that's what we're asserting on and for
00:14:16.519
now that all seems pretty reasonable to me however we want to ensure that
00:14:24.040
notified trial started is sent with the correct subscription and trial not just any
00:14:29.759
um so here we are using our specs with method to constrain our expectation but
00:14:36.920
now we have a problem how do we specify these arguments that we want to um match
00:14:43.040
on when we don't have access to subscription or trial in our test
00:14:49.000
code uh because remember subscription comes from this private
00:14:54.920
method so we instantiate a subscription in the test test um and in order to make
00:15:01.839
an assertion on it we unfortunately need to stub stretch subscriptions new method
00:15:07.199
uh to return it uh and so our test kind of starts to
00:15:13.720
look like this it grew a couple of lines and I feel somewhat uneasy about the arsic Wizardry that we had to do to stub
00:15:21.240
the subscription um I want to make note of that feeling but for now we'll move on because we still need to set up a
00:15:26.399
trial and if you'll recall um a trial is
00:15:32.319
returned by this class method on start called start so we build a trial with a factory
00:15:39.800
and again we need to stub a class method in order to verify that the trial returned by start does indeed get passed
00:15:45.560
into our Notifier uh and so this is where I begin
00:15:50.680
to juggle a few too many things in my head uh but we are so close you know we are ready to run our test so we do that
00:15:58.519
and if fails spectacularly so why why why that big
00:16:05.600
scary block of red um it turns out that following the path to update a subscription makes a request to that
00:16:13.360
stripe API um and that failure can manifest in a couple different ways you might see an error related to stripe
00:16:19.560
itself um if your app uses a library called Web moach it will complain about
00:16:24.600
making uh external network requests that you didn't stud previously uh or worst case like what we saw just
00:16:31.759
now we'll get some obtuse M Class exception because the code is just so brittle that you simply can't run the
00:16:38.759
test in isolation despite setting up everything referenced in the
00:16:44.360
class so fine uh we don't want to boser with subscription actually up executing its update method that eventually calls
00:16:51.720
the API um so we plug that up here with another allow statement and now if you can believe it
00:16:59.519
we finally arrived at a green test honestly at this point I'm pretty
00:17:06.679
mad because that sucked and I've lost a lot of my steam um when I'm in this mood
00:17:13.559
like my pessimism just blocks like any kind of critical thinking that I might
00:17:19.000
be able to have so when I try to push push through uh I I know I do worse work
00:17:25.360
um because I would like to be interacting with the code you know from like a a calm sense of State rather than
00:17:33.280
frustration at just getting the thing to work so now is an excellent time to take a break and grab a snack and pet my
00:17:42.200
dog uh I don't know just just look at guy don't you want to join us
00:17:48.840
patreon um anyway so we come back to the test in its full Glory you know after a
00:17:54.080
bit of a break and it's passing which is awesome and so we can take a moment to
00:17:59.320
celebrate what we've accomplished thus far so in testing the notified trial
00:18:06.919
started method um and that it was invoked with the correct arguments we made explicit the data
00:18:14.480
needed uh for the method under
00:18:19.799
test we unor some coupling to stripe via the subscription uh and we learned how
00:18:26.360
trials are started so uh there's a a book that I read and
00:18:32.919
loved kind of in preparation for this talk and it's called working effectively with Legacy code by Michael feathers and
00:18:38.880
in it he introduces this concept called a characterization test
00:18:44.559
um when writing tests for code you don't understand the goal is not to figure out
00:18:50.600
what it should do but what it actually does so testing no longer is this like
00:18:56.360
moral Authority but just a tool for um gathering
00:19:02.400
information and I really like this framing because it encourages Discovery
00:19:07.440
as the primary goal um even though we had some existing coverage writing the
00:19:13.159
test from scratch illuminated a lot of things about our code you know whether we liked finding that out or
00:19:22.280
not but that brings me to the to my next point which is to move at the Speed Of Trust in your tests because if you don't
00:19:29.159
have trustworthy tests it's not surprising to me that kind of that fear
00:19:34.360
of change lurks in every file um and it's not enough for tests just to fail
00:19:40.559
if you don't understand why they broke so that's why I take the time to care
00:19:45.720
for and restore tests it's the quickest and safest way to observe the behavior of um our
00:19:54.440
application so now that I'm no longer as overwhelmed um by that existing test I
00:20:00.440
because I know exactly what I wrote here um I'm more clued in to some other types of friction so let's say I start to like
00:20:08.520
have to scroll up and down a lot in this test file to navigate it that's kind of annoying um and that Clues me into what
00:20:16.120
started as a few lines like five or so lines at the beginning is actually you know taken up a lot of real
00:20:23.240
estate so in other words um this class has grown a lot of additional responsib
00:20:28.679
abilities that it might not be suited for when it was um originally written
00:20:34.679
the upgrade method now has to start a trial it has to determine if a membership has a subscription it has to
00:20:42.240
instantiate the subscription update it send the notification and then update the membership also um and so writing
00:20:48.640
out responsibilities of classes and methods like this can it can just be in a code comment or like on a Post-It if
00:20:55.120
you like um analog uh this is a technique te commonly used in domain
00:21:00.200
driven design uh and I find it really useful when I need to make sense of existing
00:21:06.440
code and with that awareness of all the things that it's doing I don't love this change because it was already managing
00:21:13.559
many tasks and I just added to it uh I mean I I think most of us have been
00:21:18.679
there um but it experience tells me that code like that only attracts more
00:21:23.919
responsibilities right um here just you see all the things that started doing
00:21:29.760
and you're like oh what's one more thing but you know now that I like have looked at it and sat with it I'm just like H is
00:21:38.440
there anything I can do here you know I'm not totally keen on just merging it because there is some aspect of thinking
00:21:44.600
like maybe my work's not complete especially because we've built up all this knowledge about um how the
00:21:51.360
code works and I want to make sure that it's put to good use you know we spent all that time learning about the the
00:21:59.039
stuff that was hidden to us um and so for me that's kind of a cue to seek out opportunities for improvement and with
00:22:05.640
our trusty test in place we can actually start to practice refactoring with
00:22:11.840
safety so here is what our test descriptions
00:22:16.919
currently look like um their setups ended up being quite similar and now is a great time to ask like why does that
00:22:23.640
duplication exist uh in a previous life before I was was a Dev I went to journalism school
00:22:31.120
where I learned the value of brevity uh so I often find myself noticing
00:22:36.520
redundancy and I've actually highlighted all the instances of the words subscription and trial here because I
00:22:43.679
think usually with that redundancy you know there's perhaps like a missing
00:22:49.320
connection you know maybe there is there's some operations that need to happen um
00:22:56.760
together and I also want follow up that on that awkwardness that I had mentioned um earlier from allowing all of these
00:23:04.320
messages uh because by doing this we kind of wave a magic wand over these methods so that they're not actually
00:23:10.480
exercised and when these allowances make up the bulk of my test I start to get a little dubious because you know how do I
00:23:16.600
know that my code actually is integrated properly um when I've allowed all these shortcuts uh in my test and that feeling
00:23:23.559
should nudge you towards a more focused unit test um and and I chose an example
00:23:29.679
with excessive stubbing because I think it's a common cause of test pain um and there is a different style of testing
00:23:35.480
that you might be familiar with that involves uh more about creating all the objects necessary to exercise the code
00:23:42.159
fully um so rather than stubbing that update method on the subscription that called the stripe API we also could have
00:23:48.320
set up more collaborators needed until we reached that boundary of the
00:23:53.440
application um but I think in general having to create many objects and likely
00:23:58.840
um they're also creating records in the test database uh is a symptom of of the same problem um so while we are taking a
00:24:05.559
bit of a different approach by stubbing here I think being a bit wary of mystery
00:24:11.039
guests that show up to the party is also a good kind of feeling to um just pay
00:24:16.760
attention to so that that doubt that I mentioned about things being plumbed kind of
00:24:22.760
correctly turns my attention to this condition uh because that is where we had to um add of some additional law
00:24:30.720
statements and I think it's kind of surprising how these mere two lines just
00:24:35.919
generated so much more um in the test and kind of to figure out what to
00:24:45.480
do about that I ended up inlining the update subscription method like so because now I can see more clearly what
00:24:52.080
all is involved and my eye couches on how we're exposing that tier name method
00:24:58.080
on the subscription because this would be available from inside the instance method
00:25:04.320
update um and that kind of brings me to my next dis discret piece of advice
00:25:09.480
which is if you start to get lost or distracted by a bunch of method calls that's a signal um there might just be
00:25:16.600
simply like too much information for your brain to hold it's not because you you know can't figure out what's going
00:25:23.279
on I made a point earlier to keep an eye on that extraneous coupling and this is what I'm talking about um the failing
00:25:29.799
test we saw earlier also reinforced this concern um we found ourselves very deep in the guts of dealing with the shape of
00:25:36.640
striped subscription API and you know I know a rabbit hole when I see one so
00:25:42.600
this code not only leaks details about subscription but as you can see we're also calling these extra methods on tier
00:25:48.559
and trial also that we now have to know about a little more or
00:25:55.520
start to maybe distract us from what this class is actually doing and so with all that laid out in
00:26:01.520
front of me I wonder like is there a meaning hidden here for me to discern is there a way to distill that information
00:26:07.159
into a single idea um and many people associate redund redundancy with
00:26:12.679
applying dry um the drive principle do not repeat yourself uh but I find that rule quite lacking in Nuance um the
00:26:20.600
point isn't just to remove duplication but it requires like sitting with the ambiguity until you're able to express
00:26:28.679
the truest and most precise abstraction um with your code and I I think anything
00:26:35.159
less risks obis skating meaning like we saw
00:26:40.440
earlier and to be clear this is very hard and it takes a lot of time um I often like to pair with someone to talk
00:26:46.679
it through because it's a very like creative and generative um task I think
00:26:53.200
so I I like someone else to just kind of to Riff on it or be like do you have any
00:26:58.279
naming ideas for this um and it also helps develop a common language for the code that we're working on together
00:27:04.159
which is just critical to sharing knowledge across the team because you know we should be able to work on code
00:27:09.760
in an application written by someone else and kind of understand what's going on and again not
00:27:16.279
because not because you can't figure it out um that's not what should be hard uh
00:27:21.679
I think it's figuring out what the code actually means or is wanting to tell us um and that is part of the work you know
00:27:29.520
is what we need to be doing so after giving a think I landed on encapsulating the two
00:27:35.360
responsibilities in a new method um we sprouted the idea of updating a
00:27:40.919
subscription specifically in the context of a trial and we wrapped it with the intention of notifying so um that's why
00:27:48.799
I've created this new method called notified update with trial and this is another strategy I
00:27:55.200
like from working effectively with Legacy code wrapping meth methods lets us add new functionality to existing
00:28:00.679
ones um without modifying uh those existing methods and we've also introduced a new seam a seam is a place
00:28:08.120
that enables Behavior to change um the one we've made here separates the class responsible for orchestrating all of
00:28:14.519
things um that needs to happen in an upgrade with the mechanisms of actually how the upgrade Works uh and then our
00:28:21.799
seam dovetails really nicely with another guideline called tell don't ask so previously the code exposed uh
00:28:28.480
information about the tier subscription and Notifier um in when it came to the arguments that we were passing in um and
00:28:35.960
so now instead of querying for those details in the tier with upgrade or trial class we simply tell the
00:28:41.799
subscription to do a notified update and um those details get kind
00:28:47.600
of uh encapsulated there so we don't have to like have that mental overhead
00:28:53.559
of trying to be like oh what are these what are all these other kind of method calls happening do I need to care about
00:29:00.159
them and the best part is that we can basically move our existing test into the spec file for strip subscription
00:29:06.320
with a few Manor adjustments uh and that leaves us with only one test needed for that condition
00:29:13.320
in tier with trial upgrader um as well as getting rid of uh two of those allow
00:29:19.600
statements to stub um our code and I think that's an improvement um and this
00:29:26.559
is kind of where we stop for now I've been sitting with this example for now two months uh and I still see areas
00:29:35.000
for improvement but perfect is the enemy of good and you know that's a task for another
00:29:41.519
day so this is what the method looks like now um You might be thinking that
00:29:47.360
that was a whole lot of effort for it to look almost exactly the same uh was it worth it h I think so the only way to
00:29:54.360
deal with complexity is to manage it and now we've created an affordance for this emerging concept related to a
00:30:01.440
subscription and we prevented this class from growing another line um another responsibility so we didn't add another
00:30:07.799
thing to that post not uh and we learned a lot we learned a lot and that is
00:30:14.159
incredibly valuable we documented those learnings as collective wisdom in our tests for our team and ourselves um
00:30:21.480
building up that knowledge is crucial because I think that's just what's required in order to shape change with
00:30:27.399
creativity and clarities just really looking at what you're dealing with um Michael feather says the biggest
00:30:35.600
obstacle to Improvement in large code bases is the existing code but I'm not talking about how hard it is to work in
00:30:41.200
difficult code I'm talking about what that code leads you to believe so code is constantly provoking reactions in us
00:30:47.880
and it doesn't even need to be old code it can be code you wrote like 10 minutes
00:30:53.080
ago um how we feel when we write tests is one of the quickest feedback loops
00:30:58.240
that we have about the quality of our system so if we ignore or numb ourselves to that pain we end up losing faith in
00:31:04.720
our work I think um or Worse we are told to do a dreaded
00:31:10.360
rewrite and we need to find better ways of of coping because that test pain matters um can you figure out what you
00:31:17.799
need to do right now to tend to itth it doesn't even need to be a sweeping refactor you know it's just even
00:31:24.760
building up that knowledge and finding a little bit of like a foothold to to grab on to um
00:31:32.360
small actions like that do add up uh and that's important so we can
00:31:38.399
continue obviously doing the good work of connecting pets and pet lovers on our very viable and profitable product
00:31:47.080
petria and to call back to the stages of change model from the beginning I would be thrilled if I were
00:31:53.200
able to help you move you know a little bit forward on it towards determination and action
00:31:58.440
um in harnessing the power of your tests and if you're ready to dive deeper
00:32:04.200
I learned referenced and found inspiration from lots and lots of resources for this talk um so you can
00:32:11.960
check a lot of these out if you want and then I talked a little bit
00:32:17.279
today about design patterns and heris stics um some of which you may have heard before uh and I wanted to share a
00:32:24.840
cool tidbit I learned which is that objectoriented programming picked up the idea of design patterns from the Art and
00:32:33.039
Science of architecture so specifically the work of an architect named Christopher Alexander and he has a book
00:32:38.799
called the Timeless way of building where he theorizes why patterns work so
00:32:44.159
well for us and he uh claims that they invoke a quality without a name and he
00:32:51.399
illustrates this by distinguishing the design of a courtyard that feels alive versus dead so a living Courtyard is one
00:32:58.600
that supports life by enabling our natural walking patterns connecting to open space with a view it just feels
00:33:05.159
good to be in uh and in contrast a dead Courtyard is one whose design like fails
00:33:10.360
to provide for the needs of human beings so it might be totally enclosed or have no shade it's uninviting and as a result
00:33:19.000
you know becomes abandoned because no one actually wants to spend time in it and um our our human intuition can tell
00:33:26.000
the difference when we inhabit these spaces right I'm sure you all know that feeling um when you yeah just enjoy
00:33:33.440
being in the world in a very like well architected or design space and I would
00:33:38.799
even say that the same is true of the code that we work
00:33:43.960
in um the tech industry loves being data driven but I actually find a lot of inspiration in remembering the purpose
00:33:51.080
of things like best practices um and I think it lies Beyond what's clean or
00:33:57.000
Superior uh and it's something that no algorithm can quite capture uh because as Dono
00:34:03.519
says pretending that something doesn't exist even if it's hard to quantify leads to faulty models human beings have
00:34:09.919
been endowed not only with the ability to count but also with the ability to assess quality
00:34:16.000
so um I would love to not lose sight of that quality without a name which is how we feel about our software uh and since
00:34:22.919
you're already writing a test um you know you can ask yourself what you need to find some pieace and ease in that
00:34:28.520
work uh and then make it so I'm Stephanie man I work at a
00:34:34.000
consultancy called thoughtbot um you can hire us to help your team write joyful
00:34:39.520
and maintainable tests if that is something that your team is struggling with uh I host a podcast weekly about
00:34:46.359
software development called bike shed um and yeah that's that's it for me thanks
00:34:53.879
hi says thanks too um happy to answer questions and yeah okay I am wrapping up
00:35:02.800
now