Startup Nugget #5: Document Everything
Over the course of TheGoodPsy's life, there have been countless changes.
In order to verify assumptions, we've tried different marketing strategies, UI changes, user flow tweaks, and anything to verify what works and what doesn't when it comes to user acquisition and retention.
Once we reached the limit in terms of what we could do with WordPress, we moved into a no-code solution: Bubble.io before going into developing a full-fledged web application. This intermediate step was necessary because we were too early to know whether we had product-market fit and too advanced to keep trying to make ends meet with a Wordpress app.
I am quite amazed in retrospect about the level of complex logic we managed to implement in such an initially toy platform.
Initially, I thought of no-code solutions as a good headstart for non-technical founders that lack coding skills and had not yet found a developer to implement the solution. However, now I do feel it is a necessary step right in between testing those assumptions and custom business logic that would fall short when one is just validating the idea with a landing page and some manual work, and investing the time and effort that comes with developing a custom solution.
Once the decision is made to go all-in with the custom solution there is a strong chance of you needing to integrate it with the existing platforms and third-party services you have been using up until then. You might have some lambda functions here, some integration with Airtable there, and some other external services for authentication, messaging, polling, etc.
Normally you cannot afford to work on the new solution in a vacuum but rather iterate through it while replacing the external components with the in-house ones one step at a time.
If you are bootstrapping, most likely you are the only developer or you are a very small team, leveraging some freelance work on the side. This means that you have so much knowledge and moving pieces in your head that you can't possibly keep track of all of it.
Moreover, in order to iterate quickly, you've had to oftentimes make shortcuts to add features as soon as possible, and many of those shortcuts are hacks that have a very concrete solution that made sense at the moment (like tweaking the cacheFlush parameter to 2 instead of 3 because of some obscure reason), but if you revisit them after some months you no longer remember the whole rationale behind it.
That's why I force myself (and encourage everyone to do so) to over comment on every feature you consider to be remotely obscure as if you think of yourself to have the memory span of a clownfish, because eventually you or someone else will have to get back to it, and life will be much easier when being able to decipher what's going on behind relatively quickly.
An example of this in some of the software I've written:
/* * The purpose of creating a reference for the email is because * since we use it in the flow: * 1. useEffect() calling setupConversationMessages() * 2. setupConversationMessages() calling conv.on('typingStarted', handleTypingStarted) * The handleTypingStarted being set up inside the useEffect() hook creates a closure over * email value, and even though it is updated later, it is not reflected on the handler. * So I create a reference to the store's selector and access it's current value. * A useCallback() call depending on the [email] parameter would work on my mind but * it doesn't and I don't know how to move forward so this works for now. */
I've had to come back to this piece of code already and the comment helped greatly to know why I did that.