Tuesday, December 12. 2006
My college career is slowly coming to an end. If everything is going according to the plan I am going to graduate with a Master of Science degree in Computer Science at the end of the next semester. During my time at college I worked as a TA for five classes and I will probably work as a TA for a sixth class next semester. Four of the five classes were Intro to C++ classes taught to 4th semester students. The other class was an Intro to Programming class taught to freshmen.
During the last few years I was in the role of the student and I was in the role of the teacher in programming classes. In that time I developed opinions about the curriculum and pretty much everything that went on in class. I already promised some of my teachers that I am going to write down everything once I hold my degree in my hands. Every complaint and every suggestion will be neatly categorized in a visually appealing LaTeX document. That's the plan at least.
One of the suggestions I'm planning to write down is the way introductory programming classes are taught and especially the programming language used in class. The style of introductory programming classes and the programming languages taught in college are certainly popular topics to complain about on the Internet. Joel Spolsky decries JavaSchools where graduates know neither pointers nor recursion. Dan Zambonini touches on the topic as part of his idea of a decent CS curriculum (the article started a Slashdot discussion with 654 comments too). On Digg someone raised a comparable question and received 154 answers. And once in a while you can hear surprising news like MIT getting rid of Scheme and replacing it with Python in undergraduate classes.
Is the language taught in first year programming classes important? Is the programming paradigm important? Should the focus rather be on what problems the students solve? These are the typical questions and as evidenced by the linked discussions there is anything but consensus on the issue and everybody seems to have an opinion. The arguments are plentiful. "People should learn assembly because it's close to the hardware". "People should learn C because everybody needs to understand pointers". "People should learn Java because it abstracts from the hardware and teaches OOP". "People should learn Lisp because it teaches algorithmic thinking".
As someone who has been on both sides of the teacher's desk I obviously have an opinion about this too. Let me first describe the status quo at my college though. Afterwards I am going to explain the problems caused by the status quo and how the situation could be improved.
The status quo at my college is that the primary language taught and used in undergraduate classes is Java. Nevertheless I do not think that we are a one-sided JavaSchool as described by Joel Spolsky. Next to Java, students at my college are taught PIC assembly as part of a 3rd semester computer architecture class, Prolog as part of a 3rd semester formal logic class, and Lisp and C++ in two 4th semester classes dedicated to these languages. Furthermore you are not limited to these languages. In classes which are not about a specific language you can generally use any language you like. I have seen other people present code written in C# and Delphi and I have used Ruby, Haskell, and Erlang myself whenever these languages were appropriate for a given problem (like Erlang in my distributed algorithms class for example).
Even though we are not a JavaSchool we still start with Java. That is a significant problem. It is not a problem because Java is a bad language. It is not a problem because it spoils the students by abstracting from concepts like pointers or memory management. It is not a problem because OOP is the wrong paradigm. These arguments against Java are oft-heard but I don't believe they really hit the core of the problem. Java is a bad choice to teach to freshmen for a completely different reason: The heterogeneity of freshmen with regard to their prior exposure to programming.
I suspect that there is probably no other college major where the skills and prior knowledge of freshmen about the subject are as diverse as in computer science. On the one hand you have students who have never programmed a single line of code in their pre-college lives. On the other hand you have students who have been hacking the Gibson since they were 12 years old. The 1 Million Euro question is now how to structure freshmen classes in a way that makes them interesting and challenging to both groups of students (and all the students in between the two extremes).
If classes are too simple the l33t hackers will not show up to class anymore, drop out and join the ranks of Slashdotters complaining how they never learned anything in college. If classes are too hard you will quickly find that 75% of the people dropped the class and switched their major to Business Studies or something. Some might say good riddance, these people were not made for CS. I say the performance of freshmen means absolutely nothing in the long term. You might lose significant talent if you think people who did not get through a tough intro to programming class are not made for CS. I've had lab partners who were brilliant theoretical computer scientists, the kind of people who double in math just for fun. But actual programming skills in a language that was not the Lambda calculus? Let's just say I wrote the final implementations and we were both better off that way.
I believe there are at least three different classes of solutions to the dilemma of strongly diverging prior knowledge. You can divide the groups, you can get rid of one group, or you can level the playing field between the groups.
An example from the first class of solutions is to create different introductory classes for different people. Divide the freshmen into two or more groups according to their knowledge about programming. Call one class "Intro to Java for people who think programming is like recalibrating the Matrix" and call the other class "Intro to Java for people who believe they're the reincarnated Alan Turing". Personally I don't like this but I'm not going to go into detail.
A solution from the second class is to create a class that appeals to people with prior knowledge. The students without prior knowledge who can not pick up the necessary skills quickly should change their major. I've already said that I don't like that.The third option - leveling the playing field between the individual groups - is the option I want to focus on. First I need to elaborate on something else though. What is the purpose of an introductory programming class? What should be achieved in class and what should the students learn? In my plan the first year programming class has two primary goals. The first goal is to level the playing field between the individual students. The second goal is to minimize the number of students who drop out because they are frustrated about the pace of the class (either because new concepts are taught too slowly or too fast). What's actually taught in class is not that important. Real foundations of computer science can be taught later. A freshmen programming class should get people interested in computer science. This could be achieved by solving nifty little problems. There are lots of little puzzles that can be expressed and solved using elementary concepts of graph theory. This might be a really cool intro to programming class.
Now how can we possibly manage to level the playing field between the Alan Kays and the Jackson Pollocks in class? The answer is simple. Use a programming language and a programming paradigm that is generally not used by high school students. I favor Haskell, Scheme or maybe ML or O'Caml. From what I have seen as a TA, high school programmers mostly write code in C, C++, Java, C#, some dialect of Basic or some dialect of Pascal. All of these languages are imperative languages while none of the suggested languages are imperative. Well, ML and O'Caml are kinda imperative but I'd focus on the functional parts of these languages.
Can you imagine what the results of teaching freshmen these languages are? Well, except the endless bitching and moaning of the students who have prior experience in languages like C++ and Java. "This is useless", "Why don't we learn C++", "That's not how it works back home", "Nobody outside of academia uses these languages", "These language are too slow". I know all the complaints already. But they're not important. What is important is to level the playing field between freshmen who believe they know everything already and freshmen who know that they don't know anything about programming. Of course we're not going to level the playing field perfectly. Prior programming experience means something, no matter in what language people programmed during high school. Consequently even the leveled playing field will not look like the Bonneville Salt Flats. It'll be more like the Low Countries but at least it's not the Himalayas anymore.
One last question remains. If we teach Haskell to freshmen what are we going to teach in the next years? Joel Spolsky doesn't like JavaSchools but I have a feeling that he'd like HaskellSchools significantly less. People who can easily create the most complicated Monads and Functors but have never heard of a for-loop are probably not be very useful in a business environment. So at one point we need to make the switch from Haskell to a language that's more useful in the industry. I'm talking about one of the boring imperative languages here. The languages that haven't changed much since the days of ALGOL 58.
The second semester is probably the right time to introduce an imperative language. The students who survived Haskell are probably really interested in majoring in CS. Regardless of what their programming knowledge was before freshman year. At this point the pre-college experience of the different students doesn't matter much anymore. Everybody has collected so much experience at this point that people without prior programming knowledge don't have to fear the competition of most of the high school hobby programmers anymore. Consequently creating a second semester Java or C++ class should be significantly easier than creating such a class for freshmen.
After the second semester it's possible to use both languages parallelly throughout the rest of the curriculum. Haskell could be used in classes that focus on algorithms. Networking classes could be taught using Java. Operating system classes could be taught using C++. And so on. This could lead to a very well-rounded CS education.
Display comments as (Linear | Threaded)
Why make kids who have been programming since jr. high take the freshman class at all? When I was a freshman in college, I tested out of a couple of levels of Pascal.
I think the idea of trying to "level the playing field" between hackers and kids who have never programmed in their lives is going to be its own problem.
the main problem with that idea is that I live in a country where that's just not possible. Everybody takes every class, no exceptions. At least I've never heard of anything like that at the two colleges I attended. However, even if that was possible I'm not sure if it's a good idea. I hinted at it when I said that I'm against dividing the groups.
There are two reasons why I believe that everybody should take the entry level classes.
First let me say that I believe that entry level classes can be made interesting enough for all audiences. If you only teach students how the syntactic elements (like loops, conditional statements, ...) work and how to do I/O the experienced people won't show up. If you let them solve cool little puzzles they might show up. That's my hope at least.
Now for the two reasons:
1. Most of the self-taught high school programmers are not nearly as awesome as they believe to be. There are very few people who would not benefit from taking an interesting intro class like I described above, a class that teaches graph theory or data structures indirectly.
2. I believe the presence of advanced students might benefit the people without prior experience. Students could be paired or put in groups with students of all skill levels. Students new to programming might pick up a trick or two.
That's a really interesting idea, in forcing everyone into a new programming language. The main resistance you will run into, in my opinion, is that there is a wide perception that schools should focus on languages that are in wide use in commercial development environments. There just aren't very many internship postings looking for ML programmers.
I'm not sure I agree with that, but that's where it is.
When I entered college 10 years ago, we started with Pascal, progressed to Modula 3 in 2nd year, and C++ in 3rd year (with forays into a few others - Scheme, MIPS assembly, etc).
I was one of the last classes to do that, as Java was being phased in to replace both Pascal and Modula 3. I think C# has made an appearance in the curriculum since then.
I'll describe how my school tackled the experience heterogeneity problem. Students self-selected from three tiers based on programming experience (basic, intermediate, advanced). There were self-test guides to help students know where they fit in when they did course selection. If you started in a lower tier, you had to progress upward (the advanced course was the only one that was a degree requirement). Of course, even in the advanced section there were the uber-1337's who complained about having to learn about pointers again, and in my first year there was an experiment to introduce an optional 'advanced project' where students could form groups to tackle a difficult programming problem. The experiment didn't work out, at least partially because, precisely as you say, self-taught high school programmers are not nearly as awesome as they believe themselves to be.
the issue you raised in the first paragraph is absolutely true. People will demand that a language is taught that's useful in commercial software development. How to argue against this point depends on who exactly complains about it I guess.
In the last paragraph you talked about dividing the students into groups. This is one possibility to solve the problem I described. Do the individual groups get different lectures or only different assignments / lab classes?
I know freshmen at my college are divided into three groups according to their prior math knowledge (there's an exam in the first week). These groups aren't just for math classes but for all classes they have to take. I believe the different groups only have different discussion classes (where they talk about homework and go through the material of the lectures again) though. I'm not totally sure about this, I spent my freshmen years at a different college.
Would it be considered fair and appropriate to give the people with some experience a harder version of the class? Harder assignments, I guess? But then, they are being "punished" for knowing more, and have to work harder for the grade. But if you don't, they are probably going to blow out the noobs in grades, anyway. Is it on a curve?
Yep, that's the question. And it's another reason why I'm against dividing freshmen into groups. Grading two versions of the same class in a way that does not put any group at disadvantage seems very hard to me.
As a second year student with a background in hobby programming [is that the PC word we're using for hacking now?], I am inclined to agree with you greatly.
My university [Auburn] teaches Java first and second semester as the primary language while dropping in things like datastructures, recursion,etc. I think [minus tests] I appeared in both classes about twice and managed triple digit scores in both. Learning a programming language not in my mainstream [C++/Java/C#/ruby] would have been much more interesting than spending 15 minutes every other week coding whatever basic problem has been given.
Nice post, even as someone who is not strictly a programmer and who took "Comp Sci Lite" (MIS).
I think you hit one of the biggest problems in very many majors: people who have lots of prior knowledge and enthusiasm and those who haven't coded anything before and may be coasting for a while. This might not be something the Comp Sci department decides how to handle, but rather maybe how the college decides to market itself in that field. I've known programs at my alma mater that are hard as hell in the first few semesters for the sole purpose of weeding out the chafe while other programs are much more inviting of all skill levels. Others have different higher level tracks for the advanced students...
It's difficult. Some students might have been like me, less enthusiastic about my career and goals in life at that early age while others might be totally digging it and getting into things...yet everyone's paying the same tuitions.
Anyway, I really like the idea you touched upon about making more interesting puzzles and challenges. I wonder if some of the content can be created such that more advanced students can use more advanced techniques to solve those puzzles while the newbies can go by the book. Maybe content can be made to stimulate both groups without being unfair in the grading? Difficult, I know...
I think that creating puzzles that can be solved in different ways is tricky. It's certainly something to think about though.
In the C++ class I TA I can only think of one example that might fit here. Right in the first assignment the students are asked to write a program that determines whether a given integer number contains three 1 bits in a row (as in 7 = 111 or 46 = 101110). Most people write a O(n) loop that iterates over all bits and checks whether three bits in a row are set. Once in a while someone realizes that a O(1) solution is possible using bit-shifts.
Curiously students doing the loop-method learn something valuable from that assignment that people using the shift-method don't learn. Since the students learned Java before, they assume that the size of data types is constant across platforms. Here they learn that this is not true in C++ and how to use the sizeof operator.
Syndicate This Blog