On the way to the office this week I’ve been listening to the Stack Overflow podcast – a podcast by Jeff Atwood and Joel Spolsky to discuss and promote their programming knowledge exchange site stackoverflow.com. So far, I guess my snap review would be to say yeah, OK, its reputation for pointlessness is not entirely undeserved, but I’m only 5 episodes in, so maybe they’re about to hit their stride … and even if not it’s enjoyable and worthwhile anyway. True, it’s not as informative as it might be, but they do do a lot of talking about stuff that’s relevant to becoming a good programmer – which as a largely self-taught programmer I find useful.
A friend who’s heard the whole thing told me that the unintentional format is basically that Joel and Jeff argue a bit about something, and Joel is right … and then the next week when Jeff’s had some time to think about it he concedes. So far that seems to be a pretty good characterization. At least, it’s certainly true that I agree with Joel a lot more often than with Jeff. In particular, on the subject of whether programmers should bother to learn C…
Joel says that “These days C is almost never the right choice of a programming language for a project,” BUT that you should learn it anyway as a training exercise, if nothing else. I couldn’t agree more. In fact, if you have the time, read his essay-length argument for this called Back to Basics, in which he gives some specific examples of where having learned some C will help you avoid what he calls “Shlemiel the Painter” implementations. Guaranteed entertaining (if you’re like me and need to get out more, that is).
Jeff tries to compare learning C to learning Latin – but Joel disagrees and says it’s more like learning how to take apart a carburetor. Right. If there’s a “Latin” of programming langauges it’s probably actually Scheme or Lisp. That is, these are the languages you learn to train yourself how to think rigorously about your program’s semantics and organization – much like people learn Latin because it helps them study how the English lexicon is organized, and also becuase it gives them some tools for talking about English grammar. And the analogy even works on a cultural level: if there are programming language linguistic prescriptivists then they are definitely the Schemers – or maybe the Haskell people. Scheme is “right” and other programming languages are deviations from this ideal … is generally the attitude of a dedicated functional programmer. C isn’t Lain so much as it is a sketch of the neurons that make up your language module. And so it’s kind of crucial, if you’re serious about being a great programmer, to learn it at some point.
So I spent some time thinking about what I would do if I had it to do all over again. What languages would a good course of study in basic programming cover? And actually, I’m pleased to say that if I had it to do over again, I would do more or less what I did, though maybe not in exactly the same order. Here it is:
- Start with C – because if you don’t start with C you’re gonna end up like Jeff and never want to bother with it. Yes, there are MUCH easier ways to write basic programs, which it why it’s probably best to start with C, when you don’t really know any better. More than that, it gets you thinking about how these things actually work right off the bat. This will be a matter of personal preference, of course, but I’m one of those who likes to know exactly what’s going on under the hood. In fact, I find it difficult to understand programming any other way. I need to know what it is that I’m abstracting over. Actual History: I learned C++ first – so I almost followed my own advice here. I think C is the better place to start, though, because C++ is sort of a jumble that includes a lot of higher-level abstractions that don’t have so much to do with the machine itself, and so can distract from the purpose here.
- Next on to Scheme – why almost no one will follow my advice. If C is “almost never” the right choice for a programming project these days, then Scheme “absolutely never” is. Still, I learned most of the useful stuff I know about programming learning Scheme. More specifically, I learned most of the useful stuff I know about programming doing exercises that implement Scheme first in C, and then in Assembler. Learning C first and Scheme second really hammers home that programming is about abstraction. It’s about identifying the correct places to write factory code – code that programs for you, in short. Scheme will help with thinking about what it is that you’re doing on a semantic level, and learning it from a background in C will help you remember what it is in reality that you’re abstracting over (actual Scheme programmers have trouble keeping the fact that there’s a real machine underneath it all in mind – in fact some of them are proud to acknowledge this, saying that they don’t want to know that there’s a machine there because that’s not what Computer Science is about. They’re right, actually – Computer Science is not about the machine. But programming as a craft is – and this is advice for programmers.) Actual History: I learned Python second, which I regret. Python is a great little language, but it’s kinda like eating dessert before you’ve finished with dinner. I think if someone is going to learn one programming language really well for the purpose of “getting things done,” it should probably be Python. But if you’re thinking of becomming and ace programmer, you should do your homework learning the basics before picking up the power tools. This decision still bites me in the ass, as when I’m in a crunch I find myself reaching for Python. If I’d taken the time to learn from first principles, it wouldn’t really matter so much which language I was working in.
- Move on to Java – I guess C++ would be OK here – I’m saying Java mostly because it’s a lot cleaner than C++, and because it has more industry applications these days. In any case, what I have in mind is an industry-useful object-oriented language of some kind. If you followed the first two steps and faithfully learned C before faithfully learning Scheme, you’re actually already equipped to easily graduate to whatever langauge you want and pick it up in no time at all. Java (or C++) seems like the logical next choice just because it’s the paradigmatic OOP language, and because it’s virtually a sine qua non on resumes for a lot of entry-level jobs. Of course, there’s something to be said for learning C++ here instead – especially if you’re in a hurry. C++ isn’t a perfect extension of C, but it’s close enough that everything you’ve learned about C already means that you really just have to add stuff to your existing C knowledge rather than start a new language completely from scratch. And in fact, if you know you’re going to be primarily a Microsoft programmer, C# is a reasonable choice at this stage too. Actual History: I started Scheme and Java at about the same time at this point, but I found Scheme a lot more interesting, with the consequence that I’ve never learned Java as well as I probably should have. To be competely honest, I’m prejudiced against Java – for all the same reasons that Paul Graham is. Unlike Graham, I won’t couch it all in fancy arguments: I’m well aware that my aversion to Java isn’t entirely rational. Mostly I think I agree with Graham on two points (I can’t be bothered to look up the sources – somewhere on his essays page): (1) that object-oriented programming is popular because it produces “a lot of what looks like work” – that is, it’s code structure for the unorganized and lazy – and (2) that Java isn’t cross-platform, Java IS a platform. It’s (2) more than (1). The annoying thing about Java for me is that it won’t stick to just being a programming language. It won’t even stick to just being a programming language with lots of useful libraries. Everything is so integrated with all this other lathered-on crap that you come away with the Microsoft feeling, without the benefit of it actually being a Microsoft product. All kinds of decisions have been made for you, how it all works together is a little mysterious, and you’re tied to all these packaged things of dubious quality that go with the platform. But OK, I wasn’t gonna rant. Java the actual language isn’t bad at all, it’s certainly a useful job skill, and you’ll suffer none of the damage that it does to first-time programmers if you learn C and/or Scheme first.
- Finish with Python – Actually, substitute any of what Dan Friedman calls “p-languages” for Python here. I just happen to think Python is the best everyday-use language on the market. Joel Spolsky claims it’s “not quite ready for prime time,” and he may be right about that. But what he means, in any case, is that he doesn’t yet trust it completely for truly large-scale projects. For medium-scale stuff, and especially for those little daily scripts that you write just to get things done, it’s about as convenient as a language can get. It’s true that it doesn’t quite have Perl’s module suite, and it’s true that it’s probably not as much fun as Ruby, but it’s a solid, competenly-designed language that’s consistent and easy to learn. Unlike with Perl or Ruby, where you quickly get surrounded by a weird fanatic culture, Python mostly just gets down to work and gets out of your way. I’m in love with it because it’s NOT a movement. But really, the point at this stage is just to get your hands on an easy tool for everyday tasks. Learning C and Scheme and then some object-oriented language has given you all the programming skills you actual need, so what you’re shooting for here is convenience. Which “p-language” you choose has to do mostly with what kinds of projects you see yourself doing, really. Actual History: I went programming language crazy and wasted a lot of time learning Perl and Ruby and Haskell – languages that I never use and promptly forgot. The advice here is to pick one and stick with it. At this stage, you can easily pick up anything, so if the boss tells you to learn Ruby over the weekend, that’s no problem, and you can quietly forget it later. The real point is just not to become a language whore. Choose one and get really, really good at it. Then, if nothing else, you can always make projects work in this language and translate them into whatever the project actually calls for.
THAT’s how I wish I’d done things. C, then Scheme, then Java more thoroughly, then Python. In reality, I did C++, then Python, then Scheme with some half-hearted Java, and some truly half-hearted dabbles into about 5 other assorted useless languages. All that I learned from that dabbling was the depth of my hatred for Perl, which is arguably worse than a useless thing to know, as I learned just enough about it to feel strongly enough about it and know enough about what I’m talking about to pick stupid fights on the internet. And in fact, I don’t really know C as well as I’d like. Since I started with C++, most of what I know about C comes from there, which isn’t really the kind of discipline that learning C is supposed to instill. All said, though, I could’ve done a lot worse. I did, at least, learn Scheme at some point, which is a Very Good Thing, and I’m not one of these people who’s divorced from C and thus generally ignorant of how the actual machine works. And I did, at this late hour, finally come to the realization that I should mostly concentrate on getting really good at Python, more than keeping all my bases covered (for example, I don’t know PHP and don’t plan to waste time learning). But if I had it to do over again, I would take a year and do things in the order given above.
I think the best takeaway point from listening to Joel’s ramblings so far is that the focus on language-as-worktool is probably overblown. A good programmer isn’t necessarily tied to any one language because he knows about algorithms, knows something about how the machine works, and knows how to write a compiler. People who get too focused on individual languages are essentially letting other people do the real thinking for them, and thus they ultimately limit the scope of what they can adapt to. It’s sort of the way a calculator will do your long division for you, but it won’t teach you about math. Learning languages for an aspiring programmer should be done more with a mind to learning programming techniques, and less with a mind to acquiring resume items. I do think it’s important to learn a language or two really, really well, so that you can function in it in your sleep for those times when something critical just needs to GET DONE – and also because it saves you time working on mundania around your office. But in general, the goal is to learn how to program, not how to use a given language. These aren’t the same thing.