Andy: It depends. There have been lots of times where I’ve done test-driven design, test-first design, and it’s saved my bacon. I’ve had some times where that’s been less appropriate, where it’s something more exploratory and I’ll go more bottom-up. You know, develop something first, kind of play with it, and then quantify the unit test and work from there. As with most things, the real danger is dogmatism where “this is my hammer and everything looks like a nail.”
That’s what you want to avoid. You always want to use the right tool for the job in the right context. So I’m a fan of test-first development. I don’t always do it. It’s not always appropriate.
It’s the same with anything else. You know, pair programming or even big up-front design. There are some cases where that’s actually the best way to go. There are more cases where it’s not, but every technique has its place somewhere in the world in some context.
Ed: Several of the people I’ve interviewed had some things to say about the intrinsic value of the tests in a software system. Do you have anything to say about that?
Andy: Some venture capitalist type once asked me where the real value was in a software system, and he was thinking it was in the source code and we were trying to convince him that, no, that’s actually not the case.
If you think about it, the most valuable part of a well-constructed software system is not the code itself. It’s the unit tests. That actually defines the behavior of the system. It is a functional working specification. In terms of intellectual property, that’s actually far more valuable, ’cause given that you could re-create the source code in any number of ways, the source code becomes far more disposable when you think of it that way.
Ed: Right. Isn’t it the case that the unit tests represent a very, very specific and strongly constrained set of requirements?
Andy: Yes, absolutely, and whatever you choose to do that happens to fulfill them, that’s a much larger set. There’s the system that happened to be written, but that doesn’t preclude writing a completely different one that would fulfill the same requirements and provably so.
Ed: Yes, it’s proven that automated testing is a bulwark against human nature. But here’s a situation often faced by human programmers. Let’s say it’s late at night, you’re up against a deadline, and you’re desperate to get a piece of code working and checked in. You come to a situation where you’re faced with the choice between doing the right thing and doing the quick thing. How do you motivate yourself to do the right thing?
Andy: I think Douglas Adams’ advice is real key there: “Don’t panic.” This is the number one place where we get into trouble as developers. We feel the crushing pressure of the deadline and we do something stupid because it’s expedient. It’s like gambling or Powerball. Every so often you win the $5 prize and go, “Woo-hoo. There’s some success to this.” Every so often you will take that cheap shortcut and it works out. You don’t get caught, you get away with it. You think, “Hey, this is great.” And then, of course, you take the next shortcut and the whole thing goes tits up and you’re just totally blown.
So the first thing I suggest is, don’t panic. If you feel like you’re compelled to do the wrong thing because it’s quicker, step away from the keyboard.
Ed: Switching to an easy subject, when you get a new machine, what do you have to do to it so it’s useful for development?
Andy: Typically what I do is I set up the connection to my CVS archive and I [do a] checkout, and then I’ve got 99 percent of what I need.
I actually had to do this the other day. One of my machines blew up, and I took it into the Mac store and they replaced it. And here comes this working machine, and I have things set so that I was back in business literally in under a half an hour.
Ed: Wow. That’s great.
Andy: So, again, people: Use version control, but use it for everything that’s important to you—you know, not just the source code of your project, but also the important stuff, config files and that sort of thing. So that’s real big with me.
Ed: That’s an excellent use of version control. I hadn’t seen that before. Version control systems are one example of the tools used by software professionals to achieve great results. How important is mastery of tools?
Andy: The key there isn’t so much [mastery of tools] -- it’s always good to have real facility with your tools. I can fly through vi and do stuff in a very short amount of time, and it doesn’t matter whether I’m local or SSH’d (connected via a secure terminal protocol, from another machine) in somewhere. I’ve seen people who do things in Emacs that I don’t know how the hell they manage it, but they’re expert at that tool.
And that’s all very helpful, but I think the real underlying thing isn’t so much proficiency with a given tool. The real expert isn’t necessarily the one who flies through Emacs, but the one who knows that “when this situation comes up, oh, I can go use this and knock this problem out in no time flat.”
So it’s more being aware of the whole catalog of what’s possible, what’s available -- be it algorithms, tools, languages, products, whatever -- just knowing that something’s out there and being able to apply it. I think that’s probably more key to productivity than anything else.
Ed: Who is the most productive programmer you’ve ever worked with, and why were they so productive?
Andy: I think the key to the most productive programmer doesn’t necessarily have to do with cranking out lots of code or doing it faster or that sort of stuff. I think the key is—and this is gonna sound contradictory to what I said before and I’ll just warn you up front—the key is not to be distracted. Take [this] scenario: A user says they want the program to do X and Y and Z, and you start looking at that and it’s very easy to get distracted by, “Ooh, there’s this neat algorithm I could put in here” or “Hey, I haven’t used the last five of the Gang of Four patterns lately. I can put that in.” And there are all these sorts of -- for lack of a better word -- “distractions” coming up. You harp on one thing that the customer said and miss their main point or miss what’s most important to them, or you seize on the first solution that comes to you and doggedly go down that road even if it really doesn’t make much sense.
So there are the usual consultant tricks you can do: Any time you come up with a solution, make sure you come up with at least three so you have two that you can throw out.
A lot of times, in the interest of speed and trying to impress each other, we blurt out the first architecture or design or idea that comes to mind and roll with it, and that’s usually not a very good idea. It’s a distraction, if you will.
So when I say “not distracted,” I’m saying the best programmers actually look at the genuine problem and work on a real solution to it without being distracted by dead ends, obvious false starts, that kinda thing. Everybody runs into trouble eventually, but the best programmers I’ve seen run into that kinda thing a lot less. They may get [a slower start] outta the gate. They may [get a faster start] outta the gate, but they take fewer wrong
Ed: How important is it to be a continual optimizer of your workstation and work environment?
Andy: I’ll admit I’m not particularly diligent about that. I’m the sort who will let small annoyances build up to the point where it’s like, “What the hell is going on here?” And then I’ll take a day and clean up six things, write a couple of shell scripts, do whatever needs to be done and get back on track again, and it’s like that story of the boiled frogs that was back in Pragmatic Programmer that we tell all the time: If you put a frog in boiling water, [it will] jump right out.
Ed: Right. Yeah, yeah.
Andy: If you put [it] in cold water and turn the heat up very slowly, [it doesn’t] notice and you cook the frog, and, as I like telling people, that is actually how we all end up in hot water. It gets turned up slowly and you don’t notice, and then you do notice and you say to yourself, “Whoa! This is a problem.” This is very true in terms of personal productivity. Small delays add up fast. Waiting for your e-mail client to load, clicking a message and waiting for the next message to show up. I cut my e-mail handling down by a half when I read this technique of how to optimize its internal database.
And the world is full of stuff like that -- your browser cache, things on your disk, things related to the operating system, whichever one you happen to use. There’s a myriad of small things all over the place that can make that application run faster or smoother, or there’s a shortcut key that you could use that you haven’t been using -- all that kinda stuff.
The irony of it is because this is what we do all day and for so long, learning one keystroke combination instead of a mouse sequence could end up saving you days at the end of a year ’cause it’s such a repeated activity, so I’m a big fan of keystrokes instead of mouse moves, key macros, anything like that.
Ed: You mentioned earlier that being aware of what’s out there in terms of algorithms, tools, patterns, etc. was hugely important for a successful developer. One aspect of that is reuse. Let’s say you find yourself writing a small piece of code that you know has been written before. How do you decide when to reuse or not?
Andy: There’s a real tension there. We like to invent and reinvent wheels over and over again, and we’ve got piles of industry-reinvented wheels. So you could argue pretty successfully that we actually haven’t invented
anything new in computer science since about 1968.
Andy: Everything is in some flavor a retread. Java is a retread of C++, which was an enhancement to C.
The other side of it is you go to look for something else to repurpose or reuse off the Net, programming by Google [for example], and you’ll find 15 implementations that are close to what you want. Then you run the danger of [using] Google [as an] IDE and you end up with Frankencode. You get this patched-together monster [that] is all stitched together and never quite works right, because each piece they drag in has a couple of pieces they didn’t really need, but it came along for the ride. And that’s where you run into real danger. What will happen is I’ll look at five implementations on the Net of something, get the best idea of how I want to proceed, and use one of those as a starting point, or just do it from scratch.
Are you really reinventing the wheel there? And in that case, I’d say no, because every project is different, every situation is different. You know, you have to make local adaptations. But on the grander scale of things, why is it something you have to go out and look for anyway? Why isn’t this a feature of the service or framework you’re using or the language you’re using? There’s a successful argument that says the design patterns as expressed in the Gang of Four book (Design Patterns, Addison-Wesley 1994) really shouldn’t exist. There are, what, 23, 26 patterns in the GoF book? And many of them are there due to limitations in C++.
You know, it’s very much limitations of one particular language at one particular point in time that doesn’t have a certain regular expression that forces you into these things. And I think that it was Paul Graham who made this argument in that particular case. But I think there’s a general case to be made: we do that [kind of reinvention] a lot of the times. It’s not strictly reinventing the wheel, but what we’re doing is inventing patches to a crappy wheel, when, instead of a wheel, we ought to be making a jet ski or whatever it may be. And I think you can really see a lot of this in the historical things that came out of the C++ community, CORBA (Common Object Request Broker Architecture) being a big example. CORBA, despite its language
neutrality, was extremely influenced by C++, similarly with Unified Modeling Language (UML). There’s a lot in UML that you can look back and go, “Oh, my God, that is C++.” If you had started simply off looking at Smalltalk or Lisp or Self or PROLOG or something weirder, Erlang, you’d get entirely different results. And that tells me, well, that’s not such a general-purpose wonderful thing. That’s really got a big old giant Band-Aid for something that wasn’t what it should have been in the first place.
Ed: On the flip side of reuse is the idea of starting over from scratch. When is it appropriate to do that?
Andy: The philosophical note I’ll throw in here is [that] a number of philosophies suggest looking at life from the point of view of abundance, not scarcity. So rather than bitching and moaning that something is scarce, be grateful and [appreciate] the abundance you actually do have. I think that is particularly true in the coder’s world, and I think a lot of the danger we get into from deploying things that are too buggy, too early, writing it too quickly, any of these sorts of issues all come from the basic idea that “That code was so hard to write the first time, I could never possibly write it again” or “The code that we have took so long to develop, we have to keep it and Band-Aid it because we couldn’t do it again,” and that’s taking a viewpoint of scarcity, which is the wrong one. And, in fact, even going back to [Fred] Brooks, there’s this idea that, hey, guess what? The second time you write it, it’s gonna go 100 times faster and end up better because you had the experience of writing it the first time. Now you actually know what to do.
So you’re better off doing it the second time and not hanging on to this fundamental idea of scarcity and hanging on to the first version, which really wasn’t that good to begin with.