How do you read code? Do you use your IDE to browse files? Likely you just waste time then. Main trick to read code fast is not read all the code.

There are 2 main ways I use to read less code.

First and most obvious way - search files for patterns. Plain old grep would do, but I highly prefer to use ag or ack as they are fine tuned for searching code.

Second way - use diffs in version control system (Git, Mercurial, Subversion, etc). We’ll get to it later as this deserves a blog post of it’s own.

So back to search. Let’s assume I’d like to explore use of some concept in code, e.g. notifications. I do simple search like this (-S stands for case-insensitive).

ag -S notification
26:- (void) enterBackgroundNotification: (NSNotification *) notification;

22:        [[NSNotificationCenter defaultCenter] addObserver: self
23:                                                 selector: @selector(enterBackgroundNotification:)
24:                                                     name: @"UIApplicationDidEnterBackgroundNotification"
32:    [[NSNotificationCenter defaultCenter] removeObserver:self];
35:- (void) enterBackgroundNotification: (NSNotification *) notification {

53:    [[NSNotificationCenter defaultCenter] addObserver: self
55:                                                 name: MPMoviePlayerPlaybackDidFinishNotification
60:    // TODO: Maybe remove notification here?
75:- (void) videoPlayerPlaybackDidFinish: (NSNotification *) notification {

Now I can easily notice that one subscribes to notifications using add Observer and removes subscription using removeObserver. So good idea to check if these calls match. Let’s highlight them.

ag "addObserver|removeObserver"

22:        [[NSNotificationCenter defaultCenter] addObserver: self
32:    [[NSNotificationCenter defaultCenter] removeObserver:self];

53:    [[NSNotificationCenter defaultCenter] addObserver: self

OOPS, looks like CXVideoViewController.m misses removeObserver call. Let’s show more context (-C 10 tells to show 10 lines around match, **/*Video* is used to restrict search to matching file list):

ag "addObserver|removeObserver" -C 10 **/*Video*
43-    // Movie playback is asynchronous, so this method returns immediately.
44-    [_player play];
47-- (void) viewWillAppear: (BOOL) animated {
48-    [super viewWillAppear: animated];
49-    self.navigationController.navigationBar.hidden = YES;
51-    [self playMovieAtURL: [_item viewVideoURL]];
53:    [[NSNotificationCenter defaultCenter] addObserver: self
54-                                             selector: @selector(videoPlayerPlaybackDidFinish:)
55-                                                 name: MPMoviePlayerPlaybackDidFinishNotification
56-                                               object: nil];
59-- (void) viewWillDisappear: (BOOL) animated {
60-    // TODO: Maybe remove notification here?
62-    [_player stop];

How sweet, we even have a TODO comment about notification.

And of course we can search for TODOs too:

9:// TODO: Better and configurable implementation, maybe use CocoaLumberjack

41:     // TODO: Item itself should either be copied or also synchronized

52:            // TODO: Maybe just update on timer, as it is additional problem to unregister callback

66:        // TODO: Why doesn't call super instead?

26:    // TODO: don't use Singleton
47:        // TODO: don't use Singleton
71:    /* TODO: Download All
101:/* TODO: Download All
192:// TODO: Refactor and use these, probably through some base table view controller

60:    // TODO: Maybe remove notification here?
69:    // TODO: Fix it

5:  s.homepage     = "http://TODO/WebToMobile"

Not that bad, I thought there would be more. ;)

Of course if your IDE is worth a dime, you’ll be able to do similar things inside IDE. Decent standalone code editors also usually provide similar functionality either built-in or as plugins.

However there are some nice features that IDEs usually don’t do:

  • search in code that isn’t configured as project in IDE (which is crucial as search is even more crucial for navigation in third-party code).
  • show context together with search results
  • easy filtering out unrelated files (using .gitignore or manually provided patterns)
  • ability to pipe search results further, e.g. save into file and work with them later

Some useful references:

  • grep - available almost on any system
  • ag - fast and takes .gitignore into account
  • ack - has easy filtering by programming language
  • git-grep - can travel in time if you use Git
  • ctags - pre-indexes symbols (useful for big projects)