Sunday 1 January 2006 — This is 19 years old. Be careful.
Joel Spolsky’s latest essay is The Perils of Java Schools. He explains in detail why he thinks teaching computer science with Java is a bad thing. It basically comes down to not learning about pointers or recursion. He laments the state of computer science education, and fears for the entire industry as a result.
At least Joel has the good sense to start the piece by making fun of himself for griping about “kids these days”. He has his knickers in a twist for no good reason.
One of the things that caught my eye about the piece was that Joel attended Penn, and discusses a course there called CSE 121. As it happens, I also went to Penn. I suspect it was a couple of years earlier than Joel, but not many. I didn’t take CSE 121. I wonder if it was offered, because it doesn’t sound familiar, but looks like an interesting course.
So I never had the legendary Intro To The Theory Of Programming Languages Using Lisp course that so many people find so fascinating. But I took another course that is germane to the discussion, Intro To Assembly Language.
I don’t think CS students today are being taught assembly language. Should they be? I don’t know. Is it useful? Yes, at the very least for debugging. Working in C++, there have been many times when dropping into disassembly in the debugger was the only way to see what was really going on. I’ve had debugging sessions with engineers with recent Master’s degrees from MIT where I started poking around in disassembly and registers, and as far as they were concerned, I might as well have been speaking in tongues.
(Side note about the Assembly Language course at Penn: we were taught PDP-11 assembly language, and did all our work in it. The final project was to write a 6502 emulator for the PDP-11. But Penn didn’t have a PDP-11; all the projects were run on a PDP-11 emulator on a Univac mainframe! Needless to say, the 6502 programs we tested our emulators with ran very slowly!)
Assembly language can be very helpful, but if you’re working in Java (or Python or Ruby or PHP or Perl), there isn’t much call for it. So should it be taught? Hard to say. Understanding it will definitely give you a deeper understanding of what’s really going on, and many areas of software engineering still require its use. But if students don’t take a semester of assembly language, they can take a semester of something else instead, something that may be more helpful in the long run. UI design? Finance? There are lots of things I never learned in college that would be handy now.
Why does Joel pick out pointers and recursion as the two gatekeeper concepts? Because he found them difficult? As Tim Bray points out, Java is perfectly adept at recursion, and concurrency may be a more important and difficult concept to master in any case. The emphasis on recursion in Lisp languages is a bit over the top, and doesn’t carry into other programming cultures. Why do people think it’s so important for software engineering? Don’t get me wrong: I love recursion when it’s the right tool for the job, but that is just not that often to warrant Joel’s focus on it as a fundamental concept.
While we’re hunting around for tough concepts that separate the men from the boys, what about the one that got Joel and I into a tussle two years ago: Exceptions. He doesn’t like them, basically, because they confuse him. Is this any different than a Java guy not liking pointers? Yes, you can avoid exceptions and use status returns, but you can also try really hard to avoid pointers. Does that mean you should? So Joel’s got the concepts he likes (pointers and recursion), and laments their decline, but doesn’t seem to notice that there are newer concepts that he’s never caught on to, which the Java kiddies feel at home with.
Joel draws an analogy to Latin and Greek being required by universities in 1900. Good point. This is where the “kids these days” arguments always fall apart. By digging back even further into the past for helpful analogies, the old timers don’t even realize the trap they are falling into. Joel didn’t learn Latin or Greek at Penn, and neither did I. Neither did 99.99% of the software engineers working today. Which means Mr. 1900 would look at every single one of us and consider us unfit for professional work. But we are not. We are fit for the world we find ourselves in.
Education changes, and the world changes. Which is the cause and which the effect? Perhaps it’s a bit of both. In any case, the colleges produce graduates, who go into industry, and produce software. Some will be good at it, some will not. This is how it has always been. In my experience, most of what is truly helpful in writing software didn’t come out of a text book or off of a blackboard. So much of the day-to-day work of writing software is completely missing from curricula anyway, why worry about it? You want a good software engineering education? The final project should be to take some other kids’ project from last year and adapt it to do something he didn’t even consider. Then the result gets passed on to another kid next year. That would be an education!
The Java kiddies will learn to write software. Some of that learning will happen in college, some will happen on the job. Joel learned on Pascal, a language specifically simplified for teaching. When I started at Penn in 1980, the first course in the computer science curriculum was Introduction to Programming in, you guessed it, Pascal, because Pascal was trendy for teaching in 1980. Java is trendy now. The industry survived Pascal and its students, and it will survive Java.
And you know what? Twenty years from now, the Java kiddies will be the old timers, and they’ll probably be lamenting how computer science is being taught in 2026. So it has always been, and so it will always be. Geez, old-timers these days!
Comments
Honestly, I don't think academically that pointers are that hard--it's when you get a bunch of different people working on a big system together that use them where it gets to be serious. His tests don't account for that. They become more like Jeopardy questions testing exposure and recall.
As for the recursion stuff, does anyone find that hard? Closures, continuations, concurrency, memoization and solid design are WAY harder than pointers/recursion, and probably better separate the men from the boys.
We end up hiring the best of them, and my full-time job is basically teaching now.
For the record, we do program video games, which involves quite a bit of to-the-metal. But it's not much different from any other embedded system programming job.
As David said, unfortunately, Joel picked some poor examples. And, I'm not a huge Joel fan, I think he's generally overrated; but, in this case, his point remains strong.
By which you / tim bray mean that java requires tail call optimization? Didn't think so . . .
strcpy ,strncpy or doing some string operations. While Java may provide handy APIs for these I would really like to test someone on these aspects (which are related to pointers btw) and its not possible with Java.
On a related point, you also missed the intention of the "Every educated person knows Latin should be a requirement" example, again assuming the direct opposite of what was said. He wrote "Are pointers and recursion the Latin and Greek of Computer Science?". And then, if one dares to read further, you realize he answers this very question: no.
Joel's essay to which you link contains an argument that is lucid, well-thought-out, and rational. The argument in your essay can be completely demolished by reading one paragraph of the essay that you decry. In light of this, and the fact that Spolsky is speaking from the experience he's had of having to staff a company from the pool of available programmers, whereas you are arguing from a much more theoretical standpoint, I think it's much less likely that Joel Spolsky is a crotchety old man then that you, on this matter at least, are simply a crochety young one.
He's not the only one who misses "the good old days", but that's not the point, and his problem is an entirely current one. You seem to have missed that, instead focusing on the literary device he used to point it out: he needs a practical means of quickly ascertaining the capacity for "systems thinking" in a candidate; a way to separate the guy who can crank out code from the guy who can think about code.
It's not about language advocacy, or whether recursion is a tougher concept to wrap your head around than list comprehensions, or whether Java is better than Ada. It's a shame you didn't pick up on that.
Compare it to a general medical doctor: it may seem that what they do most of the time is using a stetoscope and a couple of other instruments, looking up drug names in their medicine bibles and writing prescriptions. So why not teach medical students just that and leave all the difficult stuff to the others, like older doctors who already know more? Or, as an airliner pilot: theoretically, (almost) all you need to do these days is crank up the thrust, pull the stick and click the autopilot on. If that doesn't sound trustworthy, why would you trust a programmer whose perception of reality is a virtual machine?
I'm not sure how much culminates on pointers and recursion but every good programmer I've known hasn't had a problem with them. They're not that difficult even if you don't use them daily. The difficult stuff comes later, and if you claim you know that you sure as hell shouldn't have a problem with pointers and recursion.
As a professional system designer with 15 years of experience, I'd certainly hear my warning bells ringing if someone would apply for a job and didn't know pointers and recursion. How would I know if he knows the difference between the stack and the heap? What if he ends up using polynomial time algorithms where any other sane developer would find (or just "know of") linear or constant time solutions? Or if he has no idea of memory management, as he has been garbage collected all his life? Joel is at least partially on right tracks that if your candidate proovedly knows recursion and pointers, he's got at least one foot safely on the ground.
strcpy ,strncpy or doing some string operations. While Java may provide handy APIs for these I would really like to test someone on these aspects (which are related to pointers btw) and its not possible with Java.
Two things:
1) This is 2006. Nobody should be spending any time futzing around with string manipulation as there are plenty of string manipulation facilities either builtin to the languages that are used now or they are readily available in libraries. Think of something else to ask your interiewees. String manipulation questions are so '90s (no, '80s); they only serve to give the interviewee the impression that programmers at your company have to waste a lot of time reinventing the wheel.
2) If you really insist on asking such questions, there really is no reason why you can't ask someone to write something like strcpy in Java (you just need to preface the question with something like: "pretend that civilization has been mostly destroyed and you have a computer with a Java VM, a java compiler, but no string libraries...".
That's why they are not as good for making the distinction between a really smart person and a not-so-smart person as pointers are. Actually, because they are not, they are used everywhere.
All of Joel's points remain valid in my eyes. You just created new arguements out of his, and discussed them.
Thanks for writing anyway.
Isn't a lot of software development happening in Java?
If so, replace the expression "practical skills" with "Java" in the aforementioned sarcastic extract from another Joel's essay.
Concurrency is difficult to get right in Java. Most Java developers are taught to encapsulate state in objects, but not to encapsulate state to threads. The typical Java developer writes concurrent code using way too much shared state, which is very difficult to comprehend.
Shared state isn't so much a problem in different languages, such as Sheme, where state is thought of differently. Concurrency isn't considered an exceptionally difficult problem in these languages.
Knowing alternative high-level programming languages is important for selecting the right tool for the job. Really innovative developers know how to play the strengths and weaknesses of the language and import concepts from one language to another when it makes the solution simpler.
However, I did the same application in both three. C++ with wxWidgets won hands down.
The reasons? Java has at least three string classes. wxString is a single class easy to use and presumably faster too.
Gui stuff is easy with wx C++. Network is as easy as with java. The date/time picker is a joy to use in wxW. Java GUI requires inner classes and a lot of framework code that doesn't really translate in functionality, but is there just to fight against the language limitations (everything must be a class).
And in the web application, I had to use a lot of source files, that essentially are all the same (missing lisp macros there). And I had to debug the date/time picker because JavaScript is different in every browser and sometimes just doesn't work. That was the most time consuming part of all the coding. JavaScript debugging.
No, I didn't had to use pointers all the time, objects in the stack are easier. No templates either. C++ templates are uglier than anything bad that Java has.
In fact you're more efficient with a subset of C++ and the right library than with full C++, Java, or plain php. And the end result is far easier to use and more aesthetic.
But as always, managers won't listen.
It's also, however, the way that Java is taught. Pointers do exist of course in Java, they're just managed. But there are times when you have some control over them- say for example, using a WeakHashMap instead of a HashMap will release objects in a hash when they aren't referenced elsewhere. A student not familiar with pointers wouldn't understand this. It's impossible for a class in C++ to get away from this, but professors who use Java rarely spend much time worrying about something like this.
I agree with you to a point as far as Exceptions go, in so much as I disagree with Joel that OOP is all about memorization. Polymorphism isn't just a something found in an OOP programmer's glossary. However, I think OOP concepts are pretty abstract, not nearly as concrete and low-level as pointers. And I will agree with Joel that problems in OO design don't result in broken code, whereas problems with pointers are much more apparent. So if you have to cut your teeth on one language or another, it should be one that doesn't let you get away with mistakes.
*If* the schools aren't replacing pointers with other useful concepts, then that is bad. But I don't think that's the case.
That said, recursion is actually a much more fundamental concept, and it would be most disappointing if students graduated without understanding it well. They might stop teaching long division, but it's no good if they stop teaching division itself.
One reason is that some of the best future developers aren't even in the CS program. One of the best developer's I've worked with got a degree in Mechanical Engineering. Another got a degree in Biology. Personally, I got a degree in Civil Engineering. I learned pointers and recursion on the job. As I remember learning those concepts wasn't nearly as hard as studying Fluid Dynamics, understanding phase diagrams in Geochemistry, or reading Gravity's Rainbow.
Joel said, "You need training to think of things at multiple levels of abstraction simultaneously, and that kind of thinking is exactly what you need to design great software architecture." I don't think it is a matter of training. The ability to think architecturally is more of an innate ability. A CS program can only begin to manifest this ability in it's students. To really separate the kids from the adults, you need to wait three to five years after undergraduate school.
Me? An ex-mathematical physicist who cut his teeth on good solid scientific Fortran IV (no pointers or recursion there).
CSE 378 is Machine Organization and Assembly Language. It's a required course for both CS and CE, and while it's not really a course about how to be an awesome assembly hacker, we do write some programs in MIPS assembly and learn about how a processor works at the register level.
CSE 341 is Programming Languages. It varies what languages are covered, but when I took it, we had to do assignments in SML, Scheme, and Smalltalk. The class was more about programming language concepts and paradigms with the use of specific languages merely as examples and to get some practice and drive home the fact that we better learn how to learn new languages quickly. Recursion was used so much that I began to see mundane things like taking a sheet of paper from a stack and passing the rest of it on as a recursive function ;)
It's true that our introduction for programming courses are taught in Java and that there is no required course that teaches C. Many assignments are given in C anyway with a little bit of extra time and help for the first assignment for you to frantically learn C in all its pointy glory, heh. CSE 303 does cover C, shell scripting, and using Linux. It's a "highly recommended" course that I hear the department is considering making a requirement.
My opinion? Java-only seems to be an odd way to go, and I think it unnecessarily restricts the scope of a computer science education, and thus, some of the versatility of someone who graduates only knowing Java. I don't think their education is necessarily watered down, though; there are plenty of difficult problems and valuable contributions to make working at a higher level than C. I don't think computer science could progress so far without being able to abstract lower levels away and working in a ways that allow you to ignore them. It's the same in many fields of knowledge.
If all CSE educations were Java-only, then I'd worry about a Foundation Empire-esque collapse where there's no one who understands how some lower layer of technology that they depend on works. I don't really see that happening right now, though.
Steve mentions a good point. While there is huge economic pressure for computer science programs to churn out excellent programmers, that's not really what computer science is about. You could be an extremely good computer scientist and hate working with computers if you enjoyed working in computational theory. I think I'm just rambling now, so I'll shut up.
in other words, good programmers do understand "pointers & recursion" & they *do* carry that special part of brain which separates them from the herd of average programmers, now if they don't know C, Joel can not test them on his scale, they need to be tested on a different scale and by saying this Joel did not say that they are not good programmers. got the point?
i tried Java once, a long time ago, when i did not even know
what is Sun Microsystems :-), i knew only one word "Windows", sorry 3 words, Microsoft & Bill Gates too ;-) .
Java is a crap, same i say for VB. it is just a massively marketed brand like Windows. With Windows you can not tell the difference between a users possessing /common-sense/ & a user possessing /non-sense/, you are /stuck/, it will take a lot of time to figure that out BUT with UNIX (or any "Linux based GNU system") you can, you don't have to talk a lot. now that does not mean if you don't use UNIX you do not possess common-sense. actually, to sort that out, i have to forget about UNIX scale and talk from a different angle BUT with UNIX, you are enlightened :-) , try that for yourself. now, i spoke from experience.
"Exceptions. He doesn't like them, bascially, because they confuse him"
I don't buy this. He goes into some detail as to why he doesn't like them, and I find myself mostly agreeing with him, so I suspect I'm as confused as he is. If you could shed some light on my confusion by arguing some points it further detail it'd be appreciated.
Anyway the point I would like to make is you guys are talking about the effect this has on the elite programmers from MIT and Stanford. But when this kind of easy to learn/teach phenomenon reaches the lower level colleges this issue becomes more apparent. I think even if 90% of the IT jobs today don't require smart programmers, 'simplifying' down the course it only making it worse.
Pointers and recursion are the best ways to make sure programmers understand what is going on in the program stack and heap.
Add a comment: