The most common advice given to founding engineers is: "Move fast and write throwaway code."
The second most common advice is: "Build for scale from day one."
Both pieces of advice are flawed when taken to extremes.
If you build for 10 million users on day one, you will run out of runway before you find product-market fit. But if you write completely throwaway code with tangled database schemas and zero architectural boundaries, your first 500 paying users will grind your sprint velocity to zero as every bug fix causes three regressions.
Over the past three years building 0-to-1 products across AI, B2B SaaS, and workflows, I've developed a pragmatic framework for designing MVPs that can ship in days without becoming a fatal rewrite trap.
1. Code is Cheap to Rewrite. Database Schemas Are Not.
You can easily rewrite a React UI or replace an Express endpoint with FastAPI in a weekend.
What you cannot easily rewrite without downtime and agonizing data migration is a poorly modeled database schema with 50,000 live user records.
The Rule: Invest in the Relational Core
- Keep entities normalized and clearly separated:
users,organizations,workspaces,memberships,audit_logs. - Always include
created_at,updated_at, and a UUID primary key from day one. - Even if your MVP is for single-tenant users, model multi-tenancy (
workspace_id) into your schema immediately. Adding multi-tenancy later is one of the most painful retrofits in software engineering.
2. Separate Pure Logic From External I/O
When teams ship fast, they tend to mix database queries, third-party API calls, and business rules all inside a single 400-line controller function.
When that API changes (e.g. Stripe updates their billing webhook or OpenAI deprecates a model), the whole system breaks.
The Fix: Hexagonal Boundaries in Miniature
You don't need a bloated enterprise Java architecture. You just need clean function signatures:
// Good: Pure domain logic isolated from HTTP / Frameworks
export function calculateSubscriptionEntitlement(
plan: PlanTier,
usageCount: number
): EntitlementResult {
if (usageCount >= plan.limit) {
return { allowed: false, reason: 'QUOTA_EXCEEDED' };
}
return { allowed: true, remaining: plan.limit - usageCount };
}
By keeping core rules pure, you can test them in milliseconds without mocking databases or external HTTP networks.
3. Don't Deploy Microservices Until You Feel Pain
Starting an MVP with 6 microservices, Kafka, and Kubernetes is engineering vanity.
A well-structured modular monolith:
- Runs in a single Docker container.
- Uses simple Postgres transactions instead of distributed two-phase commits.
- Deploys in 60 seconds with simple CI/CD.
- Costs $20/month on a single VPS or managed container service.
The key word is modular. Keep your domain folders separate:
src/
modules/
auth/
billing/
deals/
transcription/
If the transcription worker eventually needs its own GPU instance or dedicated queue, pulling it out into an independent service takes hours, not months.
4. Observability is Not an "After-Launch" Task
You cannot fix what you cannot see. When an early-stage user says "The button didn't work", having to reply "Can you open your browser console and send a screenshot?" destroys credibility.
Before shipping an MVP to your first user:
- Configure structured logging with a request ID that propagates through the call stack.
- Set up a lightweight error tracking tool (Sentry, OpenTelemetry, or SigNoz).
- Track critical business milestones (e.g.,
user_signed_up,deal_synced,export_completed).
Final Thought
High agency in engineering isn't about writing the most code or using the newest framework. It's about knowing which 10% of architectural decisions create 90% of your future leverage.
Ship the simplest thing that solves the customer's problem today, but protect your data model and boundaries so you can build tomorrow without fear.