Starting in the Middle

When I start on a personal project, I'm bright-eyed and optimistic. I've got an idea in my head, and all I need to do is implement it. Wait, before I can begin working on the good stuff there are some foundational underpinnings that don't yet exist. I work on those for a while, then I get back to main task...until I again realize that there are other, lower-level libraries that I need to write first.

Now I'm worried, because I'm building all this stuff, but I'm no closer to seeing results. I charge ahead and write one-off routines and do whatever it takes to get a working version one-point-oh. Then I hear the creaks and groans of impending code collapse. I shift my focus to architecture and move things to separate modules, refactor, sweep out dark corners, and eventually I'm back to thinking about the real problem. It's only a short respite. As the code gets larger and more complex, I find myself having to wear my software engineering hat more and more of the time, and that's no fun.

That's the story sometimes, anyway. When using functional programming languages I take a different approach: I pick an interesting little bit that's right in the middle of the problem and start working on it. I don't build up a foundation needed to support the solution. I don't think about how it integrates into the whole. There's a huge win here that should be the selling point of functional programming: you can build large programs without worrying about architecture.

Okay, sure, that architecture dodge isn't entirely true, but it's dramatic enough that I'm surprised functional programming isn't the obvious choice for anyone writing "So you want to learn to program?" tutorials. Or at least that it isn't the focus of "Why Functional Programming is Great" essays. If nothing else, it's a more compelling hook than currying or type systems.

How can starting a project in the middle possibly work? By writing symbolic code that lets me put off as many design decisions as possible. If I'm writing the "move entity" function for a video game, the standard approach is to directly modify a structure or object representing that entity. It's much easier to return a description of the change, like {new_ypos, 76} or {new_color, red} . (Those are both Erlang tuples.) That avoids the whole issue of how to rebuild what may be a complex, nested data structure with a couple of new values.

If I want to multiply the matrices M and N, the result is {'*', M, N} . (This is another Erlang tuple. The single quotes around the asterisk mean that it's an atom--a symbol in Lisp or Scheme. Those quotes are only necessary if the atom isn't alphanumeric.) The function to transpose a matrix returns {transpose, M} .

It looks like the essential work is being dodged, but it depends what you're after. I can write code and see at a glance that it gives the right result. I can use those functions to create more interesting situations and learn about the problem. If I find my understanding of the problem is wrong, and I need to back up, that's okay. It's more than okay: it's great! Maybe it turns out that I don't need to multiply matrices after all, so I didn't waste time writing a multiply routine. Maybe the transpose function is always called with a parameter of {transpose, Something} , so the two transpositions cancel out and there's no need to do anything.

At some point I have to stop living this fantasy and do something useful with these abstract descriptions. Hopefully by that time my experiments in symbolic programming have better defined both the problem and the solution, and I won't need to spend as much time thinking about boring things like architecture.

(If you liked this, you might enjoy Living Inside Your Own Black Box.)

permalink October 24, 2011

previously