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 original set."
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: TO EAT: PRINT [OM] EAT2 TO EAT2: PRINT [NOM] EAT2 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 interesting. * "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 write myself. 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 sense above. 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 capacity. 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 libraries. 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 value. 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 Complete." 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 debugging. 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 general. 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. Today ----- 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.