"Life can only be understood backwards; but it must be lived forwards."
– Søren Kierkegaard
This weekend I’ve spent many hours working on a long time coming backend migration for otter.es and wanted to share some quick reflections with you all now that I’m about to ship this new version.
Back in the day, when we realized we had a clear picture of what features we would include on the MVP for Otter and what we wanted to validate, it was time for me to start thinking not only how to build it, but how to build it as soon as possible and in a way that could endure all the pivots and iterations we would face.
This is the balance we need to always strive for. If you spend too much time developing something before anyone uses it, you’re at risk of creating waste by focusing and optimizing for things that no one might use.
If you don’t spend enough time cleaning up the codebase and making sure you’re not piling up on technical debt, you’re at risk of hitting a blocker and not being able to iterate fast enough after you launch.
These are opposing forces that we need to keep in mind to make sure one is not pulling us too far from the other.
In Otter’s case, having a real-time chat for each project, building some features to manage budgets, and knowing that we were not going to build a mobile version, meant that we had to build a responsive and high-performance web app, something that could be used by anyone that just wanted to make custom furniture for their house or clients.
And while I knew I was able to move fast building a great frontend experience, and that made it pretty easy for me to pick NextJS + GraphQL as my architectural choices there.
But I also knew I didn’t want to sweat over details like picking the right database, building a custom backend, and having to create every single endpoint, so I decided not to write a custom backend at that moment and went with a Backend-as-a-Service tool.
But Mike! What about vendor lock-in?! And performance? You don’t have control over your database, or where your files are, or anything?!
Yes, yes. I know that. Precisely because that, I wanted to give my money to somebody else to handle those things for me, I didn’t want to focus on those details. I wanted to focus on the features that make Otter what it is today, and building a CRUD and adding file management or image resizing in there didn’t get me any closer to the MVP.
Don’t get me wrong. I knew I would eventually want to move out from there, provided things went well enough (hey, we’re still alive, so that counts, right?). So as long as I could export all the data, and as long as I wasn’t coupling my business logic with external frameworks and vendor codebases, I knew things would be fine.
And it was fine! I’ve been able to keep with this architecture and approach for over a year until the time came where I started realizing the shortcomings from this setup and started taking my time to think about a custom backend for my app.
Knowing what’s being used today and what’s in our roadmap, which database should I pick? Which kind of server? Where should I host it? Those things were things I knew I could take my time to focus on now since I know much better what I need and how it is going to be used.
Many times we as developers feel the need to have everything defined from the get-go, and when we can’t have a clear picture of what we need to optimize things for, we try to build super generic systems that we think they’ll handle anything and everything.
Chances are you are going to be wrong at first, no matter what. But with the right mindset and focus, you can become incrementally correct. And that’s all that really matters.
Instead of making a massive investment in creating the perfect architecture and system for the product you have in mind, invest just enough on what you need to ship it.
Then let the users tell you what needs to be built next, and let your success tell you what doesn’t scale.
This way you are building things that are very close to 100% known, rather than building a dreamed architecture for an unused product.
Give this one a try the next time you’re facing a larger architectural decision: what can be treated as a detail, for how long you can defer as many of those decisions? Then focus on what’s important.
Thank you for reading!
(And wish me luck with the migration! If all goes well, tomorrow is the big day!)