For a long time, I thought specifications were just a polite way to slow engineers down.
- Big documents.
- Outdated diagrams.
- Things nobody reads after sprint one.
Then I actually used specification-driven development with Kiro on a real project, and my opinion changed completely.
This article is not about a product, a framework, or a startup idea.
It is about what changed in how I think and work as an engineer once I started treating specifications as first-class citizens.
I Used to Start with Code (and Regret It Later)
My old workflow looked like this:
- “I roughly know what needs to be built”
- Sketch an architecture in my head
- Start coding
- Discover edge cases halfway through
- Refactor
- Repeat
It felt fast.
It was not.
Most of the time, I was not fixing bugs. I was fixing unclear decisions I never made explicitly.
Using Kiro forced me to stop before step two.
Writing the Requirement First Was Uncomfortable
The first thing I had to write was a requirement, not code.
Something like:
As an entity owner, I want to register my organization and receive credentials,
so that I can submit data for processing.
Followed by acceptance criteria such as:
- the system accepts only basic information
- credentials are generated once
- a default configuration is created
No cloud provider.
No database.
No crypto algorithms.
At first, this felt artificial.
I already knew how I wanted to build it, so why slow down?
Then something interesting happened.
The Spec Exposed Assumptions I Didn’t Know I Had
As I wrote the acceptance criteria, questions started appearing:
- What exactly does “registered” mean?
- What exists after registration?
- What must be returned, and what must never be returned again?
- What is intentionally out of scope?
None of these questions were about code.
They were about behavior.
I realized that I usually answered these questions implicitly while coding.
That is risky.
Acceptance Criteria Became My Decision Filter
Once the acceptance criteria were written, they became my favorite tool.
During implementation, I kept asking myself:
Does this help satisfy an acceptance criterion?
If the answer was no, I stopped.
This single habit prevented over-engineering, killed nice-to-have features early, and reduced scope creep without meetings.
Reviews also changed.
Discussions became:
Which acceptance criterion does this serve?
instead of:
I feel like this might be useful later.
What Kiro Changed That I Didn’t Expect
At this point, a fair question is:
Couldn’t you do all of this without Kiro?
Technically, yes.
Practically, I never did.
Before Kiro: Acceptance Criteria Were Optional
Before, my workflow looked like this:
- Write acceptance criteria
- Design the solution
- Start coding
- Adjust scope along the way
Nothing stopped me from:
- adding extra fields while I was there
- handling edge cases not in the requirement
- making implementation-driven decisions
The acceptance criteria existed, but they had no real weight.
With Kiro: Acceptance Criteria Became Structural
With Kiro, I could not move forward without:
- a defined requirement
- explicit acceptance criteria
- a design derived from them
- tasks mapped back to them
Skipping clarity was not forbidden. It was just uncomfortable.
If I tried to jump ahead:
- designs felt premature
- tasks felt vague
- gaps became obvious immediately
Kiro did not magically make me write better specs.
It made weak specs impossible to ignore.
Less Mental Overhead While Coding
Before Kiro, I constantly asked myself:
- Is this enough?
- Am I missing something?
- Should I add this now?
With acceptance criteria embedded into the workflow:
- many decisions were already made
- implementation became mechanical
- confidence increased
This was not about documentation.
It was about removing uncertainty at the exact moment it hurts the most, while coding.
Intent Became a System Constraint
The most important shift was subtle.
Acceptance criteria stopped being guidance and became constraints that the system enforced.
Once that happened:
- over-engineering dropped
- scope creep became visible
- refactoring felt safer
Not because I tried harder, but because deviation became obvious.
Design Became Simpler (Not Bigger)
I expected specifications to lead to heavier designs.
The opposite happened.
Because the behavioral contract was clear, the design only needed to:
- satisfy the requirement
- handle failures
- remain replaceable
No speculative abstractions.
No future-proof layers.
Design stopped being a guessing game and became a direct response to the spec.
Tasks Stopped Being Vague
Breaking the work into tasks became almost mechanical.
Each task:
- mapped to an acceptance criterion
- had a clear definition of done
- avoided vague verbs like “handle” or “manage”
Estimation improved.
Progress became visible.
Half-done work became obvious.
Tasks stopped being things to do and became contracts to fulfill.
Refactoring Suddenly Felt Safe
This part surprised me.
Because the specification defined what must happen, not how, I could:
- rewrite internals
- simplify logic
- replace components
As long as the acceptance criteria still held, the system was correct.
It changed how I view code:
Code is temporary.
Behavior is the real asset.
Mistakes I Made Along the Way
It was not perfect. I made mistakes, and they were useful.
1. I Over-Specified Security Details
My first version included:
- key formats
- cryptographic assumptions
- token strategies
That made the spec rigid and harder to evolve.
Lesson learned: specify security outcomes, not mechanisms.
2. I Treated the First Spec as Final
I assumed the spec needed to be perfect from day one.
It did not.
The best specs evolved:
- wording improved
- acceptance criteria were reordered
- unnecessary constraints were removed
A spec should be living, not frozen.
3. I Underestimated Acceptance Criteria
At first, I treated acceptance criteria like a formality.
They turned out to be the most valuable part of the entire process.
If I had to keep only one thing from the spec, it would be those.
4. I Almost Skipped Specs for Small Features
I thought some features were too small to justify a spec.
Those were exactly the ones that later caused confusion:
- unclear defaults
- inconsistent behavior
- surprising edge cases
Even a short spec was cheaper than fixing misunderstandings later.
What Actually Changed in My Workflow
Using specification-driven development consistently led to:
- fewer late surprises
- fewer abandoned implementations
- fewer “why did we build this?” moments
I now spend more time at the beginning and far less time undoing work later.
It does not slow me down.
It makes me deliberate.
Final Thought
Kiro did not invent good engineering practices.
It made them unavoidable.
It did not teach me how to write better code.
It taught me how to think before writing code.
And that turns out to be the hardest and most valuable part of engineering.
Writing code is easy.
Deciding what code should exist is the real work.
Top comments (0)