When I was younger and had both the time to listen and the motivation to care, I would tune in to my local rock-oriented radio station to hear the weekly broadcast of the syndicated show, Rockline. In a nutshell, it was the place to hear interviews with popular bands and solo artists. Being a musician myself at the time, it was also a great source of amusement. Sometimes, it was the guests that provided the chuckles, but the real source of entertainment was unscripted. One of the staples of the program was the call-in segment. In the pre-“Beavis and Butthead” days, this was a fantastic opportunity to hear semi-stoned head-bangers in their natural environment. (And kept the producer’s finger on the bleep-button!)
While some of the questions were completely unpredictable (and often only loosely relevant), there was one question that reoccurred with such startling frequency and regularity that it would have inspired the Druids to build some sort of henge-like device. My friends and I would often make informal bets as to not “if” but “when” the question would be asked of the week’s guest. I will paraphrase this mystical incantation while doing my best to reflect the linguistic prowess of the typical queriant.
“Uh… hey guys. Coo’! I can’t believe… I’m like… really… like… talkin’ to ya! Coo’! You guys rock, maan! Yeah! OK… uh, my question is, uh… like… when you guys like… make your songs… ya know? Do you… uh… like… write the music first and then, uh… like… add some words? Or do you… like… you know… write the lyrics first and uh… then… kinda like… try to make some music that… you know… kinda fits the words? Yeah! So like… which one, maan? Right on… keep rockin’ guys! Yeah!”
I’m serious folks. Every single week. I was always waiting for a time when some sort of instrumental rock band would appear on the show just to see if someone would ask the same question.
Just as often, almost as if it was deterministic fate, the answer was usually within the margin of error of the following:
“It depends. Actually, most of the time it kinda happens together.”
(Imagine, for a moment, our starry-eyed rock acolyte, eyes fixated worshipfully on his radio placed carefully under the latest concert poster, murmuring to himself. “At… the… same… time… - Wow, dude. - At the same time! - Man… these guys ROCK!”)
Regular readers of my column are used to my somewhat meandering opening anecdotes. Trust me, I’m going somewhere here. Do not be afraid.
Not long before the days where I found myself listening to Rockline, I was in High School learning my first structured programming language. (It was Pascal… remember, I’m really old!) With that education I was introduced to the concept of “bottom up” vs. “top down” design. With that, of course, came the inevitable arguments as to which approach was better. I won’t attempt to mimic the nerd-speak that would have likely typified this exchange (but it probably included words like “typified”). The dichotomy of the concept generally could be reduced to
“Which do you write first: the main program loop or the low level functions?”
To be honest, it took me a while to openly accept the answer. Part of the delay may have been waiting until my peers and I got out of our teens and, therefore, beyond the argumentative impulses that are so endemic to that period of life. However, as my programming experience and subsequent prowess accumulated, I found myself more and more offering up the truism:
“It depends. Actually, most of the time it kinda happens together.”
Obviously, this is oversimplifying somewhat. There are times when one direction is more appropriate (or even necessary) than the others. Also, there have been times in my career when I seem to be actually approaching from both sides in the hopes of meeting in the middle someplace. More often than not, my path through some sections of code would actually resemble the typical left-to-right traversal of a tree structure. Start at the top and work your way all the way down one side to a leaf node, etc. Eventually, after covering a significant portion of the tree — both branches and leaves, you will make it back to the root node to say “I’m back! What’s next?” I think of that as more “program flow” ordering. But is that the “right” way?
Naturally, this thought process only works straight out of the gate. Eventually, due to additions, afterthoughts, redesigns and the inevitable re-factoring, we all end up bouncing all over the tree like a starling after too much Mountain Dew.
While I don’t know if anyone has ever titled it as such, there are some methodologies can actually be considered “inside out” &mdash the opposite of the “meet in the middle” approach. In AI, we often work on a mid-level concept of “behaviors”. The behaviors have low-level functions that support them and they can also then be strung together into more encompassing high-level functions. But is that the “right” way?
“It depends.
Actually, most of the time
it kinda happens together.”
There’s even another way of setting this question up. Rather than talking about different layers of functions and procedures, think about the how you handle member variables for a class. Let’s face it, while we all certainly try to create the base member variables on a new class right out of the gate, we often find ourselves revisiting the header file fairly often as the need arises. In all but the most minimal functions, it is usually unlikely that we have thought of everything we need. So, we find ourselves bouncing back and forth all over the place. Between wandering about between separate functional tiers of classes, up and down through inherited classes, back and forth between similar classes, and even toggling between a header and .cpp file, it seems like all resemblance to either “bottom up” or “top down” methodologies has been lost. But is that the “right” way?
Which, I suppose, is the question. While we can all hold religious arguments over where to put the braces on an if-then statement (even Steve McConnell, author of one of the seminal style manuals, Code Complete tries to avoid weighing in on this one), is there really a “right way” to approach writing our code? For that matter, is approaching AI structure and coding the same as any of the other more mundane programming disciplines or does the particular nature of our work set us apart somehow?
Or is it something that just simply isn’t definable? By even asking this question, am I running the risk of coming across like the aforementioned semi-braindead fanboy?
“Hey dude! Like, when.. you know… like… write your AI code? Do you like… write your game loop first and then your… you know… behavior code? Or do you… like… you know… write your sensory systems first and then… you know… put them like… I mean… you know… together into cool behaviors? Rock on, maan!”
(I know… I know… it depends! Tell me about it.)
I can't help but think of plant morphogenesis. I hate to use analogies, because they inevitably break down at some point, but the main point is how organic structures build themselves. Do they grow top-down or bottom-up? It takes only a little zen considerance to see that its both at once. The thing is, at the start of growth, top and bottom are essentially the same, embedded in a seedling, and they gradually grow further and further from each other. A program may similarly start as an entry point function, but will gradually branch out into various namespaces, functions, or whatever mechanism the particular language provides. When a leaf or branch first emerges, it will, similarly to the initial seedling, start out with a unified 'top' and 'bottom'. The cells continue to divide and the leaf starts to take shape.
I guess my point is that while top-down (holism) and bottom-up (reductionism) may be useful ways for humans to examine problems, they are essentially artificial ways to simplify the true nature of development, which happens basically everywhere at once.