Thanks to the ridiculous amount of mathematics I’ve read, I have a relatively easy time thinking about computation in terms of functions which take a given input and transform it deterministically into an output. This is a sort of ‘noun-y’ thinking, in which you declare what things are, and use those declarations to get your work done.
I have less experience with computers than I do with math. So I have a harder time using the ‘verb-y’ thinking of imperative programming, where you tell the computer what to do, turning some state-before-the-command into a state-after-the-command. But part of my apprenticeship is learning to stretch myself to think in unfamiliar ways; and so, I am doing my current work in imperative, object-oriented terms, where data can change from moment to moment and no one uses friendly, familiar words like ‘endomorphism.’
I’ve been doing my assigned reading, and trying to think in terms of objects. Unfortunately, I picked up the wrong lesson for a few weeks. I kept reading how important classes were in organization of code, and how each class should be responsible for one thing. “Well,” I thought, “I better come up with a bunch of classes, then, so that I have well-organized code that’s easy to change.” So I’d go to the whiteboard and sketch some swim lanes with some plausible names for classes (to help me remember what each one’s responsibility was meant to be). I’d make a sketch or snap a photo, get back to my keyboard, and start crunching away.
(Readers familiar with object-oriented style probably see the problem already.)
I would like to tell you how this went wrong, but it’s like trying to come up with a sensible narrative of a car accident you just survived. I don’t really know what happened; everything would seem to be going fine, and then there would be a small problem, and I would think I knew how to fix it, and after a couple of hours all of my tests would be failing, or else my tests would be passing at the unit level and yet fail at the application level, and moving from commit to commit wouldn’t be helping, and everything would be non-determininistic and basically on fire. So I’d start over from scratch. Again.
I finally got my “A-ha!” moment by stepping away from the keyboard, and getting into some un-assigned reading from the company library, on unconventional programming paradigms.
Unconventional Programming Paradigms is a collection of papers presented at a 2004 workshop on the topic. I saw the title and had to grab it; I have a special fondness for people who insist on doing things differently than their peers, whether out of curiousity about untrodden research path, or just from pure contrarianism. The topics explored during this workshop included:
- Quantum information: Using process algebras to explore a possible computer language for the coming quantum computing age
- Chemical computing: The exploration of metaphors from chemistry to do computation, including reaction-diffusion processes (which have been studied by computer scientists all the way back to Alan Turing) and computing based on a simulation of reagent mixing, as though data and functions were particles floating about, randomly interacting, in a simulated fluid
- Amorphous computing: Computing using identically programmed agents, given a position in some physical or abstract data space, and given an ability to signal the results of their individual findings to their nearby peers. This reminded me a great deal of what I learned in The Social Amoebae: The Biology of Cellular Slime Molds. Slime molds are highly cooperative creatures, which sense gradients in their environments to trigger life-cycle transitions between an individualistic amoeba phase of feeding, to an animal-like ‘slug’ phase of foraging, to a fungus-like sporing phase of reproduction
- Bio-inspired computing: Looking to genetics, evolution, cell biology, and protein assembly for ideas in nanotechnology and information processing.
It was this last one that really caught my imagination. In particular, the paper on ‘Membrane Systems’ set me on a wild weekend research binge on the molecular dynamics of membranes and the variety of forms of tubulogenesis, i.e. tube formation, for a happy couple of hours. (I really know how to party.)
When I came back to my computing work on Monday, to get to work on yet another fresh start of object-oriented tic-tac-toe, I had biology on the brain. I thought to myself, Okay so, classes organize code. But organs are a relatively late invention! Remember: there were roughly a billion years of all life being unicellular before plants and animals showed up. Even if you’re just a bag of genetic information with very little structure, you can have a fulfilling life, eating tholins and splitting in two to reproduce, for a thousand million years.
So, I decided not to ‘develop organs’ — i.e., split my code into classes — until I saw a clear benefit to doing so. I still used TDD, but I used it on a single undifferentiated
TicTacToe class. I got as far as having tests and code for the board, the win/draw conditions, random computer moves, turn-taking, and a simple board display before I broke any code into a new class.
But my biological inspiration didn’t stop with delaying decisions about class organization. I also had visions of the variety of ways that organisms form tubes in my mind. So when I did finally start breaking code into a new class, I imagined the methods as genetic material that was being wrapped in a new membrane, like a bud forming from the parent cell before breaking loose. I kept running my test suite to make sure that everything was okay, hitting the undo button when a change broke a test. Bit by bit, I moved methods into the new class. I pretended that cell division was occurring, and that there was a shrinking, fragile tube between the two classes, represented in code by having my original class continue to delegate method calls to the daughter class. It wasn’t until I was confident my new class could be sent the messages directly, and my confidence resulted in passing tests, that I deleted the now-redundant methods. You can see evidence of this bio-inspired thinking in some of my commit messages:
1b6a6b3 * Bud movement choice to Player; put Display to console eee61dc * Line up referee/referee_io method chromosomes for transposing with Player
It would be a stretch to consider my simple tic-tac-toe program to have any real principles of artificial life. But thinking in terms of membranes, amoebae, organs, and tubes helped me evolve a design, rather than trying to go about designing intelligently at the beginning, when I was guaranteed to know the least amount about my code.