Write more manpages
Every program, library, framework, and application needs documentation of some sort; this much is uncontroversial. How much documentation, what kinds of documentation, and where to put that documentation are the questions that often elicit endless prognostication.
When it comes to documentation aimed at developers, there’s a spectrum. On one end, there’s zero documentation, only code. On the other end of the spectrum, are literate programs; the code is intertwined with the documentation and the language is equally geared towards marking up a document and translating ideas into machine executable code.
Somewhere along this spectrum exists a happy ideal for most programmers. Inline API docs ala JavaDoc, RDoc, and YARD have been popular for a while. Lately, tools like docco and rocco have raised enthusiasm for “semi-literate programming”. There’s also a lot of potential in projects exhaustively documenting themselves in their Cucumber features as vcr does.
All of these tools couple code with documentation, per the notion that putting them right next to each other makes it more likely documentation gets updated in sync with the code. The downside to this approach is that code gets ‘noised up’ with comments. Often this is a fair trade, but it occasionally makes navigating a file cumbersome.
It happens that Unix, in its age-old sage ways, has been storing its docs out-of-line with the relevant code for years. They’re called manpages, and they mostly don’t suck. Every C API on a modern Unix has a corresponding manpage that describes the relevant functions and structures, how to use it, and any bugs that may exist. They’re actually a pretty good source of info.
Scene change.
It so happens that Ryan Tomayko is a Unix afficionado and wrote a tool that is even better for writing manpages than the original Unix tooling. It’s called ronn, and it’s pretty rad; you write Markdown, and you get bonafide UNIX manpages plus manpage-styled HTML.
Perhaps this is a useful way to write programmer-focused docs. Keep docs out of the code, put it in manpages instead, push it to GitHub pages. Code stays focused, docs still look great.
I took John Nunemaker’s scam gem and put this idea to the test. Here’s what the manpage looks like, with the default styling provided by ronn:

Here’s the raw ronn document:
No Ruby files were harmed in the making of this documentation.
It took me about ninety minutes to put this together. Probably 33-50% of that time was simply tinkering with ronn and making sure I was writing in the style that is typical of manpages. So we’re talking about forty-five minutes to document a mixin with seven methods. For pretty good looking output and simple tooling, that’s a very modest investment.
The potential drawbacks are the same as any kind of documentation; it could fall out-of-sync with the production code. Really, I think this is more of a workflow issue. Ideally, every commit or merged branch is reviewed to make sure that relevant docs are updated. As a baseline, the release workflow for a project should include a step to make sure docs are up-to-date.
In short, I have one datapoint that tells me that ronn is a pretty great way to generate programmer-oriented documentation. I’ll keep tinkering with it and encourage other developers to do the same.
How to make a CIA spy, and other anecdotes
And the hilariously incompetent, such as the OSS operative whose cover was so far blown that when he dropped into his favorite restaurant, the band played “Boo! Boo! I’m a Spy.”
Interesting, new-to-me tidbits on what goes into making CIA spies, what they actually do in the field, and how the practitioners of spy craft have changed over the years. The bad news: spies recruitment doesn’t exactly work like in Spies Like Us. The good news: the CIA and its spying is closer to “just as bad/inept as you’d think” than “as diabolical as a James Bond villain”.
Own your development tools, and other cooking metaphors
Noel Rappin encourages all of us to use our development tools efficiently. If your editor or workflow aren’t working for you, get a new tool and learn to use it.
I’ve been working with another principle lately: minimize moving parts. I used to spend time setting up tools like autotest, guard, or spork. But it ended up that I spent too much time tweaking them or, even worse, figuring out exactly how they were working.
I’ve since adopted a much simpler workflow. Just a terminal, a text editor, and some scripts/functions/aliases/etc. for running the stuff I do all the time. I take note when I’m doing something repeatedly and figure out how I can automate it. Besides that, I don’t spend much time thinking about my tools. I spend time thinking about the problem in front of me. It makes a lot of sense, when you think about it.
I say you should “own” your tools and minimize moving parts because you should understand how they all work together and how they might change the behavior of your code. If you don’t own your tools in this way, you’ll end up wasting time debugging someone else’s code, i.e. a misbehaving tool. That’s just a waste of time; when you come across a tool that offends in this way, put aside a time block to fix it, or discard it outright.
Automated code goodness checking with cane
A few nights ago, I added Xavier Shay’s cane to Sifter. It was super simple, and cane runs surprisingly fast. Cane is designed to run as part of CI, but Sifter doesn’t really an actual CI box. Instead, I’ve added it to our preflight script that tells us whether deploying is a good idea or not, based on our spec suite. Now that preflight can tell us if we’ve regressed on code complexity or style as well. I’m pretty pumped about this setup.
Next step: add glib comments on failure. I’m thinking of something like “Yo, imma let you finish but the code you’re about to deploy is not that great.”
What kind of HTTP API is that?
An API Ontology: if you were curious about what the difference between an RPC, SOAP, REST, and Hypermedia API are, but were afraid to ask. In my opinion, this is not prescription; I don't think there's anything inherently wrong with using any of these, except SOAP. Sometimes an RPC or a simple GET is all you need.
On rolling one's own metrics kit
On instrumenting Rails, custom aggregators, bespoke dashboards, and reinventing the wheel; 37signals documents their own metrics infrastructure. They’re doing some cool things here:
- a StatsD fork that stores to Redis; for most people, this is way more sensible than the effort involved in installing Graphite, let alone maintaining it
- storing aggregated metrics to flat files; it’s super-tempting to overbuild this part, but if flat files work for you, run with it
- leaning on ActiveSupport notifications for instrumentation; I’ve tinkered with this a little and it’s awesome, I highly recommend it if you have the means
- building a custom reporting app on top of their metric data; anything is better than the Graphite reporting app
More like this, please.
One could take issue with them rolling this all on their own, rather than relying on existing services. If 37signals were a fresh new shop, one would have a point. Building out metrics infrastructure, even today with awesome tools like StatsD, can turn into an epic time sink. However, once you’ve been around for several years and thought enough about what you need to measure and act on your application, rolling your own metrics kit starts to make a lot of sense. It’s fun too!
Of course, the important part is they’re measuring things and operating based on evidence. Whether you roll your own metrics infrastructure or use something off the shelf like Librato or NewRelic, operating on hard data is the coolest thing of all.
Whither code review and pairing
Jesse Storimer has great thoughts on code review and pairing. You Should be Doing Formal Code Review:
Let’s face it, developers are often overly confident in their work, and telling them that something is done wrong can be taken as a personal attack. If you get used to letting other people look at, and critque, your code then disidentification becomes a necessity. This also goes vice versa, you need to be able to talk about the code of your peers without worrying about them taking your critiques as a personal attack. The goal here is to ensure that the best code possible makes it into your final release.
I struggle with this so much, on both the giving and receiving side. When I’m reviewing code, I find myself holding back so as not to come off as saying the other person’s code is awful and offensive. On the receiving side, I often get frustrated and feel like a huge impediment has been put in front of my ability to ship code. In reality, neither is the case. Whether I’m the reviewer or the reviewee, the other party is simply trying to get the best code possible into production.
Jesse has further great points: review helps you avoid shortcuts, encourages one to review their own code (my favorite), and it makes for better code.
More recently, Jesse’s pointed out that pairing isn’t necessarily a substitute for code review: “…pairing is heavyweight and rare. Code review is lightweight and always.”
In my experience, pairing is great for cornering a problem and figuring out what the path to the solution is. Pairing is great for bringing people into the fold of a new team or project. Review is great for enforcing team standards and identifying wholly missing functionality. Review is sometimes great for finding little bugs, as is pairing.
Neither pairing or code review is a silver bullet for better software, but when a team applies them well, really awesome things can happen.
Hip-hop for nerds: "Otis"
(Ed. Herein, I attempt to break down a current favorite of mine, “Otis” by Jay-Z and Kanye West, in terms familiar and interesting to nerds, specifically of the nerd and/or comedy persuasion.)
“Otis” is a song arranged and performed by two best pals, Jay-Z and Kanye West. It opens with a sample of Otis Redding (hence the title) singing “Try a little tenderness”. Opening with a sample like this tells us two things:
- Misters Z and West enjoy the music of Mr. Redding enough that they were compelled to include it in their own music.
- The gentlemen are also well connected and affluent, as not just everyone can afford to sample a legend like Redding in their music
A digression: sampling in hip-hop is one of its key characteristics and is of particular interest to nerds. It is a way that we can connect, through “nerding out” with the artist and find what it is that they respect and listen to. It is also a bit of a recursive structure; “Otis” samples Otis, Otis borrowed from gospel and blues, blues and gospel borrowed from traditional songs, etc. Finally, sampling is a recombinant form; in “Otis”, there is a verbatim sample in the opening bars, but the sample devolves to a looped-beat in the middle of the song and a mere sound-effect at the end of the song.
As Misters Z and West enter the song proper, the rappers trade verses about their affluence (“New watch alert, Hublot’s / Or the big face Rollie I got two of those”), the recursive (again, nerdy) deception they use to evade the papperazzi (“They ain’t see me ‘cuz I pulled up in my other Benz / Last week I was in my other other Benz”), a conflicting verse about how they would seek the paparazzi out (“Photo shoot fresh, looking like wealth / I’m ‘bout to call the paparazzi on myself”), more boasting of their affluence and skill (“Couture level flow, it’s never going on sale / Luxury rap, the Hermes of verses”), and such.
This song features a video, so we wouldn’t be properly doing a nerd dissection of it if we were to neglect that. It opens with our heroes approaching a Maybach sedan with a saw and a blow torch. Following a “car modification montage”, it appears the doors have been removed from the car and the front end of the car has been placed on the back, and vice versa. Another display of affluence, with perhaps a touch of hipster irony thrown in.
The video follows with various shots of our heroes rapping and driving the Maybach through an abandoned dock or airfield. Our heroes are in the front seat of the car and there are four models in the back seat, one seated precariously atop the one in the middle as our heroes make dangerous-looking manuvers in the car. At one point it appears they will lose a model through the door-less side of the car. At multiple points, it appears the boobs of the models might fight free of their loose fitting shirt. It should be noted that the appearance of a possible free boob could be considered quite progressive for a hip-hop music video.
The Maybach is, in my opinion, the most difficult to interpret signal the song and video send. Are we to understand that Misters Z and West are so affluent they can afford to put down six figures on the purchase and massively impractical modification of a high-end luxury car? Perhaps they had a spare one laying around and felt it would be a better use to destroy it than to leave it around. Or, perhaps this was a vehicle for a clever tax deduction?
Mr. West's CPA: You're going to owe a lot of tax on this purchase of your other-other Benz, 'Ye.
Mr. West: What if I were to use it in a music video for the purposes of promoting my upcoming album?
Mr. West's CPA: Well then you could depreciate it at 50% this year and 25% for the next two years, but you're still going to owe a lot.
Mr. West: If I were to take it to a chop shop and have them put the ass-end of the car on the front and turn the doors into wings, could I depreciate it faster?
Mr. West's CPA: throw some models in the back seat, and it *just might work*!
(Ed. as it turns out, the vehicle was to be auctioned and the proceeds donated to charity)
The other enigma of the video is the presence of comedian Aziz Ansari. Mr. Ansari has documented (Ed. hilariously) his friendship with Mr. West. Thus it is not shocking to see him appear in the video. He appears for only an instant, and his appearance marks the absence of the models in the rest of the video. Perhaps, we are to believe, Mr. Ansari is the pumpkin that the models turn into after some deadline has passed for Misters Z and West.
Despite, or perhaps because, of its mysteries, I find “Otis” is a fantastic piece of hip-hop production. The samples is well chosen and deconstructed, the verses are interesting (if mentally unchallenging), and the video is engaging to watch. I would easily rank it amongst the top songs of recent memory, were I one to make lists of top songs.
Stand on the shoulders of others' REST mistakes
Like all API design, putting a REST API on your app is tricky business that most people learn through lots of mistakes. So stand on the shoulders of other peoples mistakes! Thus, REST worst practices:
In the REST world, the resource is key, and it’s really tempting to simply look at a Django model and make a direct link between resources and models — one model, one resource. This fails, though, as soon as you need to provide any sort of aggregated resource, and it really fails with highly denormalized models. Think about a Superhero model: a single GET /heros/superman/ ought to return all his vital stats along with a list of related Power objects, a list of his related Friend objects, etc. So the data associated with a resource might actually come out of a bunch of models. Think select_related(), except arbitrary.
Mistaking the app’s internal model with what API users want to work with was the mistake I made on the first API I wrote.
Any big API is going to need to have dedicated servers that just serve API applications: the performance characteristics of large-scale APIs are so different from web apps in general that they almost always require separately-tuned servers.
This is how I prefer to roll my APIs lately. At the least, they should be a separate set of controllers. If you can extract a completely different application even better.
Represent dat API
Rails is missing an abstraction when it comes to building REST APIs, in my opinion. Requests route through controllers, controllers call models or services to obtain the right objects. And then…you awkwardly try to bang a JSON object together with an ERB template? It gets awkward quickly.
There’s a lot of experimentation in the wild attempting to figure out what works well here. You can bang out a bunch of presenter classes. You can describe and compose representations. You can go resource oriented.
I came across one yesterday that immediately caught my eye. You could just use lambda
to implement a bunch of functions that present, decorate, or map objects from one representation to another. To borrow an example:
# Define a base representation
UrlsPresenter = lambda do
{
'self' => "#{Gauges.api_url}/me",
'gauges' => "#{Gauges.api_url}/gauges",
'clients' => "#{Gauges.api_url}/clients",
}
end
# Compose the base representation with more data
UserPresenter = lambda do |user|
{
'id' => user.id,
'email' => user.email,
'name' => user.name,
'urls' => UrlsPresenter.call
}
end
# Pass an object to the presenter and convert it to JSON
UserPresenter[user].to_json
I love that this one adds no machinery and no state. Input, function, output. With just lambda
, you can describe a bunch of transformations and string them together into meaningful and interesting pipelines. I’m experimenting with this now, hoping to find an interesting way that functional programming approaches can make it simpler to build APIs with Rails.
When to Class.new
In response to Why metaprogram when you can program?, an astute reader asked for an example of when you would want to use Class.new
in Ruby. It’s a rarely needed method, but really fun when faced with a tasteful application. Herein, a couple ways I’ve used it and an example from the wild.
Dead-simple doubles
In my opinion, the most “wholly legitimate” frequent application of Class.new
is in test code. It’s a great tool for creating test doubles, fakes, stubs, and mocks without the weight of pulling in a framework. To wit:
TinyFake = Class.new do
def slow_operation
"SO FAST"
end
def critical_operation
@critical = true
end
def critical_called?
@critical
end
end
tiny_fake = TinyFake.new
tiny_fake.slow_operation
tiny_fake.critical_operation
tiny_fake.critical_called? == true
TinyFake
functions as a fake and as a mock. We can call a dummy implementation of slow_operation
without worrying about the snappiness of our suite. We can verify that a method was called in the verification section of our test method. Normally you would only do one of these things at a time, but this shows how easy it is to roll your own doubles, fakes, stubs, or mocks.
The thing I like about this approach over defining classes inside a test file or class is that it’s all scoped inside the method. We can assign the class to a local and keep the context for each test method small. This approach is also really great for testing mixins and parent classes; define a new class, add the desired functionality, and test to suit.
DSL internals
Rack and Resque are two examples of libraries that expose an API based largely on writing a class with a specific entry point. Rack middlewares are objects with a call
method that generates a response based on an environment hash and any other middlewares that are contained within the middleware. Resque expects the classes that work through enqueued jobs define a perform
method.
In practice, putting these methods in a class is the way to go. But, hypothetically, we are way too lazy to type class
/end
, or perhaps we want to wrap a bunch of standard instrumentation and logging around a simple chunk of code. In that case, we can write ourself a little shortcut:
module TinyDSL
def self.performer(&block)
c = Class.new
c.class_eval { define_method(:perform, block) }
c
end
end
Thingy = TinyDSL.performer { |*args| p args }
Thingy.new.perform("one", 2, :three)
This little DSL gives us a shortcut for defining classes that implement whatever contract is expected of performer
objects. From this humble beginning, we could mix in modules to add functionality around the performer
, or we could pass a parent class to Class.new
to make the generated class inherit from another class.
That leads us to the sort-of shortcoming of this particular application of Class.new
: if the unique function of performer
is to wrap a class around a method (for instance, as part of an API exported by another library), why not just subclass or mixin that functionality in the client application? This is the question you have to ask yourself when using Class.new
in this way and decide if the metaprogramming is pulling its weight.
How Class.new is used in Sinatra
Sinatra is a little language for writing web applications. The language specifies how HTTP requests are mapped to blocks of Ruby. Originally, you wrote your Sinatra applications like so:
get '/' { [200, {"Content-Type" => "text/plain"}, "Hello, world!"] }
Right before Sinatra 1.0, the team added a cleaner way to to build and compose applications as Ruby classes. It looks the same, except it happens inside the scope of a class instead of the global scope:
class SomeApp < Sinatra::Base
get '/' { [200, {"Content-Type" => "text/plain"}, "Hello, world!"] }
end
It turns out that the former is implemented in terms of the latter. When you use the old, global-level DSL, it creates a new class via Class.new(Sinatra::Base)
and then class_eval
s a block into it to define the routes. Short, clever, effective: the best sort of Class.new
.
So that’s how you might see Class.new
used in the wild. As with any metaprogramming or construct labeled “Advanced (!)”, the main thing to keep in mind, when you use it or when you set upon refactoring an existing usage, is whether it is pulling its conceptual weight. If there’s a simpler way to use it, do that instead.
But sometimes a nail is, in fact, a nail.
Four essential topics of 2011, in charts
The Year In 4 Charts: Planet Money does an excellent job collecting four economic charts (themselves chosen from three collections of best-of charts). I’m a dilettante as far as economics and economics go, but these charts do a great job of rolling up what seemed to have been the essential stories of the year.

A picture can nullify a thousand talking points, no?
Making a little musical thing
After software development, music is probably the thing I know the most about. My brain is full of history, trivia, and a modest bit of practical knowledge on how to read notation and make music come out. That said, I haven’t really practiced music in several years. I’ve been busy nerding out on other things, and I’ve grown a bit lazy. Too lazy to find people to play with, too lazy for scales, too lazy to even tune a stringed instrument. Very, very lazy.
Long story short, I’ve been wanting to get back into music lately, but I want to learn something new. Something entirely mysterious to me. Given my recent fascination with hip-hop, I’m eager to try my hand at making the beats that form the musical basis of the form.
There are a lot of priors to cover (tinkering with various sequencers, drum machines, and synthesizers; steeping myself in sample culture; listening to the actual music and understanding its history), but I just made a short, mediocre little beat and put it on the internet. Herein, I reflect on making that little musical thing:
- I’m sure that, if I get serious about this, I’ll need real software like Ableton or Logic. But for my tinkering, it turns out GarageBand is sufficient. The included software instruments aren’t amazing or even idiomatic samples (no TR808, no “Apache” break included), but with a little bit of tinkering, they produce results.
- Laying a drum track down that is little more than a fancy click track helps to get started. GarageBand has a handy feature where you can define the a number of bars as a loop and then record multiple takes, review them, and discard the takes you don’t want.
- What an app lacks in samples you can make up in effects. Throwing a heavy dose of echo and a ridiculous helping of reverb made an otherwise pedestrian drum track way more interesting.
- I didn’t go into this with anything in my head that I wanted to make real. For the drum track, I ended up with a pretty typical beat. A little quantization made it end up sound better and more interesting than it really is. This process, manual input with some computer-assisted tweaking, produced way better results than the iOS drum machines I’ve used in the past.
- Tapping out the bass-line took a little more time than the drums. I didn’t have anything “standard” in my head, so I doodled a bit. This is where the “takes” gizmo in GarageBand came in really handy. Record a bunch of things, decide which one is most interesting, clean it up a little, throw an effect or two on it to make it more interesting, on to the next track.
- In retrospect, lots of effects is maybe a crutch. I don’t have enough taste yet to tell.
- With the drums and bass down, it’s time to adorn the track with a melody or interesting hit for effect. I added one subtle thing, but couldn’t think of anything I liked that was worth making prominent. If I were actually trying to use this beat for something, I’d keep digging. But for my first or second beat, it’s not a big deal.
I wanted to jot down my thoughts because I’d like to write more about making and understanding music, but also because I keep meaning to write down what I find challenging and interesting as I start from a “beginner’s mind” in some craft or skill. And so I did.
You’re six hundred words into this thing now, so I’ll reward you, if we could call it a reward, with “An Beat”.
Crafting lightsabers, uptime the systems, a little Clojure
Herein, some great technical writings from the past week or two.
Crafting your editor lightsaber
Vim: revisited, on how to approach Vim and build your very own config from first principles. My personal take on editor/shell configurations is that its way better to have someone else maintain them. Find something like Janus or oh-my-zsh, tweak the things it includes to work for you, and get back to doing what you do. That said, I’m increasingly tempted to craft my own config, if only to promote the fullness and shine of my neck beard.
Uptime all the systems
Making the Netflix API More Resilient lays out the system of circuit breakers, dashboards, and automatons Netflix uses to proactively maintain API reliability in the face of external failures. Great ideas anyone maintaining a service that needs to stay online.
List All of the Riak Keys, on the trickiness of SELECT * FROM all_the_things
-style queries in Riak, or any distributed database, really. The short story is that these kinds of queries are impractical and not something you can do in production. The longer story is that there are ways to work around it with clever use of indexes and data structures. Make sure you check out the Riak Handbook from the same author.
A little bit of Clojure
Introducing Knockbox introduces a Clojure library for dealing with conflict resolution in data stored in distributed databases like Riak. If you’re working with any database that leaves you wondering what to do when two clients get in a race condition, these are the droids you’re looking for. I would have paid pretty good money to have known about this a few months ago.
Clojure’s Mini-languages is a great teaser on Clojure if, like me, you’ve tinkered with it before but are coming back to it. This is particularly useful if you’ve seen some Lisp or Scheme before, but are slightly confused by what’s going on with all the non-paren characters that appear in your typical Clojure program. Having taken a recent dive into the JVM ecosystem, I have to say there’s a lot to like in Clojure. If your brain understands static types but thinks better in dynamic types (mine does), give this a look.
I occasionally post links with shorter comments, if you’d like a slightly more-frequent dose of what you just read.
Quality in the inner loop
In software, this means that every piece of code and UI matters on its own, as it’s being crafted. Quality takes on more of a verb-like nature under this conception: to create quality is to care deeply about each bit of creation as it is added and to strive to improve one’s ability to translate that care into lasting skills and appreciable results.
When I wrote on “quality” a few months ago, I was thinking of it as an attribute one would use to describe the outer loop of a project. Do a bunch of work, locate areas that need more quality, but a few touches on those areas or note improvements for the next iteration, and ship it.
But what Brad is describing is putting quality into the inner loop. Work attains “the quality” as it is created, rather than as a secondary editing or review step. Little is done without considering its quality.
I’m extrapolating a bit from the letter of what Brad has written here, but that’s because I’ve been lucky enough to work with him. Indeed Brad’s work is of consistently high quality. Hopefully he’ll write more specifics about how quality code is created in the future (hint, Brad), and how much it relates to Christopher Alexander’s “quality without a name”.
Why metaprogram when you can program?
When I sought to learn Ruby, it was for three reasons. I’d heard of this cool thing called blocks, and that they had a lot of great use cases. I read there was this thing called metaprogramming and it was easier and more practical than learning Lisp. Plus, I knew several smart, nice people who were doing Ruby so it was probably a good thing to pay attention to. As it turns out, I will never go back to a language without the first and last. I can’t live without blocks, and I can’t live without smart, kind, fun people.
Metaprogramming requires a little more nuance. I understand metaprogramming well enough to get clever with it, and I understand it well enough to mostly understand what other people’s metaprogramming does. I still struggle with the nomenclature (eigenclass, metaclass, class Class?) and I often fall back to trial and error or brute-force tinkering to get things working.
On the other hand, I think I’ve come far enough that I can start to smell out when metaprogramming is done in good taste. See, every language has a feature that is terribly abused because it’s the cool, clever thing in the language: operator overloading in Scala, monadic everything in Haskell, XML in Java, and metaprogramming in Ruby.
Adam’s Handy Guide to Metaprogramming
This guide won’t teach you how to metaprogram, but it will teach you when to metaprogram.
I want you to think twice the next time you reach for the metaprogramming hammer. It’s a great tool for building developer-friendly APIs, little languages, and using code as data. But often, it’s a step too far. Normal, everyday programming will do you just fine.
There are two principles at work here.
Don’t metaprogram when you can just program
Exhaust all your all tricks before you reach for metaprogramming. Use Ruby’s mixins and method delegation to compose a class. Dip into your Gang of Four book and see if there isn’t a pattern that solves your problem.
Lots of metaprogramming is in support of callback-oriented programming. Think “before”/”after”/”around” hooks. You can do this by defining extension points in the public API for your class and mixing other modules into the class that implement logic around those public methods.
Another common form is configuring an object or framework. Think about things that declare models, connections, or queries. Use method chaining to build or configure an object that acts as a parameter list for another method or object.
Use the weakest form of metaprogramming possible
Once you’ve exhausted your patterns and static Ruby tricks, it’s time to play a game: how little metaprogramming can you do and get the job done?
Various forms of metaprogramming are weaker or stronger than others. The weaker ones are harder to screw up and less likely to require a deep understanding of Ruby. The stronger ones have trade-offs that require careful application and possibly need a lot of explanation to newcomers to your codebase.
Now, I will present to you a partial ordering of metaprogramming forms, in order of weak to strong. We can bicker on their specific placement, but I’m pretty certain that the first one is far better to use frequently than the last.
- Blocks - I hesitate to call this a form of metaprogramming. But, it is sometimes abused, and it is sometimes smart to use blocks instead of tricks further down this list. That said, if you find yourself needing more than one block parameter to a method, you should consider a parameter object that holds those blocks instead.
- Dynamic message send on a static object - You set a symbol on an object and later it will send that symbol as a method selector to an object that doesn’t change at runtime. This is weak because the only thing that varies is the method that gets called. On the other hand, you could have just used a block.
- Dynamic message send on a dynamic object - You set a symbol and a receiver object, at some point they are combined into a method call. This is stronger than the previous form because you’ve got two points of variability, which means two things to hunt down and two more things to hold in your brain.
Class.new
- I love this method so much. But, it’s a source of potential hurt when trying to understand a new piece of code. Classes magically poofing into existence at runtime makes code harder to read and navigate with simple tools. At the very least, have the civility to assign classes created this way to a constant so they feel like a normal class. Downsides, err, aside, I love this method so much, having it around is way better than not.define_method
- I like this method a lot too. Again, it’s way better to have it around than not. It’s got two modes of use, one gnarly and one not-so-bad. If you look at how its used in Rails, you’ll see a lot of instances where its passed a string of code, sometimes with interpolations inside said string. This is the gnarly form; unfortunately, it’s also faster on MRI and maybe other runtimes. There is another form, where you pass a block todefine_method
and the block becomes the body of the newly defined method. This one is far easier to read. Don’t even ask me the differences in how variables are bound in that block; Evan Phoenix and Wilson Bilkovich tried to explain it to me once and I just stared at them like a yokel.class_eval
- We’re getting into the big guns of metaprogramming now. The trick withclass_eval
is that its tricky to understand exactly which class (the metaclass or the class itself) the parameters toclass_eval
apply to. The upside is that’s mostly a write-time problem. It’s easy to look at code that usesclass_eval
and figure out what it intends to do. Just don’t put that stuff in front of me in an interview and expect me to tell you where the methods land without typing the damn thing into IRB.instance_eval
- Same tricks asclass_eval
. This may have simpler semantics, but I always find myself falling back to tinkering with IRB, your mileage may vary. The one really tricky thing you can do withinstance_eval
(and theclass <<some_obj
trick) is put methods on specific instances of an object. Another thing that’s better to have around than not, but always gives me pause when I see it or think I should use it.method_missing
- Behold, the easiest form of metaprogramming to grasp and thus the most widely abused. Don’t feel like typing out methods to delegate or want to build an API that’s easy to use but impossible to document?method_missing
that stuff! Builder objects are a legitimate use ofmethod_missing
. Everything else requires deep zen to justify. Remember: friends don’t let friends write objects that indiscriminately swallow messages.eval
- You almost certainly don’t need this; almost everything else is better off as a weaker form of metaprogramming. If I see this, I expect that you’re doing something really, really clever and therefore have a well-written justification and a note from your parents.
Bonus principle!
At some point you will accidentally type “meatprogram” instead of “metaprogram”. Cherish that moment!
It’s OK to write a few more lines of code if they’re simple, concise, and easy to test. Use delegation, decorators, adapters, etc. before you metaprogram. Exhaust your GoF tricks. Read up on SOLID principles and understand how they change how you program and give you much of the flexibility that metaprogramming provides without all the trickery. When you do resort to trickery, use the simplest trickery you can. Document it, test it, and have someone review it.
When it comes to metaprogramming, it’s not about how much of the language you use. It’s about what the next person to see the code whispers under their breath. Don’t let your present self make future enemies.