No feature survives contact with the user

There’s a saying in the military: “No plan survives contact with the enemy.” We try not to think of our users as the enemy, but nevertheless, you could repurpose this phrase for startup product development— No feature survives contact with the user.

​I’ll give an example. I recently implemented an internal “Invite Panel” where our team can enter an email address. When a person with that email address signs up for our product, Witful, they get a free subscription. We use this system to solicit feedback from our friends. “Hey, if you give us some product feedback, we’ll give you a free account.”

​The team asked for the invite panel feature, I wrote the code, tested it, got it reviewed, and we shipped it to production. Great.

Ship it!

​​Fast forward a few days. Turns out, the feature didn’t do what we want. Turns out, when we start talking to our friends about Witful, they get curious. They go to and they click “sign up.” They start clicking through our onboarding. They do this before we have a chance to ask them for their email address. They do this before we have a chance to mark that email address as invited. And therefore, they are sent to our checkout/payment sequence. Their account is created and marked as TypePayingUser instead of TypeGifted. There’s no way to fix it other than editing the database directly. The feature that we implemented just doesn’t get the job done right.

​What we actually needed was an administrator button to toggle a user back and forth between TypePayingUser and TypeGifted, after they’ve signed up and created their account. Lesson learned: people get curious when you talk about a product, and they will sign up before you have a chance to formally invite them.

Because I’ve been shipping features for two years now, I’m starting to get the hang of things. I’ve shipped enough features that now I do a bad job on purpose (genius, I know). I chose to ship the “Invite Panel” feature to production, knowing it was incomplete and knowing there were at least two major problems with it.

​First, I knew it would make the onboarding process for gifted accounts feel buggy. Before we shipped the feature, I tested onboarding a gifted email address. Witful’s onboarding includes a step of “Set up billing,” but for gifted email addresses, the step was skipped and marked as complete, with no explanation. It was bad UX. It would be better if Witful showed a screen that said “Thanks for accepting our invitation to try our product! Your account is on us.”

Witful's onboarding screen

Second, the administrator panel I made doesn’t show us the list of invited emails. If you input an email to mark as invited, it just says “Done” and clears the input box. Internally, it wasn’t clear to our team who they had invited so far, and whether our server had actually marked the email address as invited.

The invite panel in Witful's administrator page

I could have fixed those problems. I could have gracefully transitioned the “Set up billing” onboarding step into an “Invitation accepted” step for invited users. I could have implemented and polished a better administrator panel that would dynamically fetch the list of invited emails, the timestamps of their creation, and the names of the administrators who invited them. But that would have delayed the feature from shipping by 4-5 days. And, crucially, it would have delayed us finding out that it was the wrong feature to be working on by 4-5 days.

​The invite panel feature simply didn’t survive contact with the user. We’ve found this to be the case with features over and over and over again. We come up with an idea, it sounds good, we build it, we ship it, and it turns out it just wasn’t the right feature. But, as wasteful as it sounds, shipping *something* is the only way to get accurate information on what your users actually want and will actually use.

​Final thought: the notion of “ship an MVP and then iterate” has been around for a long time (and, more generally, the notion that “worse is better”). But even though I had read arguments for that line of thinking many times, I didn’t really internalize it until I experienced it myself while working at a startup. Hopefully, sharing my concrete example of applying this rule is helpful to others.