I was reading an article on "Lambda the Ultimate" about Bruce Mills's
book "A Theoretical Introduction to Programming," and in particular
about the difference between "menu-lookup" writing of glue code, and
"real programming", which the author defines as "to increase the
computational capacity, to begin with a set of operations, and develop
them into new operations that were not obviously implicit in the
This brought me to thinking about my evolution so far as a programmer,
which I can divide into the following phases.
- BASIC, Logo, arrogance, and incompetence: 1980
- Pascal and C: beginning to learn the depth of my ignorance: 1988
- Grokking the Basics of Functional Programming: 1993
- Learning How Magic and Beauty are Possible: 1993
- Getting Practical and Eclectic: 1995
- Getting a Job: 1996
- Joining a Startup: 2000
- Learning to Read: 2002
- Today: 2007
I'm not going to claim that everyone goes through the same phases, or
goes through them in the same order, but no doubt any programmer will
recognize some of their own history in what lies below. In each
phase, I failed to understand that it was merely a phase, and that my
knowledge was still limited --- that a few years later, I would be
able to do things I could only dream of at the moment.
BASIC, Logo, arrogance, and incompetence: about 8 years
This stage lasted from the time I got access my first computer (about
1980) until my Arthur Sittler explained recursion to me,
approximately, around 1988.
I learned Logo during this time, which was interesting, but I never
really made the connection with "real programming" in BASIC; I figured
that since my Logo procedures didn't have line numbers, they weren't
programs. I used recursion, but only tail-recursion; I remember one
of my early Logo programs looked like this:
I thought it was cool that I could define new commands in the
language, but I never made the connection that I could use GOSUB in
BASIC to do something similar, probably because the equivalent of
Logo's SQUARE 200 (calling a user-defined routine to draw a 200-pixel
square) would look like this:
1180 L = 200
1190 GOSUB 3200
and not like this:
1180 SQUARE 200
So I never made the connection, and I never wrote any interesting
BASIC programs during this time. I learned how to use the graphics
functions in TRS-80 Color Computer BASIC, so I wrote programs that did
all kinds of cool random graphics, but basically their control
structure was just loops within loops, so they couldn't do anything
* "Is that a real program or is that something somebody wrote?"
During this period, I was very interested in the outward appearance of
things. A hacker friend told me this story:
I had written a starfield screensaver, much like many other
screensavers of the time, and it was running on my Mac. A
co-worker walked by and saw the screensaver, and he asked me, "Is
that a real program, or is that something somebody wrote?"
This imaginary difference was something I was very concerned with ---
between a "real program" that I could invoke by typing "INVADERS" on
the command line, and "something somebody wrote" in BASIC, that I had
to invoke indirectly through MBASIC, which ran slowly.
I had the idea that "knowing how to program" was knowing the details
about all the programming interfaces I could use --- how to use the
PLAY statement to make music, how to use the RND function to generate
random numbers, and so on. I didn't understand that there was a kind
of programming knowledge that wasn't specific to a particular
language, although for a period of time, all the computers I came in
contact with ran BASIC, so I could usually figure out how to use them.
Looking back, I was pretty self-assured about knowing "a lot" about
computer programming, but also pretty insecure. Part of this was that
certain family members thought that I knew "a lot", and this
introduced an external-approval complication into the mix. This was
to the point that I failed to seek out people who knew more than I
did, and failed to understand why I hadn't, say, written any
interesting games. I did spend endless time reading books about
various microcomputer dialects of BASIC, and writing the same programs
over and over again.
I didn't really understand that the PLAY statement was really
implemented by other code, not so different from the BASIC code I
could read myself, rather than some kind of magic --- I didn't know
how to take it apart and see what was inside, I didn't know the
language it was written in, and it ran a lot faster than code I could
I still meet a lot of people who think that knowing how to program is
about knowing programming languages or the APIs of libraries or
"frameworks", and who are much more impressed with the quality of the
gradients an a program's UI than with its underlying functionality.
In effect, they think programming is just writing "glue code". These
beliefs amount to cognitive handicaps that prevent them from having
much success as "programmers", finding "programming" interesting, or
(so I hear) having successful work interactions with actual
programmers. Once, I thought that I had believed these things myself
because I was 6-12 years old, but apparently many adults have these
cognitive limitations too.
It isn't completely wrong, since of course learning APIs and languages
is a necessity for getting certain things done, and UI chrome affects
your mood every second you're interacting with the program. But
knowledge of APIs and language details is neither necessary nor
sufficient for "real programming"; nor is writing in a "fast
language". And it only takes a few hours to weeks (of constant work)
to become productive with a new language or a new API, while learning
to program takes decades.
The other thing that characterized this phase, for me, was a
fascination with things like graphics and sound. I observe that
generally these, together with continuous low-latency feedback from
gradually enhancing a working program, seem to be good "hooks" to get
people to start to learn to program.
This phase began to came to a close as Arthur Sittler introduced me to
Pascal, and showed me a Towers of Hanoi program with no line numbers
that fit in half a page and didn't need an interpreter to run --- but
didn't move any discs on the screen.
Pascal and C: beginning to learn the depth of my ignorance: about 4 years
This phase lasted from the time Arthur introduced me to the concept of
recursion, around 1988, until I read Robert Wilensky's "Lispcraft",
probably around 1993 or so.
I had earlier seen the Towers of Hanoi problem as a game, written in
BASIC, for an H89. You could play it interactively (trying to move
the stack of discs from one peg to another) or you could make the
computer solve it for you.
Arthur showed me recursive programs to solve the Towers of Hanoi
problem in Pascal and some other languages. They fit on one 80x24
screen. I had a hard time accepting them as programs at first, partly
due to the lack of line numbers, but he was persuasive. ("We don't
need line numbers any more. Line numbers were for when we dropped our
stack of stones on the floor on our way from the stone punch to the
stone reader, but we don't have that problem any more.") Also, the
resulting program could run without an interpreter.
I wonder what I would have thought of this OCaml version?
(* move n discs from a to z (using third peg named x) *)
let rec hanoi move n a z x = if n = 0 then () else
(hanoi move (n-1) a x z ; move n a z ; hanoi move (n-1) x z a)
let printmove disc a b = print_endline
("Move disc " ^ (string_of_int disc) ^ " from " ^ a ^ " to " ^ b) ;;
hanoi printmove 4 "peg A" "peg C" "peg B"
This was my first encounter with recursion as anything other than a
way to express iteration through tail-recursion, and also my first
encounter with compilers, with programs being stored in text files and
edited with a separate program, and with "real programming", in the
This began to show me that there was a big world of programming out
there that I didn't know about, and that it was accessible to me.
Unfortunately, I didn't have a copy of the Turbo Pascal Arthur was
using on my Z-100, and I didn't know how I would go about learning
Pascal anyway, so this was still a fairly theoretical realization.
A couple of years later, I took an independent-study computer
programming class at the Career Enrichment Center, where David Mains
and Greg Gurule began to confront the depths of my ignorance and
intransigence, and challenge me to do more --- to learn "real
programming". I struggled with Pascal, and with my ignorance and
insecurity, and with the level of self-direction needed in the
independent-study environment. (Perhaps many twelve-year-olds would
have the same problem.)
Still, I made substantial progress because of that class. I learned
Pascal, DEC VMS DCL, and some C, and I wrote my first interesting
programs --- a Pascal's Triangle generator and a one-dimensional
cellular automaton that generated a Sierpinski triangle --- and my
first useful programs, command-line utility programs written in DCL.
In retrospect, I didn't need teachers to teach me things; I needed
teachers to force me to get out of my comfort zone, and partners to
get me unstuck.
I still had far too much respect for my own skill at programming, and
it still impeded my learning. Although I could solve "fizzbuzz" level
problems, even toward the end of this time, I hardly ever wrote an
interesting program, and I would struggle for days with problems I can
solve now in an hour.
During this time, I also learned x86 assembler, although the only
program I wrote in it was a tiny Towers of Hanoi program.
Grokking the Basics of Functional Programming
Sometime around 1993, Arthur Sittler lent me "Lispcraft", which taught
me a completely different way of looking at programming problems --- I
began to understand recursion at last. But I didn't have a Lisp
system available to me, so I couldn't actually use the insights I got
from the book. Today, I don't need one; even if I were programming in
1980s MBASIC, I could use functional programming techniques to
structure the program. At the time, this was still beyond my
I still had the idea that skill at programming consisted primarily of
competence with a particular set of tools (languages and libraries),
rather than anything intrinsic.
Learning How Magic and Beauty are Possible
Also, sometime around 1993, I read Robert Sedgewick's textbook,
"Algorithms in C", which I borrowed from my father, Greg Sittler. It
opened a whole new world to me. The programs in the book are all
concise crystals of beauty, showing how a few lines of code can
transform a pile of structs of integers and pointers into a binary
search tree, or a hash table, or the minimal spanning tree of a set of
points. It used only the basics of C, and did not rely on any
This was a revelation to me; there was beauty and magic in these
programs, and it wasn't because they were calling on powerful
libraries hidden, Wizard-of-Oz-style, behind curtains. They were just
plain C code, and not very much of it, that "developed a set of
operations that were not obviously implicit in the original set," to
borrow Bruce Mills's phrase.
So I began learning about algorithms and data structures and big-O
notation and so on. It was a mathematical side to programming that I
hadn't even suspected of existing.
"Algorithms in C" taught me by example about the miracle of Turing,
which is sort of a computational analogue of Archimedes' boast, "Give
me a fixed point on which to stand, and I will move the Earth."
Turing's miracle is that given a computational substrate, even one
without much in the way of built-in features, you can still build a
program that does anything. (If you have enough space.)
I didn't write a lot of useful software during this time period,
because I became obsessed with writing code that was as beautiful and
spare as Sedgewick's example code in the book. Sadly, code that
touches the real world of existing libraries and hardware is never
that beautiful, so I didn't get a lot written.
I can think of a couple of things I pondered for days during this
time, trying to get the object models right, that I hacked out in a
few minutes to a few hours more recently --- a program for plotting
curves of Lamé and a program for 3D modeling of toruses.
Getting Practical and Eclectic
Around 1995, two revelations befell me, both from Matt Hudson.
First, he wrote a Perl program called "eyefun.pl" (unless that was
Brendan Conoboy, which is possible), which opened a bunch of "xeyes"
windows in random places on your screen. Reading this program (and
then the perl4 man page) was how I learned Perl, and thereafter I
wrote a lot of little programs in Perl --- much quicker instant
gratification than in C, and I didn't feel the same urge to equal
Sedgewick's C in beauty --- obviously impossible in Perl4.
Second, he recommended that I read Steve McConnell's "Code Complete",
which he said changed the way he thought about programming. It
changed the way I thought about programing too --- it's a book two
inches thick of explanations about the practical aspects of
programming, from the point of view of someone who spent a lot of time
programming at Microsoft. Previously, all the books I'd read and all
the (few) classes I'd taken took a fairly doctrinaire attitude about
what you should and shouldn't do, essentially because they were aimed
at complete novices, and in many cases were written by novices as
well; "Code Complete" talks about each of the various doctrinaire
points of view with a fair summary of the pluses and minuses of each.
Essentially, "Code Complete" gave me a dose of practicality and
just-get-down-to-it-ism that helped to counteract the worse effects of
Sedgewick and Wilensky's books --- without leading me to dismiss their
I also talked with Arthur some more, and he pointed out that I still
needed some more theoretical grounding. I asked him for
recommendations, and as a result, I ended up reading maybe five
thousand pages of computer-science textbooks of various kinds during
late 1995 --- the Dragon Book being the one I remember best, although
various books about APL were pretty interesting too. I learned a lot,
but none of them really changed my thinking as much as "Code
During this later part of the time, I didn't actually have a computer
at all; I would telnet from the local university computer center to my
ISP's Linux box in another state to write and compile my C++ programs.
Getting a Job
In 1996, I moved to Silicon Valley to get a job, at a company making
telecom network management software. I was still pretty incompetent;
while I had written a fair number of toy scripts, I was terrible at
There I met Jay Lark. Jay didn't have a lot of time (he was an
executive at the company) but he explained a little bit about Lisp to
me --- told me what a closure was, which Lispcraft had omitted since
it was about dynamically-scoped Franz Lisp --- and lent me Abelson and
Sussman's "Structure and Interpretation of Computer Programs." This
book taught me more about programming than all the books I had read up
to this point --- and I didn't even read the whole thing!
What Sedgewick had started, Abelson and Sussman completed. SICP
demonstrated not just the construction of algorithms and data
structures on a substrate that lacked them; they demonstrated the
construction of entire computational paradigms from almost nothing:
arithmetic, object orientation, nondeterministic backtracking
evaluation, and functions.
The job also put me in contact with many other programmers more adept
than I, and gave me the opportunity to learn a lot from them. And it
forced me out of my comfort zone again. But programming with them
wasn't my job there; I just ran the build system, the source-control
system, and the bug tracker, all of which probably needed complete
replacement rather than merely nursing along as I was doing. But I
wasn't yet up to the task.
After a year, I left for Ohio to start a marriage. But I began
working on programming projects with other programmers, which could
have given me many more opportunities to enhance my programming
skills. This part is pretty depressing to think about; for several
years, I didn't really make a lot of progress, partly because there
wasn't a lot to force me outside of my comfort zone.
Toward the end of this time, I became active on comp.lang.perl.misc,
which was extremely helpful at improving my Perl and my
programming-in- the-small skills. It was extremely helpful having
other people look at my code (which, sadly, was lacking in my day job)
and comment on how it could be improved --- and doing the same for
others. This was extremely valuable for deepening my knowledge of the
Perl language, but as I've said before, knowledge of languages is much
less important than you might suspect at first.
Sadly, I can't recommend comp.lang.perl.misc today; it was already
somewhat dysfunctional at the time, and it has gotten much worse.
During this time, I read "The Practice of Programming", which is a lot
like "Code Complete", but shorter and much higher in quality. I had
read the same authors' "The Elements of Programming Style" back in
1995, on much the same subjects, but that book is nearly unreadable
today --- it's written in PL/1 and FORTRAN IV. TPoP, aside from being
written with modern programming languages, also contains insights from
several decades more of the authors' experience.
Joining a Startup
In 2000, I moved across the country to join Rohit Khare and Adam
Rifkin at KnowNow, a startup they had just begun. For the next year,
I was constantly forced out of my comfort zone, forced to learn new
programming languages and APIs (including a bunch that didn't work
very well), and given the opportunity to work with several highly
competent technical people, including Rohit himself, Ben Sittler,
Strata Chalup, Mike Dierken, Scott Andrew, Lane Becker, Derek
Robinson, Adam Zell, Greg Burd, Matt Haughey, and Meg Hourihan.
This was my first time working with people who had such a high level
of competence, and it taught me a lot about programming very quickly.
Unfortunately, KnowNow made some bad business decisions (such as
taking funding from Kleiner Perkins and hiring some really third-rate
management), so the company kind of got stuck, and I got myself fired;
very few of the highly competent technical people I listed above
remained long after me.
Learning to Read
In 2002, I joined a startup company named AirWave, which practiced
Extreme Programming with a team of six; I stayed there for three
years. The practical consequences of this included constant social
interaction, high-bandwidth skill sharing, and constantly maintaining
code I didn't write.
Two of the XP core practices are "collective ownership" and "pair
programming". The XP reasons for these are that they "produce
business value," meaning they are valuable to the people who are using
the software being developed, but they were also very beneficial to me
as a member of the team.
Collective ownership means that nobody owns any part of the code, so
when you're making some modification, you're not any more likely to be
modifying code you wrote than code any other team member wrote. In a
team of six, that means that five sixths of the time you're
programming, you're editing code somebody else wrote. This alone
gives you a lot of practice reading code.
"Pair programming" means that half the time you're working on a task,
you're not even at the keyboard --- you're watching somebody else
type. It's expected that you're paying attention, too, so that you
can spot bugs, departures from the standard coding conventions, and
excessive complexity in the code that's being written.
Due to these two practices, I spent a heck of a lot of time reading
code. This improved my skills in three unanticipated areas: reading,
maintainability, and debugging.
Unsurprisingly (in retrospect), reading code made me better at reading
code. This is handy when I start any new programming project,
especially one that someone else has been working on. I thought I
could read code before this experience, but I got much, much quicker
at it. Previously, I hadn't understood the psychological aspect of
code-reading --- you have to understand not just what the code does,
but what the previous programmer or programmers were thinking when
they wrote it.
Reading code also made me better at writing maintainable code.
"Maintaining" code means changing it, usually to add features, and
most of the time spent in a typical "maintenance" task is spent
understanding the existing code. Consequently, the most important
aspect of maintainability is readability --- avoiding unnecessarily
complex constructs, clear naming, helpful commenting. Of course,
"Code Complete" and "The Practice of Programming" have advice about
how to do these things, but spending three years reading other
people's code in order to figure out how to modify it is much more
educational than reading a book or two.
The biggest surprise was how much it helped in debugging. Debugging
is what you do when the original programmer thought the program would
do one thing, and it actually does something different. You can
perform experiments of various kinds to figure out what it's actually
doing, and you often must; but in the end, it comes down to finding
the piece of wrong code, reading what it is actually doing, figuring
out what its author wanted it to do, and understanding how to make it
do that. It turns out this is the same process as reading code in
I think I learned more about programming in three years from the
AirWave team (Matt Albright, Joe Arnold, Darrell Bishop, Dan DiPasquo,
Jason Luther, Blake Mills, Dave W. Smith, and Sujatha Mandava) than I
had in my previous 22 years of programming. Unlike most of the
previous teachers I listed, this was a relationship of partnership,
where I think I taught as much as I learned.
Of course, I don't know what my next phase will look like. Presumably
certain things I currently struggle with --- to the point of not
knowing how they're even possible --- will get easy, and it will seem
strange that they were ever difficult. But I don't know what those
things will be. But I'm pretty sure I'm not done learning yet, and
surely there are folks out there who look at the stuff I have trouble
with now and scoff. And I'm pretty sure that having good partners or
mentors will be crucial in getting to that next stage; I'm wandering
around South America, in part, to find them.