Monday, April 27, 2009

Rethinking The C Word (clever)

A friend rightfully takes me to task:
The anti-cleverness you describe is anti-badness. I think we all can agree that bad is bad. But you and most of the other anti-clever crusaders have no definition for it other than it made your life miserable or you at least don't like it.

And then you assume someone you never met thought they were being smart. That's where your ice gets really thin. You weren't there and you don't know what the constraints were at the time.

And what really makes it irksome is that you have a whole library of well defined "bad code smells" which are a lot more specific. Why don't you use those? Those have meaning and in many cases they have remedies.

It comes across as smug blaming of the guy who left, and dirties what I've observed is an otherwise a healthy data driven approach.

See, I like it when my friends help me keep it honest and real. If one wants to improve, one must remain introspective and consider feedback when it is given. Desiring to be both wise and pleasant some day, I thank my friend for this rebuke.

I should not assume that someone is proud of the way this code turned out, or that they did it to satisfy their own ego. That is as at least as likely as not to be unfair and wrong... and smug.

I'd not heard of the Anti-Cleverness Crusade before. I feel less lonely in my smug, opinionated jerkitude. I thought it was just me, Wally, and occasionally UncleBob. I wonder if there are membership dues. Or tee shirts. I could use a tee shirt.

When David Tennant as Dr. Who says "clever", I know he means "ingenious." Ingenuity can be wonderful or it can be awful, or perhaps wonderfully awful. In the series, the enemy is generally "clever" in the sense of being "ingenious" and "diabolical."

A bit of research (*cough*google*cough*) and I find something that reflects the sense I'm hoping to convey. Rube Goldberg's self-operating napkin is certainly clever, and ingenious. From the article:
A Rube Goldberg machine or device is any exceedingly complex apparatus that performs a very simple task in a very indirect and convoluted way.
When I say "clever" I am referring to misspent ingenuity. It is intelligence gone wrong.

I don't know a good word that says "unwanted, wasteful, vulgar ingenuity". My friend Wally simply said "clever" with that clearly pejorative inflection. It stuck with me. I have carried it for some years, and have spread the use of the term. I'm sure Wally picked it up somewhere as well. Having some handle for the idea has been helpful. I can't tell you how many times I've rethought some bit of work because it might be (in this sense) "clever."

It is not merely "bad". If it were bad, the code would not function correctly. The NOT (A XOR B) is a small thing, and I figured it out with a short pause, so it's not opaque or indecipherable. It has only two operators (where one is sufficient, so 200% overdesign). It does the right thing provided A and B are booleans and implemented in the expected fashion. It *works*. That makes "badness" a difficult call.

The term fragile doesn't properly apply though the code invites misunderstanding. It doesn't depend upon conditions not algorithmically guaranteed in the code around it. It doesn't have a set of values within the domain of the parameters that will provide undefined behavior. It's wrong, just silly.

My issue with the !(A^B) code is that it is indirect and convoluted. One has to run the truth table in his head. Knowing that T^T is false, and F^F is false, and that T^F and F^T are true, and that the result of that operation is inverted so that T becomes F and F becomes T. So it is F if A^B is T, which is the set of cases when A and B are non-identical. Therefore, it is the value of not-not-(A==B). Needlessly convoluted, but approachable. A bit high-handed. It's hard to not see it as arrogant, though we will endeavor here.

The rest of the framework I have trouble with indirectness. You have repetition (violates DRY) but it's only near-duplication. Some of the code being for rendering, and some of it for compiling data from the database, and some is for both. It takes time to determine which is which. You have to dig into the code, or conduct code experiments to see what values end up where, and which 'names' are actually keys that must match in multiple dictionary structures for the code to run. You have to know which constructor parameters are ignored (some are) and in which circumstances. It is implicit, and indirect, and convoluted. And largely test-free.

It is possible that the original author was so intelligent that he/she needed no cues or clues to know which part did which thing nor why. Perhaps they could hold it in their heads without struggling, even across days or weeks. Perhaps the indirectness seemed to them to be ingenious, or maybe they were ashamed that they couldn't think of something simpler. Maybe they were scrambling to get something out the door (a sin in itself). Maybe they were used to working with code that was far less clear and direct.

My friend points out that the original author(s)' motives are lost to me, and that it is poor form to speculate and/or lay blame in the absence of such information. I accept that criticism with thanks.

Whatever the reason, the code requires that the readers make a noticeable investment for little reward. A better framework (hopefully whatever we're getting next) will be much more direct, obvious, and clear.

I am willing to lay aside "clever" and accept a better term. Perhaps "clever" was a needlessly clever term to use. I wonder what Wally would say.

Best Rube Goldberg Ever - Watch more Funny Videos