Naming the Beast

I’ve been writing code for a command-line input buffer.

Seems a bit odd in this day and age, eh? OS X already has a command line implementation – several, in fact.

But this one’s for my home project, which is a curious combination of Web browser and command line tool.

Per the Windows port, this command line acts a little odd. You can move up and move down in the command history using the up and down arrow keys, but if you modify any of the previous commands, those changes don’t “take”. Only changes to the last command are remembered if you move up and down the history.

Oh, and the current command – the one you’re looking at on the screen at any particular moment – needs to be held in an external buffer controlled by the cross-platform engine.

I have an NSArray of all the previous commands, and logic to copy the proper entry in that array to the buffer if the user moves up and down through the command history, but that last command line makes things a bit more fiddly. If you move up, I have to remember the contents of it, even though I have to fill the external buffer with new contents. But I don’t want to add it to the history, because you haven’t pressed return yet.

I said “fiddly,” not hard. My particular solution was to add it to the history array anyway, for the benefits I get from reusing the code that copies from the array to the buffer. As soon as you move up, we enter this special “extra entry added” mode, which we leave again if you move all the way back down again, or hit return.

So I knew that whenever the current command index didn’t point to the very end, I was in my mode, but I found myself getting a little confused, not able to nail everything down, even though the code itself wasn’t very complex. I knew what I wanted, but the code didn’t look like what I wanted.

The solution (and the point of this long-winded entry) was all about naming. Instead of the logic looking like this:

if(mCurrentCommandIndex < [mCommands count])

I made it look like this:

if([self bufferTemporarilyAddedToCommands])

and exiting the mode, instead of looking like this:

[mCommands removeLastObject]

I changed to look like this:

[self removeBufferTemporarilyAddedToCommands]

Not rocket science, but it allowed me to see where the code was doing its job, and where it wasn’t, and make the appropriate corrections.

Oh, that, and unit tests.

P.S. Yes, I use PowerPlant-style variable prefixes in my Cocoa code. So sue me.

Form vs. Function

As I’ve said before, for my small home project, where the most interesting work lies at the intersection of AppKit and a cross-platform C++ engine, I can’t write code the “unit test” way – writing the tests first – because those intersections are precisely what can’t be isolated from the entire application.

But I have changed some habits.

Now, I move the little snippets of logic I’ve written from their organically-grown locations to separate stand-alone functions.

These functions are grouped by purpose in their own files, such as UTF8 Functions.c or Geometry Translation Functions.m.

Because they aren’t classes, they need all their context passed in as parameters. This can be a pain in the ass, but it also prevents me from grouping too much functionality together; it would be too tedious to add all the necessary parameters.

It also means that I can access the logic directly from unit tests. I can try out in isolation all the little variations I need to really ensure the code is sound.

This works well for a small, home project. Splitting functionality out into lots of additional files may work less well in large-scale endeavors, where there are already hundreds of files in a project.

Then again, in such huge projects, the data model may be elaborate enough that there are more classes that, without modification, can be tested in isolation from AppKit (or each other).