Выбрать главу

Crockford: Yeah, definitely, because I believe I’m using the only correct style and everybody else got it wrong! I think Thompson and Ritchie did the world a disservice by not defining the pretty-print presentation for C. Saying, “This is how we do it, but you can do it some other way,” has had a huge toll on humanity, and it will probably continue to always have one.

Seibeclass="underline" So your preferred style is K&R?

Crockford: Yeah, I think they got it right. Their initial style is right. Particularly in JavaScript. JavaScript does semicolon insertion, and so there are places where the meaning of a program will change in a drastically bad way if you put the braces on the left instead of on the right. It turns out the K&R style is not subject to that problem, but the flush style is.

So I can argue in the case of JavaScript, there absolutely is a correct way of placing the braces. In other C-flavored languages I can’t make that same case. Some people like to have their braces flush and I’ve seen people argue for hours about which way is right, and none of the explanations make any sense on either side, because what they’re really arguing is, what I used in school, or what I used at my first job, or the style that’s used by someone who impressed me, now looks right to me and everything else looks wrong.

It’s similar, I suppose, to an argument about, should we be driving on the left side of the street or the right. Ultimately there’s not a good case for doing it one way or another. If you live on an island, you can do it the wrong way and it doesn’t matter, but ultimately the community benefits if we can all figure out how to drive on the same side.

Seibeclass="underline" So if you changed jobs and went somewhere where they programmed C or Java in a different style than you prefer, would you say, “Well, I’ll switch and I know that after a little bit, I’ll be happy to see this style”? Or would you just not take the job?

Crockford: Maybe that’s something that people should look at—what is the house of style here? Are we on the left or the right? And maybe not go work at a place that gets them on the wrong side. It does take on a Dr. Seuss quality where you get really upset about whether you’ve got a star on your belly or not. Ultimately you have to embrace the house style and you hope that the people who put the house style together knew what they were doing. They probably didn’t; maybe it doesn’t matter. It’s more important that everybody be on the same page.

Seibeclass="underline" So when you’re reading code you start with a typographical cleanup, how deeply or dramatically do you refactor things?

Crockford: I’ll rearrange code so that everything is declared and set up before it’s called. Some languages give you a lot of flexibility around that so you don’t have to. I don’t want that flexibility.

Seibeclass="underline" So you want no forward references?

Crockford: Right, or if there is a forward reference, I want it to be explicit. I don’t want code to come in any random order unless I’m doing a literate programming thing in which I’m explicitly breaking the code in terms of a presentational order rather than the order that the language wants, and I like that a lot. But unless you’re actually using literate tools, you shouldn’t be doing that.

Seibeclass="underline" In one of your talks you quoted Exodus 23:10 and 11: “And six years thou shalt sow thy land, and shalt gather in the fruits thereof: But the seventh year thou shalt let it rest and lie still” and suggested that every seventh sprint should be spent cleaning up code. What is the right time frame for that?

Crockford: Six cycles—whatever the cycle is between when you ship something. If you’re on a monthly delivery cycle then I think every half year you should skip a cycle and just spend time cleaning the code up.

Seibeclass="underline" So if you don’t clean up every seventh cycle you may be faced with the choice of whether or not to do a big rewrite. How do you know when, if ever, it’s time for a big rewrite?

Crockford: Generally the team knows when it’s time. Management finds out a lot later. The team is getting beat up pretty regularly, making too many bugs; the code’s too big, it’s too slow; we’re falling behind. They know why. It’s not because they became stupider or lazier. It’s because the code base is no longer serving the purpose that it needs to.

It’s a really difficult thing for management to see, particularly managers who are not programmers. But even programming managers have trouble with this because you’ve seen that you’ve invested so much time to get to this point. And starting over means we’ve got to go all the way back to there and bring it up. And in the meantime we’re not going to be going forward on anything else and it’s just impossible. No, we go forward with what we have.

The fallacy is that it’s going to take that amount of time again, though there are counterexamples. You’ve got the second-system problem where people who’ve had some success are given a blank slate and allowed to do whatever they want. Generally, they will fail because they’ll be too ambitious, they won’t understand the limits. And you get nothing out of that. You have to have extreme discipline to say, “It’s not a blank slate; it’s reimplementing what we had here; it’s doing what we knew.”

Part of what makes programming difficult is most of the time we’re doing stuff we’ve never done before. If it was stuff that had been done before we’d be reusing something else. For most of what we do, we’re doing something that we haven’t done before. And doing things that you haven’t done before is hard. It’s a lot of fun but it’s difficult. Particularly if you’re using a classical methodology you’re having to do classification on systems that you don’t fully understand. And the likelihood that you’re going to get the classification wrong is high.

Seibeclass="underline" By “classical” you mean using classes.

Crockford: Right. I’ve found it’s less of a problem in the prototypal world because you focus on the instances. If you can find one instance which is sort of typical of what the problem is, you’re done. And generally you don’t have to refactor those. But in a classical system you can’t do that—you’re always working from the abstract back to the instance. And then making hierarchy out of that is really difficult to get right. So ultimately when you understand the problem better you have to go back and refactor it. But often that can have a huge impact on the code, particularly if the code’s gotten big since you figured it out. So you don’t. So you keep bundling these new things on top of it to try to patch the problems that were in the original hierarchy and it gets cruftier and worse.

Seibeclass="underline" But you do think that refactoring can work, if you take every seventh interval to do it? You don’t have to end up needing a big rewrite?

Crockford: I think it can work. Throw it out and start over should only be considered in the cases where you didn’t do that or you did it badly or something went wrong and you’ve got a code base that has become unworkable. And you can make a reasonable judgment that it will be faster to replace it than to fix it.

Seibeclass="underline" What about the risk that you don’t fully understand what the code you want to rewrite actually does. Because any piece of code contains bits of embedded knowledge—little bits of cruft that are hard-won functionality that you don’t think of when you say, “Oh, we can just rewrite this.”

Crockford: That is a real problem. One of the reasons that we’re in the mess that we’re in is that the Web is so poorly specified. The specifications were incomplete and were largely misinterpreted and many of those misinterpretations have become part of the canon. So these systems are way more complicated than they should be due to those historical reasons. Working at that level, yeah, I have huge sympathy for that, that there is a lot of undocumented knowledge that is reflected in the code base.