0:00:00.512,0:00:17.222 (jazzy music) 0:00:17.222,0:00:20.166 Sandi:So you'd think that writing 0:00:20.166,0:00:23.288 object-oriented code was hard. 0:00:23.288,0:00:26.661 All you have to do is[br]look at our apps, alright? 0:00:26.661,0:00:29.972 We mean well, and we write[br]code that almost always 0:00:29.972,0:00:35.261 inevitably we eventually come to hate it. 0:00:35.261,0:00:36.965 And the more I think[br]about this, these days, 0:00:36.965,0:00:39.449 somehow my job is to think[br]about how to write better code. 0:00:39.449,0:00:42.598 And the more I think about[br]it, the more I think that 0:00:42.598,0:00:47.340 all of the problems we cause[br]have the same simple solution, 0:00:47.340,0:00:49.463 and that when people ask me now 0:00:49.463,0:00:51.254 how to write object-oriented code, 0:00:51.254,0:00:54.771 I give them one small piece of advice. 0:00:54.771,0:00:58.425 I say make smaller[br]things, that's all it is. 0:00:58.425,0:01:00.593 Make smaller classes,[br]make smaller methods, 0:01:00.593,0:01:04.931 and let them know as little[br]about each other as possible. 0:01:04.931,0:01:06.640 And lately I've been on a quest. 0:01:06.640,0:01:08.234 I've had this obsession for[br]the last couple of months, 0:01:08.234,0:01:10.483 and it's been about conditionals. 0:01:10.483,0:01:11.448 There's a lot of code out there 0:01:11.448,0:01:12.867 with nasty conditionals in it, 0:01:12.867,0:01:15.685 and I've been wondering,[br]when should I replace 0:01:15.685,0:01:17.874 conditionals with small objects, 0:01:17.874,0:01:19.634 and how should I do this, 0:01:19.634,0:01:22.594 and what would happen to my code if I do? 0:01:22.594,0:01:24.378 And I was really confident[br]in Miami in November 0:01:24.378,0:01:26.970 and I inflicted this[br]obsession upon Jim Weirich, 0:01:26.970,0:01:29.650 whom some of you probably knew, 0:01:29.650,0:01:33.449 and he pointed me in the[br]direction of the Gilded Rose. 0:01:33.449,0:01:34.879 Now this is a Kata, it's apparently 0:01:34.879,0:01:37.226 really well known, but[br]I don't get out much, 0:01:37.226,0:01:38.838 so I had...[br](laughter) 0:01:38.838,0:01:40.629 never heard of it. 0:01:40.629,0:01:43.689 And so, it is so famous[br]that you can just Google it, 0:01:43.689,0:01:46.729 and get an explanation of the[br]problem, but I didn't do that. 0:01:46.729,0:01:48.379 I wanted to treat this problem as if 0:01:48.379,0:01:50.345 it was a real production problem, 0:01:50.345,0:01:51.973 and that my only source of information 0:01:51.973,0:01:54.152 was the test and the code. 0:01:54.152,0:01:56.337 And so I looked at his. 0:01:56.337,0:01:58.391 I checked it out of his [repo], 0:01:58.391,0:01:59.317 and I looked at the problem, 0:01:59.317,0:02:02.330 and I was so interested in it[br]that it became the skeleton 0:02:02.330,0:02:06.776 around which I have hung[br]the ideas for today's talk. 0:02:06.776,0:02:09.574 I have altered his code just a little bit, 0:02:09.574,0:02:11.256 but it's just to make[br]it easier to talk about. 0:02:11.256,0:02:13.688 This really is the Gilded Rose Kata, 0:02:13.688,0:02:14.514 and here's how it goes. 0:02:14.514,0:02:17.368 There's a Gilded Rose class,[br]and it's structured like this. 0:02:17.368,0:02:20.454 It has attributes for name,[br]quality, and days remaining, 0:02:20.454,0:02:22.326 it sets those in an initializer, 0:02:22.326,0:02:24.934 and then there's a tick method. 0:02:24.934,0:02:27.527 Now here's the tick[br]method, well actually, no, 0:02:27.527,0:02:32.836 that's just the first half[br]of it, here's the rest. 0:02:32.836,0:02:34.336 Now, I know you can't read this. 0:02:34.336,0:02:36.229 Well, don't even try,[br]even if you can, alright? 0:02:36.229,0:02:37.384 This is the whole method. 0:02:37.384,0:02:38.999 I just want you to get some sense 0:02:38.999,0:02:39.845 of the size and shape of it. 0:02:39.845,0:02:43.255 It's a 43-line "if" statement. 0:02:43.255,0:02:45.441 And this seems really, really hard to me, 0:02:45.441,0:02:48.752 but I am known to be Bullion-impaired. 0:02:48.752,0:02:50.440 (laughter) 0:02:50.440,0:02:52.344 So, I know that my subjective[br]sense of how difficult this is 0:02:52.344,0:02:55.268 to understand is probably not correct, 0:02:55.268,0:02:57.330 and so instead I used some metrics. 0:02:57.330,0:03:00.513 I ran a complexity metric[br]called "Flog" against it. 0:03:00.513,0:03:02.476 So Flog is a metric. OK, what's a metric? 0:03:02.476,0:03:06.391 A metric is a crowdsource[br]idea about something. 0:03:06.391,0:03:09.619 Right? I have my own opinion[br]about how complex this is, 0:03:09.619,0:03:12.563 but I can use this sort of[br]wisdom-of-the-crowd metric, 0:03:12.563,0:03:14.658 the Flog metric, which scores... 0:03:14.658,0:03:17.250 It's an ABC metric, so[br]it scores assignments, 0:03:17.250,0:03:18.789 branches, and conditionals. 0:03:18.789,0:03:20.660 It just counts things, and adds them up. 0:03:20.660,0:03:21.957 Higher scores are worse. 0:03:21.957,0:03:23.890 They indicate a more complex code, 0:03:23.890,0:03:25.240 a code that's going to be harder 0:03:25.240,0:03:26.951 to understand and reason about. 0:03:26.951,0:03:30.454 And so, Flog says the Gilded[br]Rose class scored a 50, 0:03:30.454,0:03:33.611 and that one method tick scored a 45. 0:03:33.611,0:03:36.121 (moans) [br]Yeah, just hurts, doesn't it? 0:03:36.121,0:03:38.153 So, Flog says it's complicated, 0:03:38.153,0:03:40.169 but before we go on I want to introduce 0:03:40.169,0:03:44.370 a very subjective metric about complexity. 0:03:44.370,0:03:45.686 So, I spend a lot of time these days 0:03:45.686,0:03:51.200 going to places and looking[br]at code I know nothing about. 0:03:51.200,0:03:52.641 People call me up, and I go to their shop, 0:03:52.641,0:03:54.305 and I spend a few days. 0:03:54.305,0:03:55.943 And as you might imagine, 0:03:55.943,0:03:59.749 no one calls me if things are going well. 0:03:59.749,0:04:01.800 (laughter)[br]Alright? 0:04:01.800,0:04:03.593 And when I get there, they don't ask me 0:04:03.593,0:04:06.650 to look at the code they're proud of. 0:04:06.650,0:04:09.304 They ask me to look at the most[br]heinous bits of their apps, 0:04:09.304,0:04:11.178 the things that have sort of complex, 0:04:11.178,0:04:13.650 lengthy contexts in history. 0:04:13.650,0:04:16.584 Code that has just absolutely[br]gotten out of hand. 0:04:16.584,0:04:19.509 And not only are the[br]explanations long and confusing 0:04:19.509,0:04:21.750 because the problem is hard, 0:04:21.750,0:04:22.490 but they do that thing that we all do, 0:04:22.490,0:04:24.504 you know that thing[br]you do when you have to 0:04:24.504,0:04:26.406 explain a bit of code that you wrote 0:04:26.406,0:04:28.416 that you're embarrassed about to someone? 0:04:28.416,0:04:30.489 You don't just tell them how it works. 0:04:30.489,0:04:31.559 You feel compelled to explain 0:04:31.559,0:04:34.914 all the reasons why it got[br]that way. (laughter) Right? 0:04:34.914,0:04:37.155 You laugh. I do it. I know[br]you do it, too, right? 0:04:37.155,0:04:38.594 It just hurts. We hate that. 0:04:38.594,0:04:40.177 And so, these explanations are long 0:04:40.177,0:04:41.367 and confusing and they have lots of 0:04:41.367,0:04:44.332 sort of sideways kind of information. 0:04:44.332,0:04:46.199 And there's a point in[br]time, I really mean well, 0:04:46.199,0:04:47.449 but there's a point in time during every 0:04:47.449,0:04:50.210 explanation when I start[br]feeling like that dog, 0:04:50.210,0:04:54.720 Ginger, in this Gary Larson's cartoon 0:04:54.720,0:04:56.483 where it starts turning[br]into, blah, blah, blah, 0:04:56.483,0:04:58.474 Sandi, blah, blah, blah. (laughs)[br](laughter) 0:04:58.474,0:05:00.400 And then suddenly I get startled back 0:05:00.400,0:05:01.512 into awareness when I hear them say, 0:05:01.512,0:05:03.556 "So, what do you think we should do 0:05:03.556,0:05:07.211 "about this line of code?" (laughs)[br](laughter) 0:05:07.211,0:05:08.937 And it used to terrify me, right? 0:05:08.937,0:05:10.801 I felt like I had to understand everything 0:05:10.801,0:05:12.931 in order to help with anything. 0:05:12.931,0:05:14.371 But it turned out that after a few trips, 0:05:14.371,0:05:15.956 I realized that there was a really 0:05:15.956,0:05:17.413 simple thing I could do to help me 0:05:17.413,0:05:19.977 identify code that they[br]could benefit from changing. 0:05:19.977,0:05:24.242 And I call this the "squint test".[br](laughter) 0:05:24.242,0:05:25.862 Here's how it works. 0:05:25.862,0:05:29.173 You squint your eyes, you lean back, 0:05:29.173,0:05:30.856 and you look at the code. 0:05:30.856,0:05:36.329 And we're looking for changes in shape,[br](laughter) 0:05:36.329,0:05:39.701 and changes in color. 0:05:39.701,0:05:41.270 Changes in shape mean you[br]have nested conditionals 0:05:41.270,0:05:44.208 and they are always going[br]to be hard to reason about. 0:05:44.208,0:05:45.640 Changes in color mean that your code is 0:05:45.640,0:05:48.890 at differing levels of abstraction, 0:05:48.890,0:05:50.337 and it means the story it tells 0:05:50.337,0:05:52.343 is going to be hard to follow. 0:05:52.343,0:05:53.685 Now, what is it about this code? 0:05:53.685,0:05:55.512 Well, it has 16 if statements, 0:05:55.512,0:05:56.977 some of those are not equal to them, 0:05:56.977,0:05:58.570 and connect something with an "&", 0:05:58.570,0:06:00.730 there are three magic strings,[br]they're used all over, 0:06:00.730,0:06:01.559 and a number of magic numbers, 0:06:01.559,0:06:04.554 I don't even know how many.[br](laughter) 0:06:04.554,0:06:06.210 Now, at least it has tests. 0:06:06.210,0:06:07.956 Oh, I'm sorry, here are the magic strings. 0:06:07.956,0:06:08.856 These three things: 0:06:08.856,0:06:11.655 Brie, Sulfuras, and Backstage passes, 0:06:11.655,0:06:13.365 whatever that means. 0:06:13.365,0:06:17.797 And it does have tests, and they pass. 0:06:17.797,0:06:21.632 Now, there are six skipped tests, alright?[br](laughter) 0:06:21.632,0:06:24.820 So, I don't know what that's about. 0:06:24.820,0:06:26.934 And so, I pry open the code, I[br]just look at this first test. 0:06:26.934,0:06:31.153 Oh, sorry, the tests cluster[br]around the magic strings, 0:06:31.153,0:06:32.736 except for this set, which is for 0:06:32.736,0:06:34.185 something called "Normal", 0:06:34.185,0:06:37.712 which is never mentioned in[br]the "if" statement. (laughter) 0:06:37.712,0:06:40.370 I suspect there's something[br]in an [L's] branch 0:06:40.370,0:06:41.410 somewhere that matters here, alright? 0:06:41.410,0:06:42.976 So, I pry open the test and I look at it. 0:06:42.976,0:06:46.199 Here's one, they all look just like this. 0:06:46.199,0:06:50.410 I'm selling something, ok? 0:06:50.410,0:06:51.622 Given a Gilded Rose that has this name, 0:06:51.622,0:06:55.106 attribute, and quality, those[br]are our three [add-a-readers], 0:06:55.106,0:06:59.704 When I tick, in this case,[br]quality goes down by one, 0:06:59.704,0:07:02.305 days remaining goes down by one, 0:07:02.305,0:07:03.224 they both go down by one. 0:07:03.224,0:07:04.258 So, it's as if I'm selling milk, 0:07:04.258,0:07:06.563 or eggs, or cheese or something[br]that has a sell-by date, 0:07:06.563,0:07:10.377 that's going to expire, where[br]they go bad at some date. 0:07:10.377,0:07:12.625 OK, so, I'm still exploring around, 0:07:12.625,0:07:15.145 I don't even know what my job is yet, 0:07:15.145,0:07:17.576 and I look at the six skipped tests, 0:07:17.576,0:07:22.850 and there is something called "Conjured",[br](laughter) 0:07:22.850,0:07:23.279 and they all follow the same pattern, 0:07:23.279,0:07:24.872 all of the tests look like given that 0:07:24.872,0:07:26.809 when I tick, I see this change. 0:07:26.809,0:07:30.138 And at this point, I realize, holy crap, 0:07:30.138,0:07:33.457 I'm supposed to change this code.[br](laughter) 0:07:33.457,0:07:36.948 And so I tried, I tried, 0:07:36.948,0:07:41.961 very obediently, I tried, but[br]I was a miserable failure. 0:07:41.961,0:07:43.121 I couldn't do it. 0:07:43.121,0:07:44.704 That 43 lines of statement defeated me. 0:07:44.704,0:07:47.920 Every time I went, I would[br]like pry open a Conjured test 0:07:47.920,0:07:49.123 and I'd go make some change[br]in that "if" statement 0:07:49.123,0:07:51.940 to make that test pass, it[br]would break something else. 0:07:51.940,0:07:53.129 I spent hours on it. 0:07:53.129,0:07:54.793 Now, I am impaired, but[br]really, it was hard. 0:07:54.793,0:07:56.916 It would be hard for you, too, I think. 0:07:56.916,0:07:58.743 And so, if changing that "if" statement 0:07:58.743,0:08:00.308 was so hard, you have to ask, 0:08:00.308,0:08:02.297 why was I trying? Why did I try to do, 0:08:02.297,0:08:03.457 what possessed me to try to alter 0:08:03.457,0:08:09.145 that incredibly complicated bit of code? 0:08:09.145,0:08:12.456 And the answer is, I felt[br]like I was supposed to. 0:08:12.456,0:08:13.634 And here's what happens, right? 0:08:13.634,0:08:16.720 You write some code,[br]someone asks for a change. 0:08:16.720,0:08:17.610 What do we do? 0:08:17.610,0:08:18.279 You go look around at the code base 0:08:18.279,0:08:20.743 for a code that's the closest thing 0:08:20.743,0:08:22.495 to the new thing you're trying to do, 0:08:22.495,0:08:24.657 and you put the new code there. 0:08:24.657,0:08:25.368 That's how we behave. 0:08:25.368,0:08:28.480 Novices especially, they're[br]afraid to make new objects, 0:08:28.480,0:08:30.615 so they just go put more[br]code in where they can 0:08:30.615,0:08:32.515 find a thing like the thing[br]they're trying to add, 0:08:32.515,0:08:34.283 and if that place already[br]has an "if" statement, 0:08:34.283,0:08:36.948 they just put another branch on it, right? 0:08:36.948,0:08:38.590 That's how it works. 0:08:38.590,0:08:40.111 And what happens is,[br]so the natural tendency 0:08:40.111,0:08:41.288 of code is to grow bigger, 0:08:41.288,0:08:42.460 and bigger, and bigger. 0:08:42.460,0:08:43.465 And there comes a point, right? 0:08:43.465,0:08:44.416 It gets bigger, and bigger, and bigger. 0:08:44.416,0:08:46.306 And there comes a point where it tips, 0:08:46.306,0:08:48.115 and at that point it's so big that 0:08:48.115,0:08:50.536 you cannot imagine putting[br]code anywhere else. 0:08:50.536,0:08:53.216 We have a bargain to follow the pattern, 0:08:53.216,0:08:55.863 and if the pattern is a[br]good one, code gets better. 0:08:55.863,0:08:59.193 And if the pattern is a bad[br]one, we exacerbate the problem. 0:08:59.193,0:09:01.720 Nobody adds a 10-line helper class to a 0:09:01.720,0:09:04.213 5000-line active record object. 0:09:04.213,0:09:05.636 They just get bigger. 0:09:05.636,0:09:09.235 Once they reach a certain[br]size, they just get bigger. 0:09:09.235,0:09:12.809 And so, I could not follow the pattern. 0:09:12.809,0:09:14.295 I was not good enough[br]to follow the pattern, 0:09:14.295,0:09:17.170 and so I decided I was[br]going to make a new pattern, 0:09:17.170,0:09:19.410 That I was going to refactor this code. 0:09:19.410,0:09:21.390 Now, this is real refactoring according 0:09:21.390,0:09:23.290 to the definition of refactoring, 0:09:23.290,0:09:25.810 I'm going to refactor this code, 0:09:25.810,0:09:26.673 I'm going to change its arrangement 0:09:26.673,0:09:28.888 without altering its behavior. 0:09:28.888,0:09:30.515 I'm not going to try to add Conjured, 0:09:30.515,0:09:31.643 I'm going to try to move this code 0:09:31.643,0:09:34.979 around so that I can add Conjured. 0:09:34.979,0:09:36.681 And for refactoring, for refactoring 0:09:36.681,0:09:38.966 it's like this test with[br]a wall at your back. 0:09:38.966,0:09:39.890 You've got to have tests, 0:09:39.890,0:09:41.814 or you don't know what you're doing. 0:09:41.814,0:09:43.304 And so, I'm just going[br]to start at the top. 0:09:43.304,0:09:44.726 I'm going to start with[br]these Normal tests, 0:09:44.726,0:09:45.731 and I've got this code. 0:09:45.731,0:09:47.270 This is what tick looks like. 0:09:47.270,0:09:49.412 Now this is a big, long procedure. 0:09:49.412,0:09:51.367 This is not object-oriented code. 0:09:51.367,0:09:54.550 In object-oriented code, you[br]have lots of little objects, 0:09:54.550,0:09:56.197 and you send messages between them. 0:09:56.197,0:09:57.701 And those messages give you a level of 0:09:57.701,0:09:59.624 indirection so that you can substitute 0:09:59.624,0:10:01.608 different objects at the back. 0:10:01.608,0:10:04.871 Messages create seams so that[br]you can do a different thing, 0:10:04.871,0:10:08.533 and there is no seam here[br]because this is a procedure. 0:10:08.533,0:10:09.793 And so the first thing I have to do 0:10:09.793,0:10:13.139 if I want to refactor is[br]I have to make a seam, 0:10:13.139,0:10:15.353 and I'm going to do that just by 0:10:15.353,0:10:17.928 tracking Normal and Bailing. 0:10:17.928,0:10:23.173 At this point, four tests should[br]fail, and they do, alright? 0:10:23.173,0:10:26.962 And I am not about to add[br]more code to the tick method, 0:10:26.962,0:10:29.733 so I'm just going to[br]send a message to myself, 0:10:29.733,0:10:33.144 and four tests should[br]still fail, and they do. 0:10:33.144,0:10:34.340 And so, now that I believe that I have 0:10:34.340,0:10:36.625 caught that execution path, 0:10:36.625,0:10:38.434 I'm going to just break[br]open the first test 0:10:38.434,0:10:41.862 and I'm going to write[br]the code and make it pass. 0:10:41.862,0:10:45.242 Quality goes down by[br]one, that's easy enough. 0:10:45.242,0:10:47.710 I can write that code. 0:10:47.710,0:10:52.248 Days remaining goes down by[br]one, and that test passes. 0:10:52.248,0:10:54.575 Alright? One down, three to go. 0:10:54.575,0:10:56.431 Here's the next test. 0:10:56.431,0:10:58.826 In this case, it looks[br]like I'm out of time, 0:10:58.826,0:11:03.226 I'm on the sale-by-date, so[br]now quality goes down by two. 0:11:03.226,0:11:07.300 So, I'll just make sure my[br]old test keeps on passing, 0:11:07.300,0:11:10.513 and I'll write code to[br]make this test pass. 0:11:10.513,0:11:12.513 And so, now I think two tests should pass, 0:11:12.513,0:11:14.993 so I should have two failures. 0:11:14.993,0:11:17.511 But something I just did made some test 0:11:17.511,0:11:20.320 I haven't looked at[br]pass, and we love that. 0:11:20.320,0:11:24.839 I'm not even going to look[br]at it. (laughter) Alright? 0:11:24.839,0:11:26.962 I don't need to understand[br]it, I've got tests. (laughter) 0:11:26.962,0:11:28.688 OK, so I'm going to just go, 0:11:28.688,0:11:30.371 I'm going to make this one pass, alright? 0:11:30.371,0:11:32.922 I'll just open the last one. 0:11:32.922,0:11:37.993 So, this one says if the[br]quality is already zero, 0:11:37.993,0:11:39.936 don't change it. 0:11:39.936,0:11:41.817 And so I'm just going[br]to wrap this whole thing 0:11:41.817,0:11:46.145 in an "if" statement, and not[br]do anything if quality is zero. 0:11:46.145,0:11:49.105 OK, so now I'm back to green. 0:11:49.105,0:11:51.761 That code was not smart or clever, 0:11:51.761,0:11:53.831 but that's the whole point. 0:11:53.831,0:11:56.248 Once I get to green, I can now refactor. 0:11:56.248,0:11:58.968 So my goal is to get to[br]green as quickly as possible. 0:11:58.968,0:12:02.551 Red is not when you[br]ponder the abstraction. 0:12:02.551,0:12:05.650 Red is when you scramble toward green. 0:12:05.650,0:12:06.311 You're trying to reach to look for the 0:12:06.311,0:12:08.246 lowest hanging green here, 0:12:08.246,0:12:10.920 and so I got there, I'm at green now, 0:12:10.920,0:12:13.970 and I confessed to you already[br]that I am Bullion-impaired, 0:12:13.970,0:12:14.211 and I have written code that even 0:12:14.211,0:12:17.825 I at this moment do not understand, 0:12:17.825,0:12:20.546 but now I'm green, so I can refactor. 0:12:20.546,0:12:22.273 It looks to me that they always 0:12:22.273,0:12:24.695 subtract one from days remaining, 0:12:24.695,0:12:25.929 so I'm going to do that first. 0:12:25.929,0:12:28.537 I like that story better. 0:12:28.537,0:12:31.138 It looks to me like[br]they don't do anything, 0:12:31.138,0:12:33.190 I can just bail if quality is zero, 0:12:33.190,0:12:34.364 so I can take that whole outer 0:12:34.364,0:12:36.472 nesting out of that "if" statement, 0:12:36.472,0:12:37.482 and now once I get to here, 0:12:37.482,0:12:39.936 I can ponder these two remaining cases. 0:12:39.936,0:12:42.259 Are there two cases here? 0:12:42.259,0:12:43.960 Is there a case where I[br]subtract one from quality 0:12:43.960,0:12:46.640 and two from quality, or[br]is this, I don't think so. 0:12:46.640,0:12:48.378 Now that I look at it this way, 0:12:48.378,0:12:51.367 I think I always subtract[br]one from quality, 0:12:51.367,0:12:52.725 and there's a special case in which 0:12:52.725,0:12:56.772 I subtract another, if[br]I'm past the sell-by date. 0:12:56.772,0:12:57.925 And so, I can just delete all that, 0:12:57.925,0:13:00.579 and now I have this, which is all the same 0:13:00.579,0:13:02.658 level of abstraction,[br]and I can understand it. 0:13:02.658,0:13:04.322 I love the story this code tells. 0:13:04.322,0:13:05.528 It's very simple. 0:13:05.528,0:13:08.922 It was easy to get here,[br]and now my test will pass. 0:13:08.922,0:13:09.830 Alright, so we're going to do this 0:13:09.830,0:13:11.521 over and over again, much[br]more quickly than this one. 0:13:11.521,0:13:13.581 I'm going to just take you[br]through a quick reprise here. 0:13:13.581,0:13:17.470 So, I create a seam, I[br]send a message to myself, 0:13:17.470,0:13:19.107 I tracked all the[br]execution paths into here, 0:13:19.107,0:13:20.582 I wrote some code, I hated it, 0:13:20.582,0:13:21.755 I got to green as quick as possible, 0:13:21.755,0:13:22.868 and then I used green to let me 0:13:22.868,0:13:25.225 refactor to code that was sensible, 0:13:25.225,0:13:27.000 and now Normal is done. 0:13:27.000,0:13:28.728 All the Normal tests passed. 0:13:28.728,0:13:29.985 So, now I'm just going to bust right 0:13:29.985,0:13:31.525 through all the other cases. 0:13:31.525,0:13:33.809 Here's Brie, there's a[br]whole bunch of stuff. 0:13:33.809,0:13:34.835 I'm going to turn that into a case 0:13:34.835,0:13:37.121 statement so I can track Brie. 0:13:37.121,0:13:38.968 There are seven tests, and[br]they're all failing now, 0:13:38.968,0:13:41.539 so I have confidence[br]that I have caught them. 0:13:41.539,0:13:42.647 I'm going to write the code, 0:13:42.647,0:13:43.986 but you don't even need to look at it 0:13:43.986,0:13:45.417 because you can see how easy it is, right? 0:13:45.417,0:13:48.900 Now that I am only[br]having to write code for 0:13:48.900,0:13:50.461 one test at a time, it's pretty[br]simple to write the code. 0:13:50.461,0:13:53.497 What I end up with looks like this. 0:13:53.497,0:13:55.523 And now Brie is done. 0:13:55.523,0:13:59.924 And now a really[br]interesting thing happens. 0:13:59.924,0:14:01.178 When this stuff was buried in the 0:14:01.178,0:14:02.499 43-line "if" statement, 0:14:02.499,0:14:06.537 I had no idea the ways in which[br]Normal and Brie were like, 0:14:06.537,0:14:10.297 but now that I'm using this,[br]they seem a lot alike to me. 0:14:10.297,0:14:12.547 Now, there's differences sort[br]of in the driving data here, 0:14:12.547,0:14:14.690 but the algorithm, you can see the shape 0:14:14.690,0:14:17.297 of the algorithm here, and the[br]algorithm is really the same. 0:14:17.297,0:14:18.799 And it is very tempting. 0:14:18.799,0:14:22.193 We've had the DRY rule[br]browbeat into us so strongly, 0:14:22.193,0:14:23.704 it's very tempting at this point. 0:14:23.704,0:14:25.891 I'm on a road, I'm on a refactoring road. 0:14:25.891,0:14:28.393 It's very tempting now to go on a tangent 0:14:28.393,0:14:29.697 and try to clean this up. 0:14:29.697,0:14:30.840 Because we believe the greatest, 0:14:30.840,0:14:33.703 we've been taught like the[br]greatest virtue is DRY. 0:14:33.703,0:14:36.256 And I will tell you that's[br]the wrong idea here. 0:14:36.256,0:14:37.589 I'm about to get a lot more information 0:14:37.589,0:14:39.520 about what this algorithm looks like, 0:14:39.520,0:14:42.710 and I need to finish[br]the refactoring I'm on 0:14:42.710,0:14:44.393 before I go on any tangents,[br]so I'm going to notice 0:14:44.393,0:14:47.606 that similarity and keep the duplication, 0:14:47.606,0:14:50.700 and just keep on going down[br]this path to see where it leads. 0:14:50.700,0:14:52.599 And this brings me to my[br]first big point of this talk. 0:14:52.599,0:14:56.818 It is far cheaper to keep duplication 0:14:56.818,0:14:59.545 than it is to have to mess[br]with the wrong abstraction. 0:14:59.545,0:15:00.984 The first rule we teach novices 0:15:00.984,0:15:03.157 is don't repeat yourself - DRY. 0:15:03.157,0:15:05.849 But have you ever thought about[br]why we teach them that rule? 0:15:05.849,0:15:09.443 It's because they can't understand[br]anything else. (laughter) 0:15:09.443,0:15:10.857 They don't know anything, but by God, 0:15:10.857,0:15:13.790 they can recognize duplication,[br]and it's a good rule. 0:15:13.790,0:15:15.178 I'm not saying it's a bad rule, 0:15:15.178,0:15:20.916 but I'm saying that now you're[br]grown up, you know more, 0:15:20.916,0:15:22.989 and you have enough experience 0:15:22.989,0:15:24.903 now to tolerate a little duplication 0:15:24.903,0:15:26.448 and wait on a better abstraction. 0:15:26.448,0:15:29.842 It's really hard to deal[br]with the wrong abstraction. 0:15:29.842,0:15:31.921 I often make a "dup tag". 0:15:31.921,0:15:33.930 You know how you can make a "to do" tag? 0:15:33.930,0:15:35.207 Like people say, "Oh, I'm going to 0:15:35.207,0:15:36.627 "lose track of my duplication." 0:15:36.627,0:15:37.697 Well, fix that problem. 0:15:37.697,0:15:40.119 Make a "dup tag" and give[br]every "dup" a number, 0:15:40.119,0:15:43.386 so if you have the same[br]code in two or three places, 0:15:43.386,0:15:45.571 like if that's the sixth[br]instance of duplication, 0:15:45.571,0:15:46.988 give it an ID like a database, 0:15:46.988,0:15:49.270 and put "dup six" in a bunch[br]of places in your code. 0:15:49.270,0:15:50.178 You'll know. 0:15:50.178,0:15:51.825 You'll see the duplication[br]if you change a part, 0:15:51.825,0:15:54.147 like fix the problem of[br]not being able to find it, 0:15:54.147,0:15:56.561 rather than reaching too[br]soon for an abstraction. 0:15:56.561,0:15:59.554 It's much easier to[br]deal with a duplication. 0:15:59.554,0:16:00.714 Alright, so moving on. 0:16:00.714,0:16:02.840 Here's Sulfuras. There's three tests. 0:16:02.840,0:16:06.104 You would think if I put my[br]shim in and put an empty method, 0:16:06.104,0:16:12.178 I would have three test failures.[br](laughter) 0:16:12.178,0:16:13.949 And yet they all pass. 0:16:13.949,0:16:14.826 So, what's this about? 0:16:14.826,0:16:16.560 Well, I look at the test and I realize 0:16:16.560,0:16:17.866 in all the tests [unintelligible] that 0:16:17.866,0:16:20.527 nothing happens if it's Sulfuras. 0:16:20.527,0:16:22.230 And again, I had no idea when I was 0:16:22.230,0:16:23.446 looking at that 43 lines of statement 0:16:23.446,0:16:26.155 that somehow it all asserted[br]that nothing happened, 0:16:26.155,0:16:30.617 so it turns out this is the code[br]that makes the tests pass. (laughter) 0:16:30.617,0:16:33.945 How nice is that? We love that, OK? 0:16:33.945,0:16:35.475 So here's Backstage, and[br]there's a whole bunch of these, 0:16:35.475,0:16:37.346 and it looks like this. 0:16:37.346,0:16:39.462 That's the code that makes the tests pass. 0:16:39.462,0:16:41.820 And so now, we're totally back to green. 0:16:41.820,0:16:44.231 This looks exactly like[br]it did when I started. 0:16:44.231,0:16:46.922 And this is what I got. 0:16:46.922,0:16:48.407 I put this case statement in the front, 0:16:48.407,0:16:50.634 and it tracked all the execution paths. 0:16:50.634,0:16:52.933 I have a bunch of methods[br]that look like this 0:16:52.933,0:16:55.785 that I created and added[br]to the Gilded Rose class, 0:16:55.785,0:16:57.207 and the rest of the tick methods still 0:16:57.207,0:17:00.230 contains that monstrous[br]43-line "if" statement, 0:17:00.230,0:17:02.851 which I don't understand,[br]but I no longer need, 0:17:02.851,0:17:06.607 so I'm just going to delete it, it's gone. 0:17:06.607,0:17:11.640 Now if you don't have good tests,[br]this may freak you out, (laughter) 0:17:11.640,0:17:13.512 but then if you feel freaked out by this 0:17:13.512,0:17:14.664 and you don't have good tests, 0:17:14.664,0:17:16.329 you're really making a choice here, right? 0:17:16.329,0:17:19.016 If you have code that you don't understand 0:17:19.016,0:17:20.690 and that you're afraid to change, 0:17:20.690,0:17:24.992 you can keep it forever, if[br]you think that's a good idea, 0:17:24.992,0:17:27.950 or you can put some kind of test [harness) 0:17:27.950,0:17:29.267 around it so that you can refactor, 0:17:29.267,0:17:31.750 but keeping it forever is[br]not really a good choice, 0:17:31.750,0:17:32.165 so you want to get to the point where 0:17:32.165,0:17:34.773 you have confidence that[br]you can safely refactor, 0:17:34.773,0:17:37.347 and it means you never have[br]to understand that code, 0:17:37.347,0:17:39.894 you can do characterization[br]tests around the edges, 0:17:39.894,0:17:41.154 so that you'll have green, 0:17:41.154,0:17:42.406 you'll have a wall at your back for tests, 0:17:42.406,0:17:43.719 and then you can refactor your way, 0:17:43.719,0:17:44.833 to the point where you can delete 0:17:44.833,0:17:47.560 the code that you don't understand. 0:17:47.560,0:17:48.612 And the moral of this story is that 0:17:48.612,0:17:51.556 small methods are simple. 0:17:51.556,0:17:52.393 Here we have it. 0:17:52.393,0:17:53.651 This is the code we just wrote. 0:17:53.651,0:17:55.423 This is the squint test[br]version, don't try to read it. 0:17:55.423,0:17:56.737 This is the code we[br]just wrote on the right, 0:17:56.737,0:17:58.492 and this is how we start it on the left. 0:17:58.492,0:18:02.166 You notice that the shape is flat, 0:18:02.166,0:18:04.216 and the colors are starting to cluster. 0:18:04.216,0:18:06.510 Now, again I believe in metrics, because 0:18:06.510,0:18:08.248 I know that my personal notion of what 0:18:08.248,0:18:10.866 is simple or complex is just my opinion, 0:18:10.866,0:18:14.915 and I totally know that[br]metrics are fallible, 0:18:14.915,0:18:18.182 but human opinion is no more precise. 0:18:18.182,0:18:20.665 And that metrics are kind[br]of a crowdsource idea 0:18:20.665,0:18:22.810 of what a bunch of people[br]thought a metric could be. 0:18:22.810,0:18:26.194 It is a useful data point[br]for me to compare to my own. 0:18:26.194,0:18:27.847 The original class Flogged to 50, 0:18:27.847,0:18:30.808 and this new class Flogs to 40, 0:18:30.808,0:18:32.580 but that overstates its complexity 0:18:32.580,0:18:33.419 because now there's a bunch of methods, 0:18:33.419,0:18:36.855 and the most complex method is[br]Backstage and if Flogs to 12. 0:18:36.855,0:18:39.688 This code is way simpler. 0:18:39.688,0:18:41.361 Well, this is great, and you'd think that 0:18:41.361,0:18:43.673 everyone would just do this. 0:18:43.673,0:18:46.168 And so, it's an interesting[br]question why they don't. 0:18:46.168,0:18:47.380 Now, one of the things I already told you, 0:18:47.380,0:18:48.640 I already gave you one reason, right? 0:18:48.640,0:18:50.809 We do more of what's there. 0:18:50.809,0:18:53.342 And so, the tendency is to add more 0:18:53.342,0:18:54.498 to the "if" statement, if that's there, 0:18:54.498,0:18:55.856 but I think there's another reason 0:18:55.856,0:18:58.609 why we don't undertake these refactorings, 0:18:58.609,0:18:59.824 and it's because of this. 0:18:59.824,0:19:02.615 I'm just going to make the[br]50 smaller and move it over. 0:19:02.615,0:19:05.863 It took me 10 refactoring steps to get 0:19:05.863,0:19:09.957 from the big conditional to[br]a bunch of small methods, 0:19:09.957,0:19:15.285 and here's the Flog score of[br]all the intermediate steps. 0:19:15.285,0:19:16.823 All the intermediate refactorings 0:19:16.823,0:19:19.578 made code more complicated. 0:19:19.578,0:19:21.865 I know that I'm going to get to that 40. 0:19:21.865,0:19:24.266 I understand the principles[br]of object-oriented design, 0:19:24.266,0:19:25.974 and I know the value of small methods, 0:19:25.974,0:19:29.209 and because of that, I[br]believe in the refactorings, 0:19:29.209,0:19:31.715 and that lets me tolerate[br]the intermediate complexity. 0:19:31.715,0:19:35.250 But if you don't know,[br]if you haven't learned 0:19:35.250,0:19:36.278 about the value of small methods, 0:19:36.278,0:19:38.646 it's hard to undertake[br]those intermediate steps. 0:19:38.646,0:19:43.819 They seem like academic things that 0:19:43.819,0:19:48.551 people will do that are[br]for some pie-in-the-sky 0:19:48.551,0:19:51.186 principle that don't improve code, 0:19:51.186,0:19:53.240 but I can promise you that if you can see 0:19:53.240,0:19:55.492 far enough to see to the end, 0:19:55.492,0:19:59.817 this intermediate complexity[br]leads to ultimate simplicity. 0:19:59.817,0:20:02.822 And, so now I'm going to[br]circle back around my task, 0:20:02.822,0:20:04.170 now that I've done this refactoring, 0:20:04.170,0:20:05.593 I can circle back around my original task 0:20:05.593,0:20:08.490 which is to implement Conjure. 0:20:08.490,0:20:10.183 How should I do this? 0:20:10.183,0:20:13.764 Here's what I got, I've got this. 0:20:13.764,0:20:17.569 Should I do that? 0:20:17.569,0:20:20.935 It would be easy, it would be really easy. 0:20:20.935,0:20:23.797 The answer to that is[br]"no", I should not do that. 0:20:23.797,0:20:26.830 That is not the way I[br]should solve this problem, 0:20:26.830,0:20:29.960 and it's because this[br]code is not open/closed. 0:20:29.960,0:20:34.327 It is not open for extension,[br]and closed for modification. 0:20:34.327,0:20:37.861 Open/closed supplies the[br]"O" in [solid], and it is, 0:20:37.861,0:20:38.951 and I'm going to say it right out loud, 0:20:38.951,0:20:43.450 it's a principle of[br]object-oriented design. 0:20:43.450,0:20:46.424 It's one of the pieces[br]of cumulative wisdom 0:20:46.424,0:20:47.543 created by folks who've written 0:20:47.543,0:20:49.496 a mountain of object-oriented code, 0:20:49.496,0:20:51.772 and they have experienced every 0:20:51.772,0:20:54.680 possible kind of programming pain. 0:20:54.680,0:20:58.135 And over time, they have[br]noticed some principles, 0:20:58.135,0:21:01.264 and they developed a style guide 0:21:01.264,0:21:03.749 about how to organize code. 0:21:03.749,0:21:05.144 That's what object-oriented design is. 0:21:05.144,0:21:07.206 That's what the rules of[br]object-oriented design are. 0:21:07.206,0:21:10.598 It's a style guide about[br]how to organize code 0:21:10.598,0:21:12.585 with all the obvious tradeoffs, 0:21:12.585,0:21:14.636 all the places where you[br]can make your own decisions. 0:21:14.636,0:21:19.216 In this case, you can feel free[br]to ignore their discoveries, 0:21:19.216,0:21:20.341 in which case you'll get to experience 0:21:20.341,0:21:23.465 all that pain over again for yourself. 0:21:23.465,0:21:24.789 That's what will happen. 0:21:24.789,0:21:26.576 On the macro level, this style guide says 0:21:26.576,0:21:30.617 it's best to arrange code[br]so that adding new behavior 0:21:30.617,0:21:34.326 does not require that[br]you edit existing code. 0:21:34.326,0:21:35.661 I know that seems impossible. 0:21:35.661,0:21:37.155 I'm going to say it again, right? 0:21:37.155,0:21:40.460 Open/closed says you ought to[br]be able to add new behavior 0:21:40.460,0:21:43.247 without editing existing code. 0:21:43.247,0:21:45.367 Now, forget about how impossible[br]that seems for a minute. 0:21:45.367,0:21:47.400 I just want you to[br]imagine something for me. 0:21:47.400,0:21:53.150 Imagine the world, imagine[br]your apps, if that is true. 0:21:53.150,0:21:55.713 Imagine that you can add new behavior 0:21:55.713,0:21:57.559 without editing existing code. 0:21:57.559,0:22:00.890 Think about what that means. 0:22:00.890,0:22:02.483 It means you always have green tests, 0:22:02.483,0:22:04.100 it means you are always safe, 0:22:04.100,0:22:06.504 it means you never cause some 0:22:06.504,0:22:08.680 distant and unrelated side-effect. 0:22:08.680,0:22:10.921 That is a sweet, sweet world, 0:22:10.921,0:22:12.991 if your code is open/closed. 0:22:12.991,0:22:14.528 And so, on the macro[br]level, we are trying to get 0:22:14.528,0:22:16.438 to the point where we[br]can add new behavior, 0:22:16.438,0:22:18.223 without editing existing code. 0:22:18.223,0:22:20.568 And on the micro level,[br]what that means here, 0:22:20.568,0:22:22.989 right now, in this code, 0:22:22.989,0:22:24.553 is that when we see methods that have 0:22:24.553,0:22:27.946 a repeating prefix or repeating suffix, 0:22:27.946,0:22:30.440 there is a tortured object in there 0:22:30.440,0:22:34.694 that's trying to get out.[br](laughter) 0:22:34.694,0:22:36.726 Right here, in this place, 0:22:36.726,0:22:38.374 you're about to make a decision 0:22:38.374,0:22:40.500 that's going to have consequences 0:22:40.500,0:22:43.341 that echo through your code base forever. 0:22:43.341,0:22:45.736 Are you going to write procedures, 0:22:45.736,0:22:48.264 or are you going to trust objects? 0:22:48.264,0:22:50.775 If you insist on having[br]all the logic visible, 0:22:50.775,0:22:52.753 right here where you can see it, 0:22:52.753,0:22:54.176 you are insisting really on knowing 0:22:54.176,0:22:56.633 both the condition on which you switch, 0:22:56.633,0:22:57.966 and the thing that you do, 0:22:57.966,0:23:00.358 the action that you take[br]when that switch happens. 0:23:00.358,0:23:02.103 If you're uncomfortable, and unless 0:23:02.103,0:23:05.890 you know both those things[br]at once in this file, 0:23:05.890,0:23:07.225 under your eyes, in this[br]code, then you're going to 0:23:07.225,0:23:09.814 be forced to add a new method right here. 0:23:09.814,0:23:12.631 You have to put that conjured[br]tick method right here. 0:23:12.631,0:23:14.503 But if you don't, if you're OK with that, 0:23:14.503,0:23:16.231 you can listen to object-oriented design. 0:23:16.231,0:23:18.784 It says that when you[br]have differing prefixes, 0:23:18.784,0:23:21.313 and common suffixes,[br]then what you really have 0:23:21.313,0:23:25.110 is a normal class that[br]ought to have a method tick, 0:23:25.110,0:23:27.378 and a Gilded Rose ought to be holding on 0:23:27.378,0:23:29.990 to an instance of it. 0:23:29.990,0:23:31.833 And it is real easy to right that code. 0:23:31.833,0:23:34.983 If you can think of that[br]thing, thinking of the thing 0:23:34.983,0:23:36.755 is far harder than writing the code. 0:23:36.755,0:23:38.131 Here's how the code looks. 0:23:38.131,0:23:39.704 I've got this Normal tick method, 0:23:39.704,0:23:41.505 I'm just going to call it "tick", 0:23:41.505,0:23:43.018 I'm going to put in a Normal class, 0:23:43.018,0:23:44.525 I'm going to throw a cruft in there to get 0:23:44.525,0:23:47.611 the initialization and[br]the attributes defined, 0:23:47.611,0:23:49.352 I'm going to go back into Gilded Rose 0:23:49.352,0:23:50.855 and the Normal tick method there, 0:23:50.855,0:23:52.672 I'll get an instance of my new class, 0:23:52.672,0:23:56.534 and I'll forward this[br]message - boom, that's it. 0:23:56.534,0:23:59.431 Alright, well, so I've got this, 0:23:59.431,0:24:02.355 so Normal is an object,[br]but nothing else is, 0:24:02.355,0:24:03.813 and I'm about to go back on the path where 0:24:03.813,0:24:07.206 I have to increase[br]intermediate complexity, 0:24:07.206,0:24:08.825 because look what just happened, alright? 0:24:08.825,0:24:10.994 My new Normal tick method looks like this. 0:24:10.994,0:24:12.163 It uses this item class. 0:24:12.163,0:24:13.765 But Brie, the Brie tick method is still 0:24:13.765,0:24:16.564 calculated inside the Gilded Rose. 0:24:16.564,0:24:18.248 The quality and days remaining are part 0:24:18.248,0:24:20.180 of the public API for Gilded Rose, 0:24:20.180,0:24:21.188 and so now I have to say, well, 0:24:21.188,0:24:23.204 if I have an item, go[br]get the item's quality, 0:24:23.204,0:24:25.445 otherwise, get the one I know about. 0:24:25.445,0:24:28.800 And I have to do the same thing[br]for days remaining, alright? 0:24:28.800,0:24:32.600 It looks messy, but it's[br]short-term, it will go away. 0:24:32.600,0:24:34.560 And so, let's just walk[br]through all the other objects. 0:24:34.560,0:24:35.584 Now that you understand this pattern, 0:24:35.584,0:24:36.873 it's really easy, right? 0:24:36.873,0:24:38.851 Class Brie, move method tick, 0:24:38.851,0:24:41.924 put the cruft in there,[br]forward the message. 0:24:41.924,0:24:43.333 Easy enough. 0:24:43.333,0:24:45.492 This is really interesting. 0:24:45.492,0:24:47.570 Now some trust is coming into play, right? 0:24:47.570,0:24:49.317 I have an empty method,[br]look what I have to do. 0:24:49.317,0:24:50.919 Make a new class, put the method in, 0:24:50.919,0:24:52.486 pry this method open, get an instance 0:24:52.486,0:24:53.800 of that class, forward the message. 0:24:53.800,0:24:58.296 You can be forgiven for[br]being suspicious about this, 0:24:58.296,0:24:59.783 but if you trust the refactorings, 0:24:59.783,0:25:00.890 you have confidence that this is 0:25:00.890,0:25:02.680 going to turn out well in the end. 0:25:02.680,0:25:05.766 I'm not going to diverge,[br]I'm not taking a detour, 0:25:05.766,0:25:06.838 I'm going to go all the way down 0:25:06.838,0:25:09.472 this path and finish this refactoring. 0:25:09.472,0:25:11.344 Backstage, I'll make the tick method, 0:25:11.344,0:25:15.800 I'll make that stuff,[br]I'll do the forwarding. 0:25:15.800,0:25:21.332 Alright, so now they're all[br]objects and I've got this. 0:25:21.332,0:25:23.250 And I'm back here. 0:25:23.250,0:25:27.442 So now, in the beginning, I moved logic 0:25:27.442,0:25:28.423 into methods of their own, 0:25:28.423,0:25:29.765 because I didn't want to put a bunch 0:25:29.765,0:25:31.491 of code in this case statement, 0:25:31.491,0:25:33.995 but now that I have objects,[br]everything is simpler, 0:25:33.995,0:25:37.350 and I'm going to just start[br]rewinding my decisions. 0:25:37.350,0:25:39.410 I'm just going to delete the method, 0:25:39.410,0:25:41.444 and shove the code that[br]used to be in the method 0:25:41.444,0:25:44.906 back up in the branches[br]of the case statement. 0:25:44.906,0:25:46.510 We'll do that. 0:25:46.510,0:25:48.400 Now, earlier I said that duplication was 0:25:48.400,0:25:49.560 cheaper than the wrong abstraction, 0:25:49.560,0:25:51.800 but now we're starting[br]to see abstractions, 0:25:51.800,0:25:55.122 and I'm just going to go and[br]abstract away some duplication. 0:25:55.122,0:25:56.616 I'm going to put the cruft back up in here 0:25:56.616,0:25:59.664 so in Gilded Rose, I no longer need that. 0:25:59.664,0:26:02.455 What I really need to do[br]is be able to get an item. 0:26:02.455,0:26:04.633 And the way I need to get an item is that. 0:26:04.633,0:26:05.576 That's how I'm going to get it. 0:26:05.576,0:26:06.711 If I just knew the class name, 0:26:06.711,0:26:09.723 I could send that message[br]to it, and it would work. 0:26:09.723,0:26:12.217 And it's actually really easy[br]to figure out the class name. 0:26:12.217,0:26:14.540 The code's already here. 0:26:14.540,0:26:17.162 It's this, there it is. 0:26:17.162,0:26:18.552 That will get me the class name back, 0:26:18.552,0:26:20.820 so if I just give that a name, 0:26:20.820,0:26:22.530 I can send that message to myself, 0:26:22.530,0:26:25.697 and now I have the right kind of item. 0:26:25.697,0:26:28.810 I don't need a name anymore,[br]so that got simpler. 0:26:28.810,0:26:31.266 So now, I have separated[br]the reason I'm switching 0:26:31.266,0:26:34.920 from the thing I do when I switch. 0:26:34.920,0:26:36.345 And I can just forget about what's 0:26:36.345,0:26:37.702 inside that class [form] method. 0:26:37.702,0:26:38.904 I don't really care anymore. 0:26:38.904,0:26:40.000 It just answers the right class. 0:26:40.000,0:26:41.930 It's going to work. 0:26:41.930,0:26:42.514 It's going to hand back a thing that can 0:26:42.514,0:26:44.793 answer the message I'm[br]going to send to it. 0:26:44.793,0:26:46.612 And now tick looks like[br]that and these now, 0:26:46.612,0:26:48.430 so I'm rewinding the complexity, 0:26:48.430,0:26:49.288 I don't need this anymore. 0:26:49.288,0:26:52.686 I have items in every case,[br]so I'll get rid of all that. 0:26:52.686,0:26:56.371 And now here's the whole[br]body of code that I have. 0:26:56.371,0:26:58.262 I'm holding an instance of[br]the correct item object, 0:26:58.262,0:27:00.709 and I just sent it the tick method. 0:27:00.709,0:27:02.476 so, we have four different,[br]down at the bottom there, 0:27:02.476,0:27:04.856 you can see we have four[br]different kinds of item classes, 0:27:04.856,0:27:08.916 but from Gilded Rose's point[br]of view, item is a role. 0:27:08.916,0:27:12.857 It doesn't think of it like[br]this, it thinks of it like that. 0:27:12.857,0:27:15.907 You just need someone in there[br]that can answer that API, 0:27:15.907,0:27:19.201 that knows those messages, it's[br]a [duck] type, if you will. 0:27:19.201,0:27:20.433 And if you look at the code I have now, 0:27:20.433,0:27:22.999 the message passing works like this. 0:27:22.999,0:27:24.358 All these messages get forwarded, 0:27:24.358,0:27:26.580 and if you had a Foo[br]that had a Gilded Rose 0:27:26.580,0:27:29.400 that sent those messages,[br]it would look like this. 0:27:29.400,0:27:32.437 And so, now I'm in a situation like this. 0:27:32.437,0:27:34.390 When an object's only purpose is to 0:27:34.390,0:27:35.644 forward messages somewhere else, 0:27:35.644,0:27:38.852 you have to wonder if it[br]justifies its existence. 0:27:38.852,0:27:40.662 This actually is a code[br][unintelligible] that has a name, 0:27:40.662,0:27:43.297 and its name is Middleman. 0:27:43.297,0:27:46.500 So, if that's all the Gilded Rose does, 0:27:46.500,0:27:48.128 it probably shouldn't[br]exist, but it turns out 0:27:48.128,0:27:50.595 it still does something important. 0:27:50.595,0:27:55.750 Given a string like Normal,[br]it can figure out what 0:27:55.750,0:27:59.495 item class, what class plays[br]the appropriate item role. 0:27:59.495,0:28:01.699 And so now, I'm going to use another word 0:28:01.699,0:28:05.110 that you should love, you[br]should love this word. 0:28:05.110,0:28:06.368 Gilded Rose, the only thing that 0:28:06.368,0:28:09.677 Gilded Rose is is an item factory. 0:28:09.677,0:28:11.767 I just need to figure out[br]how to get the right object, 0:28:11.767,0:28:13.217 and then I can send it a message. 0:28:13.217,0:28:15.396 We've simplified our problem by 0:28:15.396,0:28:17.976 separating the thing I'm switching on 0:28:17.976,0:28:19.794 from the thing I do when I switch. 0:28:19.794,0:28:21.235 We've divided those things in half, 0:28:21.235,0:28:23.881 so I can make the code[br][unintelligible] less, 0:28:23.881,0:28:26.334 and we can do smaller things. 0:28:26.334,0:28:28.425 I don't need to know what they do, 0:28:28.425,0:28:31.492 I just need to know how[br]to get the right one. 0:28:31.492,0:28:33.384 And so, I'm going to change this[br]code to reflect the reality. 0:28:33.384,0:28:35.417 I'm going to make Gilded Rose a module. 0:28:35.417,0:28:37.737 I'm going to say four,[br]some people put new. 0:28:37.737,0:28:39.609 They make a new method on module, 0:28:39.609,0:28:41.940 and I just can't bear that, 0:28:41.940,0:28:44.199 but it's OK with me if you do it that way. 0:28:44.199,0:28:45.476 So, I have to make it a class method 0:28:45.476,0:28:46.825 because I'm calling it. 0:28:46.825,0:28:48.274 I'm no longer keeping[br]an instance of anything, 0:28:48.274,0:28:50.346 so I don't need an [add-a-reader]. 0:28:50.346,0:28:51.849 All these Middleman messages now, 0:28:51.849,0:28:53.349 since you're really[br]going to talk to the item 0:28:53.349,0:28:54.834 that you get back when you call four, 0:28:54.834,0:28:57.706 all these messages, they just go away. 0:28:57.706,0:28:59.684 So now, this is what we have. 0:28:59.684,0:29:01.818 And the way you use it is you send four 0:29:01.818,0:29:04.390 to Gilded Rose, and it gives back an item, 0:29:04.390,0:29:07.420 and it's the item that you talked to. 0:29:07.420,0:29:09.367 And so, now that we've[br]fixed the Gilded Rose, 0:29:09.367,0:29:11.238 I'm going to turn my attention to the 0:29:11.238,0:29:16.404 classes that play the item role. 0:29:16.404,0:29:18.670 There's a lot of duplication here that 0:29:18.670,0:29:19.713 we've been tolerating for a long time. 0:29:19.713,0:29:20.983 They all have this in them. 0:29:20.983,0:29:23.556 And I'm going to create[br]an inheritance hierarchy, 0:29:23.556,0:29:25.590 and clean that up. 0:29:25.590,0:29:27.310 I'm going to make a little item class, 0:29:27.310,0:29:29.783 push all that stuff up to[br]it, then all these guys, 0:29:29.783,0:29:31.368 I can delete that code[br]from all these guys, 0:29:31.368,0:29:34.903 and make them subclasses of item. 0:29:34.903,0:29:37.684 Now, despite what you may have heard, 0:29:37.684,0:29:41.138 inheritance is not evil, 0:29:41.138,0:29:43.973 and I can tell you exactly[br]when it's safe to use it. 0:29:43.973,0:29:45.190 Now here's what you want. 0:29:45.190,0:29:48.274 You want a shallow, narrow hierarchy, 0:29:48.274,0:29:49.768 you don't want it to be deep, 0:29:49.768,0:29:51.506 and you don't want it to be wide, alright? 0:29:51.506,0:29:54.457 Shallow and narrow, you would[br]like the subclasses to be, 0:29:54.457,0:29:56.553 OK, I will say this twice. 0:29:56.553,0:29:57.736 You would like the subclasses to be 0:29:57.736,0:30:01.699 at the leaf nodes of[br]your object graph, right? 0:30:01.699,0:30:03.221 So, you have objects, and[br]you've got other objects, 0:30:03.221,0:30:04.166 and you've got other objects, 0:30:04.166,0:30:06.494 and down at the end of your sort of tree, 0:30:06.494,0:30:09.610 there are objects that don't[br]know about any other things. 0:30:09.610,0:30:11.401 Right? So we want the subclasses to be 0:30:11.401,0:30:14.425 the leaf nodes of the object[br]we have to be at the edge, 0:30:14.425,0:30:17.286 and we want all the subclasses to use 0:30:17.286,0:30:19.633 all the codes in the superclass. 0:30:19.633,0:30:20.642 Now, I'm going to repeat that again. 0:30:20.642,0:30:24.458 Shallow, narrow, subclasses[br]at the leaf nodes, 0:30:24.458,0:30:26.995 and subclasses use all the[br]behavior in the superclass. 0:30:26.995,0:30:29.398 If that is the problem that you have, 0:30:29.398,0:30:31.457 there is no better[br]solution than inheritance, 0:30:31.457,0:30:34.535 and you are free to use it. 0:30:34.535,0:30:37.146 So, however, although I love inheritance, 0:30:37.146,0:30:40.339 I use it in appropriate[br]ways, and it is not evil, 0:30:40.339,0:30:42.741 but sometimes we are.[br](laughter) 0:30:42.741,0:30:44.388 You might be. 0:30:44.388,0:30:46.196 And it's easy to get inheritance wrong, 0:30:46.196,0:30:50.227 and this tree has a little problem, 0:30:50.227,0:30:52.104 and it's this, I don't like this. 0:30:52.104,0:30:55.240 The public API of item is[br]quality of days remaining, 0:30:55.240,0:30:57.193 and the public API of[br]those four subclasses 0:30:57.193,0:30:59.291 contains one additional method tick. 0:30:59.291,0:31:01.906 And I think that superclass[br]ought to play the item role, 0:31:01.906,0:31:04.372 which means to me it's[br]got to implement tick. 0:31:04.372,0:31:06.515 And the question then becomes, 0:31:06.515,0:31:08.150 what is the appropriate implementation 0:31:08.150,0:31:10.819 of tick to put in the superclass? 0:31:10.819,0:31:13.352 You could define tick and[br]have it raise an error 0:31:13.352,0:31:15.494 that says subclasses[br]have to implement tick. 0:31:15.494,0:31:17.514 You could do that, I do that sometimes, 0:31:17.514,0:31:19.563 but here I think there's[br]a default implementation 0:31:19.563,0:31:23.746 that's appropriate, and it's this. 0:31:23.746,0:31:26.499 Do nothing. 0:31:26.499,0:31:29.352 It's perfectly OK with[br]me, tick to do nothing. 0:31:29.352,0:31:30.802 And now, I did that because the 0:31:30.802,0:31:32.372 inheritance heirarchy bothered me, 0:31:32.372,0:31:35.200 and I'm just removing code now. 0:31:35.200,0:31:37.700 Now that I've done that,[br]you might notice something 0:31:37.700,0:31:39.511 about Sulfuras' implementation of tick. 0:31:39.511,0:31:42.400 It overrides item, it subclasses item to 0:31:42.400,0:31:45.640 override tick to do exactly[br]what the superclass does. 0:31:45.640,0:31:50.104 And what that means is that here 0:31:50.104,0:31:54.933 it would be equally correct to say this, 0:31:54.933,0:31:59.496 which means that this[br]class is not necessary 0:31:59.496,0:32:01.673 and all the intermediate[br]complexity that I created 0:32:01.673,0:32:06.470 as I was following this[br]refactoring just went away. 0:32:06.470,0:32:09.671 There is no more Sulfuras class. 0:32:09.671,0:32:11.770 So, I'm going to do one last thing. 0:32:11.770,0:32:12.167 We're almost finished here. 0:32:12.167,0:32:14.126 So, this case statement contains 0:32:14.126,0:32:17.248 two different types of information. 0:32:17.248,0:32:20.886 It contains a set of[br]string to class mappings, 0:32:20.886,0:32:24.384 and it contains the[br]algorithm to hook them up. 0:32:24.384,0:32:26.392 And I contend to you that case statements 0:32:26.392,0:32:27.717 are meant for business logic, 0:32:27.717,0:32:30.387 and this doesn't really[br]feel like business logic. 0:32:30.387,0:32:33.123 This feels like configuration information. 0:32:33.123,0:32:37.361 And so, I'm just going to[br]extract configuration data here. 0:32:37.361,0:32:39.989 I'm going to make a hash,[br]and then I'm going to change 0:32:39.989,0:32:44.470 the algorithm to just be the[br]algorithm that uses that hash. 0:32:44.470,0:32:46.530 Now, in real life, this would probably go 0:32:46.530,0:32:48.645 through some transitions[br]where now the hash 0:32:48.645,0:32:51.154 can change independently of the algorithm 0:32:51.154,0:32:52.675 that matches these things up, 0:32:52.675,0:32:54.220 and if you find the hash changing a lot, 0:32:54.220,0:32:57.202 you might be tempted to[br]maybe make it a Yamo file, 0:32:57.202,0:32:58.634 and if you find the Yamo[br]file changing a lot, 0:32:58.634,0:33:01.830 you might be tempted[br]to put in the database. 0:33:01.830,0:33:03.140 Now I can vary that data independently of 0:33:03.140,0:33:07.360 this rule about how they[br]get hooked up together. 0:33:07.360,0:33:10.419 And so, that's it, that's[br]the whole refactoring. 0:33:10.419,0:33:12.522 We've got a bunch of small objects 0:33:12.522,0:33:14.200 now instead of small methods. 0:33:14.200,0:33:15.902 Here's the whole code. 0:33:15.902,0:33:18.545 In the Gilded Rose module,[br]there's an item class, 0:33:18.545,0:33:21.570 and then there's three item subclasses, 0:33:21.570,0:33:23.989 each of which contains a tick method. 0:33:23.989,0:33:26.499 There's a set of configuration information 0:33:26.499,0:33:28.759 that's used by this algorithm to decide 0:33:28.759,0:33:31.989 what item class is[br]appropriate for what string. 0:33:31.989,0:33:35.507 Here's the squint testable[br]version of small objects, 0:33:35.507,0:33:38.326 and this is it compared to[br]the original big conditional. 0:33:38.326,0:33:40.663 Now that's interesting that[br]in the small objects string, 0:33:40.663,0:33:42.277 it looks like it's nested[br]too deep, but it's not. 0:33:42.277,0:33:44.101 I just have the classes[br]inside the modules. 0:33:44.101,0:33:47.810 Right? So, that is only[br]really one level of indenting. 0:33:47.810,0:33:48.601 The more interesting comparison here is 0:33:48.601,0:33:51.730 the squint test between[br]the intermediate solution, 0:33:51.730,0:33:54.377 the small method solution,[br]and the small object solution. 0:33:54.377,0:33:56.789 Notice that small objects[br]is a little bit longer, 0:33:56.789,0:34:00.990 but the colors are clustered[br]more tightly together. 0:34:00.990,0:34:02.170 So we have really distilled the things 0:34:02.170,0:34:05.714 that change together in single places. 0:34:05.714,0:34:08.179 Here's the Flog scores[br]that we used to have. 0:34:08.179,0:34:11.400 So, OK, I have time to make you guess. 0:34:11.400,0:34:14.351 I made a bunch of small[br]objects...what's the Flog score? 0:34:14.351,0:34:18.951 Male:Well, 15. 0:34:18.951,0:34:20.775 Sandi:But you know what? OK, here. 0:34:20.775,0:34:23.827 What's in the intermediate,[br]we'll come back to that. 0:34:23.827,0:34:25.475 I like that 15 guess, that[br]was an excellent guess, 0:34:25.475,0:34:26.474 and you'll know why in a minute. 0:34:26.474,0:34:29.928 Here's the intermediate complexity scores. 0:34:29.928,0:34:30.755 Alright, so I've got this. 0:34:30.755,0:34:33.159 That 33 vastly overstates the complexity 0:34:33.159,0:34:36.830 of the final solution,[br]and it's because of this. 0:34:36.830,0:34:38.855 When you have the first[br][string] was one class, 0:34:38.855,0:34:40.510 the whole Gilded Rose class, 0:34:40.510,0:34:41.905 and you gotta kind of[br]know all about that class. 0:34:41.905,0:34:43.956 And the second solution[br]of the small methods 0:34:43.956,0:34:46.405 it was the Gilded Rose version two, right? 0:34:46.405,0:34:48.565 It was a single class, and[br]you gotta kind of know, 0:34:48.565,0:34:50.321 you've gotta hold that class in your head. 0:34:50.321,0:34:53.201 This third solution is a[br]bunch of small classes, 0:34:53.201,0:34:54.385 it's a bunch of different classes, 0:34:54.385,0:34:57.670 and you don't need to reason[br]about all of them at once. 0:34:57.670,0:34:59.130 As a matter of fact,[br]you really only need to 0:34:59.130,0:35:00.856 read the most complicated object in there, 0:35:00.856,0:35:02.629 and the most complicated[br]class is a backstage class 0:35:02.629,0:35:05.401 and it Flogs to 12, close to the 15, 0:35:05.401,0:35:07.212 and the average complexity of the set of 0:35:07.212,0:35:10.537 classes in that final solution is seven. 0:35:10.537,0:35:13.921 And so, I contend to you, the complexity 0:35:13.921,0:35:19.622 has fallen by 75% because[br]I made many small objects. 0:35:19.622,0:35:20.724 And so now I'm going to circle back around 0:35:20.724,0:35:23.350 to my task, implement Conjured. 0:35:23.350,0:35:30.343 Take a minute and imagine how to do it. 0:35:30.343,0:35:34.580 There's a code that[br]makes all the tests pass. 0:35:34.580,0:35:38.387 Here's how to use it. 0:35:38.387,0:35:41.242 And now we're done. 0:35:41.242,0:35:45.100 Alright, so, summary. 0:35:45.100,0:35:48.314 When you are new at[br]this, they told you DRY. 0:35:48.314,0:35:49.697 Right? Don't repeat yourself. 0:35:49.697,0:35:51.255 And I'm not saying it's bad, 0:35:51.255,0:35:53.170 and I'm not saying that[br]duplication is good, 0:35:53.170,0:35:54.442 but I'm telling you that if your choice 0:35:54.442,0:35:57.169 is between duplication[br]and the wrong abstraction, 0:35:57.169,0:35:58.886 you should choose duplication. 0:35:58.886,0:36:01.477 Trying to fix a problem by increasing 0:36:01.477,0:36:03.574 the complexity of the wrong abstraction 0:36:03.574,0:36:06.496 is like chasing a beach[br]ball in the outgoing tide. 0:36:06.496,0:36:08.295 Every time you take a stroke,[br]it recedes ahead of you, 0:36:08.295,0:36:10.548 and pretty soon, you're[br]out way over your head. 0:36:10.548,0:36:14.215 It's very hard to fix those problems. 0:36:14.215,0:36:16.200 Next, don't try to get to the future. 0:36:16.200,0:36:18.250 Open/closed, the right code that can 0:36:18.250,0:36:20.564 adapt to the future when it arrives. 0:36:20.564,0:36:22.645 New requirements, this[br]requirement to implement Conjured 0:36:22.645,0:36:26.152 was the impetus to make a change. 0:36:26.152,0:36:29.609 It gives you the information[br]you need about how 0:36:29.609,0:36:32.202 to make a choice about how[br]to rearrange your code now, 0:36:32.202,0:36:35.500 so that you can do the next thing. 0:36:35.500,0:36:38.712 Kent Beck has a wonderfully[br]succinct way to put this. 0:36:38.712,0:36:42.768 He says, "Make the change easy, 0:36:42.768,0:36:45.420 "and then make the easy change." 0:36:45.420,0:36:46.855 He actually put it a little bit longer. 0:36:46.855,0:36:50.761 He said, "Make the change[br]easy, this might be hard, 0:36:50.761,0:36:52.419 "and then make the easy change." 0:36:52.419,0:36:56.330 And so, we spent 99% of this[br]talk making the change easy, 0:36:56.330,0:37:00.326 and then it took one slide[br]to make the easy change. 0:37:00.326,0:37:02.524 At the core of this, at the[br]underpinnings of all this 0:37:02.524,0:37:04.545 is the idea of making small objects, 0:37:04.545,0:37:07.832 making objects that had[br]a single responsibility. 0:37:07.832,0:37:12.152 And finally, trust the principles[br]of object-oriented design. 0:37:12.152,0:37:14.678 They let you predict the consequences 0:37:14.678,0:37:17.630 of your code arrangement choices, 0:37:17.630,0:37:20.148 and learning something about[br]what those consequences are, 0:37:20.148,0:37:22.514 is going to let you raise your game. 0:37:22.514,0:37:25.306 Metrics are useful, but they're fallible, 0:37:25.306,0:37:26.952 but opinions are no more precise, 0:37:26.952,0:37:30.308 so use metrics to give you[br]another body of information 0:37:30.308,0:37:32.458 about how complicated your code is, 0:37:32.458,0:37:35.320 and then learn the rules[br]of object-oriented design 0:37:35.320,0:37:39.400 so that you can choose which[br]direction you want to go in. 0:37:39.400,0:37:43.130 Intermediate refactorings often[br]make code more complicated, 0:37:43.130,0:37:44.371 but if you know the rules, you can 0:37:44.371,0:37:46.919 trust yourself to work through complexity, 0:37:46.919,0:37:50.393 and finally reach more[br]open/closed code that's simpler, 0:37:50.393,0:37:53.604 and smaller, and that lets[br]you have straightforward, 0:37:53.604,0:37:56.945 changeable, beautiful code. 0:37:56.945,0:38:01.522 I'm Sandi Metz, I wrote this book, 0:38:01.522,0:38:04.565 I'm writing this book,[br](laughter) 0:38:04.565,0:38:06.780 It'll be in the slide deck. 0:38:06.780,0:38:07.173 I'm teaching in London. 0:38:07.173,0:38:09.310 There's a public course in[br]London coming up in June or July, 0:38:09.310,0:38:11.681 in case you're from over there. 0:38:11.681,0:38:13.921 Thanks to you all, and[br]thanks to Jim Weirich 0:38:13.921,0:38:15.541 who gave me this Kata. 0:38:15.541,0:38:26.890 (applause) 0:38:26.890,0:38:44.484 (jazzy music)