Embracing the Unscalable: A Technical Framework for Iterative Learning
Paul Graham famously advises, “Do things that don’t scale.” However, applying this principle effectively in the realm of coding remains a less explored topic. Drawing from my experience in developing an AI podcast platform over the past eight months, I’ve implemented a straightforward framework: any temporary, unscalable solution is given a lifespan of three months. After this period, we assess its value—either it evolves into a robust solution or is discarded.
As engineers, our instinct is often to prioritize scalable solutions from the very beginning—focusing on design patterns, microservices, and sophisticated architectures that can support millions of users. However, this approach often aligns more with large corporations than with the realities of a startup. In fact, placing too much emphasis on scalability can lead to costly procrastination, as we might be optimizing for users who have yet to materialize or solving problems that may never arise. My three-month rule compels me to prioritize simplicity, allowing me to ship faster and learn what my users genuinely need.
My Current Infrastructure Decisions: Smart Choices for Rapid Learning
1. Consolidated Infrastructure on a Single VM
I’m currently running my entire stack—including the database, web server, background jobs, and caching—on a single $40/month virtual machine, without redundancy. While this may appear reckless, it has provided invaluable insights into my resource requirements. In just two months, I’ve learned my “AI-heavy” platform rarely exceeds 4GB of RAM. Instead of getting lost in the complexity of Kubernetes, which I almost implemented, I’ve received first-hand data on what truly causes outages—often surprising me.
2. Hardcoded Configuration for Simplicity
I prefer hardcoded configuration constants throughout my code—no configuration files or environment variables here. Adjusting any values necessitates redeployment, allowing for straightforward tracking in git history. While building a configuration service could take significant development time, I’ve only changed these constants three times in three months, equating to a mere 15 minutes of redeployment compared to an extensive 40 hours of engineering effort.
3. Using SQLite for Production
Yes, I’m utilizing SQLite for a web application designed to accommodate multiple users. At just 47MB, it seamlessly handles 50 concurrent users. This setup revealed that my access patterns are predominantly read-based, making SQLite an ideal fit. Had I opted for Postgres from the start,
One Comment
This approach exemplifies the power of embracing simplicity and rapid iteration in early-stage development. The three-month rule effectively balances the need for quick learning with disciplined evaluation, preventing analysis paralysis often caused by prematurely optimizing for scale. Your use of a single VM and hardcoded configs highlights that gathering real-world data should take precedence over complex setups—especially when resources and time are limited.
Moreover, testing SQLite in a production context demonstrates that sometimes, unscalable solutions can indeed serve well for specific use cases, allowing teams to validate assumptions before investing in more complex infrastructure. The key takeaway is that engineering decisions should be guided by actual user needs and empirical evidence, not just best practices or future possibilities. Your framework encourages a pragmatic, lean approach that can adapt as the project matures—an invaluable mindset for startups and indie developers alike.