The grep test - my personal experience
Possible you've read the grep test, particularly if you read Hacker News. The premise of "the grep test" is that if you write code that is not greppable, you fail "the grep test". Whether or not this is a good thing is a matter of debate, but here's my experience.
When I'm hacking in vim, if my cursor is over an identifier, I simply type <leader>f
('f'ind) and vim will find all instances of that identifier in my code base, present me with a list of file names and I type the number of the filename I want and jump straight to that identifier. This saves me a huge amount of time in debugging and understanding systems.
I used to work for a company where the developers seemed to take an almost perverse delight in writing obscure, difficult to follow code. I still remember the time I encountered this bizarre construct involving do
, and anonymous function declared and used on the fly, a cache in said function and, and, and ...
I replaced that code with something like require $_ for uniq values %hash
after spending a lot of time just trying to figure out the original intent. My code wasn't perfect, but it was a damned sight easier to read.
One day at said company I was struggling with some broken code (they had plenty) and there was a method I was trying to track down. In this case, I usually type <leader>gs
('g'oto 's'ub) and vim will take me straight to the sub declaration (or present a list of files with said declaration).
Not this time. But that's OK, there was numerous ways of declaring subs/methods, so I did the brute force <leader>f
to find all instances of that method and, to my astonishment, I was finding it all over the place, but nowhere did I find a declaration. I searched and searched and searched and probably waste two hours looking for a method declaration.
I finally found a list being iterated over where the method names were all generated dynamically. If this is infrequent, so be it, but in this company, writing obfuscated code seemed to be a hobby and I was frustrated. I spoke to the developer who wrote said code and I explained why code being "greppable" is such a good thing.
He blew me off pretty quickly with a "you must learn your code base" argument. I don't buy this argument because when you're delving into hundreds of thousands of lines of obfuscated, legacy code, you're going to learn the business rules, but not the code base. Further, much of that code was "silo"ed at that company and while we dug into one another's code from time to time, it was a long, painful experience made worse by "cleverness" (something which frustrates me).
Wasting hours looking for code where grep
fails me was normal at that company. Today, I freelance and while my rates aren't the highest out there, neither am I the lowest. I'm sure most companies who retain my services would be very unhappy learning that I'm spending hours looking for a single line of code that I could otherwise find in a couple of seconds using grep.
Amusingly, some of you may call me on my hypocrisy due to my blog post from yesterday! I showed the following code that I have in a production system:
foreach my $type (qw/sites persons/) {
foreach my $status (qw/new updated deleted/) {
has "num_${status}_$type" => (
traits => ['Counter'],
is => 'ro',
isa => 'Int',
default => 0,
handles => { "_inc_${status}_$type" => 'inc' },
documentation => "Number of $status $type",
);
}
}
Maybe I'm a hypocrite and wanting other people to write greppable code but I don't hold myself to the same standard?
What you didn't see in the code snipped I posted was the comment I had immediately over this declaration: it listed all of the generated method names. Further, the POD (which I will be writing on Monday) will also list them.
I'm not saying that you always have to write greppable code, but does the business really want people spending hours trying to find a simple method declaration or do they want those hours spent building features?
I've been doing that even in my own code for as long as i can think in Perl, for the sake of my own sanity. I cannot imagine the blindness of people who expect someone to understand other people's code without that single bit of politeness in it.
Even when you "know the codebase", there will come times where you want to find all invocants of a function/method. Especially when refactoring.
Like so many other things, keeping thing grep-able isn't a hard and fast rule. But dynamically generating method names/calls is certainly something to avoid when possible.
I assume you know that
will tell you exactly where a method was declared? Ah yes, Sub::Information, of course you do...
This doesn't help with finding calls, of course.
Hi Ovid,
would like to see another blog post showing your vim environment and mappings making your life with programming Perl easier.
Best regards McA
(This is where Smalltalk’s “it’s all a live image” approach has the upper hand: metaprogramming doesn’t hide things from you, because generated methods show up in the code browser just like any hand-written method would.)
But shouldn't you add some code to automatically revise the comments with the names of the routines that are being dynamically generated?
I actually do have some code up on the cpan that is automatically generated from a template at build time... I've been meaning to make the templating a little more usable, so thanks for the reminder. :)