Specs First or Code First? I Wasted Months Learning the Wrong Lesson
The Mess I Created
Six months ago, I started building a payment processing module. I was confident. I’d built similar systems before. So I dove straight into code, figuring the requirements were obvious enough.
Three months in, I had this conversation with my tech lead:
Tech Lead: "What happens when a payment fails after the customer is charged?"Me: "Um... I haven't implemented that yet."Tech Lead: "What about partial refunds?"Me: "That's... on the backlog."Tech Lead: "Currency conversion errors?"Me: "..."Turns out, what I thought were “obvious requirements” had about twenty edge cases I’d never considered. Each one required rewriting chunks of the core logic. The code-first approach that felt fast in week one had created a slow-motion disaster by month three.
But here’s the thing: my colleague on the same team took the opposite approach. She spent three weeks writing detailed specifications for her module. By month three, she was still implementing because stakeholders kept changing their minds about what they actually wanted. Her specs became obsolete before she finished coding.
We both got it wrong. The problem isn’t specs vs code. The problem is applying one approach to everything.
The False Binary
The industry loves binary debates:
- Waterfall vs Agile
- Monolith vs Microservices
- Tabs vs Spaces
And now: Specs First vs Code First.
But real development doesn’t work in binaries. It works on a spectrum:
Pure Specs Pure Code | | | Spec-Heavy Hybrid Code-Heavy | | | | v v v v[Docs First] ---> [Spec + Prototype] ---> [Code First] | | v vSlow start, stable finish Fast start, messy finishI’ve worked on both ends of this spectrum. Neither is universally right. The trick is knowing which end to choose for each situation.
When Specs First Saved Me
After the payment module disaster, I was assigned to build an authentication system. I almost made the same mistake, but my tech lead insisted on specs first.
I spent a week documenting:
## Authentication Flow
1. User submits credentials2. System validates against user store3. System generates JWT token (15 min expiry)4. System issues refresh token (7 day expiry)
## Edge Cases- Failed login: Rate limit after 5 attempts- Expired token: Use refresh token- Compromised account: Admin revoke endpoint
## Security Requirements- Password: bcrypt, cost factor 12- Token: RS256 signing- Session: Single active session per userThis took a week. But here’s what happened:
- Stakeholders caught two security gaps I’d missed
- The team reviewed the spec and pointed out scalability issues
- We identified dependencies on the user service team early
- Implementation took exactly three weeks, no rewrites
The upfront investment paid off because:
- Requirements were clear (we knew what auth looks like)
- Risk was high (security issues are expensive)
- Multiple teams were involved (coordination needed)
When Code First Saved Me
Later, I was tasked with building a dashboard for content creators. The requirements doc said: “Show engagement metrics.”
I almost started writing specs. Then I paused and asked the product manager: “What engagement metrics?”
They listed five things. I started sketching them. They changed their mind three times in the same meeting.
This was my signal: specs would be premature.
Instead, I built a quick prototype in two days:
// Quick prototype to validate UX assumptionsfunction renderDashboard(user) { return { metrics: ["views", "clicks", "conversions"], timeRange: "30d", layout: "horizontal_cards" // Testing this assumption }}I showed it to three content creators. Their feedback:
- “I need to compare to last month” (not in original requirements)
- “Loading takes too long, show skeleton first” (I hadn’t thought of this)
- “Can I filter by content type?” (scope creep, but valid)
The prototype surfaced real requirements in two days that would have taken weeks of meetings to discover. Code-first worked because:
- Requirements were uncertain (“I’ll know it when I see it”)
- User validation was needed
- Risk was low (dashboard changes are cheap)
The Decision Framework
After making every mistake possible, I built myself a decision checklist:
## Should I Spec First?
Answer these questions. If most answers are "Yes," invest in specs.If most are "No," start with code.
### Requirements Clarity- [ ] Do I understand exactly what needs to be built?- [ ] Could I explain this to another developer without questions?- [ ] Are edge cases already identified?
### Risk Assessment- [ ] Would a bug here cause significant damage?- [ ] Is this hard to change later?- [ ] Are there security or compliance implications?
### Team Context- [ ] Will others build on this work?- [ ] Do we need to coordinate with other teams?- [ ] Will this need to be maintained by someone else?
### Domain Knowledge- [ ] Have I built something similar before?- [ ] Does the team have expertise in this area?- [ ] Are there existing patterns to follow?Here’s how different components scored on my last project:
High Clarity of Requirements | | SPEC FIRST | SPEC FIRST (document contracts) | (reduce risk) | [APIs/Services]------------+------------[Security/Auth] | | CODE FIRST | HYBRID (explore interactions) | (prototype then spec) | [UI/UX Components]---------+---------[Business Logic] | | Low Clarity of RequirementsThe Hybrid Approach: What Actually Works
Most experienced teams don’t pick one approach. They slide along the spectrum based on what they’re building.
Here’s the workflow I now use:
Phase 1: Light Spec (10-20% detail) | Just enough to define boundaries, not implementation vPhase 2: Prototype Core (validate assumptions) | Build minimal viable version vPhase 3: Harden Spec (fill in details) | Document what actually worked vPhase 4: Complete ImplementationWhen to shift from code to specs:
- The prototype starts to stabilize
- Others need to build on your work
- The feature becomes production-critical
- Requirements crystallize after user feedback
A Real Example
For that dashboard project, here’s how the hybrid approach worked:
Week 1: Light Spec (2 hours)
Feature: User Dashboard AnalyticsScope: Display engagement metrics for content creatorsBoundaries: - Read-only (no admin actions in this phase) - Last 30 days only (expand later) - Three core metrics: views, clicks, conversionsOut of Scope: - Export functionality - Historical comparisons - Real-time updatesDependencies: - Analytics API (exists) - User auth (exists)Risk: Low - can iterate quicklyDecision: CODE FIRST, spec details as patterns emergeWeek 2: Prototype (2 days)
Built the minimal version, tested with users, discovered real requirements.
Week 3: Harden Spec (1 day)
Verified Pattern: - Horizontal card layout confirmed via user testing - Users want comparison to previous period - Need loading states for slow API calls
Extended Spec (post-validation): - Add period-over-period comparison - Implement skeleton loading states - Cache metrics client-sideWeek 4: Complete Implementation
Built the full feature with confidence. No rewrites.
Anti-Patterns I’ve Learned to Avoid
Premature Specification
I once wrote detailed specs for a UI redesign. Two weeks of documentation. Then user testing revealed the entire approach was wrong. The specs went straight to the trash.
Lesson: Don’t spec what you haven’t validated.
Code Without Direction
The payment module story. No specs, no plan, just code. Result: three rewrites and a frustrated team.
Lesson: Critical systems need upfront thinking.
One-Size-Fits-All
A previous team insisted on detailed specs for everything. Even internal tools. Even experimental features. They spent more time documenting than building.
Lesson: Match the investment to the component type.
The Time Budget Reality
Someone on Reddit captured the real constraint:
“With a limited number of hours available per week, it’s really important to choose where to focus.”
This is the actual question. Not “specs or code?” but “where do I invest my limited hours for maximum impact?”
Here’s my current allocation heuristic:
| Component Type | Spec Investment | Code Investment |
|---|---|---|
| Security/Auth | 40% spec | 60% code |
| API Contracts | 50% spec | 50% code |
| Business Logic | 20% spec | 80% code |
| UI Components | 5% spec | 95% code |
| Internal Tools | 5% spec | 95% code |
Your percentages may differ. The point is to be intentional about where you invest.
Summary
The specs-first vs code-first question isn’t about which is “right.” It’s about matching your approach to your situation.
Use specs-first when:
- Requirements are clear
- Risk is high
- Multiple people need alignment
- You’re building on stable patterns
- The cost of mistakes outweighs planning time
Use code-first when:
- Requirements are uncertain
- User validation is needed
- Risk is low
- You’re exploring new domains
- The cost of exploration is less than premature planning
The real insight: Experienced developers don’t choose one approach. They slide along the spectrum based on what they’re building. Routes and auth get spec’d first. UI and interfaces get prototyped first. Business logic gets hybrid treatment.
Stop asking “specs or code?” Start asking “what does this component need?” The answer will tell you where to invest your limited hours.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Is Design Dead? - Martin Fowler
- 👨💻 Painless Functional Specifications - Joel Spolsky
- 👨💻 Agile Manifesto
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments