Изменить стиль страницы

Seibel: How do you design code?

Eich: A lot of prototyping. I used to do sort of high-level pseudocode, and then I’d start filling in bottom up. I do less of the high-level pseudocode because I can usually hold it in my head and just do bottom-up until it joins. Often I’m working with existing pieces of code adding some new subsystem or something on the side and I can almost do it bottom-up. When I get in trouble in the middle I do still write pseudo-code and just start working bottom up until I can complete it. I try not to let that take too long because you’ve got to be able to test it; you’ve got to be able to see it run and step through it and make sure it’s doing what it’s supposed to be doing.

Before that level of design, there may be some entity relationships or gross modularization. There’s probably an algorithm or three that we’re thinking of where you’re reasoning about the complexity of it—is it linear? Is it constant? Every time I’ve written some kind of linear search that’s going to compound quadratically, and unleashed it on the Web, web developers have found that to be a problem. They’ve written enough stuff it stresses it. So we tend to do a lot of data structures that are constant time. And even then, constant can be not one—it can be big enough that you care.

So we do lots of prototyping, we do lots of bottom-up and top-down and they meet in the middle. And I think actually we, at Mozilla, don’t do enough rewriting. We’re very conservative. We are open source, so we have community we try to build and bring new people into. We certainly have value that users benefit from, and we don’t want to take a three-year break rewriting, which is what would happen if we tried too much.

But if you really are trying to move a needle and you don’t know exactly what you’re doing, rewrite. It’s going to take several tries to know what the hell you’re doing. And then when you have a design more firm you’ll stick with it and you’ll start patching it more, and you’ll get to this mature state where we creak with patches. It’s kind of an evolutionary dead-end for code. You know, maybe it’s a good sunk cost and you can stand on it for years. Maybe it’s this thing that’s crying out for replacement. Maybe in the open-source world some better standard library has emerged.

And that gets back to the craft of programming, I think. You don’t just write code based on some old design. You want to keep practicing, and the practicing involves thinking about design and feeding back your experience in coding to the design process.

I have this big allergy to ivory-tower design and design patterns. Peter Norvig, when he was at Harlequin, he did this paper about how design patterns are really just flaws in your programming language. Get a better programming language. He’s absolutely right. Worshipping patterns and thinking about, “Oh, I’ll use the X pattern.”

Seibel: So newer experiences can show you better ways going forward. But what about when writing the code shows you big flaws in your existing design?

Eich: That does happen. It happens a lot. Sometimes it’s difficult to throw out and go back to square one. You’ve already made commitments, and you get into this trap. I did this with JavaScript. In a great big hurry, I wrote a byte-code interpreter. Even at the time I knew I was going to regret some of the things I’d done. But it was a design that was understandable to other people and I could hope to get other people helping me work on. So I question design all the time. I just realize that we don’t always get the luxury of revisiting our deepest design decisions. And that is where we then attempt to do a big rewrite, because you really would have a hard time incrementally rewriting to change deep design decisions.

Seibel: How do you decide when it’s right to do a big rewrite? Thanks to Joel Spolsky, Netscape is in some ways the poster child for the dangers of the big rewrite.

Eich: There was an imperative from Netscape to make the acquisition that waved the Design Patterns book around feel like they were winners by using their new rendering engine, which was like My First Object-Oriented Rendering Engine. From a high level it sounded good; it used C++ and design patterns. But it had a lot of problems.

But the second reason we did the big rewrite—I was in mozilla.org and I really was kind of pissed at Netscape, like Jamie, who was getting ready to quit. I thought, you know, we need to open up homesteading space to new contributors. We can’t do it with this old hairball of student code from 1994. Or my fine Unix kernel-style interpreter code.

We needed to do a fairly big reset. Yeah, we were going to be four years from shipping. At that point I don’t think we were telling upper management that because they didn’t want to hear it, so we were optimizing to them. And that cost some of the management their heads. Though they all made out fabulously on the options—much better than I did. But for Mozilla that was the right trade.

We were lucky in hindsight, because we could have had a more rapid evolution of the Web. Microsoft was—some people claim this was due to the antitrust case more than their nature—inclined to sit on the Web and stagnate it. So that gave us time to wave the standards flag—which is twoedged and half bullshit—and go rewrite. Like Joel, I’m skeptical of rewrites. I think it’s rare to find that kind of an alignment of interests and get enough funding to live through it and not miss the market. The exceptions are very rare.

The rewrites I was speaking of earlier, though, were when you’re prototyping. That’s critical and smaller-scale. It may be a cross-cutting change to a big pile of code so it’s small in lines, but it’s big in reach and all the invariants you have to satisfy. Or maybe it’s a new JIT or whatever, and that you can get away with.

Seibel: Have you ever done any literate programming, a la Knuth?

Eich: I followed the original stuff. It was very neat. I liked it. It was word retrieval. He had some kind of a hash-trie data structure and it was all literately programmed. Then Doug McIlroy came along and did it all with a pipeline.

Our programs are heavily commented but we don’t have any way of extracting the prose and somehow making it be checked by humans, if not automatically, against the code. Python people have done some more interesting work there. I have not done anything more than heavily comment. I do go back and maintain comments—it’s a real pain and sometimes I don’t do it and then I regret it because somebody gets a bum steer.

I actually like McIlroy’s rejoinder. It wasn’t a rebuttal of literate programming—but it was kind of. You don’t want to write too many words, prose or code. In some ways the code should speak for itself at the small level. It’s at the bigger level, the big monster function or the module boundary, that you need docs. So doc comments or things like them—doc strings. Embedding the test in the comment. I guess that’s the big Python thing. That’s good.

There is something to literate programming, especially these integrated tests and doc strings. I’d like to see more of that supported by languages. We tried to add doc comments of some sort to ES4 with first-class metadata hooks or reflection hooks and it was just impossible to get everybody to agree.

Seibel: Do you read code you’re not working on?

Eich: I do it as part of my job. Code review is a mandatory pre-check-in step, mostly to compensate for Netscape’s bad hiring, but we kept it and still use it for integration review. We have a separate “super review” for when you’re touching a lot of modules and you don’t know all the hidden invariants that Joe Schmoe, who no longer works on Mozilla, knew in his head. Somebody else may have figured them out so you have somebody experienced to look at the big picture. Sometimes you can bypass it if you know what you’re doing and you’re in the sort of Jedi council, but we’re not trying to cheat on it too much.