Wednesday, February 27, 2008

Never Complain. Only Ever Code.

That way you can avoid idiots who think they're entitled to tell you their opinion on debuggers.

Learn from me. I learned this lesson the hard way - by listening to tons of people telling me their opinion on debuggers. By the law of averages alone I can guarantee for a fact that at least some of these people were idiots.

But blogging this was a mistake, or at least, blogging it with comments enabled was a mistake. Blogging mistakes are very easy to make. Avdi Grimm recently made a good point in a self-defeating way and pissed some people off in the process. But the people who are angry need to chill.

"Metaprogramming" is a new thing for many people, a shiny magic hammer that turns everything around it into a nail, and the results can be silly bugs. I've seen gems with "clever" uses of method_missing trap errors from utterly unrelated code; I've seen Rails evaluate any and all code in my .irbrc and had Jeremy Kemper from Rails core angrily telling me that this was not a bug. We do need to evolve norms like the Emacs system Avdi describes:

I look at the Emacs community as an inspiration. Emacs, as many of you probably know, is essentially just a lisp machine. Emacs Lisp, the language it is written in, is every bit as dynamic as Ruby. Functions can be replaced at any time, by code in any package. And because all Emacs Lisp code is intended to extend the Emacs editor, it is not uncommon for hundreds of different Emacs Lisp packages to be running in the same process, all coexisting and interacting. And yet, for the most part this melting pot of extensions all function together smoothly and without breakage.

Why? I think the biggest reason is community conventions. I’ve read a lot of ELisp code, and I have very rarely seen the equivalent of Ruby-style monkey patching. Even the advice mechanism, an AOP-like feature which enables functions to be dynamically wrapped and chained, somewhat like Rails’ alias_method_chain, is used sparingly. Instead, every mature Emacs extension exposes a plethora of “hooks”, extension points that other packages can attach their own handlers to. Other packages add their handlers to these hooks, and to hooks that the core Emacs code provides, and thus they cooperate largely without collisions.

Although it's dangerous to look at the Emacs community as inspiration, Ruby will obviously have to evolve some set of norms. Convention over configuration is also about conventions over confusion.

But what Avdi's saying is presented unwisely, as a complaint, and makes the first person to present any solution become the hero with the solution.

That hero is Pat Maddox.

There's a crazy idea out there that monkey-patching is bad. alias_method_chain is perhaps the worst offender. It allows you to easily decorate an object with behavior at runtime. The problem occurs when maintaining code that is all alias_method_chain'ed out - such as ActiveRecord::Base and the gazillion plugins that monkey patch it. It's tough to figure out what method you're actually aliasing away, and god help you if you rely on ordering.

Some may criticize, but I prefer to Do Cool Shit™.

Pat's solution is some cleverness around alias_method_chain and it's probably one of the only uses of "metaprogramming" you'll ever see which is truly meta. Pat runs alias_method_chain on alias_method_chain to introduce alias_method_chain logging.

Although this totally kicks ass, it's just a solution. It's not the solution. The solution will probably be some set of similar techniques - some group of different ways to Do Cool Shit™. This solution obviously deserves a place in that set of techniques, but since it only addresses one particular instance of the problem class Avdi identified, it only addresses that portion of the problem space. More techniques will arise over time. I guarantee it.

But for bloggers and programmers, the real moral of the story is: Always program first and blog second. Nobody will reward you, and the people who write the code that you correctly identified the need for will be like "booyah!" at you, even though in a sense it was really your idea. This puts everything on the wrong footing.

For instance, Pat's code uses globals. Any time a programmer brags about using globals, you know something fucked up is happening. Starting everything off with a complaint skews the whole conversation, and even the solutions end up tainted.

Also, poor blogging tactics can make you look like less of a programmer than you really are. For the record, Avdi contributed some wicked code to my Utility Belt gem recently which allows you to run Unix diff on any arbitrary pair of Ruby objects. (Wicked not in its complexity, but in the sheer lovely madness of the very idea.)

Never complain. Only ever code. Always program first and blog second.