A few years ago, a developer once told me, “We never really get around to iterating on things, so we try really hard to get it exactly right the first time, and so it takes us longer to ship.”

I found this argument, while well-intentioned, utterly baffling. Agile has taken over software development in name, but the core tenets are still poorly understood. Most developers just give up, do their best to be productive, and wish all this overhead would disappear. But there is a lot of value left on the table.

Let’s consider an imaginary project we would like to optimize for three things:

  1. Total developer time to build the project.
  2. Accuracy of the data.
  3. Utility of the data provided as determined by the business users.

To belabor the point, here are a few wrong ways to do iteration:

  1. Never consult the end user at all. Make a guess about what they want and build it as fast as possible. Whenever the developer gets stuck, compromise with whatever is easiest. When you ship, hope it works out. This will minimize developer time at the total exclusion of accuracy and utility. These types of projects usually get thrown away.

  2. Refuse to start the project until all requirements are determined in painstaking detail. These projects can be easily identified by a complete refusal to commit to a design. With even a modest number of stakeholders, these projects can get stuck in the ‘defining requirements’ stage forever. It also puts an unrealistic burden on the end user as they seldom know the full set of requirements upfront. Once the requirements are identified, the developer will shift to the strategy from bullet one, disappear and deliver exactly the spec regardless of what they learned while developing or changes in business requirements. This is basically what everyone derisively calls ‘waterfall.’ I know this has fallen out of favor, but there are a small number of projects where this can work, but they must have concrete, unchanging requirements. I’ve never worked on one that met that criteria. Most of the time, this process is slow and has below-average utility and accuracy. My developer friend from the opening paragraph fits in this camp.

And one way to be a little more right:

  1. Start writing code immediately, but anytime any ambiguity shows up, stop working and meet with end users. This is still an improvement over the first two, and your odds of accuracy and utility being improved go way up. However, the developer will be constantly stuck, and getting end-user time may take a lot of work. These types of projects are often in a constant state of stall. And the end user won’t be particularly thrilled to be constantly interrupted.

And now a way that might actually work

  1. Break the project into cycles that allow iteration. Idea #3 was getting close but suffers from constant bottlenecks. Since user time is hard to get and developer time is expensive, we want to maximize both. Combine the best parts of strategies #2 and #3. Do a small amount of planning up front and quickly get as many known requirements as possible. Write it down. Deal with unknowns. Then choose as short a time frame as is reasonable and do some work that you can show off. Then, meet again. Update any new requirements, show off what you can, and confirm that what you’re doing is accurate and useful. Repeat until the project is finished. In doing this, you’ve minimized developer downtime, minimized end-user time requirements, and maximized accuracy and utility.

Some might even call it agile.