eno writer

006 - the iteration trap / conflicting edits / what do I know?

The Iteration Trap

Early stage startups are frequently advised to build a minimum viable product (MVP) and get it used by someone as early as possible. Startup founders can then improve off of the MVP based on the feedback they receive. Building something greater than an MVP risks creating an elaborate complex product that no one actually wants.

This is more or less how we went about things at my last startup and it worked pretty well. Having actual users early helped guide decisions about where to invest effort. Many features we had dreamt up turned out to be of little interest to our users. The MVP approach saved us countless hours of precious development time that we would have wasted building these unwanted features.

Notwithstanding this positive experience, I am throwing out this particular piece of advice with eno. The issue with having a product in use by users is that it drastically narrows what your product can potentially become. The only places you can take your product are places that are connected by a sequence of iterative steps. This is compounded by the fact that it is incredibly difficult to remove things from a product that users have in their hands. Your product grows like a snowball rolling down a hill.

With zero users, you can throw everything out at a moment's notice. You can try features and see how they feel. You can write something one way, realize it doesn't work and write it all over again. The bounds on what your product can become are the bounds of your imagination. The social aspects cannot be overstated either. Your users are kind of doing you a huge favour by taking a risk on your early stage product. When they ask for new functionality, it is incredibly difficult to say no to them. If they are paying customers, it becomes even more difficult. Now actual money is at risk with how you manage these relationships.

Is there a precedent for my approach? I'm definitely not the first person to have done it. In his book Zero to One, Peter Thiel advises founders to avoid careful incremental advances saying "it's better to risk boldness than triviality". Once again, I find myself looking to the indie game world where I believe this is essentially the status quo for product development. In the extreme case, Jonathan Blow spent seven years writing The Witness. Of course he did playtesting along the way but the number of active users was essentially zero during that entire development timeline. It's crazy but it definitely can work.

Conflicting Edits

Last week I wrote about the viability of Git for use in the world of business documents. I received a lot of comments back on LinkedIn, including a full write up by Tom Bartley who worked on this exact problem for a number of years.

It did not surprise me that one of the chief issues Tom identified was the complexity of dealing with merge conflicts in business documents. Merge conflicts occur when trying to reconcile two versions of a document into a single version where the changes within them conflict with one another. Take for example the following sentence where two different people start from Original and draft Versions A and B:

Original: "The quick brown fox jumped over the dog."

A: "The quick brown fox jumped over the green dog."

B: "The fast brown fox jumped over the dog."

If Git were trying to combine Version A and B into a single version, it would not be able to. As far as it is concerned, both versions completely replace the original sentence and so a human must take a look and decide how to merge them together. This is not generally a big problem because in practice, when developers work on code, they tend to edit different parts of a file, and only infrequently end up editing the same line of text at the same time.

A keen human observer might note that these changes do not actually conflict. If there was version software that could interpret Version A as "change quick to fast" and Version B as "add green before dog", then there would be no problem automatically combining these into a single version.

There are other changes that are fundamentally incompatible. For example if Version A changed "quick" to "swift" and Version B changed "quick" to "fast" it would be a matter of opinion which change should prevail (some might even suggest removing the unnecessary adjective if no one can agree on it). In these cases, software could just arbitrarily pick one Version (perhaps the most recent edit). In my opinion this is user hostile behaviour. Really, the software should show the user the conflict as clearly as possible and give them the power to resolve it as they see fit.

What do I know?

I am now writing a core piece of eno for the third time. Without spoiling too much, one of the key features of eno is that documents will be "alive". In the cover letter example I gave the other week, changes made to the original template letter would instantly propagate to all the cover letters you have written - even if you had made edits over top of the template in the various letters.

If you conceived of this as a relational model, you can imagine making a Document instance to represent the template which would have a Document ID. You could then make an additional Document for each cover letter you want to write, each with its own Document ID. You would then link these cover letter Documents to the Template by an action like document.SetTemplateTo(template_document_id). Now in the template you could do something like document.addParagraph() which would return a Paragraph ID for the new paragraph. Now, imagine that all the cover letter documents also get a copy of that paragraph automatically. Do we want to manage the lifecycle of all these pseudo paragraphs by actually creating, deleting and syncing them as needed? How do we reconcile changes between the source paragraphs and the customized cover letter paragraphs? It gets complicated very quickly.

I've spent a lot of time modelling this out, switching between drawing diagrams of systems that could work and then trying to actually write them. Through this, I often get more confused. One thing that has helped is trying to go back to the most core things that I know about this problem. There are two of them:

  1. Users will press buttons on their keyboard.
  2. Things will appear on the screen.

Building off of that, when users press buttons, they will effectively be issuing commands like CreateDocument, LinkDocument, CreateParagraph and EditParagraph. On the screen we will see several documents that all have copies of the same paragraph. At the render stage, I want to have datastructures with an explicit representation of what actually appears (i.e. one object per visible paragraph on the screen). My job is to come up with a pipeline to get from these commands to the things displaying on the screen:

     Keyboard Input -> Commands -> ??? -> Documents and Paragraphs -> Render to Screen

So, when I call EditParagraph for one of these pseudo paragraphs in a cover letter, do I give it a Paragraph ID or something else?

Note: I am extrapolating from how my actual code works to convey the general sense of the problem I am working on. I do not actually have a concept of Paragraphs as a datatype in eno and the actions approximate other things. I also don't use many document.xyz() type methods.


If you liked this post, please consider sharing it with a friend.

Powered by Buttondown.

We also have an RSS feed