[Script Info] Title: [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text Dialogue: 0,0:00:00.51,0:00:17.22,Default,,0000,0000,0000,,(jazzy music) Dialogue: 0,0:00:17.22,0:00:20.17,Default,,0000,0000,0000,,Sandi:So you'd think that writing Dialogue: 0,0:00:20.17,0:00:23.29,Default,,0000,0000,0000,,object-oriented code was hard. Dialogue: 0,0:00:23.29,0:00:26.66,Default,,0000,0000,0000,,All you have to do is\Nlook at our apps, alright? Dialogue: 0,0:00:26.66,0:00:29.97,Default,,0000,0000,0000,,We mean well, and we write\Ncode that almost always Dialogue: 0,0:00:29.97,0:00:35.26,Default,,0000,0000,0000,,inevitably we eventually come to hate it. Dialogue: 0,0:00:35.26,0:00:36.96,Default,,0000,0000,0000,,And the more I think\Nabout this, these days, Dialogue: 0,0:00:36.96,0:00:39.45,Default,,0000,0000,0000,,somehow my job is to think\Nabout how to write better code. Dialogue: 0,0:00:39.45,0:00:42.60,Default,,0000,0000,0000,,And the more I think about\Nit, the more I think that Dialogue: 0,0:00:42.60,0:00:47.34,Default,,0000,0000,0000,,all of the problems we cause\Nhave the same simple solution, Dialogue: 0,0:00:47.34,0:00:49.46,Default,,0000,0000,0000,,and that when people ask me now Dialogue: 0,0:00:49.46,0:00:51.25,Default,,0000,0000,0000,,how to write object-oriented code, Dialogue: 0,0:00:51.25,0:00:54.77,Default,,0000,0000,0000,,I give them one small piece of advice. Dialogue: 0,0:00:54.77,0:00:58.42,Default,,0000,0000,0000,,I say make smaller\Nthings, that's all it is. Dialogue: 0,0:00:58.42,0:01:00.59,Default,,0000,0000,0000,,Make smaller classes,\Nmake smaller methods, Dialogue: 0,0:01:00.59,0:01:04.93,Default,,0000,0000,0000,,and let them know as little\Nabout each other as possible. Dialogue: 0,0:01:04.93,0:01:06.64,Default,,0000,0000,0000,,And lately I've been on a quest. Dialogue: 0,0:01:06.64,0:01:08.23,Default,,0000,0000,0000,,I've had this obsession for\Nthe last couple of months, Dialogue: 0,0:01:08.23,0:01:10.48,Default,,0000,0000,0000,,and it's been about conditionals. Dialogue: 0,0:01:10.48,0:01:11.45,Default,,0000,0000,0000,,There's a lot of code out there Dialogue: 0,0:01:11.45,0:01:12.87,Default,,0000,0000,0000,,with nasty conditionals in it, Dialogue: 0,0:01:12.87,0:01:15.68,Default,,0000,0000,0000,,and I've been wondering,\Nwhen should I replace Dialogue: 0,0:01:15.68,0:01:17.87,Default,,0000,0000,0000,,conditionals with small objects, Dialogue: 0,0:01:17.87,0:01:19.63,Default,,0000,0000,0000,,and how should I do this, Dialogue: 0,0:01:19.63,0:01:22.59,Default,,0000,0000,0000,,and what would happen to my code if I do? Dialogue: 0,0:01:22.59,0:01:24.38,Default,,0000,0000,0000,,And I was really confident\Nin Miami in November Dialogue: 0,0:01:24.38,0:01:26.97,Default,,0000,0000,0000,,and I inflicted this\Nobsession upon Jim Weirich, Dialogue: 0,0:01:26.97,0:01:29.65,Default,,0000,0000,0000,,whom some of you probably knew, Dialogue: 0,0:01:29.65,0:01:33.45,Default,,0000,0000,0000,,and he pointed me in the\Ndirection of the Gilded Rose. Dialogue: 0,0:01:33.45,0:01:34.88,Default,,0000,0000,0000,,Now this is a Kata, it's apparently Dialogue: 0,0:01:34.88,0:01:37.23,Default,,0000,0000,0000,,really well known, but\NI don't get out much, Dialogue: 0,0:01:37.23,0:01:38.84,Default,,0000,0000,0000,,so I had...\N(laughter) Dialogue: 0,0:01:38.84,0:01:40.63,Default,,0000,0000,0000,,never heard of it. Dialogue: 0,0:01:40.63,0:01:43.69,Default,,0000,0000,0000,,And so, it is so famous\Nthat you can just Google it, Dialogue: 0,0:01:43.69,0:01:46.73,Default,,0000,0000,0000,,and get an explanation of the\Nproblem, but I didn't do that. Dialogue: 0,0:01:46.73,0:01:48.38,Default,,0000,0000,0000,,I wanted to treat this problem as if Dialogue: 0,0:01:48.38,0:01:50.34,Default,,0000,0000,0000,,it was a real production problem, Dialogue: 0,0:01:50.34,0:01:51.97,Default,,0000,0000,0000,,and that my only source of information Dialogue: 0,0:01:51.97,0:01:54.15,Default,,0000,0000,0000,,was the test and the code. Dialogue: 0,0:01:54.15,0:01:56.34,Default,,0000,0000,0000,,And so I looked at his. Dialogue: 0,0:01:56.34,0:01:58.39,Default,,0000,0000,0000,,I checked it out of his [repo], Dialogue: 0,0:01:58.39,0:01:59.32,Default,,0000,0000,0000,,and I looked at the problem, Dialogue: 0,0:01:59.32,0:02:02.33,Default,,0000,0000,0000,,and I was so interested in it\Nthat it became the skeleton Dialogue: 0,0:02:02.33,0:02:06.78,Default,,0000,0000,0000,,around which I have hung\Nthe ideas for today's talk. Dialogue: 0,0:02:06.78,0:02:09.57,Default,,0000,0000,0000,,I have altered his code just a little bit, Dialogue: 0,0:02:09.57,0:02:11.26,Default,,0000,0000,0000,,but it's just to make\Nit easier to talk about. Dialogue: 0,0:02:11.26,0:02:13.69,Default,,0000,0000,0000,,This really is the Gilded Rose Kata, Dialogue: 0,0:02:13.69,0:02:14.51,Default,,0000,0000,0000,,and here's how it goes. Dialogue: 0,0:02:14.51,0:02:17.37,Default,,0000,0000,0000,,There's a Gilded Rose class,\Nand it's structured like this. Dialogue: 0,0:02:17.37,0:02:20.45,Default,,0000,0000,0000,,It has attributes for name,\Nquality, and days remaining, Dialogue: 0,0:02:20.45,0:02:22.33,Default,,0000,0000,0000,,it sets those in an initializer, Dialogue: 0,0:02:22.33,0:02:24.93,Default,,0000,0000,0000,,and then there's a tick method. Dialogue: 0,0:02:24.93,0:02:27.53,Default,,0000,0000,0000,,Now here's the tick\Nmethod, well actually, no, Dialogue: 0,0:02:27.53,0:02:32.84,Default,,0000,0000,0000,,that's just the first half\Nof it, here's the rest. Dialogue: 0,0:02:32.84,0:02:34.34,Default,,0000,0000,0000,,Now, I know you can't read this. Dialogue: 0,0:02:34.34,0:02:36.23,Default,,0000,0000,0000,,Well, don't even try,\Neven if you can, alright? Dialogue: 0,0:02:36.23,0:02:37.38,Default,,0000,0000,0000,,This is the whole method. Dialogue: 0,0:02:37.38,0:02:38.100,Default,,0000,0000,0000,,I just want you to get some sense Dialogue: 0,0:02:38.100,0:02:39.84,Default,,0000,0000,0000,,of the size and shape of it. Dialogue: 0,0:02:39.84,0:02:43.26,Default,,0000,0000,0000,,It's a 43-line "if" statement. Dialogue: 0,0:02:43.26,0:02:45.44,Default,,0000,0000,0000,,And this seems really, really hard to me, Dialogue: 0,0:02:45.44,0:02:48.75,Default,,0000,0000,0000,,but I am known to be Bullion-impaired. Dialogue: 0,0:02:48.75,0:02:50.44,Default,,0000,0000,0000,,(laughter) Dialogue: 0,0:02:50.44,0:02:52.34,Default,,0000,0000,0000,,So, I know that my subjective\Nsense of how difficult this is Dialogue: 0,0:02:52.34,0:02:55.27,Default,,0000,0000,0000,,to understand is probably not correct, Dialogue: 0,0:02:55.27,0:02:57.33,Default,,0000,0000,0000,,and so instead I used some metrics. Dialogue: 0,0:02:57.33,0:03:00.51,Default,,0000,0000,0000,,I ran a complexity metric\Ncalled "Flog" against it. Dialogue: 0,0:03:00.51,0:03:02.48,Default,,0000,0000,0000,,So Flog is a metric. OK, what's a metric? Dialogue: 0,0:03:02.48,0:03:06.39,Default,,0000,0000,0000,,A metric is a crowdsource\Nidea about something. Dialogue: 0,0:03:06.39,0:03:09.62,Default,,0000,0000,0000,,Right? I have my own opinion\Nabout how complex this is, Dialogue: 0,0:03:09.62,0:03:12.56,Default,,0000,0000,0000,,but I can use this sort of\Nwisdom-of-the-crowd metric, Dialogue: 0,0:03:12.56,0:03:14.66,Default,,0000,0000,0000,,the Flog metric, which scores... Dialogue: 0,0:03:14.66,0:03:17.25,Default,,0000,0000,0000,,It's an ABC metric, so\Nit scores assignments, Dialogue: 0,0:03:17.25,0:03:18.79,Default,,0000,0000,0000,,branches, and conditionals. Dialogue: 0,0:03:18.79,0:03:20.66,Default,,0000,0000,0000,,It just counts things, and adds them up. Dialogue: 0,0:03:20.66,0:03:21.96,Default,,0000,0000,0000,,Higher scores are worse. Dialogue: 0,0:03:21.96,0:03:23.89,Default,,0000,0000,0000,,They indicate a more complex code, Dialogue: 0,0:03:23.89,0:03:25.24,Default,,0000,0000,0000,,a code that's going to be harder Dialogue: 0,0:03:25.24,0:03:26.95,Default,,0000,0000,0000,,to understand and reason about. Dialogue: 0,0:03:26.95,0:03:30.45,Default,,0000,0000,0000,,And so, Flog says the Gilded\NRose class scored a 50, Dialogue: 0,0:03:30.45,0:03:33.61,Default,,0000,0000,0000,,and that one method tick scored a 45. Dialogue: 0,0:03:33.61,0:03:36.12,Default,,0000,0000,0000,,(moans) \NYeah, just hurts, doesn't it? Dialogue: 0,0:03:36.12,0:03:38.15,Default,,0000,0000,0000,,So, Flog says it's complicated, Dialogue: 0,0:03:38.15,0:03:40.17,Default,,0000,0000,0000,,but before we go on I want to introduce Dialogue: 0,0:03:40.17,0:03:44.37,Default,,0000,0000,0000,,a very subjective metric about complexity. Dialogue: 0,0:03:44.37,0:03:45.69,Default,,0000,0000,0000,,So, I spend a lot of time these days Dialogue: 0,0:03:45.69,0:03:51.20,Default,,0000,0000,0000,,going to places and looking\Nat code I know nothing about. Dialogue: 0,0:03:51.20,0:03:52.64,Default,,0000,0000,0000,,People call me up, and I go to their shop, Dialogue: 0,0:03:52.64,0:03:54.30,Default,,0000,0000,0000,,and I spend a few days. Dialogue: 0,0:03:54.30,0:03:55.94,Default,,0000,0000,0000,,And as you might imagine, Dialogue: 0,0:03:55.94,0:03:59.75,Default,,0000,0000,0000,,no one calls me if things are going well. Dialogue: 0,0:03:59.75,0:04:01.80,Default,,0000,0000,0000,,(laughter)\NAlright? Dialogue: 0,0:04:01.80,0:04:03.59,Default,,0000,0000,0000,,And when I get there, they don't ask me Dialogue: 0,0:04:03.59,0:04:06.65,Default,,0000,0000,0000,,to look at the code they're proud of. Dialogue: 0,0:04:06.65,0:04:09.30,Default,,0000,0000,0000,,They ask me to look at the most\Nheinous bits of their apps, Dialogue: 0,0:04:09.30,0:04:11.18,Default,,0000,0000,0000,,the things that have sort of complex, Dialogue: 0,0:04:11.18,0:04:13.65,Default,,0000,0000,0000,,lengthy contexts in history. Dialogue: 0,0:04:13.65,0:04:16.58,Default,,0000,0000,0000,,Code that has just absolutely\Ngotten out of hand. Dialogue: 0,0:04:16.58,0:04:19.51,Default,,0000,0000,0000,,And not only are the\Nexplanations long and confusing Dialogue: 0,0:04:19.51,0:04:21.75,Default,,0000,0000,0000,,because the problem is hard, Dialogue: 0,0:04:21.75,0:04:22.49,Default,,0000,0000,0000,,but they do that thing that we all do, Dialogue: 0,0:04:22.49,0:04:24.50,Default,,0000,0000,0000,,you know that thing\Nyou do when you have to Dialogue: 0,0:04:24.50,0:04:26.41,Default,,0000,0000,0000,,explain a bit of code that you wrote Dialogue: 0,0:04:26.41,0:04:28.42,Default,,0000,0000,0000,,that you're embarrassed about to someone? Dialogue: 0,0:04:28.42,0:04:30.49,Default,,0000,0000,0000,,You don't just tell them how it works. Dialogue: 0,0:04:30.49,0:04:31.56,Default,,0000,0000,0000,,You feel compelled to explain Dialogue: 0,0:04:31.56,0:04:34.91,Default,,0000,0000,0000,,all the reasons why it got\Nthat way. (laughter) Right? Dialogue: 0,0:04:34.91,0:04:37.16,Default,,0000,0000,0000,,You laugh. I do it. I know\Nyou do it, too, right? Dialogue: 0,0:04:37.16,0:04:38.59,Default,,0000,0000,0000,,It just hurts. We hate that. Dialogue: 0,0:04:38.59,0:04:40.18,Default,,0000,0000,0000,,And so, these explanations are long Dialogue: 0,0:04:40.18,0:04:41.37,Default,,0000,0000,0000,,and confusing and they have lots of Dialogue: 0,0:04:41.37,0:04:44.33,Default,,0000,0000,0000,,sort of sideways kind of information. Dialogue: 0,0:04:44.33,0:04:46.20,Default,,0000,0000,0000,,And there's a point in\Ntime, I really mean well, Dialogue: 0,0:04:46.20,0:04:47.45,Default,,0000,0000,0000,,but there's a point in time during every Dialogue: 0,0:04:47.45,0:04:50.21,Default,,0000,0000,0000,,explanation when I start\Nfeeling like that dog, Dialogue: 0,0:04:50.21,0:04:54.72,Default,,0000,0000,0000,,Ginger, in this Gary Larson's cartoon Dialogue: 0,0:04:54.72,0:04:56.48,Default,,0000,0000,0000,,where it starts turning\Ninto, blah, blah, blah, Dialogue: 0,0:04:56.48,0:04:58.47,Default,,0000,0000,0000,,Sandi, blah, blah, blah. (laughs)\N(laughter) Dialogue: 0,0:04:58.47,0:05:00.40,Default,,0000,0000,0000,,And then suddenly I get startled back Dialogue: 0,0:05:00.40,0:05:01.51,Default,,0000,0000,0000,,into awareness when I hear them say, Dialogue: 0,0:05:01.51,0:05:03.56,Default,,0000,0000,0000,,"So, what do you think we should do Dialogue: 0,0:05:03.56,0:05:07.21,Default,,0000,0000,0000,,"about this line of code?" (laughs)\N(laughter) Dialogue: 0,0:05:07.21,0:05:08.94,Default,,0000,0000,0000,,And it used to terrify me, right? Dialogue: 0,0:05:08.94,0:05:10.80,Default,,0000,0000,0000,,I felt like I had to understand everything Dialogue: 0,0:05:10.80,0:05:12.93,Default,,0000,0000,0000,,in order to help with anything. Dialogue: 0,0:05:12.93,0:05:14.37,Default,,0000,0000,0000,,But it turned out that after a few trips, Dialogue: 0,0:05:14.37,0:05:15.96,Default,,0000,0000,0000,,I realized that there was a really Dialogue: 0,0:05:15.96,0:05:17.41,Default,,0000,0000,0000,,simple thing I could do to help me Dialogue: 0,0:05:17.41,0:05:19.98,Default,,0000,0000,0000,,identify code that they\Ncould benefit from changing. Dialogue: 0,0:05:19.98,0:05:24.24,Default,,0000,0000,0000,,And I call this the "squint test".\N(laughter) Dialogue: 0,0:05:24.24,0:05:25.86,Default,,0000,0000,0000,,Here's how it works. Dialogue: 0,0:05:25.86,0:05:29.17,Default,,0000,0000,0000,,You squint your eyes, you lean back, Dialogue: 0,0:05:29.17,0:05:30.86,Default,,0000,0000,0000,,and you look at the code. Dialogue: 0,0:05:30.86,0:05:36.33,Default,,0000,0000,0000,,And we're looking for changes in shape,\N(laughter) Dialogue: 0,0:05:36.33,0:05:39.70,Default,,0000,0000,0000,,and changes in color. Dialogue: 0,0:05:39.70,0:05:41.27,Default,,0000,0000,0000,,Changes in shape mean you\Nhave nested conditionals Dialogue: 0,0:05:41.27,0:05:44.21,Default,,0000,0000,0000,,and they are always going\Nto be hard to reason about. Dialogue: 0,0:05:44.21,0:05:45.64,Default,,0000,0000,0000,,Changes in color mean that your code is Dialogue: 0,0:05:45.64,0:05:48.89,Default,,0000,0000,0000,,at differing levels of abstraction, Dialogue: 0,0:05:48.89,0:05:50.34,Default,,0000,0000,0000,,and it means the story it tells Dialogue: 0,0:05:50.34,0:05:52.34,Default,,0000,0000,0000,,is going to be hard to follow. Dialogue: 0,0:05:52.34,0:05:53.68,Default,,0000,0000,0000,,Now, what is it about this code? Dialogue: 0,0:05:53.68,0:05:55.51,Default,,0000,0000,0000,,Well, it has 16 if statements, Dialogue: 0,0:05:55.51,0:05:56.98,Default,,0000,0000,0000,,some of those are not equal to them, Dialogue: 0,0:05:56.98,0:05:58.57,Default,,0000,0000,0000,,and connect something with an "&", Dialogue: 0,0:05:58.57,0:06:00.73,Default,,0000,0000,0000,,there are three magic strings,\Nthey're used all over, Dialogue: 0,0:06:00.73,0:06:01.56,Default,,0000,0000,0000,,and a number of magic numbers, Dialogue: 0,0:06:01.56,0:06:04.55,Default,,0000,0000,0000,,I don't even know how many.\N(laughter) Dialogue: 0,0:06:04.55,0:06:06.21,Default,,0000,0000,0000,,Now, at least it has tests. Dialogue: 0,0:06:06.21,0:06:07.96,Default,,0000,0000,0000,,Oh, I'm sorry, here are the magic strings. Dialogue: 0,0:06:07.96,0:06:08.86,Default,,0000,0000,0000,,These three things: Dialogue: 0,0:06:08.86,0:06:11.66,Default,,0000,0000,0000,,Brie, Sulfuras, and Backstage passes, Dialogue: 0,0:06:11.66,0:06:13.36,Default,,0000,0000,0000,,whatever that means. Dialogue: 0,0:06:13.36,0:06:17.80,Default,,0000,0000,0000,,And it does have tests, and they pass. Dialogue: 0,0:06:17.80,0:06:21.63,Default,,0000,0000,0000,,Now, there are six skipped tests, alright?\N(laughter) Dialogue: 0,0:06:21.63,0:06:24.82,Default,,0000,0000,0000,,So, I don't know what that's about. Dialogue: 0,0:06:24.82,0:06:26.93,Default,,0000,0000,0000,,And so, I pry open the code, I\Njust look at this first test. Dialogue: 0,0:06:26.93,0:06:31.15,Default,,0000,0000,0000,,Oh, sorry, the tests cluster\Naround the magic strings, Dialogue: 0,0:06:31.15,0:06:32.74,Default,,0000,0000,0000,,except for this set, which is for Dialogue: 0,0:06:32.74,0:06:34.18,Default,,0000,0000,0000,,something called "Normal", Dialogue: 0,0:06:34.18,0:06:37.71,Default,,0000,0000,0000,,which is never mentioned in\Nthe "if" statement. (laughter) Dialogue: 0,0:06:37.71,0:06:40.37,Default,,0000,0000,0000,,I suspect there's something\Nin an [L's] branch Dialogue: 0,0:06:40.37,0:06:41.41,Default,,0000,0000,0000,,somewhere that matters here, alright? Dialogue: 0,0:06:41.41,0:06:42.98,Default,,0000,0000,0000,,So, I pry open the test and I look at it. Dialogue: 0,0:06:42.98,0:06:46.20,Default,,0000,0000,0000,,Here's one, they all look just like this. Dialogue: 0,0:06:46.20,0:06:50.41,Default,,0000,0000,0000,,I'm selling something, ok? Dialogue: 0,0:06:50.41,0:06:51.62,Default,,0000,0000,0000,,Given a Gilded Rose that has this name, Dialogue: 0,0:06:51.62,0:06:55.11,Default,,0000,0000,0000,,attribute, and quality, those\Nare our three [add-a-readers], Dialogue: 0,0:06:55.11,0:06:59.70,Default,,0000,0000,0000,,When I tick, in this case,\Nquality goes down by one, Dialogue: 0,0:06:59.70,0:07:02.30,Default,,0000,0000,0000,,days remaining goes down by one, Dialogue: 0,0:07:02.30,0:07:03.22,Default,,0000,0000,0000,,they both go down by one. Dialogue: 0,0:07:03.22,0:07:04.26,Default,,0000,0000,0000,,So, it's as if I'm selling milk, Dialogue: 0,0:07:04.26,0:07:06.56,Default,,0000,0000,0000,,or eggs, or cheese or something\Nthat has a sell-by date, Dialogue: 0,0:07:06.56,0:07:10.38,Default,,0000,0000,0000,,that's going to expire, where\Nthey go bad at some date. Dialogue: 0,0:07:10.38,0:07:12.62,Default,,0000,0000,0000,,OK, so, I'm still exploring around, Dialogue: 0,0:07:12.62,0:07:15.14,Default,,0000,0000,0000,,I don't even know what my job is yet, Dialogue: 0,0:07:15.14,0:07:17.58,Default,,0000,0000,0000,,and I look at the six skipped tests, Dialogue: 0,0:07:17.58,0:07:22.85,Default,,0000,0000,0000,,and there is something called "Conjured",\N(laughter) Dialogue: 0,0:07:22.85,0:07:23.28,Default,,0000,0000,0000,,and they all follow the same pattern, Dialogue: 0,0:07:23.28,0:07:24.87,Default,,0000,0000,0000,,all of the tests look like given that Dialogue: 0,0:07:24.87,0:07:26.81,Default,,0000,0000,0000,,when I tick, I see this change. Dialogue: 0,0:07:26.81,0:07:30.14,Default,,0000,0000,0000,,And at this point, I realize, holy crap, Dialogue: 0,0:07:30.14,0:07:33.46,Default,,0000,0000,0000,,I'm supposed to change this code.\N(laughter) Dialogue: 0,0:07:33.46,0:07:36.95,Default,,0000,0000,0000,,And so I tried, I tried, Dialogue: 0,0:07:36.95,0:07:41.96,Default,,0000,0000,0000,,very obediently, I tried, but\NI was a miserable failure. Dialogue: 0,0:07:41.96,0:07:43.12,Default,,0000,0000,0000,,I couldn't do it. Dialogue: 0,0:07:43.12,0:07:44.70,Default,,0000,0000,0000,,That 43 lines of statement defeated me. Dialogue: 0,0:07:44.70,0:07:47.92,Default,,0000,0000,0000,,Every time I went, I would\Nlike pry open a Conjured test Dialogue: 0,0:07:47.92,0:07:49.12,Default,,0000,0000,0000,,and I'd go make some change\Nin that "if" statement Dialogue: 0,0:07:49.12,0:07:51.94,Default,,0000,0000,0000,,to make that test pass, it\Nwould break something else. Dialogue: 0,0:07:51.94,0:07:53.13,Default,,0000,0000,0000,,I spent hours on it. Dialogue: 0,0:07:53.13,0:07:54.79,Default,,0000,0000,0000,,Now, I am impaired, but\Nreally, it was hard. Dialogue: 0,0:07:54.79,0:07:56.92,Default,,0000,0000,0000,,It would be hard for you, too, I think. Dialogue: 0,0:07:56.92,0:07:58.74,Default,,0000,0000,0000,,And so, if changing that "if" statement Dialogue: 0,0:07:58.74,0:08:00.31,Default,,0000,0000,0000,,was so hard, you have to ask, Dialogue: 0,0:08:00.31,0:08:02.30,Default,,0000,0000,0000,,why was I trying? Why did I try to do, Dialogue: 0,0:08:02.30,0:08:03.46,Default,,0000,0000,0000,,what possessed me to try to alter Dialogue: 0,0:08:03.46,0:08:09.14,Default,,0000,0000,0000,,that incredibly complicated bit of code? Dialogue: 0,0:08:09.14,0:08:12.46,Default,,0000,0000,0000,,And the answer is, I felt\Nlike I was supposed to. Dialogue: 0,0:08:12.46,0:08:13.63,Default,,0000,0000,0000,,And here's what happens, right? Dialogue: 0,0:08:13.63,0:08:16.72,Default,,0000,0000,0000,,You write some code,\Nsomeone asks for a change. Dialogue: 0,0:08:16.72,0:08:17.61,Default,,0000,0000,0000,,What do we do? Dialogue: 0,0:08:17.61,0:08:18.28,Default,,0000,0000,0000,,You go look around at the code base Dialogue: 0,0:08:18.28,0:08:20.74,Default,,0000,0000,0000,,for a code that's the closest thing Dialogue: 0,0:08:20.74,0:08:22.50,Default,,0000,0000,0000,,to the new thing you're trying to do, Dialogue: 0,0:08:22.50,0:08:24.66,Default,,0000,0000,0000,,and you put the new code there. Dialogue: 0,0:08:24.66,0:08:25.37,Default,,0000,0000,0000,,That's how we behave. Dialogue: 0,0:08:25.37,0:08:28.48,Default,,0000,0000,0000,,Novices especially, they're\Nafraid to make new objects, Dialogue: 0,0:08:28.48,0:08:30.62,Default,,0000,0000,0000,,so they just go put more\Ncode in where they can Dialogue: 0,0:08:30.62,0:08:32.52,Default,,0000,0000,0000,,find a thing like the thing\Nthey're trying to add, Dialogue: 0,0:08:32.52,0:08:34.28,Default,,0000,0000,0000,,and if that place already\Nhas an "if" statement, Dialogue: 0,0:08:34.28,0:08:36.95,Default,,0000,0000,0000,,they just put another branch on it, right? Dialogue: 0,0:08:36.95,0:08:38.59,Default,,0000,0000,0000,,That's how it works. Dialogue: 0,0:08:38.59,0:08:40.11,Default,,0000,0000,0000,,And what happens is,\Nso the natural tendency Dialogue: 0,0:08:40.11,0:08:41.29,Default,,0000,0000,0000,,of code is to grow bigger, Dialogue: 0,0:08:41.29,0:08:42.46,Default,,0000,0000,0000,,and bigger, and bigger. Dialogue: 0,0:08:42.46,0:08:43.46,Default,,0000,0000,0000,,And there comes a point, right? Dialogue: 0,0:08:43.46,0:08:44.42,Default,,0000,0000,0000,,It gets bigger, and bigger, and bigger. Dialogue: 0,0:08:44.42,0:08:46.31,Default,,0000,0000,0000,,And there comes a point where it tips, Dialogue: 0,0:08:46.31,0:08:48.12,Default,,0000,0000,0000,,and at that point it's so big that Dialogue: 0,0:08:48.12,0:08:50.54,Default,,0000,0000,0000,,you cannot imagine putting\Ncode anywhere else. Dialogue: 0,0:08:50.54,0:08:53.22,Default,,0000,0000,0000,,We have a bargain to follow the pattern, Dialogue: 0,0:08:53.22,0:08:55.86,Default,,0000,0000,0000,,and if the pattern is a\Ngood one, code gets better. Dialogue: 0,0:08:55.86,0:08:59.19,Default,,0000,0000,0000,,And if the pattern is a bad\None, we exacerbate the problem. Dialogue: 0,0:08:59.19,0:09:01.72,Default,,0000,0000,0000,,Nobody adds a 10-line helper class to a Dialogue: 0,0:09:01.72,0:09:04.21,Default,,0000,0000,0000,,5000-line active record object. Dialogue: 0,0:09:04.21,0:09:05.64,Default,,0000,0000,0000,,They just get bigger. Dialogue: 0,0:09:05.64,0:09:09.24,Default,,0000,0000,0000,,Once they reach a certain\Nsize, they just get bigger. Dialogue: 0,0:09:09.24,0:09:12.81,Default,,0000,0000,0000,,And so, I could not follow the pattern. Dialogue: 0,0:09:12.81,0:09:14.30,Default,,0000,0000,0000,,I was not good enough\Nto follow the pattern, Dialogue: 0,0:09:14.30,0:09:17.17,Default,,0000,0000,0000,,and so I decided I was\Ngoing to make a new pattern, Dialogue: 0,0:09:17.17,0:09:19.41,Default,,0000,0000,0000,,That I was going to refactor this code. Dialogue: 0,0:09:19.41,0:09:21.39,Default,,0000,0000,0000,,Now, this is real refactoring according Dialogue: 0,0:09:21.39,0:09:23.29,Default,,0000,0000,0000,,to the definition of refactoring, Dialogue: 0,0:09:23.29,0:09:25.81,Default,,0000,0000,0000,,I'm going to refactor this code, Dialogue: 0,0:09:25.81,0:09:26.67,Default,,0000,0000,0000,,I'm going to change its arrangement Dialogue: 0,0:09:26.67,0:09:28.89,Default,,0000,0000,0000,,without altering its behavior. Dialogue: 0,0:09:28.89,0:09:30.52,Default,,0000,0000,0000,,I'm not going to try to add Conjured, Dialogue: 0,0:09:30.52,0:09:31.64,Default,,0000,0000,0000,,I'm going to try to move this code Dialogue: 0,0:09:31.64,0:09:34.98,Default,,0000,0000,0000,,around so that I can add Conjured. Dialogue: 0,0:09:34.98,0:09:36.68,Default,,0000,0000,0000,,And for refactoring, for refactoring Dialogue: 0,0:09:36.68,0:09:38.97,Default,,0000,0000,0000,,it's like this test with\Na wall at your back. Dialogue: 0,0:09:38.97,0:09:39.89,Default,,0000,0000,0000,,You've got to have tests, Dialogue: 0,0:09:39.89,0:09:41.81,Default,,0000,0000,0000,,or you don't know what you're doing. Dialogue: 0,0:09:41.81,0:09:43.30,Default,,0000,0000,0000,,And so, I'm just going\Nto start at the top. Dialogue: 0,0:09:43.30,0:09:44.73,Default,,0000,0000,0000,,I'm going to start with\Nthese Normal tests, Dialogue: 0,0:09:44.73,0:09:45.73,Default,,0000,0000,0000,,and I've got this code. Dialogue: 0,0:09:45.73,0:09:47.27,Default,,0000,0000,0000,,This is what tick looks like. Dialogue: 0,0:09:47.27,0:09:49.41,Default,,0000,0000,0000,,Now this is a big, long procedure. Dialogue: 0,0:09:49.41,0:09:51.37,Default,,0000,0000,0000,,This is not object-oriented code. Dialogue: 0,0:09:51.37,0:09:54.55,Default,,0000,0000,0000,,In object-oriented code, you\Nhave lots of little objects, Dialogue: 0,0:09:54.55,0:09:56.20,Default,,0000,0000,0000,,and you send messages between them. Dialogue: 0,0:09:56.20,0:09:57.70,Default,,0000,0000,0000,,And those messages give you a level of Dialogue: 0,0:09:57.70,0:09:59.62,Default,,0000,0000,0000,,indirection so that you can substitute Dialogue: 0,0:09:59.62,0:10:01.61,Default,,0000,0000,0000,,different objects at the back. Dialogue: 0,0:10:01.61,0:10:04.87,Default,,0000,0000,0000,,Messages create seams so that\Nyou can do a different thing, Dialogue: 0,0:10:04.87,0:10:08.53,Default,,0000,0000,0000,,and there is no seam here\Nbecause this is a procedure. Dialogue: 0,0:10:08.53,0:10:09.79,Default,,0000,0000,0000,,And so the first thing I have to do Dialogue: 0,0:10:09.79,0:10:13.14,Default,,0000,0000,0000,,if I want to refactor is\NI have to make a seam, Dialogue: 0,0:10:13.14,0:10:15.35,Default,,0000,0000,0000,,and I'm going to do that just by Dialogue: 0,0:10:15.35,0:10:17.93,Default,,0000,0000,0000,,tracking Normal and Bailing. Dialogue: 0,0:10:17.93,0:10:23.17,Default,,0000,0000,0000,,At this point, four tests should\Nfail, and they do, alright? Dialogue: 0,0:10:23.17,0:10:26.96,Default,,0000,0000,0000,,And I am not about to add\Nmore code to the tick method, Dialogue: 0,0:10:26.96,0:10:29.73,Default,,0000,0000,0000,,so I'm just going to\Nsend a message to myself, Dialogue: 0,0:10:29.73,0:10:33.14,Default,,0000,0000,0000,,and four tests should\Nstill fail, and they do. Dialogue: 0,0:10:33.14,0:10:34.34,Default,,0000,0000,0000,,And so, now that I believe that I have Dialogue: 0,0:10:34.34,0:10:36.62,Default,,0000,0000,0000,,caught that execution path, Dialogue: 0,0:10:36.62,0:10:38.43,Default,,0000,0000,0000,,I'm going to just break\Nopen the first test Dialogue: 0,0:10:38.43,0:10:41.86,Default,,0000,0000,0000,,and I'm going to write\Nthe code and make it pass. Dialogue: 0,0:10:41.86,0:10:45.24,Default,,0000,0000,0000,,Quality goes down by\None, that's easy enough. Dialogue: 0,0:10:45.24,0:10:47.71,Default,,0000,0000,0000,,I can write that code. Dialogue: 0,0:10:47.71,0:10:52.25,Default,,0000,0000,0000,,Days remaining goes down by\None, and that test passes. Dialogue: 0,0:10:52.25,0:10:54.58,Default,,0000,0000,0000,,Alright? One down, three to go. Dialogue: 0,0:10:54.58,0:10:56.43,Default,,0000,0000,0000,,Here's the next test. Dialogue: 0,0:10:56.43,0:10:58.83,Default,,0000,0000,0000,,In this case, it looks\Nlike I'm out of time, Dialogue: 0,0:10:58.83,0:11:03.23,Default,,0000,0000,0000,,I'm on the sale-by-date, so\Nnow quality goes down by two. Dialogue: 0,0:11:03.23,0:11:07.30,Default,,0000,0000,0000,,So, I'll just make sure my\Nold test keeps on passing, Dialogue: 0,0:11:07.30,0:11:10.51,Default,,0000,0000,0000,,and I'll write code to\Nmake this test pass. Dialogue: 0,0:11:10.51,0:11:12.51,Default,,0000,0000,0000,,And so, now I think two tests should pass, Dialogue: 0,0:11:12.51,0:11:14.99,Default,,0000,0000,0000,,so I should have two failures. Dialogue: 0,0:11:14.99,0:11:17.51,Default,,0000,0000,0000,,But something I just did made some test Dialogue: 0,0:11:17.51,0:11:20.32,Default,,0000,0000,0000,,I haven't looked at\Npass, and we love that. Dialogue: 0,0:11:20.32,0:11:24.84,Default,,0000,0000,0000,,I'm not even going to look\Nat it. (laughter) Alright? Dialogue: 0,0:11:24.84,0:11:26.96,Default,,0000,0000,0000,,I don't need to understand\Nit, I've got tests. (laughter) Dialogue: 0,0:11:26.96,0:11:28.69,Default,,0000,0000,0000,,OK, so I'm going to just go, Dialogue: 0,0:11:28.69,0:11:30.37,Default,,0000,0000,0000,,I'm going to make this one pass, alright? Dialogue: 0,0:11:30.37,0:11:32.92,Default,,0000,0000,0000,,I'll just open the last one. Dialogue: 0,0:11:32.92,0:11:37.99,Default,,0000,0000,0000,,So, this one says if the\Nquality is already zero, Dialogue: 0,0:11:37.99,0:11:39.94,Default,,0000,0000,0000,,don't change it. Dialogue: 0,0:11:39.94,0:11:41.82,Default,,0000,0000,0000,,And so I'm just going\Nto wrap this whole thing Dialogue: 0,0:11:41.82,0:11:46.14,Default,,0000,0000,0000,,in an "if" statement, and not\Ndo anything if quality is zero. Dialogue: 0,0:11:46.14,0:11:49.10,Default,,0000,0000,0000,,OK, so now I'm back to green. Dialogue: 0,0:11:49.10,0:11:51.76,Default,,0000,0000,0000,,That code was not smart or clever, Dialogue: 0,0:11:51.76,0:11:53.83,Default,,0000,0000,0000,,but that's the whole point. Dialogue: 0,0:11:53.83,0:11:56.25,Default,,0000,0000,0000,,Once I get to green, I can now refactor. Dialogue: 0,0:11:56.25,0:11:58.97,Default,,0000,0000,0000,,So my goal is to get to\Ngreen as quickly as possible. Dialogue: 0,0:11:58.97,0:12:02.55,Default,,0000,0000,0000,,Red is not when you\Nponder the abstraction. Dialogue: 0,0:12:02.55,0:12:05.65,Default,,0000,0000,0000,,Red is when you scramble toward green. Dialogue: 0,0:12:05.65,0:12:06.31,Default,,0000,0000,0000,,You're trying to reach to look for the Dialogue: 0,0:12:06.31,0:12:08.25,Default,,0000,0000,0000,,lowest hanging green here, Dialogue: 0,0:12:08.25,0:12:10.92,Default,,0000,0000,0000,,and so I got there, I'm at green now, Dialogue: 0,0:12:10.92,0:12:13.97,Default,,0000,0000,0000,,and I confessed to you already\Nthat I am Bullion-impaired, Dialogue: 0,0:12:13.97,0:12:14.21,Default,,0000,0000,0000,,and I have written code that even Dialogue: 0,0:12:14.21,0:12:17.82,Default,,0000,0000,0000,,I at this moment do not understand, Dialogue: 0,0:12:17.82,0:12:20.55,Default,,0000,0000,0000,,but now I'm green, so I can refactor. Dialogue: 0,0:12:20.55,0:12:22.27,Default,,0000,0000,0000,,It looks to me that they always Dialogue: 0,0:12:22.27,0:12:24.70,Default,,0000,0000,0000,,subtract one from days remaining, Dialogue: 0,0:12:24.70,0:12:25.93,Default,,0000,0000,0000,,so I'm going to do that first. Dialogue: 0,0:12:25.93,0:12:28.54,Default,,0000,0000,0000,,I like that story better. Dialogue: 0,0:12:28.54,0:12:31.14,Default,,0000,0000,0000,,It looks to me like\Nthey don't do anything, Dialogue: 0,0:12:31.14,0:12:33.19,Default,,0000,0000,0000,,I can just bail if quality is zero, Dialogue: 0,0:12:33.19,0:12:34.36,Default,,0000,0000,0000,,so I can take that whole outer Dialogue: 0,0:12:34.36,0:12:36.47,Default,,0000,0000,0000,,nesting out of that "if" statement, Dialogue: 0,0:12:36.47,0:12:37.48,Default,,0000,0000,0000,,and now once I get to here, Dialogue: 0,0:12:37.48,0:12:39.94,Default,,0000,0000,0000,,I can ponder these two remaining cases. Dialogue: 0,0:12:39.94,0:12:42.26,Default,,0000,0000,0000,,Are there two cases here? Dialogue: 0,0:12:42.26,0:12:43.96,Default,,0000,0000,0000,,Is there a case where I\Nsubtract one from quality Dialogue: 0,0:12:43.96,0:12:46.64,Default,,0000,0000,0000,,and two from quality, or\Nis this, I don't think so. Dialogue: 0,0:12:46.64,0:12:48.38,Default,,0000,0000,0000,,Now that I look at it this way, Dialogue: 0,0:12:48.38,0:12:51.37,Default,,0000,0000,0000,,I think I always subtract\None from quality, Dialogue: 0,0:12:51.37,0:12:52.72,Default,,0000,0000,0000,,and there's a special case in which Dialogue: 0,0:12:52.72,0:12:56.77,Default,,0000,0000,0000,,I subtract another, if\NI'm past the sell-by date. Dialogue: 0,0:12:56.77,0:12:57.92,Default,,0000,0000,0000,,And so, I can just delete all that, Dialogue: 0,0:12:57.92,0:13:00.58,Default,,0000,0000,0000,,and now I have this, which is all the same Dialogue: 0,0:13:00.58,0:13:02.66,Default,,0000,0000,0000,,level of abstraction,\Nand I can understand it. Dialogue: 0,0:13:02.66,0:13:04.32,Default,,0000,0000,0000,,I love the story this code tells. Dialogue: 0,0:13:04.32,0:13:05.53,Default,,0000,0000,0000,,It's very simple. Dialogue: 0,0:13:05.53,0:13:08.92,Default,,0000,0000,0000,,It was easy to get here,\Nand now my test will pass. Dialogue: 0,0:13:08.92,0:13:09.83,Default,,0000,0000,0000,,Alright, so we're going to do this Dialogue: 0,0:13:09.83,0:13:11.52,Default,,0000,0000,0000,,over and over again, much\Nmore quickly than this one. Dialogue: 0,0:13:11.52,0:13:13.58,Default,,0000,0000,0000,,I'm going to just take you\Nthrough a quick reprise here. Dialogue: 0,0:13:13.58,0:13:17.47,Default,,0000,0000,0000,,So, I create a seam, I\Nsend a message to myself, Dialogue: 0,0:13:17.47,0:13:19.11,Default,,0000,0000,0000,,I tracked all the\Nexecution paths into here, Dialogue: 0,0:13:19.11,0:13:20.58,Default,,0000,0000,0000,,I wrote some code, I hated it, Dialogue: 0,0:13:20.58,0:13:21.76,Default,,0000,0000,0000,,I got to green as quick as possible, Dialogue: 0,0:13:21.76,0:13:22.87,Default,,0000,0000,0000,,and then I used green to let me Dialogue: 0,0:13:22.87,0:13:25.22,Default,,0000,0000,0000,,refactor to code that was sensible, Dialogue: 0,0:13:25.22,0:13:27.00,Default,,0000,0000,0000,,and now Normal is done. Dialogue: 0,0:13:27.00,0:13:28.73,Default,,0000,0000,0000,,All the Normal tests passed. Dialogue: 0,0:13:28.73,0:13:29.98,Default,,0000,0000,0000,,So, now I'm just going to bust right Dialogue: 0,0:13:29.98,0:13:31.52,Default,,0000,0000,0000,,through all the other cases. Dialogue: 0,0:13:31.52,0:13:33.81,Default,,0000,0000,0000,,Here's Brie, there's a\Nwhole bunch of stuff. Dialogue: 0,0:13:33.81,0:13:34.84,Default,,0000,0000,0000,,I'm going to turn that into a case Dialogue: 0,0:13:34.84,0:13:37.12,Default,,0000,0000,0000,,statement so I can track Brie. Dialogue: 0,0:13:37.12,0:13:38.97,Default,,0000,0000,0000,,There are seven tests, and\Nthey're all failing now, Dialogue: 0,0:13:38.97,0:13:41.54,Default,,0000,0000,0000,,so I have confidence\Nthat I have caught them. Dialogue: 0,0:13:41.54,0:13:42.65,Default,,0000,0000,0000,,I'm going to write the code, Dialogue: 0,0:13:42.65,0:13:43.99,Default,,0000,0000,0000,,but you don't even need to look at it Dialogue: 0,0:13:43.99,0:13:45.42,Default,,0000,0000,0000,,because you can see how easy it is, right? Dialogue: 0,0:13:45.42,0:13:48.90,Default,,0000,0000,0000,,Now that I am only\Nhaving to write code for Dialogue: 0,0:13:48.90,0:13:50.46,Default,,0000,0000,0000,,one test at a time, it's pretty\Nsimple to write the code. Dialogue: 0,0:13:50.46,0:13:53.50,Default,,0000,0000,0000,,What I end up with looks like this. Dialogue: 0,0:13:53.50,0:13:55.52,Default,,0000,0000,0000,,And now Brie is done. Dialogue: 0,0:13:55.52,0:13:59.92,Default,,0000,0000,0000,,And now a really\Ninteresting thing happens. Dialogue: 0,0:13:59.92,0:14:01.18,Default,,0000,0000,0000,,When this stuff was buried in the Dialogue: 0,0:14:01.18,0:14:02.50,Default,,0000,0000,0000,,43-line "if" statement, Dialogue: 0,0:14:02.50,0:14:06.54,Default,,0000,0000,0000,,I had no idea the ways in which\NNormal and Brie were like, Dialogue: 0,0:14:06.54,0:14:10.30,Default,,0000,0000,0000,,but now that I'm using this,\Nthey seem a lot alike to me. Dialogue: 0,0:14:10.30,0:14:12.55,Default,,0000,0000,0000,,Now, there's differences sort\Nof in the driving data here, Dialogue: 0,0:14:12.55,0:14:14.69,Default,,0000,0000,0000,,but the algorithm, you can see the shape Dialogue: 0,0:14:14.69,0:14:17.30,Default,,0000,0000,0000,,of the algorithm here, and the\Nalgorithm is really the same. Dialogue: 0,0:14:17.30,0:14:18.80,Default,,0000,0000,0000,,And it is very tempting. Dialogue: 0,0:14:18.80,0:14:22.19,Default,,0000,0000,0000,,We've had the DRY rule\Nbrowbeat into us so strongly, Dialogue: 0,0:14:22.19,0:14:23.70,Default,,0000,0000,0000,,it's very tempting at this point. Dialogue: 0,0:14:23.70,0:14:25.89,Default,,0000,0000,0000,,I'm on a road, I'm on a refactoring road. Dialogue: 0,0:14:25.89,0:14:28.39,Default,,0000,0000,0000,,It's very tempting now to go on a tangent Dialogue: 0,0:14:28.39,0:14:29.70,Default,,0000,0000,0000,,and try to clean this up. Dialogue: 0,0:14:29.70,0:14:30.84,Default,,0000,0000,0000,,Because we believe the greatest, Dialogue: 0,0:14:30.84,0:14:33.70,Default,,0000,0000,0000,,we've been taught like the\Ngreatest virtue is DRY. Dialogue: 0,0:14:33.70,0:14:36.26,Default,,0000,0000,0000,,And I will tell you that's\Nthe wrong idea here. Dialogue: 0,0:14:36.26,0:14:37.59,Default,,0000,0000,0000,,I'm about to get a lot more information Dialogue: 0,0:14:37.59,0:14:39.52,Default,,0000,0000,0000,,about what this algorithm looks like, Dialogue: 0,0:14:39.52,0:14:42.71,Default,,0000,0000,0000,,and I need to finish\Nthe refactoring I'm on Dialogue: 0,0:14:42.71,0:14:44.39,Default,,0000,0000,0000,,before I go on any tangents,\Nso I'm going to notice Dialogue: 0,0:14:44.39,0:14:47.61,Default,,0000,0000,0000,,that similarity and keep the duplication, Dialogue: 0,0:14:47.61,0:14:50.70,Default,,0000,0000,0000,,and just keep on going down\Nthis path to see where it leads. Dialogue: 0,0:14:50.70,0:14:52.60,Default,,0000,0000,0000,,And this brings me to my\Nfirst big point of this talk. Dialogue: 0,0:14:52.60,0:14:56.82,Default,,0000,0000,0000,,It is far cheaper to keep duplication Dialogue: 0,0:14:56.82,0:14:59.54,Default,,0000,0000,0000,,than it is to have to mess\Nwith the wrong abstraction. Dialogue: 0,0:14:59.54,0:15:00.98,Default,,0000,0000,0000,,The first rule we teach novices Dialogue: 0,0:15:00.98,0:15:03.16,Default,,0000,0000,0000,,is don't repeat yourself - DRY. Dialogue: 0,0:15:03.16,0:15:05.85,Default,,0000,0000,0000,,But have you ever thought about\Nwhy we teach them that rule? Dialogue: 0,0:15:05.85,0:15:09.44,Default,,0000,0000,0000,,It's because they can't understand\Nanything else. (laughter) Dialogue: 0,0:15:09.44,0:15:10.86,Default,,0000,0000,0000,,They don't know anything, but by God, Dialogue: 0,0:15:10.86,0:15:13.79,Default,,0000,0000,0000,,they can recognize duplication,\Nand it's a good rule. Dialogue: 0,0:15:13.79,0:15:15.18,Default,,0000,0000,0000,,I'm not saying it's a bad rule, Dialogue: 0,0:15:15.18,0:15:20.92,Default,,0000,0000,0000,,but I'm saying that now you're\Ngrown up, you know more, Dialogue: 0,0:15:20.92,0:15:22.99,Default,,0000,0000,0000,,and you have enough experience Dialogue: 0,0:15:22.99,0:15:24.90,Default,,0000,0000,0000,,now to tolerate a little duplication Dialogue: 0,0:15:24.90,0:15:26.45,Default,,0000,0000,0000,,and wait on a better abstraction. Dialogue: 0,0:15:26.45,0:15:29.84,Default,,0000,0000,0000,,It's really hard to deal\Nwith the wrong abstraction. Dialogue: 0,0:15:29.84,0:15:31.92,Default,,0000,0000,0000,,I often make a "dup tag". Dialogue: 0,0:15:31.92,0:15:33.93,Default,,0000,0000,0000,,You know how you can make a "to do" tag? Dialogue: 0,0:15:33.93,0:15:35.21,Default,,0000,0000,0000,,Like people say, "Oh, I'm going to Dialogue: 0,0:15:35.21,0:15:36.63,Default,,0000,0000,0000,,"lose track of my duplication." Dialogue: 0,0:15:36.63,0:15:37.70,Default,,0000,0000,0000,,Well, fix that problem. Dialogue: 0,0:15:37.70,0:15:40.12,Default,,0000,0000,0000,,Make a "dup tag" and give\Nevery "dup" a number, Dialogue: 0,0:15:40.12,0:15:43.39,Default,,0000,0000,0000,,so if you have the same\Ncode in two or three places, Dialogue: 0,0:15:43.39,0:15:45.57,Default,,0000,0000,0000,,like if that's the sixth\Ninstance of duplication, Dialogue: 0,0:15:45.57,0:15:46.99,Default,,0000,0000,0000,,give it an ID like a database, Dialogue: 0,0:15:46.99,0:15:49.27,Default,,0000,0000,0000,,and put "dup six" in a bunch\Nof places in your code. Dialogue: 0,0:15:49.27,0:15:50.18,Default,,0000,0000,0000,,You'll know. Dialogue: 0,0:15:50.18,0:15:51.82,Default,,0000,0000,0000,,You'll see the duplication\Nif you change a part, Dialogue: 0,0:15:51.82,0:15:54.15,Default,,0000,0000,0000,,like fix the problem of\Nnot being able to find it, Dialogue: 0,0:15:54.15,0:15:56.56,Default,,0000,0000,0000,,rather than reaching too\Nsoon for an abstraction. Dialogue: 0,0:15:56.56,0:15:59.55,Default,,0000,0000,0000,,It's much easier to\Ndeal with a duplication. Dialogue: 0,0:15:59.55,0:16:00.71,Default,,0000,0000,0000,,Alright, so moving on. Dialogue: 0,0:16:00.71,0:16:02.84,Default,,0000,0000,0000,,Here's Sulfuras. There's three tests. Dialogue: 0,0:16:02.84,0:16:06.10,Default,,0000,0000,0000,,You would think if I put my\Nshim in and put an empty method, Dialogue: 0,0:16:06.10,0:16:12.18,Default,,0000,0000,0000,,I would have three test failures.\N(laughter) Dialogue: 0,0:16:12.18,0:16:13.95,Default,,0000,0000,0000,,And yet they all pass. Dialogue: 0,0:16:13.95,0:16:14.83,Default,,0000,0000,0000,,So, what's this about? Dialogue: 0,0:16:14.83,0:16:16.56,Default,,0000,0000,0000,,Well, I look at the test and I realize Dialogue: 0,0:16:16.56,0:16:17.87,Default,,0000,0000,0000,,in all the tests [unintelligible] that Dialogue: 0,0:16:17.87,0:16:20.53,Default,,0000,0000,0000,,nothing happens if it's Sulfuras. Dialogue: 0,0:16:20.53,0:16:22.23,Default,,0000,0000,0000,,And again, I had no idea when I was Dialogue: 0,0:16:22.23,0:16:23.45,Default,,0000,0000,0000,,looking at that 43 lines of statement Dialogue: 0,0:16:23.45,0:16:26.16,Default,,0000,0000,0000,,that somehow it all asserted\Nthat nothing happened, Dialogue: 0,0:16:26.16,0:16:30.62,Default,,0000,0000,0000,,so it turns out this is the code\Nthat makes the tests pass. (laughter) Dialogue: 0,0:16:30.62,0:16:33.94,Default,,0000,0000,0000,,How nice is that? We love that, OK? Dialogue: 0,0:16:33.94,0:16:35.48,Default,,0000,0000,0000,,So here's Backstage, and\Nthere's a whole bunch of these, Dialogue: 0,0:16:35.48,0:16:37.35,Default,,0000,0000,0000,,and it looks like this. Dialogue: 0,0:16:37.35,0:16:39.46,Default,,0000,0000,0000,,That's the code that makes the tests pass. Dialogue: 0,0:16:39.46,0:16:41.82,Default,,0000,0000,0000,,And so now, we're totally back to green. Dialogue: 0,0:16:41.82,0:16:44.23,Default,,0000,0000,0000,,This looks exactly like\Nit did when I started. Dialogue: 0,0:16:44.23,0:16:46.92,Default,,0000,0000,0000,,And this is what I got. Dialogue: 0,0:16:46.92,0:16:48.41,Default,,0000,0000,0000,,I put this case statement in the front, Dialogue: 0,0:16:48.41,0:16:50.63,Default,,0000,0000,0000,,and it tracked all the execution paths. Dialogue: 0,0:16:50.63,0:16:52.93,Default,,0000,0000,0000,,I have a bunch of methods\Nthat look like this Dialogue: 0,0:16:52.93,0:16:55.78,Default,,0000,0000,0000,,that I created and added\Nto the Gilded Rose class, Dialogue: 0,0:16:55.78,0:16:57.21,Default,,0000,0000,0000,,and the rest of the tick methods still Dialogue: 0,0:16:57.21,0:17:00.23,Default,,0000,0000,0000,,contains that monstrous\N43-line "if" statement, Dialogue: 0,0:17:00.23,0:17:02.85,Default,,0000,0000,0000,,which I don't understand,\Nbut I no longer need, Dialogue: 0,0:17:02.85,0:17:06.61,Default,,0000,0000,0000,,so I'm just going to delete it, it's gone. Dialogue: 0,0:17:06.61,0:17:11.64,Default,,0000,0000,0000,,Now if you don't have good tests,\Nthis may freak you out, (laughter) Dialogue: 0,0:17:11.64,0:17:13.51,Default,,0000,0000,0000,,but then if you feel freaked out by this Dialogue: 0,0:17:13.51,0:17:14.66,Default,,0000,0000,0000,,and you don't have good tests, Dialogue: 0,0:17:14.66,0:17:16.33,Default,,0000,0000,0000,,you're really making a choice here, right? Dialogue: 0,0:17:16.33,0:17:19.02,Default,,0000,0000,0000,,If you have code that you don't understand Dialogue: 0,0:17:19.02,0:17:20.69,Default,,0000,0000,0000,,and that you're afraid to change, Dialogue: 0,0:17:20.69,0:17:24.99,Default,,0000,0000,0000,,you can keep it forever, if\Nyou think that's a good idea, Dialogue: 0,0:17:24.99,0:17:27.95,Default,,0000,0000,0000,,or you can put some kind of test [harness) Dialogue: 0,0:17:27.95,0:17:29.27,Default,,0000,0000,0000,,around it so that you can refactor, Dialogue: 0,0:17:29.27,0:17:31.75,Default,,0000,0000,0000,,but keeping it forever is\Nnot really a good choice, Dialogue: 0,0:17:31.75,0:17:32.16,Default,,0000,0000,0000,,so you want to get to the point where Dialogue: 0,0:17:32.16,0:17:34.77,Default,,0000,0000,0000,,you have confidence that\Nyou can safely refactor, Dialogue: 0,0:17:34.77,0:17:37.35,Default,,0000,0000,0000,,and it means you never have\Nto understand that code, Dialogue: 0,0:17:37.35,0:17:39.89,Default,,0000,0000,0000,,you can do characterization\Ntests around the edges, Dialogue: 0,0:17:39.89,0:17:41.15,Default,,0000,0000,0000,,so that you'll have green, Dialogue: 0,0:17:41.15,0:17:42.41,Default,,0000,0000,0000,,you'll have a wall at your back for tests, Dialogue: 0,0:17:42.41,0:17:43.72,Default,,0000,0000,0000,,and then you can refactor your way, Dialogue: 0,0:17:43.72,0:17:44.83,Default,,0000,0000,0000,,to the point where you can delete Dialogue: 0,0:17:44.83,0:17:47.56,Default,,0000,0000,0000,,the code that you don't understand. Dialogue: 0,0:17:47.56,0:17:48.61,Default,,0000,0000,0000,,And the moral of this story is that Dialogue: 0,0:17:48.61,0:17:51.56,Default,,0000,0000,0000,,small methods are simple. Dialogue: 0,0:17:51.56,0:17:52.39,Default,,0000,0000,0000,,Here we have it. Dialogue: 0,0:17:52.39,0:17:53.65,Default,,0000,0000,0000,,This is the code we just wrote. Dialogue: 0,0:17:53.65,0:17:55.42,Default,,0000,0000,0000,,This is the squint test\Nversion, don't try to read it. Dialogue: 0,0:17:55.42,0:17:56.74,Default,,0000,0000,0000,,This is the code we\Njust wrote on the right, Dialogue: 0,0:17:56.74,0:17:58.49,Default,,0000,0000,0000,,and this is how we start it on the left. Dialogue: 0,0:17:58.49,0:18:02.17,Default,,0000,0000,0000,,You notice that the shape is flat, Dialogue: 0,0:18:02.17,0:18:04.22,Default,,0000,0000,0000,,and the colors are starting to cluster. Dialogue: 0,0:18:04.22,0:18:06.51,Default,,0000,0000,0000,,Now, again I believe in metrics, because Dialogue: 0,0:18:06.51,0:18:08.25,Default,,0000,0000,0000,,I know that my personal notion of what Dialogue: 0,0:18:08.25,0:18:10.87,Default,,0000,0000,0000,,is simple or complex is just my opinion, Dialogue: 0,0:18:10.87,0:18:14.92,Default,,0000,0000,0000,,and I totally know that\Nmetrics are fallible, Dialogue: 0,0:18:14.92,0:18:18.18,Default,,0000,0000,0000,,but human opinion is no more precise. Dialogue: 0,0:18:18.18,0:18:20.66,Default,,0000,0000,0000,,And that metrics are kind\Nof a crowdsource idea Dialogue: 0,0:18:20.66,0:18:22.81,Default,,0000,0000,0000,,of what a bunch of people\Nthought a metric could be. Dialogue: 0,0:18:22.81,0:18:26.19,Default,,0000,0000,0000,,It is a useful data point\Nfor me to compare to my own. Dialogue: 0,0:18:26.19,0:18:27.85,Default,,0000,0000,0000,,The original class Flogged to 50, Dialogue: 0,0:18:27.85,0:18:30.81,Default,,0000,0000,0000,,and this new class Flogs to 40, Dialogue: 0,0:18:30.81,0:18:32.58,Default,,0000,0000,0000,,but that overstates its complexity Dialogue: 0,0:18:32.58,0:18:33.42,Default,,0000,0000,0000,,because now there's a bunch of methods, Dialogue: 0,0:18:33.42,0:18:36.86,Default,,0000,0000,0000,,and the most complex method is\NBackstage and if Flogs to 12. Dialogue: 0,0:18:36.86,0:18:39.69,Default,,0000,0000,0000,,This code is way simpler. Dialogue: 0,0:18:39.69,0:18:41.36,Default,,0000,0000,0000,,Well, this is great, and you'd think that Dialogue: 0,0:18:41.36,0:18:43.67,Default,,0000,0000,0000,,everyone would just do this. Dialogue: 0,0:18:43.67,0:18:46.17,Default,,0000,0000,0000,,And so, it's an interesting\Nquestion why they don't. Dialogue: 0,0:18:46.17,0:18:47.38,Default,,0000,0000,0000,,Now, one of the things I already told you, Dialogue: 0,0:18:47.38,0:18:48.64,Default,,0000,0000,0000,,I already gave you one reason, right? Dialogue: 0,0:18:48.64,0:18:50.81,Default,,0000,0000,0000,,We do more of what's there. Dialogue: 0,0:18:50.81,0:18:53.34,Default,,0000,0000,0000,,And so, the tendency is to add more Dialogue: 0,0:18:53.34,0:18:54.50,Default,,0000,0000,0000,,to the "if" statement, if that's there, Dialogue: 0,0:18:54.50,0:18:55.86,Default,,0000,0000,0000,,but I think there's another reason Dialogue: 0,0:18:55.86,0:18:58.61,Default,,0000,0000,0000,,why we don't undertake these refactorings, Dialogue: 0,0:18:58.61,0:18:59.82,Default,,0000,0000,0000,,and it's because of this. Dialogue: 0,0:18:59.82,0:19:02.62,Default,,0000,0000,0000,,I'm just going to make the\N50 smaller and move it over. Dialogue: 0,0:19:02.62,0:19:05.86,Default,,0000,0000,0000,,It took me 10 refactoring steps to get Dialogue: 0,0:19:05.86,0:19:09.96,Default,,0000,0000,0000,,from the big conditional to\Na bunch of small methods, Dialogue: 0,0:19:09.96,0:19:15.28,Default,,0000,0000,0000,,and here's the Flog score of\Nall the intermediate steps. Dialogue: 0,0:19:15.28,0:19:16.82,Default,,0000,0000,0000,,All the intermediate refactorings Dialogue: 0,0:19:16.82,0:19:19.58,Default,,0000,0000,0000,,made code more complicated. Dialogue: 0,0:19:19.58,0:19:21.86,Default,,0000,0000,0000,,I know that I'm going to get to that 40. Dialogue: 0,0:19:21.86,0:19:24.27,Default,,0000,0000,0000,,I understand the principles\Nof object-oriented design, Dialogue: 0,0:19:24.27,0:19:25.97,Default,,0000,0000,0000,,and I know the value of small methods, Dialogue: 0,0:19:25.97,0:19:29.21,Default,,0000,0000,0000,,and because of that, I\Nbelieve in the refactorings, Dialogue: 0,0:19:29.21,0:19:31.72,Default,,0000,0000,0000,,and that lets me tolerate\Nthe intermediate complexity. Dialogue: 0,0:19:31.72,0:19:35.25,Default,,0000,0000,0000,,But if you don't know,\Nif you haven't learned Dialogue: 0,0:19:35.25,0:19:36.28,Default,,0000,0000,0000,,about the value of small methods, Dialogue: 0,0:19:36.28,0:19:38.65,Default,,0000,0000,0000,,it's hard to undertake\Nthose intermediate steps. Dialogue: 0,0:19:38.65,0:19:43.82,Default,,0000,0000,0000,,They seem like academic things that Dialogue: 0,0:19:43.82,0:19:48.55,Default,,0000,0000,0000,,people will do that are\Nfor some pie-in-the-sky Dialogue: 0,0:19:48.55,0:19:51.19,Default,,0000,0000,0000,,principle that don't improve code, Dialogue: 0,0:19:51.19,0:19:53.24,Default,,0000,0000,0000,,but I can promise you that if you can see Dialogue: 0,0:19:53.24,0:19:55.49,Default,,0000,0000,0000,,far enough to see to the end, Dialogue: 0,0:19:55.49,0:19:59.82,Default,,0000,0000,0000,,this intermediate complexity\Nleads to ultimate simplicity. Dialogue: 0,0:19:59.82,0:20:02.82,Default,,0000,0000,0000,,And, so now I'm going to\Ncircle back around my task, Dialogue: 0,0:20:02.82,0:20:04.17,Default,,0000,0000,0000,,now that I've done this refactoring, Dialogue: 0,0:20:04.17,0:20:05.59,Default,,0000,0000,0000,,I can circle back around my original task Dialogue: 0,0:20:05.59,0:20:08.49,Default,,0000,0000,0000,,which is to implement Conjure. Dialogue: 0,0:20:08.49,0:20:10.18,Default,,0000,0000,0000,,How should I do this? Dialogue: 0,0:20:10.18,0:20:13.76,Default,,0000,0000,0000,,Here's what I got, I've got this. Dialogue: 0,0:20:13.76,0:20:17.57,Default,,0000,0000,0000,,Should I do that? Dialogue: 0,0:20:17.57,0:20:20.94,Default,,0000,0000,0000,,It would be easy, it would be really easy. Dialogue: 0,0:20:20.94,0:20:23.80,Default,,0000,0000,0000,,The answer to that is\N"no", I should not do that. Dialogue: 0,0:20:23.80,0:20:26.83,Default,,0000,0000,0000,,That is not the way I\Nshould solve this problem, Dialogue: 0,0:20:26.83,0:20:29.96,Default,,0000,0000,0000,,and it's because this\Ncode is not open/closed. Dialogue: 0,0:20:29.96,0:20:34.33,Default,,0000,0000,0000,,It is not open for extension,\Nand closed for modification. Dialogue: 0,0:20:34.33,0:20:37.86,Default,,0000,0000,0000,,Open/closed supplies the\N"O" in [solid], and it is, Dialogue: 0,0:20:37.86,0:20:38.95,Default,,0000,0000,0000,,and I'm going to say it right out loud, Dialogue: 0,0:20:38.95,0:20:43.45,Default,,0000,0000,0000,,it's a principle of\Nobject-oriented design. Dialogue: 0,0:20:43.45,0:20:46.42,Default,,0000,0000,0000,,It's one of the pieces\Nof cumulative wisdom Dialogue: 0,0:20:46.42,0:20:47.54,Default,,0000,0000,0000,,created by folks who've written Dialogue: 0,0:20:47.54,0:20:49.50,Default,,0000,0000,0000,,a mountain of object-oriented code, Dialogue: 0,0:20:49.50,0:20:51.77,Default,,0000,0000,0000,,and they have experienced every Dialogue: 0,0:20:51.77,0:20:54.68,Default,,0000,0000,0000,,possible kind of programming pain. Dialogue: 0,0:20:54.68,0:20:58.14,Default,,0000,0000,0000,,And over time, they have\Nnoticed some principles, Dialogue: 0,0:20:58.14,0:21:01.26,Default,,0000,0000,0000,,and they developed a style guide Dialogue: 0,0:21:01.26,0:21:03.75,Default,,0000,0000,0000,,about how to organize code. Dialogue: 0,0:21:03.75,0:21:05.14,Default,,0000,0000,0000,,That's what object-oriented design is. Dialogue: 0,0:21:05.14,0:21:07.21,Default,,0000,0000,0000,,That's what the rules of\Nobject-oriented design are. Dialogue: 0,0:21:07.21,0:21:10.60,Default,,0000,0000,0000,,It's a style guide about\Nhow to organize code Dialogue: 0,0:21:10.60,0:21:12.58,Default,,0000,0000,0000,,with all the obvious tradeoffs, Dialogue: 0,0:21:12.58,0:21:14.64,Default,,0000,0000,0000,,all the places where you\Ncan make your own decisions. Dialogue: 0,0:21:14.64,0:21:19.22,Default,,0000,0000,0000,,In this case, you can feel free\Nto ignore their discoveries, Dialogue: 0,0:21:19.22,0:21:20.34,Default,,0000,0000,0000,,in which case you'll get to experience Dialogue: 0,0:21:20.34,0:21:23.46,Default,,0000,0000,0000,,all that pain over again for yourself. Dialogue: 0,0:21:23.46,0:21:24.79,Default,,0000,0000,0000,,That's what will happen. Dialogue: 0,0:21:24.79,0:21:26.58,Default,,0000,0000,0000,,On the macro level, this style guide says Dialogue: 0,0:21:26.58,0:21:30.62,Default,,0000,0000,0000,,it's best to arrange code\Nso that adding new behavior Dialogue: 0,0:21:30.62,0:21:34.33,Default,,0000,0000,0000,,does not require that\Nyou edit existing code. Dialogue: 0,0:21:34.33,0:21:35.66,Default,,0000,0000,0000,,I know that seems impossible. Dialogue: 0,0:21:35.66,0:21:37.16,Default,,0000,0000,0000,,I'm going to say it again, right? Dialogue: 0,0:21:37.16,0:21:40.46,Default,,0000,0000,0000,,Open/closed says you ought to\Nbe able to add new behavior Dialogue: 0,0:21:40.46,0:21:43.25,Default,,0000,0000,0000,,without editing existing code. Dialogue: 0,0:21:43.25,0:21:45.37,Default,,0000,0000,0000,,Now, forget about how impossible\Nthat seems for a minute. Dialogue: 0,0:21:45.37,0:21:47.40,Default,,0000,0000,0000,,I just want you to\Nimagine something for me. Dialogue: 0,0:21:47.40,0:21:53.15,Default,,0000,0000,0000,,Imagine the world, imagine\Nyour apps, if that is true. Dialogue: 0,0:21:53.15,0:21:55.71,Default,,0000,0000,0000,,Imagine that you can add new behavior Dialogue: 0,0:21:55.71,0:21:57.56,Default,,0000,0000,0000,,without editing existing code. Dialogue: 0,0:21:57.56,0:22:00.89,Default,,0000,0000,0000,,Think about what that means. Dialogue: 0,0:22:00.89,0:22:02.48,Default,,0000,0000,0000,,It means you always have green tests, Dialogue: 0,0:22:02.48,0:22:04.10,Default,,0000,0000,0000,,it means you are always safe, Dialogue: 0,0:22:04.10,0:22:06.50,Default,,0000,0000,0000,,it means you never cause some Dialogue: 0,0:22:06.50,0:22:08.68,Default,,0000,0000,0000,,distant and unrelated side-effect. Dialogue: 0,0:22:08.68,0:22:10.92,Default,,0000,0000,0000,,That is a sweet, sweet world, Dialogue: 0,0:22:10.92,0:22:12.99,Default,,0000,0000,0000,,if your code is open/closed. Dialogue: 0,0:22:12.99,0:22:14.53,Default,,0000,0000,0000,,And so, on the macro\Nlevel, we are trying to get Dialogue: 0,0:22:14.53,0:22:16.44,Default,,0000,0000,0000,,to the point where we\Ncan add new behavior, Dialogue: 0,0:22:16.44,0:22:18.22,Default,,0000,0000,0000,,without editing existing code. Dialogue: 0,0:22:18.22,0:22:20.57,Default,,0000,0000,0000,,And on the micro level,\Nwhat that means here, Dialogue: 0,0:22:20.57,0:22:22.99,Default,,0000,0000,0000,,right now, in this code, Dialogue: 0,0:22:22.99,0:22:24.55,Default,,0000,0000,0000,,is that when we see methods that have Dialogue: 0,0:22:24.55,0:22:27.95,Default,,0000,0000,0000,,a repeating prefix or repeating suffix, Dialogue: 0,0:22:27.95,0:22:30.44,Default,,0000,0000,0000,,there is a tortured object in there Dialogue: 0,0:22:30.44,0:22:34.69,Default,,0000,0000,0000,,that's trying to get out.\N(laughter) Dialogue: 0,0:22:34.69,0:22:36.73,Default,,0000,0000,0000,,Right here, in this place, Dialogue: 0,0:22:36.73,0:22:38.37,Default,,0000,0000,0000,,you're about to make a decision Dialogue: 0,0:22:38.37,0:22:40.50,Default,,0000,0000,0000,,that's going to have consequences Dialogue: 0,0:22:40.50,0:22:43.34,Default,,0000,0000,0000,,that echo through your code base forever. Dialogue: 0,0:22:43.34,0:22:45.74,Default,,0000,0000,0000,,Are you going to write procedures, Dialogue: 0,0:22:45.74,0:22:48.26,Default,,0000,0000,0000,,or are you going to trust objects? Dialogue: 0,0:22:48.26,0:22:50.78,Default,,0000,0000,0000,,If you insist on having\Nall the logic visible, Dialogue: 0,0:22:50.78,0:22:52.75,Default,,0000,0000,0000,,right here where you can see it, Dialogue: 0,0:22:52.75,0:22:54.18,Default,,0000,0000,0000,,you are insisting really on knowing Dialogue: 0,0:22:54.18,0:22:56.63,Default,,0000,0000,0000,,both the condition on which you switch, Dialogue: 0,0:22:56.63,0:22:57.97,Default,,0000,0000,0000,,and the thing that you do, Dialogue: 0,0:22:57.97,0:23:00.36,Default,,0000,0000,0000,,the action that you take\Nwhen that switch happens. Dialogue: 0,0:23:00.36,0:23:02.10,Default,,0000,0000,0000,,If you're uncomfortable, and unless Dialogue: 0,0:23:02.10,0:23:05.89,Default,,0000,0000,0000,,you know both those things\Nat once in this file, Dialogue: 0,0:23:05.89,0:23:07.22,Default,,0000,0000,0000,,under your eyes, in this\Ncode, then you're going to Dialogue: 0,0:23:07.22,0:23:09.81,Default,,0000,0000,0000,,be forced to add a new method right here. Dialogue: 0,0:23:09.81,0:23:12.63,Default,,0000,0000,0000,,You have to put that conjured\Ntick method right here. Dialogue: 0,0:23:12.63,0:23:14.50,Default,,0000,0000,0000,,But if you don't, if you're OK with that, Dialogue: 0,0:23:14.50,0:23:16.23,Default,,0000,0000,0000,,you can listen to object-oriented design. Dialogue: 0,0:23:16.23,0:23:18.78,Default,,0000,0000,0000,,It says that when you\Nhave differing prefixes, Dialogue: 0,0:23:18.78,0:23:21.31,Default,,0000,0000,0000,,and common suffixes,\Nthen what you really have Dialogue: 0,0:23:21.31,0:23:25.11,Default,,0000,0000,0000,,is a normal class that\Nought to have a method tick, Dialogue: 0,0:23:25.11,0:23:27.38,Default,,0000,0000,0000,,and a Gilded Rose ought to be holding on Dialogue: 0,0:23:27.38,0:23:29.99,Default,,0000,0000,0000,,to an instance of it. Dialogue: 0,0:23:29.99,0:23:31.83,Default,,0000,0000,0000,,And it is real easy to right that code. Dialogue: 0,0:23:31.83,0:23:34.98,Default,,0000,0000,0000,,If you can think of that\Nthing, thinking of the thing Dialogue: 0,0:23:34.98,0:23:36.76,Default,,0000,0000,0000,,is far harder than writing the code. Dialogue: 0,0:23:36.76,0:23:38.13,Default,,0000,0000,0000,,Here's how the code looks. Dialogue: 0,0:23:38.13,0:23:39.70,Default,,0000,0000,0000,,I've got this Normal tick method, Dialogue: 0,0:23:39.70,0:23:41.50,Default,,0000,0000,0000,,I'm just going to call it "tick", Dialogue: 0,0:23:41.50,0:23:43.02,Default,,0000,0000,0000,,I'm going to put in a Normal class, Dialogue: 0,0:23:43.02,0:23:44.52,Default,,0000,0000,0000,,I'm going to throw a cruft in there to get Dialogue: 0,0:23:44.52,0:23:47.61,Default,,0000,0000,0000,,the initialization and\Nthe attributes defined, Dialogue: 0,0:23:47.61,0:23:49.35,Default,,0000,0000,0000,,I'm going to go back into Gilded Rose Dialogue: 0,0:23:49.35,0:23:50.86,Default,,0000,0000,0000,,and the Normal tick method there, Dialogue: 0,0:23:50.86,0:23:52.67,Default,,0000,0000,0000,,I'll get an instance of my new class, Dialogue: 0,0:23:52.67,0:23:56.53,Default,,0000,0000,0000,,and I'll forward this\Nmessage - boom, that's it. Dialogue: 0,0:23:56.53,0:23:59.43,Default,,0000,0000,0000,,Alright, well, so I've got this, Dialogue: 0,0:23:59.43,0:24:02.36,Default,,0000,0000,0000,,so Normal is an object,\Nbut nothing else is, Dialogue: 0,0:24:02.36,0:24:03.81,Default,,0000,0000,0000,,and I'm about to go back on the path where Dialogue: 0,0:24:03.81,0:24:07.21,Default,,0000,0000,0000,,I have to increase\Nintermediate complexity, Dialogue: 0,0:24:07.21,0:24:08.82,Default,,0000,0000,0000,,because look what just happened, alright? Dialogue: 0,0:24:08.82,0:24:10.99,Default,,0000,0000,0000,,My new Normal tick method looks like this. Dialogue: 0,0:24:10.99,0:24:12.16,Default,,0000,0000,0000,,It uses this item class. Dialogue: 0,0:24:12.16,0:24:13.76,Default,,0000,0000,0000,,But Brie, the Brie tick method is still Dialogue: 0,0:24:13.76,0:24:16.56,Default,,0000,0000,0000,,calculated inside the Gilded Rose. Dialogue: 0,0:24:16.56,0:24:18.25,Default,,0000,0000,0000,,The quality and days remaining are part Dialogue: 0,0:24:18.25,0:24:20.18,Default,,0000,0000,0000,,of the public API for Gilded Rose, Dialogue: 0,0:24:20.18,0:24:21.19,Default,,0000,0000,0000,,and so now I have to say, well, Dialogue: 0,0:24:21.19,0:24:23.20,Default,,0000,0000,0000,,if I have an item, go\Nget the item's quality, Dialogue: 0,0:24:23.20,0:24:25.44,Default,,0000,0000,0000,,otherwise, get the one I know about. Dialogue: 0,0:24:25.44,0:24:28.80,Default,,0000,0000,0000,,And I have to do the same thing\Nfor days remaining, alright? Dialogue: 0,0:24:28.80,0:24:32.60,Default,,0000,0000,0000,,It looks messy, but it's\Nshort-term, it will go away. Dialogue: 0,0:24:32.60,0:24:34.56,Default,,0000,0000,0000,,And so, let's just walk\Nthrough all the other objects. Dialogue: 0,0:24:34.56,0:24:35.58,Default,,0000,0000,0000,,Now that you understand this pattern, Dialogue: 0,0:24:35.58,0:24:36.87,Default,,0000,0000,0000,,it's really easy, right? Dialogue: 0,0:24:36.87,0:24:38.85,Default,,0000,0000,0000,,Class Brie, move method tick, Dialogue: 0,0:24:38.85,0:24:41.92,Default,,0000,0000,0000,,put the cruft in there,\Nforward the message. Dialogue: 0,0:24:41.92,0:24:43.33,Default,,0000,0000,0000,,Easy enough. Dialogue: 0,0:24:43.33,0:24:45.49,Default,,0000,0000,0000,,This is really interesting. Dialogue: 0,0:24:45.49,0:24:47.57,Default,,0000,0000,0000,,Now some trust is coming into play, right? Dialogue: 0,0:24:47.57,0:24:49.32,Default,,0000,0000,0000,,I have an empty method,\Nlook what I have to do. Dialogue: 0,0:24:49.32,0:24:50.92,Default,,0000,0000,0000,,Make a new class, put the method in, Dialogue: 0,0:24:50.92,0:24:52.49,Default,,0000,0000,0000,,pry this method open, get an instance Dialogue: 0,0:24:52.49,0:24:53.80,Default,,0000,0000,0000,,of that class, forward the message. Dialogue: 0,0:24:53.80,0:24:58.30,Default,,0000,0000,0000,,You can be forgiven for\Nbeing suspicious about this, Dialogue: 0,0:24:58.30,0:24:59.78,Default,,0000,0000,0000,,but if you trust the refactorings, Dialogue: 0,0:24:59.78,0:25:00.89,Default,,0000,0000,0000,,you have confidence that this is Dialogue: 0,0:25:00.89,0:25:02.68,Default,,0000,0000,0000,,going to turn out well in the end. Dialogue: 0,0:25:02.68,0:25:05.77,Default,,0000,0000,0000,,I'm not going to diverge,\NI'm not taking a detour, Dialogue: 0,0:25:05.77,0:25:06.84,Default,,0000,0000,0000,,I'm going to go all the way down Dialogue: 0,0:25:06.84,0:25:09.47,Default,,0000,0000,0000,,this path and finish this refactoring. Dialogue: 0,0:25:09.47,0:25:11.34,Default,,0000,0000,0000,,Backstage, I'll make the tick method, Dialogue: 0,0:25:11.34,0:25:15.80,Default,,0000,0000,0000,,I'll make that stuff,\NI'll do the forwarding. Dialogue: 0,0:25:15.80,0:25:21.33,Default,,0000,0000,0000,,Alright, so now they're all\Nobjects and I've got this. Dialogue: 0,0:25:21.33,0:25:23.25,Default,,0000,0000,0000,,And I'm back here. Dialogue: 0,0:25:23.25,0:25:27.44,Default,,0000,0000,0000,,So now, in the beginning, I moved logic Dialogue: 0,0:25:27.44,0:25:28.42,Default,,0000,0000,0000,,into methods of their own, Dialogue: 0,0:25:28.42,0:25:29.76,Default,,0000,0000,0000,,because I didn't want to put a bunch Dialogue: 0,0:25:29.76,0:25:31.49,Default,,0000,0000,0000,,of code in this case statement, Dialogue: 0,0:25:31.49,0:25:33.100,Default,,0000,0000,0000,,but now that I have objects,\Neverything is simpler, Dialogue: 0,0:25:33.100,0:25:37.35,Default,,0000,0000,0000,,and I'm going to just start\Nrewinding my decisions. Dialogue: 0,0:25:37.35,0:25:39.41,Default,,0000,0000,0000,,I'm just going to delete the method, Dialogue: 0,0:25:39.41,0:25:41.44,Default,,0000,0000,0000,,and shove the code that\Nused to be in the method Dialogue: 0,0:25:41.44,0:25:44.91,Default,,0000,0000,0000,,back up in the branches\Nof the case statement. Dialogue: 0,0:25:44.91,0:25:46.51,Default,,0000,0000,0000,,We'll do that. Dialogue: 0,0:25:46.51,0:25:48.40,Default,,0000,0000,0000,,Now, earlier I said that duplication was Dialogue: 0,0:25:48.40,0:25:49.56,Default,,0000,0000,0000,,cheaper than the wrong abstraction, Dialogue: 0,0:25:49.56,0:25:51.80,Default,,0000,0000,0000,,but now we're starting\Nto see abstractions, Dialogue: 0,0:25:51.80,0:25:55.12,Default,,0000,0000,0000,,and I'm just going to go and\Nabstract away some duplication. Dialogue: 0,0:25:55.12,0:25:56.62,Default,,0000,0000,0000,,I'm going to put the cruft back up in here Dialogue: 0,0:25:56.62,0:25:59.66,Default,,0000,0000,0000,,so in Gilded Rose, I no longer need that. Dialogue: 0,0:25:59.66,0:26:02.46,Default,,0000,0000,0000,,What I really need to do\Nis be able to get an item. Dialogue: 0,0:26:02.46,0:26:04.63,Default,,0000,0000,0000,,And the way I need to get an item is that. Dialogue: 0,0:26:04.63,0:26:05.58,Default,,0000,0000,0000,,That's how I'm going to get it. Dialogue: 0,0:26:05.58,0:26:06.71,Default,,0000,0000,0000,,If I just knew the class name, Dialogue: 0,0:26:06.71,0:26:09.72,Default,,0000,0000,0000,,I could send that message\Nto it, and it would work. Dialogue: 0,0:26:09.72,0:26:12.22,Default,,0000,0000,0000,,And it's actually really easy\Nto figure out the class name. Dialogue: 0,0:26:12.22,0:26:14.54,Default,,0000,0000,0000,,The code's already here. Dialogue: 0,0:26:14.54,0:26:17.16,Default,,0000,0000,0000,,It's this, there it is. Dialogue: 0,0:26:17.16,0:26:18.55,Default,,0000,0000,0000,,That will get me the class name back, Dialogue: 0,0:26:18.55,0:26:20.82,Default,,0000,0000,0000,,so if I just give that a name, Dialogue: 0,0:26:20.82,0:26:22.53,Default,,0000,0000,0000,,I can send that message to myself, Dialogue: 0,0:26:22.53,0:26:25.70,Default,,0000,0000,0000,,and now I have the right kind of item. Dialogue: 0,0:26:25.70,0:26:28.81,Default,,0000,0000,0000,,I don't need a name anymore,\Nso that got simpler. Dialogue: 0,0:26:28.81,0:26:31.27,Default,,0000,0000,0000,,So now, I have separated\Nthe reason I'm switching Dialogue: 0,0:26:31.27,0:26:34.92,Default,,0000,0000,0000,,from the thing I do when I switch. Dialogue: 0,0:26:34.92,0:26:36.34,Default,,0000,0000,0000,,And I can just forget about what's Dialogue: 0,0:26:36.34,0:26:37.70,Default,,0000,0000,0000,,inside that class [form] method. Dialogue: 0,0:26:37.70,0:26:38.90,Default,,0000,0000,0000,,I don't really care anymore. Dialogue: 0,0:26:38.90,0:26:40.00,Default,,0000,0000,0000,,It just answers the right class. Dialogue: 0,0:26:40.00,0:26:41.93,Default,,0000,0000,0000,,It's going to work. Dialogue: 0,0:26:41.93,0:26:42.51,Default,,0000,0000,0000,,It's going to hand back a thing that can Dialogue: 0,0:26:42.51,0:26:44.79,Default,,0000,0000,0000,,answer the message I'm\Ngoing to send to it. Dialogue: 0,0:26:44.79,0:26:46.61,Default,,0000,0000,0000,,And now tick looks like\Nthat and these now, Dialogue: 0,0:26:46.61,0:26:48.43,Default,,0000,0000,0000,,so I'm rewinding the complexity, Dialogue: 0,0:26:48.43,0:26:49.29,Default,,0000,0000,0000,,I don't need this anymore. Dialogue: 0,0:26:49.29,0:26:52.69,Default,,0000,0000,0000,,I have items in every case,\Nso I'll get rid of all that. Dialogue: 0,0:26:52.69,0:26:56.37,Default,,0000,0000,0000,,And now here's the whole\Nbody of code that I have. Dialogue: 0,0:26:56.37,0:26:58.26,Default,,0000,0000,0000,,I'm holding an instance of\Nthe correct item object, Dialogue: 0,0:26:58.26,0:27:00.71,Default,,0000,0000,0000,,and I just sent it the tick method. Dialogue: 0,0:27:00.71,0:27:02.48,Default,,0000,0000,0000,,so, we have four different,\Ndown at the bottom there, Dialogue: 0,0:27:02.48,0:27:04.86,Default,,0000,0000,0000,,you can see we have four\Ndifferent kinds of item classes, Dialogue: 0,0:27:04.86,0:27:08.92,Default,,0000,0000,0000,,but from Gilded Rose's point\Nof view, item is a role. Dialogue: 0,0:27:08.92,0:27:12.86,Default,,0000,0000,0000,,It doesn't think of it like\Nthis, it thinks of it like that. Dialogue: 0,0:27:12.86,0:27:15.91,Default,,0000,0000,0000,,You just need someone in there\Nthat can answer that API, Dialogue: 0,0:27:15.91,0:27:19.20,Default,,0000,0000,0000,,that knows those messages, it's\Na [duck] type, if you will. Dialogue: 0,0:27:19.20,0:27:20.43,Default,,0000,0000,0000,,And if you look at the code I have now, Dialogue: 0,0:27:20.43,0:27:22.100,Default,,0000,0000,0000,,the message passing works like this. Dialogue: 0,0:27:22.100,0:27:24.36,Default,,0000,0000,0000,,All these messages get forwarded, Dialogue: 0,0:27:24.36,0:27:26.58,Default,,0000,0000,0000,,and if you had a Foo\Nthat had a Gilded Rose Dialogue: 0,0:27:26.58,0:27:29.40,Default,,0000,0000,0000,,that sent those messages,\Nit would look like this. Dialogue: 0,0:27:29.40,0:27:32.44,Default,,0000,0000,0000,,And so, now I'm in a situation like this. Dialogue: 0,0:27:32.44,0:27:34.39,Default,,0000,0000,0000,,When an object's only purpose is to Dialogue: 0,0:27:34.39,0:27:35.64,Default,,0000,0000,0000,,forward messages somewhere else, Dialogue: 0,0:27:35.64,0:27:38.85,Default,,0000,0000,0000,,you have to wonder if it\Njustifies its existence. Dialogue: 0,0:27:38.85,0:27:40.66,Default,,0000,0000,0000,,This actually is a code\N[unintelligible] that has a name, Dialogue: 0,0:27:40.66,0:27:43.30,Default,,0000,0000,0000,,and its name is Middleman. Dialogue: 0,0:27:43.30,0:27:46.50,Default,,0000,0000,0000,,So, if that's all the Gilded Rose does, Dialogue: 0,0:27:46.50,0:27:48.13,Default,,0000,0000,0000,,it probably shouldn't\Nexist, but it turns out Dialogue: 0,0:27:48.13,0:27:50.60,Default,,0000,0000,0000,,it still does something important. Dialogue: 0,0:27:50.60,0:27:55.75,Default,,0000,0000,0000,,Given a string like Normal,\Nit can figure out what Dialogue: 0,0:27:55.75,0:27:59.50,Default,,0000,0000,0000,,item class, what class plays\Nthe appropriate item role. Dialogue: 0,0:27:59.50,0:28:01.70,Default,,0000,0000,0000,,And so now, I'm going to use another word Dialogue: 0,0:28:01.70,0:28:05.11,Default,,0000,0000,0000,,that you should love, you\Nshould love this word. Dialogue: 0,0:28:05.11,0:28:06.37,Default,,0000,0000,0000,,Gilded Rose, the only thing that Dialogue: 0,0:28:06.37,0:28:09.68,Default,,0000,0000,0000,,Gilded Rose is is an item factory. Dialogue: 0,0:28:09.68,0:28:11.77,Default,,0000,0000,0000,,I just need to figure out\Nhow to get the right object, Dialogue: 0,0:28:11.77,0:28:13.22,Default,,0000,0000,0000,,and then I can send it a message. Dialogue: 0,0:28:13.22,0:28:15.40,Default,,0000,0000,0000,,We've simplified our problem by Dialogue: 0,0:28:15.40,0:28:17.98,Default,,0000,0000,0000,,separating the thing I'm switching on Dialogue: 0,0:28:17.98,0:28:19.79,Default,,0000,0000,0000,,from the thing I do when I switch. Dialogue: 0,0:28:19.79,0:28:21.24,Default,,0000,0000,0000,,We've divided those things in half, Dialogue: 0,0:28:21.24,0:28:23.88,Default,,0000,0000,0000,,so I can make the code\N[unintelligible] less, Dialogue: 0,0:28:23.88,0:28:26.33,Default,,0000,0000,0000,,and we can do smaller things. Dialogue: 0,0:28:26.33,0:28:28.42,Default,,0000,0000,0000,,I don't need to know what they do, Dialogue: 0,0:28:28.42,0:28:31.49,Default,,0000,0000,0000,,I just need to know how\Nto get the right one. Dialogue: 0,0:28:31.49,0:28:33.38,Default,,0000,0000,0000,,And so, I'm going to change this\Ncode to reflect the reality. Dialogue: 0,0:28:33.38,0:28:35.42,Default,,0000,0000,0000,,I'm going to make Gilded Rose a module. Dialogue: 0,0:28:35.42,0:28:37.74,Default,,0000,0000,0000,,I'm going to say four,\Nsome people put new. Dialogue: 0,0:28:37.74,0:28:39.61,Default,,0000,0000,0000,,They make a new method on module, Dialogue: 0,0:28:39.61,0:28:41.94,Default,,0000,0000,0000,,and I just can't bear that, Dialogue: 0,0:28:41.94,0:28:44.20,Default,,0000,0000,0000,,but it's OK with me if you do it that way. Dialogue: 0,0:28:44.20,0:28:45.48,Default,,0000,0000,0000,,So, I have to make it a class method Dialogue: 0,0:28:45.48,0:28:46.82,Default,,0000,0000,0000,,because I'm calling it. Dialogue: 0,0:28:46.82,0:28:48.27,Default,,0000,0000,0000,,I'm no longer keeping\Nan instance of anything, Dialogue: 0,0:28:48.27,0:28:50.35,Default,,0000,0000,0000,,so I don't need an [add-a-reader]. Dialogue: 0,0:28:50.35,0:28:51.85,Default,,0000,0000,0000,,All these Middleman messages now, Dialogue: 0,0:28:51.85,0:28:53.35,Default,,0000,0000,0000,,since you're really\Ngoing to talk to the item Dialogue: 0,0:28:53.35,0:28:54.83,Default,,0000,0000,0000,,that you get back when you call four, Dialogue: 0,0:28:54.83,0:28:57.71,Default,,0000,0000,0000,,all these messages, they just go away. Dialogue: 0,0:28:57.71,0:28:59.68,Default,,0000,0000,0000,,So now, this is what we have. Dialogue: 0,0:28:59.68,0:29:01.82,Default,,0000,0000,0000,,And the way you use it is you send four Dialogue: 0,0:29:01.82,0:29:04.39,Default,,0000,0000,0000,,to Gilded Rose, and it gives back an item, Dialogue: 0,0:29:04.39,0:29:07.42,Default,,0000,0000,0000,,and it's the item that you talked to. Dialogue: 0,0:29:07.42,0:29:09.37,Default,,0000,0000,0000,,And so, now that we've\Nfixed the Gilded Rose, Dialogue: 0,0:29:09.37,0:29:11.24,Default,,0000,0000,0000,,I'm going to turn my attention to the Dialogue: 0,0:29:11.24,0:29:16.40,Default,,0000,0000,0000,,classes that play the item role. Dialogue: 0,0:29:16.40,0:29:18.67,Default,,0000,0000,0000,,There's a lot of duplication here that Dialogue: 0,0:29:18.67,0:29:19.71,Default,,0000,0000,0000,,we've been tolerating for a long time. Dialogue: 0,0:29:19.71,0:29:20.98,Default,,0000,0000,0000,,They all have this in them. Dialogue: 0,0:29:20.98,0:29:23.56,Default,,0000,0000,0000,,And I'm going to create\Nan inheritance hierarchy, Dialogue: 0,0:29:23.56,0:29:25.59,Default,,0000,0000,0000,,and clean that up. Dialogue: 0,0:29:25.59,0:29:27.31,Default,,0000,0000,0000,,I'm going to make a little item class, Dialogue: 0,0:29:27.31,0:29:29.78,Default,,0000,0000,0000,,push all that stuff up to\Nit, then all these guys, Dialogue: 0,0:29:29.78,0:29:31.37,Default,,0000,0000,0000,,I can delete that code\Nfrom all these guys, Dialogue: 0,0:29:31.37,0:29:34.90,Default,,0000,0000,0000,,and make them subclasses of item. Dialogue: 0,0:29:34.90,0:29:37.68,Default,,0000,0000,0000,,Now, despite what you may have heard, Dialogue: 0,0:29:37.68,0:29:41.14,Default,,0000,0000,0000,,inheritance is not evil, Dialogue: 0,0:29:41.14,0:29:43.97,Default,,0000,0000,0000,,and I can tell you exactly\Nwhen it's safe to use it. Dialogue: 0,0:29:43.97,0:29:45.19,Default,,0000,0000,0000,,Now here's what you want. Dialogue: 0,0:29:45.19,0:29:48.27,Default,,0000,0000,0000,,You want a shallow, narrow hierarchy, Dialogue: 0,0:29:48.27,0:29:49.77,Default,,0000,0000,0000,,you don't want it to be deep, Dialogue: 0,0:29:49.77,0:29:51.51,Default,,0000,0000,0000,,and you don't want it to be wide, alright? Dialogue: 0,0:29:51.51,0:29:54.46,Default,,0000,0000,0000,,Shallow and narrow, you would\Nlike the subclasses to be, Dialogue: 0,0:29:54.46,0:29:56.55,Default,,0000,0000,0000,,OK, I will say this twice. Dialogue: 0,0:29:56.55,0:29:57.74,Default,,0000,0000,0000,,You would like the subclasses to be Dialogue: 0,0:29:57.74,0:30:01.70,Default,,0000,0000,0000,,at the leaf nodes of\Nyour object graph, right? Dialogue: 0,0:30:01.70,0:30:03.22,Default,,0000,0000,0000,,So, you have objects, and\Nyou've got other objects, Dialogue: 0,0:30:03.22,0:30:04.17,Default,,0000,0000,0000,,and you've got other objects, Dialogue: 0,0:30:04.17,0:30:06.49,Default,,0000,0000,0000,,and down at the end of your sort of tree, Dialogue: 0,0:30:06.49,0:30:09.61,Default,,0000,0000,0000,,there are objects that don't\Nknow about any other things. Dialogue: 0,0:30:09.61,0:30:11.40,Default,,0000,0000,0000,,Right? So we want the subclasses to be Dialogue: 0,0:30:11.40,0:30:14.42,Default,,0000,0000,0000,,the leaf nodes of the object\Nwe have to be at the edge, Dialogue: 0,0:30:14.42,0:30:17.29,Default,,0000,0000,0000,,and we want all the subclasses to use Dialogue: 0,0:30:17.29,0:30:19.63,Default,,0000,0000,0000,,all the codes in the superclass. Dialogue: 0,0:30:19.63,0:30:20.64,Default,,0000,0000,0000,,Now, I'm going to repeat that again. Dialogue: 0,0:30:20.64,0:30:24.46,Default,,0000,0000,0000,,Shallow, narrow, subclasses\Nat the leaf nodes, Dialogue: 0,0:30:24.46,0:30:26.100,Default,,0000,0000,0000,,and subclasses use all the\Nbehavior in the superclass. Dialogue: 0,0:30:26.100,0:30:29.40,Default,,0000,0000,0000,,If that is the problem that you have, Dialogue: 0,0:30:29.40,0:30:31.46,Default,,0000,0000,0000,,there is no better\Nsolution than inheritance, Dialogue: 0,0:30:31.46,0:30:34.54,Default,,0000,0000,0000,,and you are free to use it. Dialogue: 0,0:30:34.54,0:30:37.15,Default,,0000,0000,0000,,So, however, although I love inheritance, Dialogue: 0,0:30:37.15,0:30:40.34,Default,,0000,0000,0000,,I use it in appropriate\Nways, and it is not evil, Dialogue: 0,0:30:40.34,0:30:42.74,Default,,0000,0000,0000,,but sometimes we are.\N(laughter) Dialogue: 0,0:30:42.74,0:30:44.39,Default,,0000,0000,0000,,You might be. Dialogue: 0,0:30:44.39,0:30:46.20,Default,,0000,0000,0000,,And it's easy to get inheritance wrong, Dialogue: 0,0:30:46.20,0:30:50.23,Default,,0000,0000,0000,,and this tree has a little problem, Dialogue: 0,0:30:50.23,0:30:52.10,Default,,0000,0000,0000,,and it's this, I don't like this. Dialogue: 0,0:30:52.10,0:30:55.24,Default,,0000,0000,0000,,The public API of item is\Nquality of days remaining, Dialogue: 0,0:30:55.24,0:30:57.19,Default,,0000,0000,0000,,and the public API of\Nthose four subclasses Dialogue: 0,0:30:57.19,0:30:59.29,Default,,0000,0000,0000,,contains one additional method tick. Dialogue: 0,0:30:59.29,0:31:01.91,Default,,0000,0000,0000,,And I think that superclass\Nought to play the item role, Dialogue: 0,0:31:01.91,0:31:04.37,Default,,0000,0000,0000,,which means to me it's\Ngot to implement tick. Dialogue: 0,0:31:04.37,0:31:06.52,Default,,0000,0000,0000,,And the question then becomes, Dialogue: 0,0:31:06.52,0:31:08.15,Default,,0000,0000,0000,,what is the appropriate implementation Dialogue: 0,0:31:08.15,0:31:10.82,Default,,0000,0000,0000,,of tick to put in the superclass? Dialogue: 0,0:31:10.82,0:31:13.35,Default,,0000,0000,0000,,You could define tick and\Nhave it raise an error Dialogue: 0,0:31:13.35,0:31:15.49,Default,,0000,0000,0000,,that says subclasses\Nhave to implement tick. Dialogue: 0,0:31:15.49,0:31:17.51,Default,,0000,0000,0000,,You could do that, I do that sometimes, Dialogue: 0,0:31:17.51,0:31:19.56,Default,,0000,0000,0000,,but here I think there's\Na default implementation Dialogue: 0,0:31:19.56,0:31:23.75,Default,,0000,0000,0000,,that's appropriate, and it's this. Dialogue: 0,0:31:23.75,0:31:26.50,Default,,0000,0000,0000,,Do nothing. Dialogue: 0,0:31:26.50,0:31:29.35,Default,,0000,0000,0000,,It's perfectly OK with\Nme, tick to do nothing. Dialogue: 0,0:31:29.35,0:31:30.80,Default,,0000,0000,0000,,And now, I did that because the Dialogue: 0,0:31:30.80,0:31:32.37,Default,,0000,0000,0000,,inheritance heirarchy bothered me, Dialogue: 0,0:31:32.37,0:31:35.20,Default,,0000,0000,0000,,and I'm just removing code now. Dialogue: 0,0:31:35.20,0:31:37.70,Default,,0000,0000,0000,,Now that I've done that,\Nyou might notice something Dialogue: 0,0:31:37.70,0:31:39.51,Default,,0000,0000,0000,,about Sulfuras' implementation of tick. Dialogue: 0,0:31:39.51,0:31:42.40,Default,,0000,0000,0000,,It overrides item, it subclasses item to Dialogue: 0,0:31:42.40,0:31:45.64,Default,,0000,0000,0000,,override tick to do exactly\Nwhat the superclass does. Dialogue: 0,0:31:45.64,0:31:50.10,Default,,0000,0000,0000,,And what that means is that here Dialogue: 0,0:31:50.10,0:31:54.93,Default,,0000,0000,0000,,it would be equally correct to say this, Dialogue: 0,0:31:54.93,0:31:59.50,Default,,0000,0000,0000,,which means that this\Nclass is not necessary Dialogue: 0,0:31:59.50,0:32:01.67,Default,,0000,0000,0000,,and all the intermediate\Ncomplexity that I created Dialogue: 0,0:32:01.67,0:32:06.47,Default,,0000,0000,0000,,as I was following this\Nrefactoring just went away. Dialogue: 0,0:32:06.47,0:32:09.67,Default,,0000,0000,0000,,There is no more Sulfuras class. Dialogue: 0,0:32:09.67,0:32:11.77,Default,,0000,0000,0000,,So, I'm going to do one last thing. Dialogue: 0,0:32:11.77,0:32:12.17,Default,,0000,0000,0000,,We're almost finished here. Dialogue: 0,0:32:12.17,0:32:14.13,Default,,0000,0000,0000,,So, this case statement contains Dialogue: 0,0:32:14.13,0:32:17.25,Default,,0000,0000,0000,,two different types of information. Dialogue: 0,0:32:17.25,0:32:20.89,Default,,0000,0000,0000,,It contains a set of\Nstring to class mappings, Dialogue: 0,0:32:20.89,0:32:24.38,Default,,0000,0000,0000,,and it contains the\Nalgorithm to hook them up. Dialogue: 0,0:32:24.38,0:32:26.39,Default,,0000,0000,0000,,And I contend to you that case statements Dialogue: 0,0:32:26.39,0:32:27.72,Default,,0000,0000,0000,,are meant for business logic, Dialogue: 0,0:32:27.72,0:32:30.39,Default,,0000,0000,0000,,and this doesn't really\Nfeel like business logic. Dialogue: 0,0:32:30.39,0:32:33.12,Default,,0000,0000,0000,,This feels like configuration information. Dialogue: 0,0:32:33.12,0:32:37.36,Default,,0000,0000,0000,,And so, I'm just going to\Nextract configuration data here. Dialogue: 0,0:32:37.36,0:32:39.99,Default,,0000,0000,0000,,I'm going to make a hash,\Nand then I'm going to change Dialogue: 0,0:32:39.99,0:32:44.47,Default,,0000,0000,0000,,the algorithm to just be the\Nalgorithm that uses that hash. Dialogue: 0,0:32:44.47,0:32:46.53,Default,,0000,0000,0000,,Now, in real life, this would probably go Dialogue: 0,0:32:46.53,0:32:48.64,Default,,0000,0000,0000,,through some transitions\Nwhere now the hash Dialogue: 0,0:32:48.64,0:32:51.15,Default,,0000,0000,0000,,can change independently of the algorithm Dialogue: 0,0:32:51.15,0:32:52.68,Default,,0000,0000,0000,,that matches these things up, Dialogue: 0,0:32:52.68,0:32:54.22,Default,,0000,0000,0000,,and if you find the hash changing a lot, Dialogue: 0,0:32:54.22,0:32:57.20,Default,,0000,0000,0000,,you might be tempted to\Nmaybe make it a Yamo file, Dialogue: 0,0:32:57.20,0:32:58.63,Default,,0000,0000,0000,,and if you find the Yamo\Nfile changing a lot, Dialogue: 0,0:32:58.63,0:33:01.83,Default,,0000,0000,0000,,you might be tempted\Nto put in the database. Dialogue: 0,0:33:01.83,0:33:03.14,Default,,0000,0000,0000,,Now I can vary that data independently of Dialogue: 0,0:33:03.14,0:33:07.36,Default,,0000,0000,0000,,this rule about how they\Nget hooked up together. Dialogue: 0,0:33:07.36,0:33:10.42,Default,,0000,0000,0000,,And so, that's it, that's\Nthe whole refactoring. Dialogue: 0,0:33:10.42,0:33:12.52,Default,,0000,0000,0000,,We've got a bunch of small objects Dialogue: 0,0:33:12.52,0:33:14.20,Default,,0000,0000,0000,,now instead of small methods. Dialogue: 0,0:33:14.20,0:33:15.90,Default,,0000,0000,0000,,Here's the whole code. Dialogue: 0,0:33:15.90,0:33:18.54,Default,,0000,0000,0000,,In the Gilded Rose module,\Nthere's an item class, Dialogue: 0,0:33:18.54,0:33:21.57,Default,,0000,0000,0000,,and then there's three item subclasses, Dialogue: 0,0:33:21.57,0:33:23.99,Default,,0000,0000,0000,,each of which contains a tick method. Dialogue: 0,0:33:23.99,0:33:26.50,Default,,0000,0000,0000,,There's a set of configuration information Dialogue: 0,0:33:26.50,0:33:28.76,Default,,0000,0000,0000,,that's used by this algorithm to decide Dialogue: 0,0:33:28.76,0:33:31.99,Default,,0000,0000,0000,,what item class is\Nappropriate for what string. Dialogue: 0,0:33:31.99,0:33:35.51,Default,,0000,0000,0000,,Here's the squint testable\Nversion of small objects, Dialogue: 0,0:33:35.51,0:33:38.33,Default,,0000,0000,0000,,and this is it compared to\Nthe original big conditional. Dialogue: 0,0:33:38.33,0:33:40.66,Default,,0000,0000,0000,,Now that's interesting that\Nin the small objects string, Dialogue: 0,0:33:40.66,0:33:42.28,Default,,0000,0000,0000,,it looks like it's nested\Ntoo deep, but it's not. Dialogue: 0,0:33:42.28,0:33:44.10,Default,,0000,0000,0000,,I just have the classes\Ninside the modules. Dialogue: 0,0:33:44.10,0:33:47.81,Default,,0000,0000,0000,,Right? So, that is only\Nreally one level of indenting. Dialogue: 0,0:33:47.81,0:33:48.60,Default,,0000,0000,0000,,The more interesting comparison here is Dialogue: 0,0:33:48.60,0:33:51.73,Default,,0000,0000,0000,,the squint test between\Nthe intermediate solution, Dialogue: 0,0:33:51.73,0:33:54.38,Default,,0000,0000,0000,,the small method solution,\Nand the small object solution. Dialogue: 0,0:33:54.38,0:33:56.79,Default,,0000,0000,0000,,Notice that small objects\Nis a little bit longer, Dialogue: 0,0:33:56.79,0:34:00.99,Default,,0000,0000,0000,,but the colors are clustered\Nmore tightly together. Dialogue: 0,0:34:00.99,0:34:02.17,Default,,0000,0000,0000,,So we have really distilled the things Dialogue: 0,0:34:02.17,0:34:05.71,Default,,0000,0000,0000,,that change together in single places. Dialogue: 0,0:34:05.71,0:34:08.18,Default,,0000,0000,0000,,Here's the Flog scores\Nthat we used to have. Dialogue: 0,0:34:08.18,0:34:11.40,Default,,0000,0000,0000,,So, OK, I have time to make you guess. Dialogue: 0,0:34:11.40,0:34:14.35,Default,,0000,0000,0000,,I made a bunch of small\Nobjects...what's the Flog score? Dialogue: 0,0:34:14.35,0:34:18.95,Default,,0000,0000,0000,,Male:Well, 15. Dialogue: 0,0:34:18.95,0:34:20.78,Default,,0000,0000,0000,,Sandi:But you know what? OK, here. Dialogue: 0,0:34:20.78,0:34:23.83,Default,,0000,0000,0000,,What's in the intermediate,\Nwe'll come back to that. Dialogue: 0,0:34:23.83,0:34:25.48,Default,,0000,0000,0000,,I like that 15 guess, that\Nwas an excellent guess, Dialogue: 0,0:34:25.48,0:34:26.47,Default,,0000,0000,0000,,and you'll know why in a minute. Dialogue: 0,0:34:26.47,0:34:29.93,Default,,0000,0000,0000,,Here's the intermediate complexity scores. Dialogue: 0,0:34:29.93,0:34:30.76,Default,,0000,0000,0000,,Alright, so I've got this. Dialogue: 0,0:34:30.76,0:34:33.16,Default,,0000,0000,0000,,That 33 vastly overstates the complexity Dialogue: 0,0:34:33.16,0:34:36.83,Default,,0000,0000,0000,,of the final solution,\Nand it's because of this. Dialogue: 0,0:34:36.83,0:34:38.86,Default,,0000,0000,0000,,When you have the first\N[string] was one class, Dialogue: 0,0:34:38.86,0:34:40.51,Default,,0000,0000,0000,,the whole Gilded Rose class, Dialogue: 0,0:34:40.51,0:34:41.90,Default,,0000,0000,0000,,and you gotta kind of\Nknow all about that class. Dialogue: 0,0:34:41.90,0:34:43.96,Default,,0000,0000,0000,,And the second solution\Nof the small methods Dialogue: 0,0:34:43.96,0:34:46.40,Default,,0000,0000,0000,,it was the Gilded Rose version two, right? Dialogue: 0,0:34:46.40,0:34:48.56,Default,,0000,0000,0000,,It was a single class, and\Nyou gotta kind of know, Dialogue: 0,0:34:48.56,0:34:50.32,Default,,0000,0000,0000,,you've gotta hold that class in your head. Dialogue: 0,0:34:50.32,0:34:53.20,Default,,0000,0000,0000,,This third solution is a\Nbunch of small classes, Dialogue: 0,0:34:53.20,0:34:54.38,Default,,0000,0000,0000,,it's a bunch of different classes, Dialogue: 0,0:34:54.38,0:34:57.67,Default,,0000,0000,0000,,and you don't need to reason\Nabout all of them at once. Dialogue: 0,0:34:57.67,0:34:59.13,Default,,0000,0000,0000,,As a matter of fact,\Nyou really only need to Dialogue: 0,0:34:59.13,0:35:00.86,Default,,0000,0000,0000,,read the most complicated object in there, Dialogue: 0,0:35:00.86,0:35:02.63,Default,,0000,0000,0000,,and the most complicated\Nclass is a backstage class Dialogue: 0,0:35:02.63,0:35:05.40,Default,,0000,0000,0000,,and it Flogs to 12, close to the 15, Dialogue: 0,0:35:05.40,0:35:07.21,Default,,0000,0000,0000,,and the average complexity of the set of Dialogue: 0,0:35:07.21,0:35:10.54,Default,,0000,0000,0000,,classes in that final solution is seven. Dialogue: 0,0:35:10.54,0:35:13.92,Default,,0000,0000,0000,,And so, I contend to you, the complexity Dialogue: 0,0:35:13.92,0:35:19.62,Default,,0000,0000,0000,,has fallen by 75% because\NI made many small objects. Dialogue: 0,0:35:19.62,0:35:20.72,Default,,0000,0000,0000,,And so now I'm going to circle back around Dialogue: 0,0:35:20.72,0:35:23.35,Default,,0000,0000,0000,,to my task, implement Conjured. Dialogue: 0,0:35:23.35,0:35:30.34,Default,,0000,0000,0000,,Take a minute and imagine how to do it. Dialogue: 0,0:35:30.34,0:35:34.58,Default,,0000,0000,0000,,There's a code that\Nmakes all the tests pass. Dialogue: 0,0:35:34.58,0:35:38.39,Default,,0000,0000,0000,,Here's how to use it. Dialogue: 0,0:35:38.39,0:35:41.24,Default,,0000,0000,0000,,And now we're done. Dialogue: 0,0:35:41.24,0:35:45.10,Default,,0000,0000,0000,,Alright, so, summary. Dialogue: 0,0:35:45.10,0:35:48.31,Default,,0000,0000,0000,,When you are new at\Nthis, they told you DRY. Dialogue: 0,0:35:48.31,0:35:49.70,Default,,0000,0000,0000,,Right? Don't repeat yourself. Dialogue: 0,0:35:49.70,0:35:51.26,Default,,0000,0000,0000,,And I'm not saying it's bad, Dialogue: 0,0:35:51.26,0:35:53.17,Default,,0000,0000,0000,,and I'm not saying that\Nduplication is good, Dialogue: 0,0:35:53.17,0:35:54.44,Default,,0000,0000,0000,,but I'm telling you that if your choice Dialogue: 0,0:35:54.44,0:35:57.17,Default,,0000,0000,0000,,is between duplication\Nand the wrong abstraction, Dialogue: 0,0:35:57.17,0:35:58.89,Default,,0000,0000,0000,,you should choose duplication. Dialogue: 0,0:35:58.89,0:36:01.48,Default,,0000,0000,0000,,Trying to fix a problem by increasing Dialogue: 0,0:36:01.48,0:36:03.57,Default,,0000,0000,0000,,the complexity of the wrong abstraction Dialogue: 0,0:36:03.57,0:36:06.50,Default,,0000,0000,0000,,is like chasing a beach\Nball in the outgoing tide. Dialogue: 0,0:36:06.50,0:36:08.30,Default,,0000,0000,0000,,Every time you take a stroke,\Nit recedes ahead of you, Dialogue: 0,0:36:08.30,0:36:10.55,Default,,0000,0000,0000,,and pretty soon, you're\Nout way over your head. Dialogue: 0,0:36:10.55,0:36:14.22,Default,,0000,0000,0000,,It's very hard to fix those problems. Dialogue: 0,0:36:14.22,0:36:16.20,Default,,0000,0000,0000,,Next, don't try to get to the future. Dialogue: 0,0:36:16.20,0:36:18.25,Default,,0000,0000,0000,,Open/closed, the right code that can Dialogue: 0,0:36:18.25,0:36:20.56,Default,,0000,0000,0000,,adapt to the future when it arrives. Dialogue: 0,0:36:20.56,0:36:22.64,Default,,0000,0000,0000,,New requirements, this\Nrequirement to implement Conjured Dialogue: 0,0:36:22.64,0:36:26.15,Default,,0000,0000,0000,,was the impetus to make a change. Dialogue: 0,0:36:26.15,0:36:29.61,Default,,0000,0000,0000,,It gives you the information\Nyou need about how Dialogue: 0,0:36:29.61,0:36:32.20,Default,,0000,0000,0000,,to make a choice about how\Nto rearrange your code now, Dialogue: 0,0:36:32.20,0:36:35.50,Default,,0000,0000,0000,,so that you can do the next thing. Dialogue: 0,0:36:35.50,0:36:38.71,Default,,0000,0000,0000,,Kent Beck has a wonderfully\Nsuccinct way to put this. Dialogue: 0,0:36:38.71,0:36:42.77,Default,,0000,0000,0000,,He says, "Make the change easy, Dialogue: 0,0:36:42.77,0:36:45.42,Default,,0000,0000,0000,,"and then make the easy change." Dialogue: 0,0:36:45.42,0:36:46.86,Default,,0000,0000,0000,,He actually put it a little bit longer. Dialogue: 0,0:36:46.86,0:36:50.76,Default,,0000,0000,0000,,He said, "Make the change\Neasy, this might be hard, Dialogue: 0,0:36:50.76,0:36:52.42,Default,,0000,0000,0000,,"and then make the easy change." Dialogue: 0,0:36:52.42,0:36:56.33,Default,,0000,0000,0000,,And so, we spent 99% of this\Ntalk making the change easy, Dialogue: 0,0:36:56.33,0:37:00.33,Default,,0000,0000,0000,,and then it took one slide\Nto make the easy change. Dialogue: 0,0:37:00.33,0:37:02.52,Default,,0000,0000,0000,,At the core of this, at the\Nunderpinnings of all this Dialogue: 0,0:37:02.52,0:37:04.54,Default,,0000,0000,0000,,is the idea of making small objects, Dialogue: 0,0:37:04.54,0:37:07.83,Default,,0000,0000,0000,,making objects that had\Na single responsibility. Dialogue: 0,0:37:07.83,0:37:12.15,Default,,0000,0000,0000,,And finally, trust the principles\Nof object-oriented design. Dialogue: 0,0:37:12.15,0:37:14.68,Default,,0000,0000,0000,,They let you predict the consequences Dialogue: 0,0:37:14.68,0:37:17.63,Default,,0000,0000,0000,,of your code arrangement choices, Dialogue: 0,0:37:17.63,0:37:20.15,Default,,0000,0000,0000,,and learning something about\Nwhat those consequences are, Dialogue: 0,0:37:20.15,0:37:22.51,Default,,0000,0000,0000,,is going to let you raise your game. Dialogue: 0,0:37:22.51,0:37:25.31,Default,,0000,0000,0000,,Metrics are useful, but they're fallible, Dialogue: 0,0:37:25.31,0:37:26.95,Default,,0000,0000,0000,,but opinions are no more precise, Dialogue: 0,0:37:26.95,0:37:30.31,Default,,0000,0000,0000,,so use metrics to give you\Nanother body of information Dialogue: 0,0:37:30.31,0:37:32.46,Default,,0000,0000,0000,,about how complicated your code is, Dialogue: 0,0:37:32.46,0:37:35.32,Default,,0000,0000,0000,,and then learn the rules\Nof object-oriented design Dialogue: 0,0:37:35.32,0:37:39.40,Default,,0000,0000,0000,,so that you can choose which\Ndirection you want to go in. Dialogue: 0,0:37:39.40,0:37:43.13,Default,,0000,0000,0000,,Intermediate refactorings often\Nmake code more complicated, Dialogue: 0,0:37:43.13,0:37:44.37,Default,,0000,0000,0000,,but if you know the rules, you can Dialogue: 0,0:37:44.37,0:37:46.92,Default,,0000,0000,0000,,trust yourself to work through complexity, Dialogue: 0,0:37:46.92,0:37:50.39,Default,,0000,0000,0000,,and finally reach more\Nopen/closed code that's simpler, Dialogue: 0,0:37:50.39,0:37:53.60,Default,,0000,0000,0000,,and smaller, and that lets\Nyou have straightforward, Dialogue: 0,0:37:53.60,0:37:56.94,Default,,0000,0000,0000,,changeable, beautiful code. Dialogue: 0,0:37:56.94,0:38:01.52,Default,,0000,0000,0000,,I'm Sandi Metz, I wrote this book, Dialogue: 0,0:38:01.52,0:38:04.56,Default,,0000,0000,0000,,I'm writing this book,\N(laughter) Dialogue: 0,0:38:04.56,0:38:06.78,Default,,0000,0000,0000,,It'll be in the slide deck. Dialogue: 0,0:38:06.78,0:38:07.17,Default,,0000,0000,0000,,I'm teaching in London. Dialogue: 0,0:38:07.17,0:38:09.31,Default,,0000,0000,0000,,There's a public course in\NLondon coming up in June or July, Dialogue: 0,0:38:09.31,0:38:11.68,Default,,0000,0000,0000,,in case you're from over there. Dialogue: 0,0:38:11.68,0:38:13.92,Default,,0000,0000,0000,,Thanks to you all, and\Nthanks to Jim Weirich Dialogue: 0,0:38:13.92,0:38:15.54,Default,,0000,0000,0000,,who gave me this Kata. Dialogue: 0,0:38:15.54,0:38:26.89,Default,,0000,0000,0000,,(applause) Dialogue: 0,0:38:26.89,0:38:44.48,Default,,0000,0000,0000,,(jazzy music)