A snarky friend asked, how is it possible that We’re Not As Smart As We Think We Are? Isn’t that an infinite regress?
To understand why it isn’t, I’m going to geek out a bit and talk about some lessons a lot of folks – including myself – have learned the hard way about building software:
a) Nonfunctional Prototypes. If I’m managing a project to build a complex piece of software, before the programmers start writing code I often ask them to create a “nonfunctional prototype” – some quick-and-dirty sketches or mockups that the users can react to. Why? Because no matter how well a programmer or I think we understand what users said they want, we almost never get it right the first time – and usually not the second or third or fourth time either. And it’s a hell of a lot cheaper to rip up a quick sketch than to rip up days or weeks or months of coding.
And it’s not just us coders. Someone like Jacob Nielsen, the granddaddy’s of studying “usability,” does the same thing. Why? Because even Nielson isn’t smart enough to know what users want.
Here’s what makes this tricky. When you’re building the first mockups, an awful lot of the time you’re pretty sure you know what users will and won’t like. Even if you’ve been doing this for many years and have been surprised over and over by what users do and don’t find intuitive, some part of your lizard brain thinks you nailed it — or at least a good part of it. And that’s why we have the rule about nonfunctional protos: to put that part of your brain in check.
b) Building Software Iteratively. Rather than trying to build a program all in one swoop, break it into a series of mini projects or “iterations.” Why? Because, as they say in the military, no plan survives first contact with the enemy. It often turns out that users didn’t know what they really wanted – especially if they haven’t used the type of software you’re building. Or halfway through the project, your organization’s needs change. Or you discover that some parts you thought would be straightforward turn out to be a real mess and take three times as long to code. Or after you’ve gotten started, you realize that for a critical facet of the project you’ve been trying to solve the wrong problem. And so on. If you design the whole thing and then build it in one shot, you have to get it exactly right the first time. But if you build it iteratively, each iteration is another chance to respond or recover from the almost inevitable surprises.
When I start a complicated project, one part of my brain knows this. But the other part is whistling, hi ho, hi ho, it’s off to work we go! It’s cheerfully optimistic about how the project will play out. That, ultimately, is why iterations are crucial: they save you from yourself.
And that crazy optimism may be necessary. A developer I know likes to say that new software projects are like giving birth to her second child: if she remembered what it was really like the first time she gave birth, she’d never do it again.
I’ve worked with developers who do remember it all, in vivid detail. These folks don’t tend to get much done. They’re so bogged down by uncertainties and so disillusioned about what’s probably going to happen that they can’t do good work, and they tend to suck the energy out of everybody else.
It takes an insane level of can-do optimism to pull off great software. That’s probably true of a lot of things in life – creating a new company, trying to solve a social problem. That insane optimism is the engine that keeps you running. But you also need a structure that protects you from that optimism, that keeps gently but firmly reminding you, We Aren’t As Smart as We Think We Are.