(pop music) (train horn) - I'm Sandi Metz and I am
the last but one speaker which means you've almost made it. (laughter) You get a break after this and then there's another keynote, If you stay for that. It's really bright up here, I'm gonna have to look at you some. So, yeah you've almost survived. Even those of you who are new have almost survived an entire railsconf, so I think we should all, let's do this, sponsors, pay the bills,
they do, we're glad. (claps) Thank 'em. But even more than that, human people organize this conference and if you see, this is your
job before you leave today, find someone in one of those red shirts and say "Thank you". Aight, let's thank 'em here. (claps) Thank 'em in person. Start my clock, I have about, I really do have about 40 minutes. I don't have 500 slides of code this year so (laughs) it's not gonna be that bad. Yeah, let's just go. So, I'm Sandi Metz, I'm
really happy to be here. And I haven't talked for you this year, this talk is about code smells. This is a term invented by this guy so, really, we did not plan
that I would follow Katrina but it's the perfect
talk to follow her talk. She just mentioned this guy's name, it's one of the last things she said. This is Kent Beck, this is Martin Fowler, he's
the man who wrote this book. Which is the book that teaches
us how to do refactoring. They collaborated together on
the third chapter of that book and that's why they want, it's like naming things wins, and the name code smells they wanted. And so the reason you know that term today is because of what these
guys did back in the 1990s. Now, I wrote a book a couple years ago, before that I wrote code for 35 years, I went to my desk
everyday and I wrote code. And now I don't do that, I teach, I teach classes in object oriented design. And in my class I have
occasion to ask people if they've heard of code smells, and just like I suspect all of you, everyone in my classes they always say, "Oh, yeah we know what code smells are." And then I ask them to
list five and no one can. Alright, okay I can hear you trying, but really most of you cannot. (laughs) I know that, okay. And so we all think we
know about this term but it doesn't mean I don't like your code and I can't tell you why (laughs) that is not what a code smell is. There is some opinion involved but really it's not just, it's not
just that I disagree with how you wrote your
code, the standard is higher, these smells, these 22 different smells all have very precise meanings. And the power, the magic, if you will, of this list is that
they've given things names. Once you give a complex idea a name, if we could all just learn
what that name stood for it means that we could talk to each other in a unambiguous way without
having miscommunications. And so, one of the things they talk about, very often when people
talk about code smells, they prefix code smell with the word bad. They say bad smells. As if, but really the
definition of a code smell is that it might indicate a problem not that it does, that it might. And so, you don't have an
obligation to filter out all the smells, it's actually
important that you not. And it's worth, it's also
worth getting through with code smells because
they have such great names. Okay, look at this list,
feature envy, that's cool. I like this one the one that
needs a code of conduct, inappropriate intimacy, shotgun surgery that's another favorite, okay. And so, the problem with this list, well, first of all, okay I'll confess, I had that book for a really
long time before I read it. I had a really hard time with it, right? It's one of those books,
it's like a recipe book and I've heard it described
as a cookbook for people, it would be like reading a
cookbook if you did not eat. (laughter) And so I really need the story arc and I had a very hard
time following along, like persisting with a bunch of recipes that were just like shrug,
shrug, shrug, shrug. Alright, but it turns out
it was really worthwhile when I finally did it and actually Katrina made me, Katrina made me. So, this, there's 22 things on this list, I had a stack overflow at 22. It turns out there's a guy named, whose name I can't pronounce Mantyla, it will be in the credits, he wrote a paper where he grouped them, we'll throw those two away, he grouped them in five
different categories. And through the magic of keynote, I can do that. This is the only reason we make talks, so we can use the effects. (laughter) And so here, let's just
talk about this set. Okay, this is a list of
things that just do not need to be that big. Long method and large class
are probably self-explanatory, data clumps is when you have
two or more pieces of data that always appear together, pass them around over
and over again together. Long parameter list is obvious, it might only occur once
but if it's long enough, there's probably an
object in there somewhere. And this thing, this other
wonderfully named thing called primitive obsession (laughs) we saw an example of that in
the talk Katrina just gave, this is when you have like,
an instance of a base class, like a string or a number
or a hash or an array and you pass it around
to a bunch of objects and they look at it and decide what to do based on something they know about it. So, you say "Oh, I've got
a number and it's six, "so I'll do thing x." Or "It's eight" or "I'll
do something else." Right, that's just it, if only the thing you got was smarter you could just send it messages so primitive obsession is
when the objects are too dumb that you're passing around. These things are groups in
a category called bloaters. They make code bigger than it needs to be in the places where you use 'em. The next group, this one, these are things that, these are ideas that are available in
object oriented programming, that you can misuse. Switch statements, you
know they're conditionals by, in normal people
talk, that's conditionals. Refused bequest is when
it's an inheritance problem, you have a sub class
that overrides a method that it inherits from a super class and like throws an exception and says "I don't implement that
thing, I refuse the bequest." Alternative classes with
different interfaces is pretty obvious. The other thing is temporary field, it's interesting that temporary
field is on this list, right, temporary fields
can be really handy but sometimes they mean that you should've made a method with that name, right? Why are you giving it a name? What is it about the
code that you have now that feels like it needs that name? And so these things are
all grouped in a category that he called tool abusers. I have a lot of bikes, I work on bikes, I have a garage full of bikes and I'm a amateur mechanic which means I have amateur tools which sometimes involves
a very short wrench, a long pipe, and a hammer. (laughs) Right, and I can tell you it
almost always turns out badly, if you abuse your tools. Alright, next, this group, this is stuff that makes change hard. So, divergent change, shotgun surgery, which we've talked about,
parallel inheritance hierarchies, which is pretty obvious,
sometimes you have a couple of hierarchies
that each have two sides and every time you change something you've gotta go add or move in
both sides of the hierarchy. These are the kind of things
that keep you from wanting to change code, or make
code hard to change. Now, notice that, almost
everything I'm talking about if nothing ever changes,
it's probably okay. Like, code that, really embarrassing code it's fine to keep really
embarrassing code, you should be brave about
your ugly embarrassing code. Because it is not costing you
money if it's not changing. And so just because the
smells exists, you know, sometimes you should like
own 'em, be proud, walk away. Don't let people make fun of
you about having bad code. This next, this next
category lazy class, (laughs) speculative generality,
okay on top of the effects, finding the pictures
is also fun, (laughter) classes that don't enough
is a lazy class, right? Doesn't justify it's existence. I'm gonna skip speculative
generality for a minute, data class, you know we're
object oriented programmers, classes oughta have data and behavior. Duplicated code is pretty obvious. Let me go back to speculative generality, I'm gonna ask you to raise your hands, who in here has ever written
some code for a feature you thought might arrive in the future? Keep your hands up for a minute, alright, I'm gonna out
myself with you here. Who in here has ever, after many months of working around that code, ripped it out and thrown it away? (laughs) Okay, we are bad guessers. And you know I love
object oriented design, it's a thing that really interests me, but this thing of speculative generality where we say "I'm gonna
do something really cool "in my code for some feature "that I think we might need later." This is why people say
bad things about OO, alright, this is what they blame us for, it's primarily things in that category. You have to be right so the
few times that you're right have to be really big wins
to outweigh the enormous cost of being wrong. Code is read many more
times than it is written. The cost that we, the
reason that we cost money is the time we spend reading code and if you add generality, you increase the level
of abstraction of code. Very often that means
adding levels of indirection which humans are terrible at and it means that every time
someone looks at that code it's harder to understand. So, we should really try
to restrain ourselves and not speculate about the future. When the new requirements come in they'll tell us how we
wish we'd written the code and we can do it then. Dispensables, sorry here,
ah see I did that thing with the clicker, dispensables,
you've all seen it now, okay, so we'll move on. So, the last category here is this group, feature envy, inappropriate intimacy, message chains, and middle man. Feature envy is when I have an object, Joe down here, Joe's an
object that I know about and I send him way more
messages than I send myself. Could be that I'm more
tightly coupled to Joe than I know, right? Inappropriate intimacy
would be if Joe had a bunch of private methods and I
reached in and got them, okay, that would be bad (laughter). I really (laughs) I
really am sort of pushing the code of conduct aren't I? Sorry, I hope no one was
made uncomfortable by that. Message chain is the logged enter, those violations, right? You got dots, you have you send a message to something you know about
and you get a response back and you send another message to that. If the types change
across those dot chains that's a message chain. Middle man is if you have an object that you send messages and
its sole purpose in life is to forward those
messages to somebody else. Maybe, you don't need that object. These things are called,
they're grouped together in a group called couplers because the effect of this is that it binds the objects together such that even if they're beautiful, even if you've tested them, even if they're little works of art, you can't ever reach in and get one out and use it in another context. They come as a bundle, all or nothing. And so there you go, 10
minutes and 34 seconds, everything you need to
know about code smells. Okay, but we're not done. (laughs) We're not done because now I'm
gonna talk about refactoring. But not very much 'cause you just heard a talk on refactoring. But there's a thing here
that people don't know. That those guys discovered in the 90s that I want you to go
away today understanding. And it's this, refactoring,
just like code smells have names and they mean very specific things, refactoring have names,
refactorings have names they're very specific and
they come with recipes. Not hand wavy recipes, very,
very specific concrete recipes. Here's one, this is page
149 of Martin Fowler's book and it looks like a recipe right? It has numbers down the side, there's little optional clauses here for situations that might
be different in your case. You notice that it
refers to other recipes. Here where the things
are in capital letters, that's another whole recipe by itself, it's recipes within
recipes within recipes. And so all of the refactorings
work in the same way, this is not something, we
don't just wave our hands and say go refactor. Refactoring has a very
specific definition, it's to rearrange code
without changing its behavior and all the ways in which
you can rearrange code are already written down with instructions by people who really
thought a lot about this. And so now you know that
code smells have names and they're real things and refactorings have names
and they're real things and they come with recipes, I can give you one last bit of news, every code smell maps to the
curative refactoring recipe. Ponder that for a minute, what does that mean? Here's a cheat sheet, this
one is provided by the guys at Industrial Logic. Notice on the top, the code
smell they're talking about is data clump, this is
a little tiny definition of data clump, that F 81
is a reference to page 81 in Martin Fowler's book. The three things on the bottom
are the refactoring recipes that are curative for that code smell. So this slide, I just blew
it up so you could see, I extracted it from this pdf,
which is a couple pages long, it cross references all the code smells and refactorings in Martin Fowler's book, the refactoring book and
also a book by another guy named Joshua Kerievsky called
Refactoring to Patterns. And so, it turns out that this is all you need to know, the problem is solved, you do not have to reinvent this wheel. (laughter) And so, it turns out if you just learned all you need to know is a few things. And many of you, at
least in my experience, the reason I wanted to give this talk is my experience from teaching is somehow I think a generation has passed since all these books were written and that people who are new to programming in the last 15 years, I'm
a woman of a certain age, you can tell, if you're
new in the last 15 years you may not have this information. I'm gonna show you some code, now. I'm gonna give you,
I'm gonna use the last, I don't know, we're gonna
spend about 15 or 20 minutes looking at code and I'll
show you the practical effect of recognizing code smells in your code and doing refactorings. My class sale is a subclass of persistence you can think that as active record. If you're in the back it will not hurt my feelings if you get
up and come forward. That's the font size of my code. (laughter) I didn't know I was gonna
be in the key note room it just happened. Okay, so we have that and
let's say I have my class foo, it has a sales total methods takes params and maybe this is control like thing or something that will control calls. It knows the name of the sale class and it knows some other things, right? It knows that sale understands where and it knows that thing that comes back is a response from sending an
aware message, it knows sum. It also knows two attributes
that are in the sale class and it knows the name of
date and the name of cost and it knows that the,
it can pass a date range as an argument to where
and the query will work. Okay, well, that's fine. And then someone else comes
in and does this, later, someone makes bar and
bar's a lot like sale but they want weekly totals, here, it takes params and you
only need a starting date to do this, so I can calculate
ending date, right here, and then there's another
thing here that knows where and sends sum to
the thing that comes back, it knows date and cost, takes date range. Then, later so this is like agile, right? People are taking stuff off the backlog this is what happens when
you don't have code ownership and don't have oversight, I love agile, I'm not saying agile is bad but I'm saying I see a lot of code that looks like this 'cause people solve the proximate problem and
no one has the big picture. So, here comes, oh yeah, of
course now I have expenses, if I have sales that's gonna happen. Now we've got baz and
there's expense total it takes params, does this, that looks a lot like the other stuff and then this method blows up. 'Cause someone passes
in a date, a bad date, a bad string for dates, kaboom. And so someone comes in here
they get that bud report and they come in here and they fix it. So now I got this code. Let's just stop a minute
and try to identify all of the ideas in this one
slide of very simple code. There's the idea that I can
calculate a week, I know that. There's the idea that dates might, they might be pass bad dates and I can set defaults. There's the notion that start
and end date go together as a group, always, when I need it. There's the idea that
I have, I know messages that I can send away to
sale and that other object. I know the name of that attribute and I know the name of this attribute. So I got all this stuff,
it's morphed up a lot in different ways here. And it's still not so bad, right? If nothing ever changes, I don't know, maybe you should walk away. But here's what happens in my life, this is when I go out on the wad I often, I spend time
at businesses very often that have been successful,
so that means they're five to six or seven years old and they have enormous
code bases that they hate. Right, that's why they call me, that's where I go. I mean, you can imagine, right? So if your code bases at home
feel big and embarrass you it's probably because your
business has been successful. It's just the way it is,
if we live long enough the chaos accumulates. And so here, what happens,
in these situations is after you have a foo and a bar
and a baz and someone comes and makes a Larry, Curly, and Moe. And they do kinda the same thing, right? And then, someone does
a fee and a fi and a foe and then your code looks like this. And eventually, through the
power of keynote, (laughter) you have duplication and
message chains and data clumps and you have to do shotgun surgery and if you get that long
something breaks in production and all the validation is
different in different places and all the defaults are
different in different places and you find yourself unable
to understand this code. It feels like the accumulation
of simple problems has created an overwhelming mess. And it feels like you need
to understand everything in order to fix anything and I can tell you from
personal experience that if you try to attack
all of the problem at once you will never finish, it is not possible to clean up the whole mess at one time. You can't tell 'em "Shut the doors, "we're gonna go a big
two month refactoring, "it will be fine." That goes over really well with the people that pay the bills. So what we need is a way to reach in here and somehow see, we need a
way to pull one problem out and fix it, in confidence
that it will work and that's where code smells come in. We're gonna do data clump,
we're gonna find a data clump and we're gonna fix it with extract class. It's gonna remove those three colors. Here's the data clump, this is behavior that goes with that data, this behavior does not
belong in bar and baz it belongs with whatever
object I should make here. And I'm gonna skip the, I'm gonna spare you the refactoring 'cause really you can look it up. And my name sucks, sorry. So, here's date range, takes two arguments and
those have set defaults, has two methods one that returns a range and one that returns a week rage. This is an object that
stands in for the data clump, I could use it in that place. And they way you use it is like this. So, in foo, I'm about to make
this method more complicated which is why people complain about OO, let's do it, okay? I'm gonna get an object,
temporary variable, I know that temporary
variable that's a code smell. And then I'll just plug it in right there. If you run flog on this it got worse. I introduced a whole new class and this method is longer. But watch this now, this one, okay, well I
don't need that anymore I can just do it, now I got this, and the other one, I
don't need that anymore, I can just do the same
thing, now I got this. And so, these three methods, there's the data clump, right there, the cool thing about data clumps is that if you take it, if you find the data
clump, you isolate them, you make objects for them,
the behavior will coalesce into the object, it's like a
Field of Dreams kind of thing, alright, if you build it, they will come. And what that means is that
you can use date ranges everywhere and get consistent
behavior throughout your apps, the weekly range, all the
validations work the same in every place, all the defaults work the same in every place, if you change it, the change goes everywhere. And everyone in your app knows to use this they would prefer to do this rather than to roll their
own in every situation. You guys have tons of
data clumps in your app, if the only thing you've
learned from this talk is to come and make objects out of them it's a big win, alright? But let's do more. There's a message chain here, oh I hate this message chain. I so hate it and I'm gonna
have to get back to my notes 'cause I wrote a lot of
things down about it. So, what, I see this everywhere, right? I am way out in my own
objects foo and bar and baz, and I have a message chain
that reaches into my persistent object and then send messages
to stuff it gives me back. It's okay for my class
to know things about sale but it is not okay for
my class to know things about things that sale knows about. And you know, it's really
hard, I find it hard to convince people about how bad this is. And I drew you two pictures, two completely different
pictures to try to express the same idea, here's the first one. This is about the message passing, so I got my guy foo, there's that sale thing over there, and I send where to sale and then sale inherits from persistence, the active record for you guys, you can fill that in, and so that message chases up the hierarchy chain and then, but behind
persistence is this whole big enormous cloud of code
that somebody else wrote and gave us for free. Right, we love them for
it but up in there somehow there's a list and there's
a bunch of other stuff there's all kinds of things
that happen back there. Eventually, somehow, persistence
sends some message on, I don't worry my pretty little head about what that message is. And then, some comes back,
I get this list back. It comes back to sale and
then it returns it back to foo and the next thing foo
does is send a message, alright, that's what the
message passing looks like. Now, I'm gonna show you this
picture in a different way, this is how I think of it, so
that's how I think about it when I'm thinking about messages. Here's how I think about it
when I think about testing. Trying to test foo, foo has collaborators,
it knows about date range and it knows about sale. These are the immediate things, I can put a ring around these objects. When I'm writing the unit test for foo, I have to get instances
of those collaborators and set them up in order
to make my test run. Alright, that's how I set
up different contexts. However, here in this
case, foo knows about that. Something that's not
a direct collaborator, it's the next ring out,
it's in the next circle. It's where the dot is,
every dot jump a ring, here. And so what I did, what's
happening here is I know about my collaborators' collaborators and if you do this, you
probably seen the effects of this in your code,
if you don't wanna run a database query here
you have to create, stub, you have to stub in
stubs, or mock in mocks. Or in any situation where
there's a message chain, sometimes you get in this situation where you're trying to set up a test and you have a million objects, right? You have instantiate a bunch of things, it's this kind of message
chain thing that's the problem. If you do that, you're
gonna hate yourself. And I'm gonna go a little
bit more into testing about this in a minute, but first, I'm gonna just
fix the message chain, it's really easy to fix this. So I got that problem,
all these things they look just about a like, the problem here is that there's a concept that doesn't have a name. That's what happened, I have a stupecation and there's an idea that underlies it and I haven't given it a name. Now, one of the things that
happens a lot of the times when you see this is that there's a method name with a repeating prefix or suffix. And when you see that, what you know, almost inevitably you have an object that's trying to get out. And so what this means is
that I can hide the delegate by putting a total method on sale. It's as simple as that, right? I'm gonna write my own method, you would probably use
a name scope for this. Alright, I'm gonna write my own method, I'm gonna put it on that class and then I'm just gonna
change this to synto and it's gonna happen on
expense, also, of course. So, once I'm done that
I end up with this code and there's no law of
demeter violation here, I don't have a message chain up there and so we fixed it here,
we've hidden the delegate. Now, I wanna talk a little bit, Justin Searls, who's somewhere, bless him, gave a talk a couple years
ago, I don't know how long, about how much reality you want your test. And I can recommend it to
you if you haven't seen it, it's a couple years old, now, he can probably tell us what year, 2013. Look up Searls and what's the name of it, he doesn't even, (background chatter) bludgeoning reality, okay. So, let's look about, let's look at a kind of test
you could write for this code, you could do, well okay, so I know, I'm sending total the sale, right? Foo is really my sale is
sort of part of the framework and sort of mine, right? It made a devil's
bargain when it inherited it off persistence, for the benefits it would get to pay the price of that dependency. Alright, I'm happy with that bargain. Here's a test I can new up a new foo, I can send a message, I can check the output that comes back. This runs the database query, I'm a long way from the database, foo is not a subclass of
active record of persistence but it still ran an entire
query at this point. And if you do this, in enough of your code some of you probably
already had the experience, I'm gonna look at your faces
and see if I can tell who, you've had the experience
of your test suite running more and more and more slowly as you get more and more and more
code and then finally, here's what happens, it falls down. If you can quit using, if you want to refactor, if you wanna do the kind of refactors that
Katrina was showing you, you must have unit tests that run quickly. And if you couple the unit
tests for these objects that are far away too, if you have a couple unit
tests for your objects to behavior that you
don't own that's far away that's very slow, you're
going to be unable to refactor with gree-se-wall at your back. And so it's really,
really, really important like we want your test reach to run but even more than that I
want them to run quickly. Okay, well let me just go on. I was about to diverge
from my presenter notes which is always a bad idea. So the problem here is
I'm glued to this class, I'm glued to sale, I know the name of this constant inside my method. And I could, instead, depend only on the name of
the message I want to send. I could do that by injecting a model. Now, I am not unaware of the dispute that we sometimes have about dependency injection. But I think it's great and I'm gonna try to convince you that you
should be using it more. If I do that, then I can now do this, I don't really think,
I'm not very attached to sale as a class anymore,
I don't really care, I think I'm talking to a totalisable and if I decide that I'm gonna do real OO and think of objects in terms
of the roles that they play instead of the class they are, what it means is that I'm very
comfortable with this idea of decoupling myself from constants and injecting player's roles. If I do that, I can make
another player of that role and it in my mind it is equally valid, it is just as good, all people, all things,
see I polymorphize, everything that influenced
this message is equally good, the same thing in my eyes, and so in this case what I can do, I'm just gonna clear a variable there and make that a little simpler, what I can do is get an
instance in that model and inject it in my test and then I have to assert that
the right answer comes back. This is fast, it's really fast. You know, what does it prove? I know people, many people
are uncomfortable with this so let's talk about what
it means to do this test. This test proves, that my
method, if it's injected with a totalisable, somebody
implements a total method, we'll call that method and
return the result it gets back that's what got proved here. What it does not prove is that
database cruising rails work. Okay, it does not do that. But let me ask you, the
rails framework has thorough and exhaustive tests for whether or not their database queries work. In addition, my sale class,
the sale class is a subclass of persistence, it may be
that I have a test on total over there that actually runs a query but it is not necessary
for foo to jump across this message chain and do database query, jump across the network
and do database queries at the other end. I see, when I travel
around slow running tests are killing people and I think the tests that I see are running
slow for two main problems. The first one is this message chaining if you have message chaining in your code if you commit demerol violations it means that you have to new up the whole network of objects and run all those messages when you run your test. And that's gonna be slow, it's gonna be hard to
understand and hard to maintain. So, you should hide the delegates, you should hide the message
chains with delegates. The next thing is even
after you've done it which we did here, it's possible that you are tightly coupled to something that's really slow. It's really slow and if
you tightly couple yourself to slow things and don't
give yourself a way to substitute other faster
players of those roles, you are doomed to slow tests. Now, I realize it is
possible, here to stub in sale, right, I could stub that method but, and it does work, but I prefer this and it's for, I have a reason it's not just that I
like this code better, it's that this makes you think of those objects as players of the role, not as instances of their class. I can use this totalisable
double any place in my test where I want, I could use it
over the expense test too, it's a really different,
it is not the same thing to inject this object
and break the coupling, stubbing in your test is not equivalent to injecting the object
and breaking the stubbing. This is a very much more powerful idea that will improve all of your code not just make that one test faster. So there's one more thing, let me see how we're doing
on time, we're doing great. Okay, so I'm gonna do
one more code refactoring before I finish. Once I'm done that, now, that I'm here I have
the duplication here, there's thing called pull up method, pull it up into the super class, I'm not gonna break open active record and monkey patch it with total, seems like a bad idea, doesn't it? But we can use a module, here. We can put that right there, and then, notice what I've done, the code that I've put in
the module does not look exactly like the code that I am promoting from the sub classes. I did, I added some indirection, I injected, this is just
like what I just did with model equals sale, in the last example. The things that I had concrete
dependencies on my class I am now injecting as
variables and setting defaults. This is so it's exactly
the same idea, right? This gives you flexibility
without adding much complexity, now, there's a name for this code smell, and it's called speculative
generality, right, I just did it and I know I admit it. But here's the thing, if
the methods are short, so that, what we want, the problem with speculative
generality is you're wrong and it costs you money
because it increases the complexity of code, in the mean time, when you try to read it. And I assert to you that at least for me, I know it's partly what you're used to, for me my methods are short and I routinely inject the dependencies. And so I do not find, I find that the increase in flexibility is, more than outweighs the
increase in complexity. This does not feel very
much more complex to me and it's way more useful. Now, anybody can call this method on a date, on any
attribute, and sum any value and so we would use a module. Okay, wait I just put that in this morning which is why I didn't
know it was in the slide. Dependency injection is awesome and you should be using it. So we can do that use the
module just like there, so there we go. And so that's it, if you're
not intimately familiar with code smells you can move yourself, if you're waiting to move up to that next level of programming, to make that transition
to being to the next level of proficiency, the way to
do it is to go on code smells and to learn those
recipes for refactoring. These ideas are not new, they've been around, that
book was written in the 1990s and I know that many of you here probably began programming since then, for some of you this book
is older than you are and so you might have a sense that it is (laughs) part from The Old
Testament of programming. (laughter) But it's a body of work that
is practical concrete advice about how to write code. And if you're unaware of
it you should go learn it. Many problems that we have, that feel insurmountable can be solved by purely mechanical operations. And the cool thing is it doesn't take the fun out of writing code, it's not like there's
nothing left for you to do. What it does is it
removes the tedium safely, so that you can concentrate
on the harder problems. So when you learn code smells
it's like putting on glasses, right, it turns that mess
into something like this. And following the smells lets
you make straight forward easy to understand objects,
that are easy to test and a pleasure to reuse. (laughter) Wait for it. (laughter) So, while you're learning code smells you should look at Reek, is Peter here? Maybe not, okay, this is,
notice the wonderful icon, is that cool or what? So Reek is a static analysis tool that you can run against your code that will tell you what
code smells you have. So you don't even need to
really go figure it out you can just run the damn
tool on your, (stutters) sorry, I have a policy
never to do that from stage, you can run this tool on your code and it will tell you what to go look at. So smells aren't a bad thing, they're actually great. And they're all over our code but you have to kind of lean in to them, like I okay, I have a new
puppy and if that were my puppy he would reach in and bite
off one of those petals and you should do it too. It's time to learn more about smells. They're not bad, they're just information. And many of, much of the
information is neutral. If you're trying to lose weight
maybe you should avoid pizza if you've been on a long bike
ride it's the best smell ever. So, when I look back at my old code, code I wrote three years or
four year or five years ago, it's really common for me
to look at the code and say "What fool wrote this?" It's a wonderful thing about our jobs, it's the very best thing. What job can you imagine having, can you imagine having a job
where you were no better today than you were five years ago. It's such a depressing thought. I love looking at my
old code and hating it, 'cause it means I'm better, it means I've learned something since then and what a wonderful thing that is. So, I started this talk a cup of coffee and I'm gonna end this
the same way, right? It's late I know you're tired probably not the best time to
go drink coffee, right now, but tomorrow morning when you get up, it's gonna be a great smell. Go learn the code smells
and level up your game. Thank you. (clapping) Oh stop it. Oh wait, I swear this book is
so close to being out of beta, I know that you've been
very patient with me but it really is coming, it's at the editor right now, it's going to be great. I have to say, writing is very, I find writing tortuous,
I'm to the point now where I'm really proud of it. So, you may want or may not enjoy it. (pop music) (train horn) (train horn)