I’m John K. Paul
an engineering manager
and a speaker

found on

contact at

john@johnkpaul.com

about me

Often an engineering manager, with many more interests than that

Subscribe to the Monthly Newsletter

powered by TinyLetter

Git Precommit Hook Awesomeness

- - | Comments

What’s a precommit hook?

Precommit hooks are the most awesome and straightforward line of defense to add into your build system. They’re the earliest intervention we can use to make sure that bad code doesn’t make its way to production.

Precommit hooks are basically bash scripts that are run by the git executable before every single commit. This bash script can do whatever it needs to do to to verify that the commit is good, and should proceed. The script can exit with a non 0 exit code to signal to git that it shouldn’t allow the commit.

Here’s an example of a very basic pre-commit hook.

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

# run script to check if commit is valid
# you can run anything here, I happen to use a node script
node ./good-to-commit.js
RETVAL=$?

if [ $RETVAL -ne 0 ]
then
  exit 1
fi

If you put this into your .git/hooks/pre-commit file in your local cloned copy of a git repo, it will run every time that you commit. You can do whatever you’d like in good-to-commit.js. You can run a syntax validator, beautification validator, linter, all of your unit tests; it’s completely up to you and your team. The hard part is actually making sure that this precommit hook is installed on everyone’s machines.

Enforcing precommit hooks across your team

Git repos can’t actually include hooks inside when they are cloned. This would be a security issue because precommit hooks are run as the current user. We wouldn’t want someone to add rm -rf ~ in a precommit hook. I get around this in a very sneaky way, and when I say sneaky, I mean awesome.

Chances are, you’re working on a project that uses some build tool to handle common tasks. I am using grunt at the moment, but you can come up with equivalent methods with whatever tool that you use. The key idea is to use your build tools before-every-single-task hook to your advantage.

Using grunt, whenever any task is run, the entire Gruntfile.js is executed. In order to install precommit hooks for everyone who ever uses my project, I add this to the bottom of that file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//inside Gruntfile.js

grunt.registerTask('install-hook', function () {
  var fs = require('fs');

  // my precommit hook is inside the repo as /hooks/pre-commit
  // copy the hook file to the correct place in the .git directory
  grunt.file.copy('hooks/pre-commit', '.git/hooks/pre-commit');

  // chmod the file to readable and executable by all
  fs.chmodSync('.git/hooks/pre-commit', '755');
});

grunt.task.run('install-hook');

If you’re using rake or fabric, you can do very similar things. Every build tool will have a way to do it.

If you’re using npm and writing in node

If you’re using npm and node, you can do all of this sneaky hook registration in postinstall hook or use M. Chase Whittemore’s node-hooks project.

What you should do RIGHT NOW

I want you to go off and add precommit hooks to every project that you have. Let me know your experiences. I’ll talk to you in the comments and on twitter!

Break on Property Change of an Arbitrary Object

- - | Comments

Hold on to your hats, this debugger trick is awesome. If you’ve ever wondered how to figure out what is changing some property on some object behind your back, this is the way to do it.

Let’s say that you have an object in one part of your code that you’re working with.

1
2
3
4
5
6
  // /src/paging.js
  window.pagingData = {
    page: 3,
    perPage: 100,
    lastFetchedId: 1234
  };

And some other remote part of your code, that you had no idea existed, is modifying your object behind your back.

1
2
3
4
5
6
7
  // /src/path/youve/never/noticed.js

  // This is because I, the author, hate everyone

  setInterval(function(){
    window.pagingData.lastFetchedId = 42;
  }, 1000);

It’s straightforward to setup a watch in the Chrome debugger, so you could easily see that something was being changed, but the hard part is figuring out what piece of code is doing the changing. If you happen to sometimes live in a world with dozens and dozens of script tags on any given page, you’re pretty much SOL when it comes to grepping for the culprit.

This is where one very handy feature of ES5 comes in. ES5 defines many APIs in JavaScript that we use regularly, like Array.prototype.indexOf and JSON.parse, but it also has fancier pieces that like Object.defineProperty. Object.defineProperty allows you to setup accessors called get and set for any property on an object in such a way that any code that uses that property doesn’t have to know that a function is being run.

1
2
3
4
5
6
7
8
9
10
11
12
13
  (function(){
  var localLastFetchedId;

  Object.defineProperty(window.pagingData, 'lastFetchedId', {
    get: function(){
      return localLastFetchedId;
    },
    set: function(val){
      localLastFetchedId = val;
    }
  });

  }());

This code changes very little external behavior of the pagingData object. All it does is run these particular functions whenever pagingData.lastFetchedId is set to a new value or the value is being read. The exciting part is that now, you can add a breakpoint in your debugger inside of the set function that will then break whenever something sets that property.

Once you have this breakpoint, you can look through the callstack and you’ll be pointed directly at /src/path/youve/never/noticed.js.

If you want an even easier way to get that breakpoint in there, you can just add a debugger statement directly into your new debugging code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  (function(){
  var localLastFetchedId;

  Object.defineProperty(window.pagingData, 'lastFetchedId', {
    get: function(){
      return localLastFetchedId;
    },
    set: function(val){
      localLastFetchedId = val;
      debugger; // BOOM!
    }
  });

  }());

As always, make sure that you remove this kind of debugging code before you commit, and don’t let it into production. I hope you have questions. I’ll see you in the comments!

Chrome Debugger and Firebug Surprises

- - | Comments

The Chrome JavaScript debugger and Firebug are optimized beasts, but sometimes I get bit by one feature that I’m not expecting. It happens rarely enough that it always takes me a few seconds of WTF thinking before I remember. While debugging, if you try to use a variable from a closure scope in the console, that wasn’t actually used in the source, you’ll be surprised by ReferenceErrors like in:

This is because JavaScript debuggers optimize the hell out of your code and will remove variables from the Lexical Environment of a function if they are unused. See my previous post about hoisting for more information about the Lexical Environment. If you use these variables anywhere in your source, suddently they will be accessible again inside of the scope of the new function.

You don’t even have to actually cause any side effects in order to make sure they’re not removed. Just including the identifier in the source of the function will keep their values around.

Hopefully this will prevent some rare moments of JavaScript inadequacy that might strike when debugging. Don’t worry, it’s not you, it’s the debugger.