

Tips for maintainable metaprogramming - grandpa
http://philosophymademanifest.blogspot.com/2009/05/metaprogramming-still-need-programming.html

======
jerf
My tips:

All tips are subject to costs/benefits analysis, to be broken if necessary.
But don't underestimate the costs; it is very easy to do so when
metaprogramming. "Can anyone ever understand it again?" is a _big deal_. "How
does the debugger handle it?" and "Can I even get print statements/logging
into the critical places?" are also very big deals. "How long does it take a
newbie to come use the framework?" and "How long does it take for a newbie to
_understand the framework to the point they could modify it_?" are two
separate questions, and you should spend at least a bit of time thinking about
the latter one, even if it is not a primary design driver.

Metaprogramming should be additive; once some property is added to some
entity, it should generally not be modified or taken away. Some modification
forms may be acceptable, like the Decorator pattern, but those should be
carefully thought through. Think through naming _very_ carefully before
deploying, you will rapidly be stuck with the bad names.

There ought to be a simple path from unadorned program, through the
metaprogram, out to the final result. Metaprogramming should not be scattered
willy-nilly throughout the code, where if you call _this_ function with
_these_ params, suddenly all arrays grow an extra method, but otherwise they
don't. Another way of looking at this is that there should be a conceptual
"compilation" phase before any "real" code runs, where all metaprogramming has
taken effect. (It may not be literal; some things may only take effect on
module load, for instance, but if a module load is an atomic event and there's
no way to access it "before" the metaprogramming has done its thing, then it's
ok even if the module is loaded late at runtime.)

Metaprogramming construct use should be minimal. I work in Perl a lot, which
permits a surprising degree of hacking on the interpreter, such as with source
filters and the terrifying ability to take over the entire parse process
briefly. If you have to use this, OK, but at least try to avoid it first. Try
_hard_. Every construct you add by definition means it is that much harder for
the next person to understand how your metaprogram works, and by definition,
brings the semantics of your program that much further away from the base
semantics of the underlying language out into your own world. This further
means that A: the learning curve for your new language just went up and B: you
are now out on your own in language design, which is a notoriously tricky area
that really benefits from "many eyes". Don't underestimate the importance of
that last point! (In perl, so far, I usually manage to write things without
any source filter, and with only rare throwing subrefs into a symbol table
entry.)

In order to make some things easier, you must make some other thing harder (if
only relatively). Keep in mind the difference between "harder" and
"impossible"! If you are writing a glorious metaprogramming framework to make
it easy to handle querystring parameters, don't forget that people might still
legitimately need to access some parameter from multiple handler functions, or
legitimately need access to the original querystring. If you are writing a
glorious metaprogramming ORM, don't forget that I might need the full power of
SQL; does using your ORM mean giving up aggregation or (distressingly common)
joins? It doesn't have to be the common case, or the optimized case, but if
you make aggregate queries actually _impossible_ then I've got a problem. (How
could that happen? If you do something to the name of a column, and don't give
me access to the column mapping, then within the program I may not be able to
even write my own query. I can lose joins if your framework has excessively
strict ideas about controlling your tables and you don't let me put foreign
key refs in... or your framework breaks when they are there because it does
bad things!) A lot of frameworks I see make too much impossible, and a lot of
times it's just gratuitous, easily-fixed.

------
ramchip
For the author: this is possibly Opera-specific but I get this error when
opening the page: <philosophymademanifest.blogspot.com>

[Error: name: ReferenceError message: Statement on line 3: Undefined variable:
_gat Backtrace: Line 3 of inline#2 script in
[http://philosophymademanifest.blogspot.com/2009/05/metaprogr...](http://philosophymademanifest.blogspot.com/2009/05/metaprogramming-
still-need-programming.html) var pageTracker =
_gat._getTracker("UA-8120690-1");

]

