Its probably no secret that I’m suspicious of too much preparation time. While I teach a number of courses for Learning Tree International (including four that I’ve written for the company), they won’t let me teach the system design courses. I assume that’s because, back when I had a job, my boss once asked me if I’d tested a program and I responded with, “It compiled, didn’t it?” In addition to explaining why I’m now a consultant, it also explains why I’m not teaching any courses on testing and software quality (though I have taken those courses, much in the same way that someone who visits San Francisco tours Alcatraz—nice place to visit but I wouldn’t want to live there).
Analysis and design are held in high regard because, over the years, various projects have run into problems after the project has started and some code has had to be rewritten. Developers have found themselves having to back out some code that they had already done, or they had worked themselves into a corner where they could neither go forward (it just doesn’t work) or go backward (we’d have to scrap everything we’ve done). The assumption is that, with enough planning, they’d have avoided these problems and sailed on through. At the very least, they’d have known at the beginning that the project was impossible.
I’m not sure that’s the case. It seems to me that projects with many, many hours of time spent on analysis and design have collapsed anyway. One class of frequently occurring news stories is “Government IT Projects in Trouble”—occurring often enough that it seems that every year has its fair share of disasters. I assume that those projects saw the approved number of hours spent on the analysis and design phase. If these guys can’t get it right, why should I? It’s tempting to assume that those people are stupid and I am (at least) not-that-stupid. Maybe I just lack faith, but I’m not willing to assume that I’m significantly smarter than those other developers.
Software is inherently complex. More importantly, software changes things. After you’ve built some software, you’ve changed the world that you’re working in. Furthermore, if you’re doing something you haven’t done before, it seems to me unlikely that you’re going to be able to imagine your way into your future. What are you going to do? One solution is to hire a guide, of course, who’s been through the territory. Even with a guide, this particular project is still going to be new to all the participants. At best, your guide will have seen something like your project before.
I’m trying to suggest that no amount of planning is going to prevent problems. But if that’s the case, then having a problem isn’t a failure but rather what you should expect to happen. It also means that having to tear down some of what you’ve done and rebuild it is part of the normal activities of a project.
But isn’t this wasteful? I don’t think so. Presumably, as you work through the project you find out stuff about the problem that you didn’t know at the start: You get smarter. It would be sad to think that you could spend months working on a project without learning something. Surely that learning is going to mean adjustments both to the plan and to the work already completed.
I’m not suggesting that you shouldn’t plan. I am suggesting that your plan should include space for redesign, rethought, and rework. The last thing that you should do is plan down to the last detail because 1) it won’t work, and 2) you make it more difficult to take advantage of the learning that goes on as you build your project. I’m suggesting that the rework that you’ve done in every project should not be regarded as a failure or, more importantly, as the reason for doing even more analysis and design next time. Instead, you should be planning your projects so that you can take advantage of your ongoing learning and minimize the time lost through your rebuilding activities.
The first thing that you can do is design your overall architecture first: What parts do you need, what will they do (at a very high level), and what is the basis for the way that they interact? Aim for an architecture where you can snap in new, loosely coupled components. Build your components so that you can completely replace the contents of a component without having to change any other component.
The second thing that you can do is build the hard stuff first—or second, at the very latest. Do a few simple things, if necessary, to learn about the base skills that you need. Build in some “skunk work” projects that let you investigate your problems. But then go for the parts of the project where you’ll do the most learning. (I call this the “Robin Hood” principle: Steal from the hard to give to the easy.)
Finally, build small components that share generalized code. If you need to rebuild a small component, it will take less time than a large component. If you’re sharing a lot of generalized code, then you can enhance a large number of components by changing a small amount of code. And keep learning.