But there’s a discrete and a continuous way to get your mind aroundinfinity. I think that for a programmer it’s more important to have masteredthe discrete way. For example, I just mentioned induction proofs. You canprove something true for all integers. It’s kind of magical. You prove it forone integer and you prove that one implies the next and then you’ve provedit for all of them. And I think that is more important for a programmer than,let’s say, understanding the notion of limits.

Luckily we don’t have to make a choice. I think that there’s plenty of roomin the curriculum for both. So even if you’re not going to use the calculus asmuch as you use the discrete mathematics, I think it should still get taught.But I think that the importance of the discrete stuff is greater than that ofthe continuous.

Seibel: You talked before about how writing prose has many similarcharacteristics to programming. While mathematics has always been closelyassociated with computers and programming, I wonder if once you’retalking about developing things like web frameworks or a web application ontop of a framework, if it requires skills more related to writing.

Bloch: Yes—earlier you mentioned that there were two distinctcommunities of Java programmers. The need for math is much greater inthe community that writes libraries, compilers, and frameworks. If you writeweb applications on top of frameworks, you have to understandcommunication, both verbal and visual. I get infuriated at web sites whenthey drive me to do the wrong thing. It’s clear that someone just hasn’tthought about how someone approaching this thing will deal with it. So yes,the truth of the matter is that programming is at the confluence of a wholebunch of disciplines. And depending on which ones you excel at, you will bebetter at writing different applications. But even libraries, compilers, andframeworks have to be readable and maintainable. I contend that you’ll havea hard time achieving that goal if you aren’t a competent writer.

Seibel: What is your process for designing software? Do you fire up Emacsand start writing code and then move it around until it looks right? Or doyou sit down on your couch with a pad of paper?

Bloch: I gave a talk called “How to Design a Good API and Why ItMatters” at OOPSLA a couple years ago, and several versions of it arefloating around the Web. It does a pretty good job explaining how I goabout it.

The most important thing is to know what you’re trying to build: whatproblem you’re trying to solve. The importance of requirements analysiscan’t be overstated. There are people who think, “Oh, yeah, requirementsanalysis; you go to your customer, you say, ‘What do you need?’ He tellsyou, and you’re done.”

Nothing could be further from the truth. Not only is it a negotiation but it’sa process of understanding. Many customers won’t tell you a problem;they’ll tell you a solution. A customer might say, for instance, “I need you toadd support for the following 17 attributes to this system. Then you have toask, ‘Why? What are you going to do with the system? How do you expectit to evolve?’” And so on. You go back and forth until you figure out what allthe customer really needs the software to do. These are the use cases.

Coming up with a good set of use cases is the most important thing you cando at this stage. Once you have that, you have a benchmark against whichyou can measure any possible solution. It’s OK if you spend a lot of timegetting it reasonably close to right, because if you get it wrong, you’realready dead. The rest of the process will be an exercise in futility.

The worst thing that you can do—and I’ve seen this happen—is you get abunch of smart guys into a room to work for six months and write a 247-pagesystem specification before they really understand what it is they’retrying to build. Because after six months, they’ll have a very preciselyspecified system that may well be useless. And often they say, “We’veinvested so much in the spec that we have to build it.” So they build theuseless system and it never gets used. And that’s horrible. If you don’t haveuse cases, you build the thing and then you try to do something very simpleand you realize that, “Oh my gosh, doing something very simple like takingan XML document and printing it requires pages upon pages of boilerplatecode.” And that’s a horrible thing.

So get those use cases and then write a skeletal API. It should be really,really short. The whole thing should, usually, fit on a page. It doesn’t have tobe terribly precise. You want declarations for the packages, classes, andmethods and, if it’s not clear what they should do, then maybe a onesentencedescription for each. But this is not documentation of the qualitythat you will end up distributing.

The whole idea is to stay agile at this stage, to flesh the API out just enoughthat you can take the use cases and code them up with this nascent API tosee if it it’s up to the task. It’s just amazing, there are so many things thatare obvious in hindsight but when you’re designing the API, even with theuse cases in mind, you get them wrong. Then when you try to code up theuse cases you say, “Oh, yeah, this is fundamentally wrong; I have too manyclasses here; these should be combined, these need to be broken out,”whatever it is. Luckily, your API doc is only a page long, so it’s easy to fix it.

As your confidence in the API increases, then you flesh it out. But thefundamental rule is, write the code that uses the API before you write thecode that implements it. Because otherwise you may be wasting your timewriting implementation code that won’t get used. In fact, write the codethat uses the API before you even flesh out the spec, because otherwise youmay be wasting your time writing detailed specs for something that’sfundamentally broken. That’s how I go about designing stuff.

Seibel: And how specific is this to designing things like the Java collections,which are a particular kind of self-contained API?

Bloch: I claim it’s less specific than you might think. Programming of anycomplexity requires API design because big programs have to be modular,and you have to design the intermodular interfaces.

Good programmers think in terms of pieces that make sense in isolation,for several reasons. One is that you, perhaps inadvertently, end upproducing useful, reusable modules. If you write a monolithic system and,when it gets too big, you tear it into pieces, there will likely be no clearboundaries, and you’ll end up with unmaintainable sewage. So I claim thatit’s simply the best way to program, whether you consider yourself an APIdesigner or not.

That said, the world of programming is very large. If programming for you iswriting HTML, it’s probably not the best way to program. But I think thatfor many kinds of programming, it is.

Seibel: So you want a system that’s made up of modules that are cohesiveand loosely coupled. These days there’s at least two views on how you canget to that point. One is to sit down and design these intermodule APIs inadvance, the process that you’re talking about. And the other is this“simplest thing that could possibly work, refactor mercilessly” approach.

Bloch: I don’t think the two are mutually exclusive. In a sense, what I’mtalking about is test-first programming and refactoring applied to APIs. Howdo you test an API? You write use cases to it before you’ve implemented it.Although I can’t run them, I am doing test-first programming: I’m testing thequality of the API, when I code up the use cases to see whether the API isup to the task.

Seibel: So you write the client code to use the API and then look at it andask, “Is this code I would want to write?”

Bloch: Absolutely. Sometimes you don’t even get to the stage where youcan look at the client code. You try to write it and you say either, “I cannotdo this at all because I forgot this piece of functionality in the API,” or, “Ican do this but it’s going to be so tedious that this was not the rightapproach.”


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