Seibel: What’s the biggest system that you’ve worked on that youremember how it was designed?
Deutsch: I’ve been the primary mover on three large systems.Ghostscript—not counting the device drivers, which I didn’t write mostof—was probably somewhere on the order of between 50,000 and 100,000lines of C.
On the ParcPlace Smalltalk virtual machine I worked only on the just-in-timecompiler, which was probably 20 percent of it, and that was probably in thelow single-digit thousands of lines of C. Maybe 3,000, 5,000—something likethat.
And the Interlisp implementation, as much of it as I was concerned with,was probably a couple thousand lines of microcode, and maybe—I’mguessing now—maybe another 5,000 lines of Lisp. So Ghostscript isprobably the largest single system I’ve ever been involved with.
Seibel: And other than the device drivers written by other people, youbasically wrote that by yourself.
Deutsch: Up to the end of 1999, I basically wrote every line of code. Atthe beginning I made a few architectural decisions. The first one was tocompletely separate the language interpreter from the graphics.
Seibel: The language being PostScript?
Deutsch: Right. So the language interpreter knew nothing about the datastructures being used to do the graphics. It talked to a graphics library thathad an API.
The second decision I made was to structure the graphics library using adriver interface. So the graphics library understood about pixels and itunderstood about curve rendering and it understood about text renderingbut it knew as little as I could manage about how pixels were encoded for aparticular device, how pixels were transmitted to a particular device.
The third decision was that the drivers would actually implement the basicdrawing commands. Which, at the beginning, were basically draw-pixmap andfill-rectangle.
So the rendering library passed rectangles and pixel arrays to the driver.And the driver could either put together a full-page image if it wanted to or,for display, it could pass them through directly to Xlib or GDI or whatever.So those were the three big architectural decisions that I made up front andthey were all good ones. And they were pretty much motherhood. I guessthe principle that I was following was if you have a situation where you havesomething that’s operating in multiple domains and the domains don’tinherently have a lot of coupling or interaction with each other, that’s agood place to put a pretty strong software boundary.
So language interpretation and graphics don’t inherently interact with eachother very much. Graphics rendering and pixmap representation interactmore, but that seemed like a good place to put an abstraction boundary aswell.
In fact I wrote a Level 1 PostScript interpreter with no graphics before Iwrote the first line of graphics code. If you open the manual and basically gothrough all the operators that don’t make any reference to graphics, Iimplemented all of those before I even started designing the graphics. I hadto design the tokenizer; I had to decide on the representation of all thePostScript data types and the things that the PostScript manual says theinterpreter has to provide. I had to go back and redo a lot of them when wegot to PostScript Level 2, which has garbage collection. But that’s where Istarted.
Then I just let my experience with language interpreters carry me into thedesign of the data structures for the interpreter. Between the time that Istarted and the time that I was able to type in 3 4 add equals and have itcome back with 7 was about three weeks. That was very easy. And by theway, the environment in which I was working—MS-DOS. MS-DOS with astripped-down Emacs and somebody’s C compiler; I don’t rememberwhose.
Seibel: This was a task that you had done many times before, namelyimplementing an interpreter for a language. Did you just start in writing Ccode? Or fill up a notebook with data-structure diagrams?
Deutsch: The task seemed simple enough to me that I didn’t bother towrite out diagrams. My recollection was that first I sort of soaked myself inthe PostScript manual. Then I might have made some notes on paper butprobably I just started writing C header files. Because, as I say, I like todesign starting with the data.
Then I had some idea that, well, there’d have to be a file with a maininterpreter loop. There’d have to be some initialization. There’d have to bea tokenizer. There’d have to be a memory manager. There’d have to besomething to manage the PostScript notion of files. There’d have to beimplementation of the individual PostScript operators. So I divided those upinto a bunch of files sort of by functionally.
When I took the trouble of registering the copyright in the Ghostscriptcode I had to send them a complete listing of the earliest Ghostscriptimplementation. At that point it was like 10 years later—it was interestingto me to look at the original code and the original structure and the originalnames of various things and to note that probably 70 or 80 percent of thestructure and naming conventions were still there, 10 years and 2 majorPostScript language revisions later.
So basically that’s what I did—data structures first. Rough division intomodules. My belief is still, if you get the data structures and their invariantsright, most of the code will just kind of write itself.
Seibel: So when you say you write a header file, is that to get the functionsignatures or the structs, or both?
Deutsch: The structs. This was 1988, before ANSI C—there weren’tfunction signatures. Once ANSI C compilers had pretty much become thestandard, I took two months and went through and I made functionsignatures for every function in Ghostscript.
Seibel: How has your way of thinking about programming or your practiceof programming, changed from those earliest days to now?
Deutsch: It’s changed enormously because the kinds of programs that I findinteresting have changed enormously. I think it’s fair to say that theprograms that I wrote for the first few years were just little pieces of code.
Over time I’ve considered the issues of how do you take a program thatdoes something larger and interesting and structure it and think about it,and how do you think about the languages that you use for expressing it in away that manages to accomplish your goals of utility, reliability, efficiency,transparency?
Now I’m aware of a much larger set of criteria for evaluating software. AndI think about those criteria in the context of much larger and more complexprograms, programs where architectural or system-level issues is where allthe hard work is. Not to say that there isn’t still hard work to be done inindividual algorithms, but that’s not what seems most interesting to me anymore—hasn’t for a long time.
Seibel: Should all programmers grow up to work at that level?
Deutsch: No. In fact, I was just reading that an old friend of mine fromXerox PARC, Leo Guibas, just received some fairly high award in the field.He has never really been a systems guy in the sense that I’ve been; he’s beenan algorithms guy—a brilliant one. He’s found a way to think about certainclasses of analysis or optimization algorithms in a way that’s made themapplicable to a lot of different problems, and that has yielded new tools forworking with those problems. So, it’s wonderful work. Programmers shouldbe able to grow up to be Leo Guibas, too.
There’s a parallel between architectural principles and the kinds ofalgorithmic design principles that Leo and people like him use to addressthese hard optimization and analysis problems. The difference is that theprinciples for dealing with algorithmic problems are based a lot moredirectly on 5,000 or10,000 years’ worth of history in mathematics. How wego about programming now, we don’t have anything like that foundation tobuild on. Which is one of the reasons why so much software is crap: wedon’t really know what we’re doing yet.