When you go bugfixing, the quick, obvious change isn’t always the best one. And the code in front of you is never the whole story. To go beyond the easy fix, you have to know why certain decisions were made. You have to understand the history behind the code. And there are three great ways to learn what you need to know to confidently change code.

git blame

With the help of git blame, you can trace through every version of every line of code in a project, all the way back to when it was written.

For example, say you were looking at ActiveJob’s queue_name.rb file, and you wanted to know what this queue_name_delimiter attribute was all about:

activejob/lib/active_job/queue_name.rb
1
2
3
4
5
6
7
included do
  class_attribute :queue_name, instance_accessor: false
  class_attribute :queue_name_delimiter, instance_accessor: false

  self.queue_name = default_queue_name
  self.queue_name_delimiter = '_' # set default delimiter to '_'
end

You could run git blame on it:

1
2
3
4
5
6
7
8
$ git blame queue_name.rb

...
da6a86f8 lib/active_job/queue_name.rb           (Douwe Maan               2014-06-09 18:49:14 +0200 34)     included do
1e237b4e activejob/lib/active_job/queue_name.rb (Cristian Bica            2014-08-25 17:34:50 +0300 35)       class_attribute :queue_name, instance_accessor: false
11ab04b1 activejob/lib/active_job/queue_name.rb (Terry Meacham            2014-09-23 15:51:44 -0500 36)       class_attribute :queue_name_delimiter, instance_accessor: false
11ab04b1 activejob/lib/active_job/queue_name.rb (Terry Meacham            2014-09-23 15:51:44 -0500 37)
...

And for each line, in order, you’ll see:

  • The revision that changed that line most recently (11ab04b1, for example),
  • The name of the author of that commit,
  • And the date the change was made.

To learn more about that line of code, you’ll need the revision number. Pass the id (that 11ab04b1 part) to git show or git log:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git show 11ab04b1

commit 11ab04b11170253e96515c3ada6f2566b092533a
Author: Terry Meacham <zv1n.fire@gmail.com>
Date:   Tue Sep 23 15:51:44 2014 -0500

    Added queue_name_delimiter attribute.

    - Added ActiveJob::Base#queue_name_delimiter to allow for
      developers using ActiveJob to change the delimiter from the default
      ('_') to whatever else they may be using (e.g., '.', '-', ...).

    - Updated source guide to include a blurb about the delimiter.

diff --git a/activejob/lib/active_job/queue_name.rb b/activejob/lib/active_job/queue_name.rb
index d167617..6ee7142 100644
...

Cool! You get to learn a little more about the change, why it’s useful, and see the part of the Rails Guide about it that you might have missed before.

Here, we got pretty lucky. We found the information we were looking for right away. But git blame only shows you the most recent time that line changed. And sometimes, you won’t find what you’re looking for until you go two or three commits back.

To see earlier commits, you can call git blame again. But this time, pass the revision before the commit git blame found. (In git, you can say “the commit before this other commit” by putting a ^ after the revision, like 11ab04b1^):

1
2
3
4
5
6
7
8
9
10
$ git blame 11ab04b1^ queue_name.rb

...
da6a86f8 lib/active_job/queue_name.rb           (Douwe Maan               2014-06-09 18:49:14 +0200 33)     included do
1e237b4e activejob/lib/active_job/queue_name.rb (Cristian Bica            2014-08-25 17:34:50 +0300 34)       class_attribute :queue_name, instance_accessor: false
94ae25ec activejob/lib/active_job/queue_name.rb (Cristian Bica            2014-08-15 23:32:08 +0300 35)       self.queue_name = default_queue_name
...

$ git blame 1e237b4e^ queue_name.rb
... and so on ...

That’s pretty mind-numbing, though.

Instead, explore your text editor. Most editors make tracing through history with git blame easy. For example, in Emacs, after git blame-ing your code, place your cursor on a line. Then, you can press a to step back through each change that affected that line, and use l and D to see more detail about a commit.

Does your team refer to issue numbers and pull requests in your commit messages? If so, git blame can easily take you from a line of code, to a commit, to the discussion about that commit. And that discussion is where you’ll find all the really good stuff.

Github Issues

A little while ago, I noticed that Rails 4.2 removed respond_with. In the docs, it’s clear that it was removed, but I didn’t understand why.

There’s a ton of great knowledge hidden behind GitHub’s issue search box. If you want to know why a feature was removed, there’s no better place to learn than the discussion the team had while they decided to remove it.

So, if you search Rails’ GitHub repo for respond_with, you’ll find some interesting threads about respond_with. If you’re trying to find out why it was removed, you’ll probably land on this thread. Unfortunately, it describes how it was removed, but not why.

Later on in that thread, though, you’ll find a comment that points to the actual discussion about removing respond_with. That’s where the good stuff is!

As with git blame, you might not find exactly what you’re looking for right away. You’ll have to follow references, read comments, and click on links. But GitHub’s issue search will get you started in the right place. And with a little curiosity and a sense of exploration, you’ll learn what you came for.

Ask questions

Unfortunately, not all knowledge about a project can be found in its history, issues, and pull requests. Not everything is written down.

So if you can find the person that originally wrote the code, ask about it. You’ll discover the dev culture and ideas that led to a decision. You’ll learn some history about the project that might never have been recorded. And you’ll hear about paths that were never taken, which might actually make sense to try now.

The easy way can be dangerous

Sometimes, a fix just seems so easy. All you have to do is rescue this one exception in this one place, and then you can go home!

But it’s dangerous to change code you don’t understand.

So when a line of code seems off, or a decision seems weird, or a call seems useless, put on your archeologist’s hat. Learn as much as you can, however you can, about that code. That’s how you’ll make your code change intentionally, and fix the problem at its root.

Did you like this post? You should read these:

Finished another Rails tutorial and still don’t know how to start?

Have you slogged through the same guide three times and still can't retain enough to write apps on your own?

In my free 7-part course, you’ll discover the fastest way to learn and remember new Rails ideas, so you can use them when you need them. And you'll learn to use what you already know to build your own Rails project.



Comments