Embracing Imperfection: The 3-Month Rule for Non-Scalable Solutions in Tech
In the entrepreneurial world, one mantra often echoed is Paul Graham’s advice: “Do things that don’t scale.” However, the real challenge lies in figuring out how to effectively integrate this concept into the technical side of development.
Over the past eight months while developing my AI podcast platform, I’ve embraced a straightforward yet impactful strategy: I implement any unscalable workaround with an expiry date of three months. After this period, I assess whether it has proven its worth and deserves a more robust solution, or if it’s time to let it go.
As software engineers, we’re often trained to pursue scalable solutions from the get-go. From design patterns to microservices and complex distributed systems, we aim for architectures that can effortlessly manage millions of users. Unfortunately, this line of thinking can lead us astray in a startup environment where scalable solutions might just amount to costly delays. My three-month rule nudges me towards creating simple, straightforward, albeit imperfect code that actually gets deployed, allowing me to discover user needs in the process.
My Current Infrastructure Approaches: Strategic Simplicity
1. Unified Virtual Machine Deployment
By consolidating the database, web server, background jobs, and even Redis onto a single $40/month virtual machine, I’ve intentionally sacrificed redundancy. Backup processes are manual and kept on my local machine.
Why this strategy is brilliant rather than risky? In a mere couple of months, I’ve gained invaluable insights into my actual resource demands that no planning document could have provided. For instance, my “AI-heavy” platform typically maxes out at 4GB of RAM. Had I opted for a complex Kubernetes architecture, I would have been busy managing empty containers instead of focusing on the real challenges.
When outages occur (and they have), I gather genuine data about the points of failure—refreshingly, they are never what I initially anticipated.
2. Hardcoded Configuration Values
In my code, configurations such as pricing tiers and maximum user limits are hardcoded. No separate configuration files or environment variables are in place, meaning any adjustment necessitates a redeployment.
The advantage here? Quickly searching for any configuration value is a breeze. Additionally, revisions to pricing are meticulously recorded in Git history, ensuring accountability even if it’s just between me and myself during code reviews.
Constructing a separate configuration service might have taken a week, but with three configuration changes over three