How to evolve a product
Published: 2024-06-28 12:34:42

---
title: "How to evolve a product"
published: true
description: Big-company best practices make bad early-stage startups!
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cu2exwebzzyyuy8wrygb.png
# Use a ratio of 100:42 for best results.
# published_at: 2024-06-28 12:07 +0000
---

So you started your startup &mdash; now how do you find a great product ASAP? At our startup, Granola, we rapidly _evolved_ a product using principles from natural selection! We made our software friendly to _mutation_ by using repetitive code, all in one blob, with no tests. For parallel _selection_ of the best variants, we manually sent programs to target users. And to make our variants friendly to _extinction_, we avoided all launches, landing pages, and docs. Beware: big-company "best practices" make bad early-stage startups!

## The greatest startup story of all time

<figure>
  <img style="max-width: 20em; float: right;" src="https://www.granola.so/blogImages/evolve/1_pikaia.avif" alt="Pikaia" />
  <figcaption>
    <i>Pikaia (early screenshot)</i>
  </figcaption>
</figure>

This guy is _Pikaia_. He lived around 500 million years ago, grew to around 4cm long, and perhaps swam like an eel. Shortly after, along with most other species, he disappeared.

<figure className="not-prose left">
  <img src="https://www.granola.so/blogImages/evolve/2_pioneer.avif" alt="Pioneer plaque" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Pikaia sapiens?</i>
  </figcaption>
</figure>

And yet _Pikaia_ lives on: his descendants are you and me, rulers of this planet, with influence even beyond the solar system, their images engraved forever on the Pioneer spacecrafts! I believe **the Cambrian explosion is the best startup story of all time**, full of rapid prototyping and forgotten pivots! Like our early-stage startup, natural selection is a search for new, better designs in a shifting landscape.

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/3_pigeons.avif" alt="Pigeons" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Victorian hackathons</i>
  </figcaption>
</figure>

Some believe that evolution has to be _slow_, but that's just false. Darwin's theory was influenced by pigeon breeders, who were able to find wonderful new pigeon designs within strikingly short time periods. I like to think of good startups like these breeders: tastefully using **mutation** and **selection** to find wonderful new products. My claim: when designing startups, we can draw surprisingly concrete lessons from how natural selection works! For my first example: let's look at nature's attitude toward copy-paste.

## Avoid abstractions. Use copy-paste-edit!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/4_williston.avif" alt="Williston's law" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Fun fact: the snake went full circle.</i>
  </figcaption>
</figure>

How did your arms and legs come to be? Notice a difference between you and _Pikaia_: _Pikaia_ has lots of repeated segments, but your body has just a few specialized segments. This happens so often in evolution that it has a name: it’s called Williston’s Law. Roughly, it says that **nature loves to copy-paste and edit.** Nature takes a versatile body part like a leg or a tooth, duplicates it many times, gives each one a chance to specialize, then kills off the excess.

<figure className="not-prose left">
  <img
    src="https://www.granola.so/blogImages/evolve/4_hox_tree.avif"
    alt="Hox gene evolutionary tree"
  />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>The more Hox genes you paste, the more shapes you can make!</i>
  </figcaption>
</figure>

Nature's love of copy-paste can be seen genetically as well. When you were still an embryo, your body plan was drawn out by 39 different "Hox" genes. Each Hox gene corresponds to one part of your body. But our early ancestors had just one Hox gene! Nature then copy-pasted and edited it many times, and now we have 39 of them, each with a different function. In Computer Science courses, they gave us clear, static requirements, and we were supposed to implement these with "clean code". But **programs designed for certain, static requirements look very different to programs designed for uncertainty and change!**

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/4_copy_paste_edit.avif" alt="Copy-paste-edit" />
</figure>

Say you want to add a new kind of "big button" component. Instead of introducing an abstract "button" concept, try duplicating the existing button component, and allowing it to evolve along its own path. Even if your "button" abstraction is _right_ under _current_ requirements, it can stop you from implementing _new_ requirements! What's more, repetitive copy-paste code is friendly to AI-assisted change.

## Avoid splitting stuff up. Use one big blob!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/5_peacock.avif" alt="Peacock" />
</figure>

Why does the peacock not ditch that stupid enormous tail? Well, the males can’t, because the females select for it. But the peahen can’t ditch her selection choice either: she'd have sons with small tails, who wouldn’t get selected!

<figure className="not-prose left">
  <img
    src="https://www.granola.so/blogImages/evolve/5_peacock_sequence_diagram.avif"
    alt="Peacock sequence diagram"
  />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Peacock sequence diagram.</i>
  </figcaption>
</figure>

**Protocols inhibit change,** and the peacock has a broken protocol that equates "large tails" with "fitness". An asexual peacock could ditch the tail. But with two sexes, there’s no way to change without global coordination. Nature's lesson for us: **avoid splitting stuff up.** And especially avoid any splits that create distributed systems! It’s easier to change one big thing than to change many small things talking to each other. Your professor is not here to punish you any more. It's okay to keep everything in one file!

<figure className="not-prose right">
  <img
    src="https://www.granola.so/blogImages/evolve/6_client_api_db.avif"
    alt="Client, database, and API"
  />
</figure>

Even the earliest prototypes often look like this: a client, a database, and an API between them. But with this design, you’ve already introduced two splits!

<figure className="not-prose left">
  <img
    src="https://www.granola.so/blogImages/evolve/7_one_blob.avif"
    alt="Initial version of Granola"
  />
</figure>

By contrast, **the first prototype of Granola was an isolated desktop app.** It talks to the things it needs to, but is otherwise a single blob.

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/7_client_db.avif" alt="Granola using Supabase" />
</figure>

We eventually had to have some server-side stuff. Typically this means building an API layer. But we avoided that by using Supabase, which lets clients directly interact with your central database. Instead of two interfaces slowing you down, we just had one.

## Avoid auto-update. Use direct distribution!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/8_cambrian_species.avif"
    alt="Cambrian species"
  />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Btw, notice all the repeated segments.</i>
  </figcaption>
</figure>

Here are some of the bizarre life forms that lived alongside our ancestor _Pikaia_. Life is always exploring many variants in parallel! That’s the only way to quickly explore a giant possibility space. Yet most software distribution is sequential. `v1` then `v2` then `v3`, and so on. Web apps are constrained to a single “production” version being explored by users. Mobile apps are constrained to a single version published on an app store. Bad for exploration.

<figure className="not-prose left">
  <img
    src="https://www.granola.so/blogImages/evolve/10_dmg.avif"
    alt="Direct software distribution via .dmg file"
  />
</figure>

Instead, our app is directly distributed via a .dmg file. This means **we can make some radical code changes, cut a new build, and send it to a single user.** This is great for evolving a product, because we're evaluating many versions in parallel.

(You might be thinking: "But we have feature flags." Good, but you can't make _radical_ changes on a feature flag, because your single production version must act as a superposition of all possible software changes.) In early life, avoid linear auto-update. Instead, use direct distribution.

## Help your software versions die

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/11_opabinia.avif" alt="Opabinia" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Copy-pasted eyes.</i>
  </figcaption>
</figure>

_Opabinia_ lived alongside our ancestor. He had five eyes on stalks, and a single, central claw. But _Opabinia_'s descendants are not alive today &mdash; perhaps because he was a stupid design. Most of the Cambrian forms were evolutionary dead ends.
 Without death, natural selection doesn’t work! And yet much conventional advice makes it hard for us to kill our bad software versions.

<figure className="not-prose left">
  <img src="https://www.granola.so/blogImages/evolve/12_references.avif"
    alt="References to software versions"
  />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>(From left) Living Granola, dead Granola.</i>
  </figcaption>
</figure>

What is a "dead" software version? It's one with no more references to it. Think garbage collection. So, **to let your software die, avoid unnecessary references to it.** Let's look at common references we can avoid.

## Avoid automated tests. Test manually!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/13_tests.avif" alt="Tests" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Hey, come back here!</i>
  </figcaption>
</figure>

So you’ve made a software change, but now the tests are broken. Don't feel bad: it's the tests' fault, not yours!

**Tests are chains, stopping your program from running free.** The tests say: "Bad code! Stop changing! Go back and be the previous program!" So avoid writing tests. Just test the things that are unlikely to change. Test everything else manually.

(Note: type-checking is different. It tests correctness properties that apply to _any_ program. A good type-checker lets you move fast without breaking as many things.)

## Avoid unnecessary users. Build for yourself!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/13_users.avif" alt="Users" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center italic">
    <i>Please support us!</i>
  </figcaption>
</figure>

You've experienced this too: you want to remove something from your product, but some obscure users loudly complain, so you give in.  Conventional advice says to launch ASAP. But **people using your software keep it alive, and so they can slow down change.** Instead, avoid all unnecessary users. Build for a small set of target users. (That target might just be yourself!)

## Avoid landing pages. Onboard manually!

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/13_resources.avif" alt="User-facing resources" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>We'll remember you forever!</i>
  </figcaption>
</figure>

Conventional advice is to focus on top-of-funnel experience. Build a landing page to sell the product. Write docs and build a slick onboarding into the app. But all these user-facing resources reference a specific version of your product! And so they make it harder to kill that version.

**At Granola, we deliberately spent a long time pre-launch.** We targeted a small niche, and manually onboarded everyone. This reduced distractions, made it easier to throw stuff away, and helped us practice for when we eventually did build a landing page and onboarding.

## Best practices for pre-launch software are very different

<figure className="not-prose right">
  <img src="https://www.granola.so/blogImages/evolve/14_midwit.avif" alt="Midwit meme" />
  <figcaption className="text-sm text-gray-500 mt-2 text-center">
    <i>Midwit meme for you to copy-pasta.</i>
  </figcaption>
</figure>

Conventional advice says that good code is "clean code" with high test coverage, and that teams prioritize early launches, continuous delivery, and top-of-funnel experience. But in an early startup, your sole focus is to search for a product, and these "best practices" can slow down this search. Try optimizing for change, by using low-abstraction copy-paste, all in one place, with no tests. Distribute your app manually, and onboard people manually. That's what we did. After 12 months, we now think we've found our product, and it might be time to re-evaluate our approach. If you’d like to join our journey, get in touch!