00:00:00.440
Good afternoon, Ancient City Ruby! How's everybody doing? Jim can hear me in the back, and I verified that this is viewable from where you’re sitting, Jim. Can you see it okay?
00:00:07.040
I can actually see it! Awesome, Jim can see it. I can hear you, and I'm excited!
00:00:13.519
So, this talk: how many people have seen my 'Refactoring from Good to Great' talk? Very cool! So, this is not that. I've given that talk a few times, and I'm quite fond of it.
00:00:22.240
However, I was forced to let it leave the house to create a new talk that I will now inflict upon you. The good news is that this is a brand new talk, so what I would like from you, even more than usual, is feedback.
00:00:36.120
This talk is not a lecture; it isn't even really a talk. This is pair programming. We’re going to look at some code, talk about some code, make some changes to it, and discuss those changes.
00:00:43.280
The point is not for me to just drop knowledge bombs on you, although I may drop a couple. The point is for us to have a dialogue, to have a conversation.
00:00:50.120
Because we’re pairing, you must follow a very important rule of pairing: if you don’t understand something, you must be aggressive about admitting it. Do not hesitate to say, "I don’t understand what you’re saying." Heckling is encouraged!
00:01:01.160
One of my metrics for a talk's success is how long it takes me to show code, so let’s get this up there.
00:01:07.720
By the way, I work at Thoughtbot in Boston. Has anyone listened to our podcast? Cool, we have a podcast you might like.
00:01:13.440
Alright, so take a look at this code. What's good about this code? The methods are short. Yes, what's that? It’s written in Vim!
00:01:21.120
Absolutely! That’s a damn good point. The best code is always written in Vim!
00:01:29.480
As you can see, the methods are short, and the class is short. It's only six lines. I’m using something called relative numbers, so as I move this around, the numbers change. My cursor is always on line zero.
00:01:50.040
Now, for a while, I would tell people that relative numbers aren’t good because they have one downside: if you’re pairing, you might say, "Change line five," and then we’d find ourselves counting down from five, four, three, two.
00:02:00.159
But actually, relative numbers are awesome, and I’ve now been convinced of their awesomeness. You’re going to see me forget this, so I’d like you to remind me; this is a new habit I'm trying to instill.
00:02:08.000
So, every time you see me go to visual mode, that's a signal: there’s a better way to do this!
00:02:14.080
Rather than going to visual mode to delete a method, I would rather say, "d2j" so I can see that two lines below is that end, because I have relative numbers.
00:02:22.000
Or "d3j" also works. The point is you can see how many lines away things are.
00:02:28.000
If I want to drop down to user.parent or to line nine, I could just say "9j" and go down there.
00:02:33.040
It’s a little faster. I paired with Joe Ferris, our CTO, the other day for the first time in a while, and he had switched to relative numbers.
00:02:42.000
He was doing stuff, and I realized I had been wrong all these years. Relative numbers is correct. I reverse my previous incorrect position, and I think everyone should try out relative numbers.
00:02:49.599
Just set relative numbers to one. If you don’t know how it works, do a little RTFM.
00:02:58.360
So, we talked about what's good about this code. What's not so good about this code?
00:03:04.839
The Law of Demeter. Raise your hand if you think it’s DeMeter. Raise your hand if you think it’s Deiter.
00:03:10.919
It’s good, right? People who are really into the etymology of words have told me it’s DeMeter.
00:03:19.760
So, I say I will say DeMeter if you tell me that a method takes two parameters, which no one is taking me up on.
00:03:27.360
Therefore, I’m probably going to say DeMeter, but sometimes I’ll say Deeter just so I can make sure to troll you.
00:03:37.120
A police officer is a Deeter; if we were in Europe, we'd say colomer.
00:03:44.320
That’d be a better local joke. So, yes, there’s a Law of Demeter violation on line zero.
00:03:51.840
It’s also on line negative four. I’m going to hit 8j to move up.
00:03:58.800
So, right here, is that a Law of Demeter violation? Let’s clarify. The Law of Demeter says you can call methods in your own class; that's fine.
00:04:04.920
You can call methods on your parameters. You can’t call methods on the return values of your parameters unless it's of the same type.
00:04:14.640
It's okay to call methods on your parameters. If we build things in our own class—if we build something ourselves, we can call methods on that as well.
00:04:22.360
So, line zero is not a Law of Demeter violation. This is, and it’s because user returns a company, which is then called.
00:04:30.480
Also, on line four, three, two, and one, there’s an even worse Law of Demeter violation.
00:04:37.360
Now, really quick, let me get my tests ready. I'll be running tests.
00:04:43.240
They look like this; they're fast because they’re not in Rails.
00:04:49.159
So how important is the Law of Demeter? The Law of Demeter is actually kind of important.
00:04:55.080
The reason it’s kind of important is because it’s about duplication. Almost every programmer knows about DRY, right?
00:05:04.120
They know you shouldn’t take something like the number of retries a user is allowed.
00:05:12.920
There should be a single authoritative source for the number of password retries you’re allowed or other similar pieces of data.
00:05:20.560
This is data duplication you want to avoid. There’s also other kinds of duplication.
00:05:27.920
Now, Demeter is concerned with structural duplication. The problem is that user presenter knows that user, when you call, returns something.
00:05:35.760
What I’d rather have is for user presenter to be more context-independent. I want it to take a parameter that I can call certain methods on.
00:05:43.440
That's a contract I’m okay with, but I don’t want to know about the next level down.
00:05:51.480
The problem is the structure of my app is now encoded in this class. This class is coupled to other pieces of my application.
00:06:01.600
Coupling is a real pain. Let’s define this real quick. Coupling is the degree to which components in a system rely on each other.
00:06:09.080
If component A has no coupling whatsoever to component B, no matter how much you change A, you will never break B.
00:06:16.960
If they are coupled at all, some changes you can make to A will break B.
00:06:23.600
This is sort of the source of almost all the heartache in programming. If everything were decoupled, you could always make local changes.
00:06:30.960
One of the hardest things is modifying a coupled system and understanding how those changes will ripple throughout the system.
00:06:38.160
Much of programming is about managing that concern. The Law of Demeter helps ensure that structural duplications do not leak into the system.
00:06:48.480
Some coupling is necessary. If everything in the system were totally decoupled, nothing could talk to each other.
00:06:54.520
That wouldn't make much sense. You could never build a system from small pieces and build it up.
00:07:01.440
Some coupling is necessary, but there are different kinds of coupling, and we want to aim for the lowest form.
00:07:07.519
I wrote a blog post about types of coupling; you can check it out. It’s on the Thoughtbot blog.
00:07:21.000
When I talk about the Law of Demeter, how many people follow the Law of Demeter all the time?
00:07:26.960
How many people follow it most of the time? How many people just heard about it today?
00:07:32.000
Awesome! That’s a great thing to know about. Most programmers say this about duplication.
00:07:39.760
They say, "Yeah, I usually don’t allow duplication," and then they have some sort of heuristic that’s often pulled from a blog post.
00:07:50.560
How many people have a similar heuristic? Something along those lines? Okay, here’s the problem with that.
00:07:57.680
I used to have the same thing, and then someone explained how it actually works to me, and I was suddenly like, "Oh, this makes a lot of sense."
00:08:06.840
How many people do code review? How many people do code review by a pull request on GitHub or by diffs in general?
00:08:12.560
The problem is, you can’t see duplication on a diff. If I copy and paste an entire class and change one line, then submit a pull request, you will see a bunch of green which looks nice.
00:08:22.480
"Hey, that looks great! Who wrote that?" You will say, "Yep, looks good to merge." The only way you'll find that duplication is if you go searching through the source tree.
00:08:29.120
In reality, just like the idea of saying, "Oh, I’ll go back and fix that later," that almost never happens.
00:08:38.520
Has anybody played Go, the game? It’s a really cool game with incredibly simple rules, and yet the complexity and beauty are incredible.
00:08:45.440
You should absolutely at least achieve beginner competence with Go. It’s such an amazing and fascinating game.
00:08:55.760
There’s a saying in Go that goes, "Beware of going back to fix up things." It implies that when you’re playing, you should just leave things in good shape.
00:09:07.559
You shouldn’t think, "Well, there’s trouble there, but I’ll come back to fix it later." You should follow that maxim in your code as well.
00:09:12.880
Don’t even duplicate once. It's so easy to miss the next duplication when you come back to it later.
00:09:17.080
The Law of Demeter is about duplication. If you follow it, you will avoid structural duplication. I suggest you follow it almost all the time.
00:09:26.880
If you can’t follow it, you should ask yourself why.
00:09:34.480
I noticed something interesting: when programmers are new, they care a lot about duplication because they’ve read about DRY.
00:09:41.440
As they gain experience, they develop a more nuanced view about duplication, which I think is a good thing.
00:09:47.119
Nuance is important; there are very few rules in programming that are absolute or things you should always do.
00:09:54.000
I think that when it comes to duplication, there isn’t anything like that, but I see that intermediate programmers often ignore it after they've gotten away with it a few times.
00:10:00.920
On the other hand, better programmers tend to start caring about it a lot more. I think this is very important.
00:10:09.920
Kent Beck has said he thinks he’s a decent programmer with excellent habits. Good code comes out of really good habits.
00:10:18.480
You don’t need to be a genius; you just need to be disciplined, and caring about duplication is part of that discipline.
00:10:23.520
So, I know some of you learned about Demeter today; some of you knew it before but maybe weren’t clear about it.
00:10:31.920
Don’t worry so much about the definition of Demeter; worry about the duplication.
00:10:38.600
Here are my tests for the same file.
00:10:45.040
So this first test is for a method that does not violate Demeter. Notice how it’s very flat.
00:10:56.960
We’ve got a user stub and a method stub on it—using ancient mock, by the way.
00:11:03.520
This test looks good to me. This test tests a method that violates Demeter.
00:11:08.840
Here’s your clue: we build a company and then we put that company in a different stub and pass it in.
00:11:15.680
That’s your clue! Even if you don’t know what Demeter is, when you find yourself reaching for nested stubs, that should send alarm bells ringing.
00:11:22.000
It should be a smell that you pay attention to. By the way, 'code smells' is a term worth knowing. A code smell is something that indicates there may be a problem.
00:11:29.520
However, that does not indicate that there is a problem. I sometimes note code smells and ignore them because sometimes the cure is worse than the disease.
00:11:37.680
Here’s a parent company name which is even worse. Predictably, the setup is even worse. Do you see how ugly this is getting?
00:11:45.080
This is your test talking to you. This is my test talking to me and saying, "Hey, you’re making an example of Law of Demeter violations."
00:11:52.000
By the way, this is not how you fix it. Stubbing does not fix the problem.
00:12:01.320
People like to say, 'Oh, stubs suck because they’re brittle.' When I change my code, I often have to change my stubs.
00:12:09.680
Part of that is people encoding the structure of their application into their stubs, which is exactly what’s happening here.
00:12:17.440
When I change the way that users and companies are associated, I might flip them around or make one optional.
00:12:25.440
Then, I have to come back and update these stubs because they’re ugly, and they’re encoding the content of the application.
00:12:33.040
Someone tweeted that we should add a 'law of Demeter' violator to this, which is pretty awesome.
00:12:40.800
Let’s look at another example of how not to fix this. A lot of people will say, 'This code looks much cleaner!'
00:12:52.000
If I’m looking at this screen, I’d say, 'Yeah, those tests are pretty awesome. Nice and flat!'
00:12:58.800
At Thoughtbot, we have a style guide that says do not prefer to use 'let' or 'subject'.
00:13:05.440
And there are a couple reasons for this. This test seems better at a superficial level within the body of the it blocks.
00:13:11.680
However, it still has the same duplication on top as those lines still encode the structure of the application.
00:13:19.440
They just make the rest of the test look a little better, but there are a couple problems here.
00:13:27.760
Here’s the first reason we don’t use 'let': they create something called a 'mystery guest'. Without looking, what is 'user'?
00:13:35.360
You don’t know! That’s a mystery guest! It’s an object that has shown up in our verification or exercise steps.
00:13:41.200
It was not created during the setup phase, so 'let' obscures that setup phase.
00:13:47.920
It makes it happen implicitly as part of this exercise step. So when I refer to 'user' here, it calls the 'let's' and does my setup implicitly.
00:13:54.640
I prefer my tests to look flat and have an explicit setup step.
00:14:02.160
The second problem is that these tests are going to be kind of fragile because of creating a complicated fixture for every step.
00:14:10.160
I imagine many of you have had the situation where you need to add one more test.
00:14:16.040
You say, "We just need a user that doesn’t have a company!" So, you start writing that, right?
00:14:23.760
You want it to return a default when it doesn’t have a company. You get here and think, 'Okay, what am I going to do?'
00:14:31.120
Well, user already has a company, so let me destroy the company. Right, that seems awesome, right? Who here likes slow tests?
00:14:37.760
Exactly! Because we defined the standard fixture, we’ve made it harder to add tests.
00:14:44.000
That fixture tends to be fragile; it's going to be slow. We’re going to have performance concerns; we’re building more data than we need.
00:14:53.680
These are very lightweight stubs, but a lot of times they are not.
00:15:02.120
There's another concept I’ve stumbled upon recently which I really like: the Open/Close Principle.
00:15:08.800
How many people have heard of the Open/Close Principle? Good!
00:15:15.200
So, have you heard of Bob Martin and his SOLID principles?
00:15:22.400
O is open to extension but closed for modification. What does that mean?
00:15:28.960
It means it should be possible to add new behaviors to a system without changing existing classes.
00:15:36.160
The primary way you can do that is by injecting dependencies.
00:15:43.680
If your class takes an outside dependency, you can write a new class that performs differently and feed that into the existing class.
00:15:50.960
That way, you get new behavior without changing the code in the existing class.
00:15:59.000
That’s a nice benefit, because every time you change a class, you might break it. We try our best, but sometimes we muck it up.
00:16:07.040
The Open/Close Principle says it’s better if you don’t have to change the class. It’s open to extension but closed for modification.
00:16:14.720
We don’t want to change the code; we’d rather add methods or inject dependencies.
00:16:20.880
I’d like if, once I’ve written a test, I never had to edit it again.
00:16:28.080
Part of my motivation for that is because it’s hard to ensure I still have good test coverage if I break 10 tests.
00:16:36.160
I can go through and fix them, and I will do it carefully, but it’s hard for me to verify if everything that used to be tested is still being tested.
00:16:42.640
To avoid these tricky situations, I want to have good habits.
00:16:49.440
This standard fixture approach violates the Open/Close Principle for tests.
00:16:56.720
It makes it really likely that I’m going to break existing tests when I need to edit these stubs.
00:17:03.520
As someone pointed out, we have a style guide at Thoughtbot talking about the general principles for how we implement things.
00:17:09.920
It says, "Don’t use 'let'." Then, can you show us an example of not using it? Absolutely! I would love to show you an example of not using that.
00:17:18.720
So, let’s go back to the tests that I prefer.
00:17:26.880
Here we go! This is an example of not using 'let'. Notice that each test builds up exactly what it needs inside itself.
00:17:35.520
These tests need fixing though—let’s address that issue.
00:17:43.000
The problem is that we're still encoding the values. Let’s fix the Law of Demeter violation and see what happens to the tests.
00:17:50.000
Okay, so we will come in here. For 'company name', rather than this, we’ll say, 'we’ve delegated that from user.'