Seibel: Did that kind of thing get folded into any kind of automatedtesting?

Zawinski: No, when I was writing unit tests like that for my codethey would basically only run when I ran them. We did a little bit ofthat later with Grendel, the Java rewrite, because it was just so mucheasier to write a unit test when you write a new class.

Seibel: In retrospect, do you think you suffered at all because of that?Would development have been easier or faster if you guys had beenmore disciplined about testing?

Zawinski: I don’t think so. I think it would have just slowed us down.There’s a lot to be said for just getting it right the first time. In theearly days we were so focused on speed. We had to ship the thingeven if it wasn’t perfect. We can ship it later and it would be higherquality but someone else might have eaten our lunch by then.

There’s bound to be stuff where this would have gone faster if we’dhad unit tests or smaller modules or whatever. That all sounds great inprinciple. Given a leisurely development pace, that’s certainly the wayto go. But when you’re looking at, “We’ve got to go from zero todone in six weeks,” well, I can’t do that unless I cut something out.And what I’m going to cut out is the stuff that’s not absolutely critical.And unit tests are not critical. If there’s no unit test the customer isn’tgoing to complain about that. That’s an upstream issue.

I hope I don’t sound like I’m saying, “Testing is for chumps.” It’s not.It’s a matter of priorities. Are you trying to write good software orare you trying to be done by next week? You can’t do both. One ofthe jokes we made at Netscape a lot was, “We’re absolutely 100percent committed to quality. We’re going to ship the highest-qualityproduct we can on March 31st.”

Seibel: That leads to another topic, maintaining software. How doyou tackle understanding a piece of code that you didn’t write?

Zawinski: I just dive in and start reading the code.

Seibel: So where do you start? Do you start at page one and readlinearly?

Zawinski: Sometimes. The more common thing is learning how touse some new library or toolkit. If you’re lucky there’s somedocumentation. There’s an API. So you figure out the piece of it youmight be interested in using. Or work out how that was implemented.Thread your way through. Or with something like Emacs, maybe startat the bottom. What are cons cells made of? How’s that look? Andthen skip around from there. Sometimes starting with the build systemcan give you an idea how things fit together. I always find that a goodway to sort of immerse yourself in a piece of code is pick a task youwant to accomplish and then try and do it.

With something like Emacs you might do that by taking an existingmodule and gutting it. OK, now I’ve got this piece of code. Rip out thepart that actually does anything and now I’ve got the boilerplate. OK,now I know what a component of this system looks like and I can startputting my stuff back in. Sort of stripping it down to the frame.

Seibel: In Emacs you ended up rewriting the byte-code compiler andbits of the byte-code VM. And we’ve talked about how it’s more funto rewrite stuff than to fix it, but it’s not always a good idea. I wonderhow do you draw that line? Do you think that you chose to rewritethe whole compiler because it was really easier than fixing it morelocally? Or was it just, “Hey! It’d be fun to write a compiler.”

Zawinski: It sort of just turned into a rewrite. It started with me justfixing it and trying to add optimizations to it. And then eventuallythere wasn’t any of the original left. I ended up using the same APIsuntil then they were gone. I think the byte-code compiler worked outfine. Partly because that was such an isolated module. There’s onlyone entry point: compile and save.

There was definitely a lot of stuff that I put into Lucid Emacs that wasmore gratuitous than that. Really, a lot of the stuff I did was motivatedby wanting it to be more like Lisp machines. Wanting it to be morelike the Emacs I was familiar with. Which really was the Lispenvironment I was familiar with. So I put in a lot of stuff to try to makeEmacs be a less half-assed Lisp in a lot of ways: there should be eventobjects instead of a list with a number in it. Having an event object bea list with a number in it—that’s just tasteless. It’s icky. And inretrospect, those changes were some of the biggest problems. Thosekind of changes caused compatibility problems with third-partylibraries.

Seibel: Of course you didn’t know there were going to be two Emacsat that point.

Zawinski: Sure. But even without that, even if there had only beenone Emacs, there were still two Emacs—there was Emacs 18 andEmacs 19. There was still going to be a compatibility problem. Inhindsight those were changes that if I’d realized what an impact it wasgoing to make, I probably would have done that differently. Or spent alot more time on making the old way work as well. That kind of thing.

Seibel: Earlier you said something about writing code in order tomake it easier to read, which ties into maintenance. What are thecharacteristics that make code easier to read?

Zawinski: Well, comments obviously. Writing down what theassumptions are and what this does. If it’s building up a data structure,describing the layout of it. A lot of times I find that pretty helpful.Especially in writing Perl code when it’s like, uh, well, it’s a hash tableand values are bunch of references to lists, because the data structuresin Perl are just nuts. Do I need a right arrow here to get to this? I findexamples like that to be helpful.

I always wish people would comment more, though the thing thatmakes me cringe is when the comment is the name of the functionrephrased. Function’s called push_stack and the comment says, “Thispushes to the stack.” Thank you.

You’ve got to say in the comment something that’s not there already.What’s it for? Either a higher-level or a lower-level description,depending on what’s most important. Sometimes the most importantthing is, what is this for? Why would I use it? And sometimes the mostimportant thing is, what’s the range of inputs that this expects?

Long variable names. I’m not a fan of Hungarian notation, but I thinkusing actual English words to describe things, except for loopiterators, where it’s obvious. Just as much verbosity as possible, Iguess.

Seibel: What about organization—ultimately there’s some linearorganization but programs are not really linear. Do you organize yourcode top-down or bottom-up?

Zawinski: I usually end up putting the leaf nodes up at the top of thefile—try to keep it basically structured that way. And then usually upat the top, document the API. What are the top-level entry points ofthis file, this module, whatever? With an object-y language, that’s doneby the language for you. With C you’ve got to be a little more explicitabout that. In C I do tend to try to have a .h file for every .c file thathas all the externs for it. And anything that’s not exported in the .h fileis static. And then I’ll go back and say, “Wait, I need to call that,” and Ichange it. But you’re doing that explicitly rather than just by accident.

Seibel: You put the leaves first in the file, but is that how you write?Do you build up from leaves?

Zawinski: Not always. Sometimes I start at the top and sometimes Istart at the bottom. It depends. One way is, I know I’m going to needthese building blocks and I’ll put those together first. Or another wayof thinking about it is, you’ve sort of got an outline of it in your headand you dig down. I do it both ways.

Seibel: So suppose for the sake of argument that you were going tocome out of retirement and build a development team. How wouldyou organize it?


Перейти на страницу:
Изменить размер шрифта: