Design Thinking
Decision-Making Under Real Constraints
Senior engineers excel at architectural decisions under uncertainty. Learn time vs correctness vs cost trade-offs, build vs buy vs defer, and MVP vs long-term architecture.
Senior engineers distinguish themselves not by knowing more technologies, but by making better decisions under real constraints: incomplete requirements, wrong assumptions, deadline pressure, and budget limits. This topic explores how to think about architectural decisions when you don't have the luxury of perfect information.
Designing Under Incomplete or Wrong Requirements
The Reality
In practice, you will often design systems where:
- Requirements are vague: "Build something like X" with no specs
- Requirements are wrong: Stakeholders don't know what they need yet
- Requirements change: The product pivots before you ship
- Requirements conflict: Latency vs cost vs reliability can't all be optimized
Senior Approach
- Name the uncertainty: "We're uncertain about X. Here's what we're assuming."
- Design for change: Choose components that can be swapped or extended
- Build reversible decisions first: Prefer choices you can undo
- Defer irreversible ones: Don't lock in until you have signal
Example: Vague "Design a Feed"
Junior response: "I'll use Cassandra for write scalability and Redis for caching."
Senior response: "Before choosing storage, I need to clarify: Is this activity feed or algorithmic? What's the read/write ratio? Can we start with a simple append-only design and evolve? I'll assume activity feed for now and design so we can swap to ranking later."
Time vs Correctness vs Cost Trade-offs
The Triangle
Every decision sits in a triangle. You can optimize for two, rarely all three:
| Priority | What You Gain | What You Sacrifice |
|---|---|---|
| Time first | Ship fast, learn from users | Technical debt, may need rewrite |
| Correctness first | Robust, scalable, maintainable | Slower to market, higher cost |
| Cost first | Fits budget, efficient | May limit scale or features |
When to Optimize for Time
- Product-market fit unknown
- Competitive pressure
- Learning phase (MVP, experiment)
- Reversible decision
When to Optimize for Correctness
- Financial transactions, compliance, safety
- Core platform that many teams depend on
- Irreversible decisions (data model, external contracts)
When to Optimize for Cost
- Known scale, predictable load
- Cost-sensitive business model
- Optimization phase after PMF
Real-World Example: Startup vs Enterprise
Startup: Time first. Ship in 6 weeks with a monolith, PostgreSQL, and minimal infra. Accept that you'll refactor. Correctness on money movement only.
Enterprise: Correctness and compliance first. SOC2, multi-region, audit logs from day one. Time and cost are secondary.
Build vs Buy vs Defer Decisions
Framework
- Build when: Core differentiator, no good vendor fit, or vendor lock-in risk is high
- Buy when: Commodity problem, faster to integrate, vendor has scale/expertise
- Defer when: Requirements unclear, not blocking, or can use a simple interim solution
Build vs Buy Matrix
| Factor | Lean Build | Lean Buy |
|---|---|---|
| Auth | Simple JWT, session | Auth0, Cognito, Firebase Auth |
| Payments | Don't build | Stripe, Braintree |
| Search | DB LIKE, then Algolia/Elastic | Elasticsearch, Algolia |
| Don't build | SendGrid, SES | |
| Real-time | Polling → WebSockets | Pusher, Ably, or build |
Senior Insight: The Hidden Cost of Build
Building seems cheaper until you count: ongoing maintenance, security patches, scaling, monitoring, and opportunity cost. Buying often wins for non-differentiating capabilities.
Senior Insight: The Hidden Cost of Buy
Vendor lock-in, rate limits, pricing changes, and lack of customization can make buy painful. For core capabilities, build may be worth it.
MVP vs Long-Term Architecture Decisions
The Tension
- MVP: Fast, simple, good enough to learn
- Long-term: Scalable, maintainable, fits future vision
Senior Approach: Strangler Fig Pattern
Design the MVP so it can grow:
- Modular monolith: Clear boundaries even if deployed together
- Database: Choose schema that can be split (avoid cross-table joins at boundaries)
- APIs: Internal interfaces from day one, even if same process
- State: Stateless services, external state store
What to Get Right Early
- Data model for core entities (hard to change)
- Authentication/authorization model
- External contracts (webhooks, APIs you expose)
What You Can Fix Later
- Caching layer
- Queue implementation
- Read replicas vs sharding
- Service boundaries (can split monolith)
Thinking Aloud Like a Senior Engineer
Problem: "We need to add payments. We have 3 months and 2 engineers."
My first instinct: "Let's build a payment service. We need full control."
But wait — payments are regulated. PCI compliance. Chargebacks. Currency handling. Building is a 12+ month project for a small team.
I'm thinking: "Buy. Stripe or similar. Integrate in 2–4 weeks. Focus our engineers on what differentiates us."
What about lock-in? "Stripe has good abstractions. We can use their API and keep our data model. If we need to switch later, we'd migrate transactions—possible but painful. For now, speed matters more."
What about cost? "At our scale, Stripe's fees are acceptable. When we're processing $10M/month, we can reassess. That's a good problem to have."
Decision: Buy (Stripe). Defer building. Revisit at 10x scale. Document as a reversible decision with a review trigger.
How a Senior Engineer Thinks About Constraints
- Name constraints explicitly: Time, budget, team size, compliance
- Separate reversible from irreversible: Optimize confidence for irreversible
- Quantify when possible: "2 weeks to buy vs 3 months to build"
- Plan for evolution: "We'll reassess when we hit X"
- Document the trade-off: "We chose Y because of Z. We're accepting A. We'll revisit if B happens."
Best Practices
- Never assume perfect requirements: Design for change
- Make the triangle explicit: "We're optimizing for time; we accept cost"
- Default to buy for commodity: Auth, payments, email, search
- Default to build for differentiation: Core logic, unique workflows
- Defer when unclear: Simple solution first, evolve with learning
Common Interview Questions
Intermediate
Q: How do you decide between building and buying a component?
A: I consider: (1) Is it core to our product? Build. (2) Is it a commodity with good vendors? Buy. (3) Are requirements unclear? Defer—use simplest option. I also factor in team expertise, timeline, and total cost of ownership (maintenance, not just initial build).
Senior
Q: You're told to ship in 6 weeks but the right architecture would take 3 months. What do you do?
A: I'd identify what's reversible vs irreversible. For reversible choices (caching, queue tech), I'd ship the fastest option. For irreversible (data model, external API contracts), I'd push back or scope down. I'd document technical debt and create a plan to address it. I'd also ask: "What's the cost of being 6 weeks late?" Sometimes the right answer is to extend the timeline.
Summary
Decision-making under constraints is a core senior skill. Key takeaways:
- Name uncertainty and assumptions before proposing solutions
- Time vs correctness vs cost: optimize for two, rarely three
- Build vs buy vs defer: commodity → buy, differentiation → build, unclear → defer
- MVP vs long-term: modular monolith, clear boundaries, reversible decisions first
- Document trade-offs: what you chose, why, what you're accepting, when to revisit
FAQs
Q: How do I push back when requirements are wrong?
A: Frame it as risk: "If we build for X and it's actually Y, we'll spend Z weeks redoing it. Can we validate X with a quick prototype first?" Offer a low-cost way to reduce uncertainty.
Q: When should I insist on more time for correctness?
A: For safety, money, compliance, or data model. When the cost of being wrong is very high or the decision is hard to reverse.
Q: How do I explain technical debt to non-technical stakeholders?
A: "We're taking a shortcut now to hit the deadline. It will cost us X extra time later if we don't address it. Here's when we should revisit." Tie it to business impact.
Apply This Thinking
Practice what you've learned with these related system design questions:
Keep exploring
Design thinking works best when combined with practice. Explore more topics or apply what you've learned in our system design practice platform.