Monday, October 20, 2014

Why Macros Matter

Imagine you're a Senior Developer at Big Co and while reviewing Junior Programmer Jimmy's latest set of check-ins you see the following code repeated a handful of times:

  return '$' + 
         new BigDecimal(value).
          setScale(2, BigDecimal.ROUND_HALF_UP).
          toPlainString();

You pull Jimmy aside and explain that the above should really be packed into a function (or method) rather than being written out long hand. In other words, it should read:

  return Format.money(value);

You explain that by doing this Jimmy and the team will gain at least three benefits:

  1. Fewer Bugs. Not only is the function call above shorter, but there's no chance to accidentally forget part of it, or put an erroneous value in place (for example, pass 3 to setScale). And if there was a typo, such as Format.mony, you'd get a clear error message rather than just an oddly formatted value.
  2. Clearer Code. In the original version of the code, the reader has to think in terms of numeric and string operations. If the programmer wasn't familiar with BigDecimal, they might have to open up the docs to see how it's used. In the more compact form, the intention is clear: a value is being prepared for display to a human.
  3. Easier Maintenance. From a maintenance perspective, having the code wrapped up in a single location means that it can be fixed or improved upon with ease. Let's say negative values should be rendered with parenthesis around the value. Making this change to Format.money is trivial, do a find a replace throughout a massive code base, no so much.

Finally, you explain to Jimmy that if he ever finds himself copying and pasting code around alarm bells should sound in his head and he should make the appropriate abstraction.

As an aside, the above can be considered a procedural abstraction. Naturally, programmers love them (and for their sanity, need them!). So much so, in fact, that even if a language doesn't provide an official mechanism for creating procedural abstractions (assembly language perhaps? Old school BASIC?), a clever programmer will find a way to simulate them. Sure, this facility may depend on GOTO and global variables, and it may be fragile and error prone, but it will get the job done.

A few weeks later, Jimmy comes bursting into your office. He eagerly explains that he paid attention to what you suggested and has come across a abstraction that the team should adopt. If they do so, thousands of lines of code will be cleaned up. He goes to the whiteboard to explain. Rather than coding like so:

  private int foo;
  public int getFoo() {
    return foo;
  }
  public void setFoo(int _foo) {
    this.foo = _foo;
  }

The team should write:

  property(int, foo);

After all, he explains, you'll get the same 3 benefits as above, though on a larger scale because we use this pattern all over the place.

You're then left with the unfortunate task of explaining to Jimmy that while he's right, it's not so simple. Yes, they should create such an abstraction, but their language of choice (in this case, Java, Circa 2000) doesn't allow for this. That's because what's called for here is a syntatic abstraction rather than a procedural one. In fact, very few languages give you this capability.

Still, programmers are a clever bunch. Just like our Geek Forefathers and Foremothers who made do before reliable procedural abstraction, those lacking syntactic abstraction will find a way. In Java, for example, the above problem may be solved by using the Eclipse to generate the code. In PHP, you could simulate the above using property overloading. And when all else fails, you could run your source code through GNU m4. However, at the end of the day, these methods are all relatively fragile when compared to true syntactic abstractions.

And what language provides such a capability? Why, Scheme does, and the facility goes by the innocuous sounding name macros.

Learn Scheme. Learn Macros. Learn what you've been missing out on.

Thanks to Grant for helping motivate me to write this post.

2 comments:

  1. Even just /playing/ with macros lets you explore the mind-space where such abstractions may easily be realized, and it opens the door for elegant solutions whatever platform you are using.

    ReplyDelete