Almost four years ago I started my first product design job at Virb. I was fresh out of a web agency position and enthralled with the idea of product design and agile software development. I was ready for a fresh start, and I had memorized all the mantras. If I was proud of something I’d waited too long to ship it. The beauty of the web was how malleable and it was—how easily things could be improved and changed and iterated on. Regardless of what was communicated to me, I knew what product designers were expected to do: ship things, fast, and then iterate on them to make them better.

Four years later, after moving from design to direction and now product management, I look back on those years with awe and regret. Awe that I was able to design and build so much in so short a period of time, keeping pace with competitors almost 25x our size, and regret that I didn’t realize the longer-term impact of some of my decisions.

Turning in my membership

The other day, while talking to Andy, our lead engineer, about an upcoming feature rollout, I typed into Slack, “Do it once. Do it right.” And I looked at that line in the chat room with wide eyes—did I really just say that? Do I have to give my product designer membership card back? Is Jeffrey Zeldman in a dentist chair feeling strangely and inexplicably disappointed right now?

I had written the words, and after a few days of reflection I can honestly say they represent how I (and my team) now approach our work at Virb. Now at this point I could wax on about theoretical pros and cons and discuss iterative development in a vacuum, but that’s been done enough times. Instead, I wanted to share how we got here—how my thinking failed me, what the results were, and what we’re doing to fix it.

Iteration as an excuse

During the late stages of product testing, I get a challenge from my Product Manager, Rubin. He brings up a great point, a use-case I hadn’t thought of. Do I scrap the launch to go back and evaluate things or press on with this much-needed feature?

This situation happened more than I would have liked, and usually I would tell myself “That’s ok, we’ll launch it as is, and I can deal with this new wrinkle as an iteration.” Occasionally I’d have the time to “fix it in post,” but features would launch without every use-case or user scenario being fully thought out, tested, and accounted for. Sometimes we’d realize there wasn’t an issue, and sometimes we’d have to scramble to toss up hot-fixes that dealt with issues we’d inadvertently launched. Was it catastrophic? No. Lazy? Most definitely.

Iteration is not an excuse to ignore issues, however late they may present themselves in your product cycle. Take the time to examine a launch from every angle, otherwise you end up shipping half-baked ideas that need more thought put into them.

Iteration that never happens

The idea of shipping and iterating is sound in theory. Most times, my iteration stage simply never happened, becoming something more like “Ship it and forget it.” Usually another task presented itself as a higher priority—I did just launch a functioning feature after all. With a team of six people, babysitting a functioning feature to gather insights on its use or effectiveness seemed like a luxury I didn’t have. Instead I’d move to the next thing on the list, like a good list-maker who loves to check things off, and come back to iterate only if the need trumped what was next on our roadmap.

Iteration needs to be built into your product timelines. Don’t jump from one task right into another. Take the time to analyze the effectiveness of a feature before assuming it’s complete. And then you can check that task off the list (and it will feel really good, I promise).

Iteration without long-term planning

The idea of iterating led me to produce things that did exactly what they needed to do when I meant to ship them. Now that might not sound terrible, but over the course of years it leads to a codebase, UI, and general product thats more like—shoutout to Jay-Z and Yeezus—hacks on hacks on hacks. What we did was add technical debt with everything we launched, morphing features and processes from their original purpose, or finding that we didn’t build things in a way we could easily iterate on without a full re-write. Building an MVP is a great idea, but after four years of iteration on a minimally viable product sometimes you have sections of your product and codebase more worthy of being pulled off life support completely.

Have a long term plan for how your feature and product can be developed in stages, with each one being a fully functioning whole. Planning for future iterations allows you to build all the scaffolding for future features into the foundation of your product. This will save you from having to pay back tons of technical debt, rewriting key components or revisiting UIs down the road.

Iteration itself is a magical thing. It’s a tool that allows us to take ideas, sculpt them, and hone them as we grow as designers and developers. Our products mature along with us. But used improperly as an excuse, without being given due time, omitting a long-term plan, it can lead to sloppy launches, half-baked implementations, and a product that has Fort-Knox-sized technical debt. These are all the things I’m doing today to help make Virb the best product it can possibly be, and it feels good to do things once, and do them right.