Friday, July 17, 2009

parameters suck

I'm learning Objective-C, and I've come to love the way you make method calls in that language. If you'd type this in Actionscript...

shapes.arrow( 0xFF0000, 0x00FF00 )

... you'd type something like this in Objective-C:

[shapes arrowWithStrokeColor: 0xFF0000 andFillColor: 0x00FF00 ]

Though they are more verbose, Objective-C method calls make the purpose of their arguments clear.

With code, it's more important to cater to the reader than to the writer (who may wish to save himself some keystrokes.) Code gets read many more times than it gets written. If verbosity is the price we have to pay for readable code, it's time to start digging into our wallets.

I don't want to read shapes.arrow( 0xFF0000, 0x00FF00 ). I can guess that the two hex values are colors, but I don't know which is the fill color and which is the stroke color. To find out, I have to search for the method definition, which is probably in a different file from the one I'm looking at. That slows me down and makes me think about file-navigation in my IDE, rather than about the meaning of the code.

Unfortunately, Actionscript doesn't give you an elegant solution to this problem, so most developers don't bother trying to solve it. But it's a serious problem, and there are ways to deal with it:

1) via comments:

// parameters: strokeColor, fillColor
shapes.arrow( 0xFF0000, 0x00FF00 )

This is a bad solution, because comments and the code they refer to can easily get out of sync. Say that you (or someone else) changes the definition of shapes.arrow() to...

public function arrow( fillColor : uint, strokeColor: uint ) : void { ... }

... but forgets to update the comment. It will now be an incorrect and misleading comment. This is an easy mistake to make, because the comment and the method definition are in different locations. You might make the update in one place and forget to make it in the other.

In general, I'm not a fan of comments. It's too easy to use them to explain messy code. It's much better to clean the code.

2) via descriptive-method names:

shapes.arrowWithStrokAndFillColor( 0xFF0000, 0x00FF00 )

This tends to stretch method names to the point that they get hard to read, and it get absurd if there are more than a couple of parameters:

shapes.arrowWithStrokeWidthAndStrokeColorAndFillColor( 1, 0xFF0000, 0x00FF00 );

However, in certain cases, when you refer to parameters in method names, it makes the code much easier to read. Compare...

find( name, names )

... with ...

findItemInList( name, names )

Of course, if you're using someone else's API, you don't have the luxury of naming their methods. In that case, I recommend...

3) via variables:

compare ...

shapes.arrow( 0xFF0000, 0x00FF00 )

... with ...

var strokeColor : uint = 0xFF0000;
var fillColor : uint = 0x00FF00;

shapes.arrow( fillCollor, strokeColor );

This is my favorite solution, because it uses code as commentary. Self-commenting code is always better than obscure code with comments.

Bottom line: when you find yourself typing something like move( object, 1, 5, false, [10,10] ), think about what you can do to make your code readable. You may not have written the move() function, but you did write the call to it. It's your responsibility to use whatever structures exist in your language to make that call clear.

No comments:

Post a Comment