Educating the Next Generation
JB: Do you think programmers should be "armed and dangerous" with their tools like compilers, editors, debuggers, linkers, version control systems and so on very early on in their learning or careers? Do you think that universities should teach debugging and how to program in a certain environment (e.g. Unix) as well, for example?
BS: I'm not 100% sure I understand the question, but I think "yes." I don't think that it should be possible to graduate with a computer science, computer engineering, etc. degree without having used the basic tools you mention above for a couple of major projects. However, it is possible. In some famous universities, I have observed that Computer Science is the only degree you can get without writing a program.
I'm not arguing for mere training. The use of tools must not be a substitute for a good understanding of the principles of programming. Someone who knows all the power-tools well, but not the fundamental principles of software development would indeed be "armed and dangerous." Let me point to algorithms, data structures, and machine architecture as essentials. I'd also like to see a good understanding of operating systems and networking.
Some educators will point out that all of that—together with ever-popular and useful topics such as graphics and security—doesn't fit into a four-year program for most students. Something will have to give! I agree, but I think what should give is the idea that four years is enough to produce a well-rounded software developer: Let's aim to make a five-or-six-year masters the first degree considered sufficient.
JB: What should C++ programmers or any programmer do, in your view, before sitting down to write a substantial software program?
BS: Think. Discuss with colleagues and potential users. Get a good first-order understanding of the problem domain. If possible, try to be a user of an existing system in that field. Then, without too much further agonizing, try to build a simplified system to try out the fundamental ideas of a design. That "simplified system" might become a throwaway experiment or it may become the nucleus of a complete system. I'm a great fan of the idea of "growing" a system from simpler, less complete, but working and tested systems. To try out all the tool chains before making too grand plans.
How would the programmer, designer, team get those "fundamental ideas of a design"? Experience, knowledge of similar systems, of tools, and of libraries is a major part of the answer. The idea of a single developer carefully planning to write a system from the bare programming language has realistically been a myth for decades. David Wheeler wrote the first paper about how to design libraries in 1951—56 years ago!
JB: What type of programs do you personally enjoy writing? What programs have you written recently?
BS: These days I don't get enough time to write code, but I think writing libraries is the most fun. I wrote a small library supporting N-dimensional arrays with the usual mathematical operations. I have also been playing with regular expressions using the (draft) C++0x library (the boost.org version).
I also write a lot of little programs to test aspects of the language, but that's more work than fun, and also small programs to explore application domains that I haven't tried or haven't tried lately. It is a rare week that I don't write some code.
JB: In your experience, have there been any features of C++ that newcomers to the language have had the most difficulty with? Would you have any advice for newcomers to C++ or have you found a way of teaching difficult features of C++ saving students a lot of trial and error?
BS: Some trial and error is inevitable, and may even be good for the newcomer, but yes I have some experience introducing C++ to individuals and organizations—some of it successful. I don't think it's the features that are hard to learn, it is the understanding of the programming paradigms that cause trouble. I'm continuously amazed at how novices (of all backgrounds and experiences) come to C++ with fully formed and firm ideas of how the language should be used. For example, some come convinced that any techniques not easily used in C is inherently wrongheaded, hard to use, and very inefficient. It's amazing what people are willing to firmly assert without measurements and often based on briefly looking at C++ a decade ago using a compiler that was hardly out of beta—or simply based on other people's assertions without checking if they have a basis in reality. Conversely, there is now a generation who is firmly convinced that a program is only well-designed if just about everything is part of a class hierarchy and just about every decision is delayed to run-time. Obviously programs written by these "true OO" programmers become the best arguments for the "stick to C" programmers. Eventually, a "true OO" programmer will find that C++ has many features that don't serve their needs and that they indeed fail to gain that fabled efficiency.
To use C++ well, you have to use a mix of techniques; to learn C++ without undue pain and unnecessary effort, you must see how the language features serve the programming styles (the programming paradigms). Try to see concepts of an application as classes. It's not really hard when you don't worry too much about class hierarchies, templates, etc. until you have to.
Learn to use the language features to solve simple programs at first. That might sound trivial, but I receive many questions from people who have "studied C++" for a couple of weeks and are seriously confused by examples of multiple inheritance using names like B1, B2, D, D2, f, and mf. They are—usually without knowing it—trying to become language lawyers rather than programmers. I don't need multiple inheritance all that often, and certainly not the tricky parts. It is far more important to get a feel for writing a good constructor to establish an invariant and understand when to define a destructor and copy operations. My point is that the latter is almost instantly useful and not difficult (I can teach it to someone who has never programmed after a month). The finer details of inheritance and templates, on the other hand, are almost impenetrable until you have a real-world program that needs it. In The Art of Computer Programming Don Knuth apologizes for not giving good examples of co-routines, because their advantages are not obvious in small programs. Many C++ features are like that in that: They don't make sense until you face a problem of the kind and scale that needs that feature.
JB: Do you have any suggestions for people who are not programmers and want to learn how to program, and want to learn C++ as their first language? For instance, there's a book called Accelerated C++: Practical Programming by Example by Andrew Koenig and Barbara E. Moo. This book's approach is to teach by using the STL and advanced features at an early stage, like using strings, vectors and so on, with the aim of writing "real" programs faster. Would you agree that it's best to begin "the C++ way" if you could call it that, instead of starting off with a strictly procedural style and leaving classes, the Standard Library and other features often preceded with "an introduction to OOP" much later in a book?
BS: I have had to consider this question "for real" and have had the opportunity to observe the effects of my theories. I designed and repeatedly taught a freshman programming course at Texas A&M University. I use standard library features, such as string, vector, and sort, from the first week. I don't emphasize STL; I just use the facilities to have better types with which to introduce the usual control structures and programming techniques. I emphasize correctness and error handling from day 1. I show how to build a couple of simple types in lecture 6 (week three). I show much of the mechanisms for defining classes in lectures 8 and 9 together with the ways of using them. By lecture 10 and 11, I have the students using iostreams on files. By then, they are tired, but can read a file of structured temperature data and extract information from it. They can do it 6 weeks after seeing their first line of code. I emphasize the use of classes as a way of structuring code to make it easier to get right.
After that comes graphics, including some use of class hierarchies, and then comes the STL. Yes, you can do that with complete beginners in a semester. We have by now done that for more than 1,000 students. The reason for putting the STL after graphics is purely pedagogical: after iostreams the students are thoroughly tired of "calculations and CS stuff," but doing graphics is a treat! The fact that they need the basics of OOP to do that graphics is a minor detail. They can now graph the data read and fill class objects from a GUI interface.
JB: I read an interview in Texas A&M Engineering Magazine where you said, "I decided to design a first programming course after seeing how many computer science students—including students from top schools—lacked fundamental skills needed to design and implement quality software..." What were these fundamental skills students lacked, and what did you put in your programming course to address this issue?
BS: I saw so many students who simply didn't have the notion that code itself is a topic of interest and that well-structured code is a major time saver. The notion of organizing code to be sure that it is correct and maybe even for someone else to use and modify is alien: They see code as simply something needed to hand in the answers to an exercise. I am of course not talking about all students or just students from one university or from one country.
In my course I heavily emphasize structure, correctness, and define the purpose of the course as "becoming able to produce code good enough for the use of others." I use data structures and algorithms, but the topic of the course is "programming" not fiddling with pointers to implement a doubly linked list.
And yes, I do teach pointers, arrays, and casts, but not until well after strings, vectors, and class design. You need to give the students a feel of the machine as well as the mechanisms to make the (correct) use of the machine simple. This also reflects comments I have repeatedly had from industry: that they have a shortage of developers who understand "the machine" and "systems."
JB: You have said that a programmer must be able to think clearly, understand questions and express solutions. This is in agreement with G. Polya's thesis that you must have a clear and complete understanding of a question before you can ever hope to solve it. Would you recommend supplementary general reading like G. Polya's book, How to Solve It along with reading books on programming and technique? If so, what books would you recommend?
BS: I avoid teaching "how to think." I suspect that's best taught through lots of good examples. So I give lots of good examples (to set a standard) including examples of gradual development of a program from early imperfect versions. I'm not saying anything against Polya's ideas, but I don't have the room for it in my approach. The problem with designing a course (or a curriculum) is more what to leave out than what to add.
JB: What are the most useful mathematical skills, generally, that a programmer should have an understanding of if they intend to become professional, in your view? Or would there be different mathematical skills a programmer should know for different programmers and different tasks? If this is the case could you give examples?
BS: I don't know. I think of math as a splendid way to learn to think straight. Exactly what math to learn and exactly where what kinds of math can be applied is secondary to me.