Let’s start with a brilliant rant from Joel Spolsky:
Spolsky points out that people who spend their entire undergrad careers writing Java never run into hard enough problems to really teach them CS. (Or maybe that Java isn’t hard enough to weed out the people who really shouldn’t be CS majors in the first place.)
I have a little bit of experience with undergrad Java programmers. Back when I was a precocious third-year undergrad and thought I knew all there was to know about software engineering, I TAed CMPUT 201, our intro software engineering course. 201 used C, C++, and Unix to teach people who knew how to write code (this is a variable, this is a function) how to write programs (this is a module, this is a unit test). The first-year programming courses — CMPUT 114 and CMPUT 115 — had recently switched from Turbo Pascal to Java, so I got to TA a mix of students: some knew Pascal, some knew Java.
The students who’d learned Java in first year couldn’t deal with resource allocation to save their lives. That was something the runtime did for you, or maybe — maybe — a constructor or destructor in a library class. Resource management was Someone Else’s Problem, right up until the point where I wrote “malloc(foo)” on the whiteboard.
More recently, TAing an intro graphics course, I ran into a student who had no clue what pointers did or why his code segfaulted. This guy was in his fourth year, about to graduate. I had to explain stacks and addresses to him. That wasn’t necessarily his fault: I’d be willing to bet that nobody had ever told him he’d have to give a shit about such “low-level” concepts.
These same students are going to spend their first year or two as grunt programmers — er, I mean “Junior Developers” — bitching and moaning about how university didn’t teach them anything they needed to learn.
But that’s not such a big deal: after all, all ANYONE looks at is how well you did. Right?
So what does a bright young undergrad CS major need to learn?
Look, CS programmes can’t teach everything you’ll need to know to do your job. They can’t teach in-depth web development in PHP and Python and Ruby and Perl (in case you get a web-dev job) at the same time they’re teaching database wrangling in a bazillion different dialects of SQL and how to do it in DBI and ODBC and Delphi or whatever toolkit catches your future manager’s fancy (database hacker) and VHDL and C and FORTH (embedded systems) and Java and J2EE and design patterns and the Rational Unified Process (oh, you poor bastard) — just in case you get a job in one of those areas. Further, they can’t teach you about your future employer’s internal APIs and procedures
What they can do is teach you enough different styles of programming to give you a broad grasp of the basic problem: telling a computer what to do.
A friend of mine teaches Haskell and Prolog to generally disinterested third- and fourth-year undergrads. He doesn’t do it because he wants to prepare them to use Haskell and Prolog in the private sector — he does it because until that course, their worlds have been limited to procedural and object-oriented programming in C++ or Java, and they’re going to be screwed if they end up working on a project written in a particularly functional style of Python.
Suppose you’re an undergrad, and all this is making you a bit nervous. If you can’t trust the course requirements to teach you what you need to know, what can you do?
Get as much breadth as possible in terms of programming and symbolic reasoning. You’ll probably have to learn the details in your first few months on the job, so don’t waste time worrying about how you’re not being taught design patterns or eXtreme Programming or whatever the fad-of-the-month is. You want to learn as many programming styles as possible, so that when your manager sits you down in front of a system you’ve never seen before you can say “Oh yeah, pattern-matching, this is a bit like the regular expressions stuff I did in my compilers course” and get to work.
You should probably also take an operating systems course. It’s handy to know about how process environments change and how things like fork and exec work when you’re trying to figure out why your code works fine from the command line, but fails miserably when it’s called by the web server.
That happened to me when I helped judge a programming contest. Hint: initialize your variables. That memory won’t be zeroed when it comes from a lighttpd process that just exec()ed to you.
Besides, OS courses usually teach multiprocess and multithreaded programming, and with all the multicore chips coming out odds are good you’ll have to do some of that.
Take a database course. Pay attention to the SQL, of course, but pay more attention to normal forms. That’s what your data structures should look like.
Take some algebra courses — group theory, rings, fields, linear algebra — and some logic courses. Those courses teach abstract reasoning, and they’ll make you a better programmer.
Take at least one english composition course while you’re at it. You will have to write.
Stay away from area-specific courses — graphics, user interfaces, processor design, and so on — unless you’re dead set on getting a job in the area (or have some credits to spare). Compilers courses are tricky: some of them are low-level nuts and bolts lexer/parser design; some are more abstract formal-languages courses. The latter are better.
I don’t think it’s possible to teach good software engineering practices in a three-month university course. The scope is too small: you’re never going to need to maintain a fifty thousand-line codebase for two or three major and dozens of minor revisions in a single course. The best you can hope for is a brief introduction to design patterns, unit tests, and encapsulation.
All that said, you have to seek it out, not just endure thirty-six one-hour lectures, get a B+ on the final, and hope you learned something.
And when the guy next to you complains that “we’re never going to need this ‘lambda calculus’ stuff in the real world”, smile.

as-94783-sa
love what u have to say