AWS Builder Center
13 Steps, 2 Weeks, 0 Documentation: Refactoring a Production Java Microservice with Spec-Driven AI Coding

13 Steps, 2 Weeks, 0 Documentation: Refactoring a Production Java Microservice with Spec-Driven AI Coding

A field report, not a demo: a Java/Spring Boot digital-key microservice — two years in production, zero documentation — rebuilt with spec-driven AI coding (Kiro). The full 13-step process across 4 phases, with commit histories, screenshots, and hard numbers: what planning budgeted two people a month, one person closed in two weeks; a 2+-week debugging fix now takes 4 hours; 98% API test coverage.

1. Why Refactor?

1.1 The Project

The service at the center of this story is a digital key system — the kind that lets a car owner unlock their vehicle with a phone. It coordinates three platforms: the mobile app, the vehicle, and the cloud. The cloud side is a microservice built on Java + Spring Boot, with JavaScript and HTML front-end fragments, Redis for state, and MySQL for persistence.
Nothing about it sounds remarkable until you add one detail: the APIs had been running in production for over two years, carrying real traffic from real cars and real phones.
That detail changes everything about refactoring.

1.2 The Motivation

We didn't refactor for aesthetic reasons. Three pressures forced the issue:
  • Production troubleshooting took two weeks or more. When something went wrong, engineers spent more time reconstructing the system's behavior than fixing it. The maintenance cost was unsustainable.
  • Zero documentation. No technical docs existed at all. The code was the only source of truth — a massive liability for a live service.
  • Three business demands were blocked. The system had no support for internationalization, could not keep up with rapid business iteration, and was not integrated with the company's foundation framework.

1.3 The Four Challenges

Any one of these would make a refactoring project hard. We had all four at once:
  1. Zero documentation. The old project had no docs at all. Not outdated docs — no docs. The code was the only source of truth, and nobody had a complete map of it.
  2. The production red line. The APIs had been live for two years with real traffic. During the entire refactoring, we could not break production. Zero tolerance. No "we'll hotfix it" escape hatch.
  3. Three-platform coordination. Phone, vehicle, cloud — plus the hardware layer. Integration testing is a maze when all three platforms must agree.
  4. Time pressure. Tight schedule, zero room for trial-and-error. There was no room for a failed attempt and a retry.

2. Why AI Coding?

Four reasons, in order of how much each one actually mattered:
1. AI excels at code comprehension. When no docs exist, a manual refactoring starts with a human reading code to reconstruct the business logic — weeks of work before touching a single line. Understanding code logic from source alone is precisely what AI does faster than any human. The biggest bottleneck of the traditional approach was the AI's home turf.
2. No one knows the legacy code. The team had no deep understanding of the old service. Manual refactoring under those conditions is slow and risky. AI reads all of it, all at once, without fatigue.
3. Company-wide AI Coding push. Even if we refactored this service by hand, AI Coding was coming to every project anyway. Better to learn the workflow now, on a project where the stakes would force us to be rigorous.
4. Free tokens, internal support. No cost concerns. We could iterate aggressively without cost-benefit paralysis.

3. The Process: Kiro's Blueprint, 13 Steps, 4 Phases

The process was not invented from scratch — it is a translation of Kiro, AWS's agentic IDE, into the constraints of our project: zero documentation, three-platform integration, and live production traffic. Kiro gave the blueprint; our constraints — zero docs, production red line, three platforms — gave it shape.

3.1 Kiro's Design Philosophy

Four primitives make up Kiro's methodology — each one codified in a doc, not a blog post. Together they turn AI coding from improvisation into engineering.
Specs (kiro.dev/docs/specs ). Structured artifacts formalize development: requirements.md (user stories with EARS acceptance criteria) → design.md (architecture, sequence diagrams, testing strategy) → tasks.md (discrete, trackable tasks). Ideas become executable plans — with human approval gates between phases. The insight behind it is simple but radical: an LLM's output quality is bounded by the quality of its input context. A prompt is a wish; a spec is a contract. Kiro bets that most AI coding failures are context failures, and it fixes the context first.
Steering (kiro.dev/docs/steering ). Persistent project knowledge in .kiro/steering/ — product, tech, and structure files loaded into every interaction. Conventions are written once and followed always, instead of re-explained in every chat. The quality ceiling of AI output is set by the clarity of the instructions, not the cleverness of the model.
Hooks (kiro.dev/docs/hooks ). Event-driven automation: JSON configs in .kiro/hooks/ fire shell commands or agent prompts on triggers — file save, pre-tool-use, task completion. Lint on save, gate dangerous operations, auto-generate tests and docs. Standards are enforced, not remembered.
Custom Agents (kiro.dev/docs/custom-agents ). Per-task agent configs in .kiro/agents/: which tools are available, which permissions are pre-approved, which context and prompt to load. A reviewer agent and a coder agent don't share a brain — separation is built into the platform. It acknowledges an uncomfortable truth about LLMs: an agent that wrote something will approve something. Fresh context is what makes a review real.

3.2 Phase 1 — Understand (Steps 1–3)

Kiro's spec-driven path assumes the spec exists. Ours didn't — the legacy service had zero documentation. So Phase 1 is essentially reverse spec-driven development: use AI to generate the understanding artifacts from the existing code, have humans review each one, and only then start changing anything. You cannot follow the spec-driven path forward, so you walk it backward. Every generated artifact went through human review.
Step 1: Generate tech docs. We had AI read the entire legacy codebase and produce comprehensive technical documentation from scratch — architecture, module responsibilities, key flows. New team members could onboard quickly. Humans reviewed the result. This single step eliminated the "zero documentation" challenge: we now had a reviewable map of the territory.
Step 2: Generate test cases. AI generated test cases based on the old code, covering all API endpoints. Coverage reached 98% — a safety net for the refactoring to come.
Step 3: Deep Code Distillation. Beyond docs and tests, we had AI systematically capture everything: architecture, class structures, the call chain for every business scenario, every Redis key, every MySQL table schema. "Distillation" here means boiling the system down to what it actually does — and writing it down — before you change what it does.

3.3 Phase 2 — Define (Step 4)

Phase 2 is the most underestimated phase of the whole process — and, in hindsight, one of the most important. "Define" is not just about coding standards. Before a single line is refactored, Step 4 sets the contract the new code must satisfy, in two parts:
Part 1 — Define new code standards. Base framework and versions (pinned, not assumed), naming conventions (one vocabulary for classes, methods and configs), middleware integration patterns (uniform approaches for Redis, MySQL and config centers) — plus harness engineering: the docs structure and the AI Coding workflow rules that harness the agents (where each artifact lives, which skill runs at which step, what every agent must read before it writes). All decided and written down before any refactoring began. AI performs exactly as well as its instructions; this is where the quality ceiling gets set.
Part 2 — Meet new requirements. A refactor that only reproduces old behavior in new code just relocates the technical debt. Step 4 also defines where the service has to go: extensibility (ready for future key types and device categories), troubleshooting (traceable call paths, meaningful errors), and monitoring & alerting (metrics, dashboards, and alert rules shipped together with the code, not bolted on later). These requirements were written down with the same discipline as the standards.
What Phase 2 looked like in practice. Two screenshots from the actual run. First, the docs structure the AI was required to maintain from day one — specs/ and plans/ are dated design and implementation documents, architecture/ and guides/ hold the long-term knowledge:
The Phase 2 contract becomes a file tree — versioned in the repo, not in someone's head.
Second, the writing-plans skill in action. Before generating an implementation plan, it locks every existing test file and class signature (Glob + Grep over src/test/java) so each plan step executes directly against reality, not against the AI's imagination:
Plans are grounded, not imagined: the skill inventories test files and class signatures first.

3.4 Phase 3 — Refactor & Verify (Steps 5–10)

This is the heart of the process, and its most important design decision: every verification step uses a different agent, and every step ends with human review. Different agents for each verification step — separation of player and referee.
Step 5: AI refactor. AI rewrites the code according to the legacy behavior captured in Phase 1 and the standards and requirements defined in Step 4.
Step 6: Consistency check. A different agent compares the new code's behavior against the distilled documentation. Human review follows.
Step 7: Test regression. Another agent runs the Step 2 test cases against the new code and verifies the results match. Any failures get fixed, then human review again.
Step 8: Code diff. Yet another agent compares old and new code to identify every difference — so nothing changed that we didn't intend to change. Human review, again.
Step 9: New docs. Based on the new code: detailed technical docs, requirement-change records, optimization notes, and a TODO list of unfinished items.
Step 10: Knowledge base. All of the above, structured and stored as a knowledge base that future AI interactions can consume. The documentation stops being a pile of files and becomes an input to the next loop.
Why the agent-per-step separation? Because the player and the referee cannot be the same person. An agent that wrote the code will approve its own code. Fresh context per verification step is what makes the checks real.
Receipts from Phase 3. Five artifacts from the actual run. The design document was completed and passed a self-review before a human ever saw it — and the review caught real issues: transaction boundaries that would not commit, result models mixed with exception handling, cache-invalidation edge cases. Its quality gates were explicit: no TBD/TODO placeholders, explicit non-goals, security design, test strategy, and acceptance criteria:
Self-check passed: transaction boundaries, quality gates — human review before any code.
The implementation plan was written into an isolated worktree, decomposed into 7 TDD tasks, with 459 tests passing as the locked baseline:
Coding starts only after the plan is approved — and the plan already knows how it will be verified.
Before rewriting, the AI critiqued the target architecture itself — five stacked layers (Service, Coordinator, Manager, Strategy, Client) challenged, then simplified before rewriting:
The refactor skill refuses to blindly replicate the old layering — that would just relocate the debt.
Task execution fed back into the long-term knowledge docs: architecture notes and guides were flagged as must-update, so documentation shipped with the code instead of after it:
Every task ends with the knowledge base in sync — docs are an output of the workflow, not an afterthought.
And the commit history itself reads as the audit trail of all 13 steps. Every AI-generated commit carries an [AI] marker (plus a Co-authored-by attribution) — documentation generation, test case generation, code refactoring, verification fixes, grayscale release:
Every stage of the process is visible in the commit history: AI writes, humans review, the merge happens.

3.5 Phase 4 — Deploy (Steps 11–13)

Step 11: Deploy & integration. AI deploys the new code and performs integration testing across the three platforms. Issues found during joint debugging were identified and fixed immediately by AI. Outcome: the first integration run took 20 minutes.
Step 12: Grayscale plan. AI designs a gradual rollout strategy. The plan undergoes human review before execution — this is a gate, not a rubber stamp. Outcome: a risk-mitigated rollout.
Step 13: Grayscale release. The code ships to production in stages, traffic shifting incrementally under monitoring. Outcome: zero production incidents.

4. What Worked Well

1. Coding efficiency beyond manual comparison. What we budgeted as one week of coding was completed in 4 hours — a 25x productivity gain on core refactoring.
2. Integration was startlingly fast. The original plan budgeted two people for a month of joint debugging. In the end, one person closed it in two weeks.
3. First-pass success. In the first 20 minutes of three-platform integration, 90% of functions passed. Exactly 2 bugs appeared — and both were traced to human error, not AI-generated code.
4. Documentation maintains itself. Code and documentation now update together. The "docs are always six months stale" problem is structurally gone, because the docs are generated from the code as part of the workflow.
5. Full traceability. Every AI interaction is recorded. The change history is complete — you can reconstruct not just what changed, but why, step by step.
6. Strong test generation. Tests generated from real traffic data covered more ground than our hand-written suites ever did.
7. Strong bug analysis and repair. Given a failure, AI quickly localized the root cause and proposed fixes — often faster than the humans could load the relevant context.
8. Quality is determined at the planning stage. The clearer the requirement documentation, the higher the AI's output quality. Garbage in, garbage out — and the reverse.

5. What Didn't Work

An honest report includes the failures. Five of them:
1. Small changes = full cycle. A tiny edit required reloading context and running the entire iteration flow. For trivial fixes, manual coding was actually faster. The 13-step process is heavyweight; not every change deserves it.
2. Authorization interruptions. AI executing long tasks needed multiple authorization confirmations, breaking the workflow at exactly the moments when the agent was most productive.
3. Review fatigue. AI output speed is fast — and the review volume scales accordingly. Sustained, high-intensity reviewing is exhausting, and tired reviewers approve bad code.
4. Player vs. referee conflict. When the same agent wrote code and reviewed its own code, review quality visibly dropped. Context isolation between agents isn't a nice-to-have; it's the mechanism that makes verification meaningful.
5. Doc-dependent bug analysis. AI analyzes bugs by comparing against generated docs. If those docs contain a bias or a gap, AI may miss the true root cause — confidently. The safety net can itself have holes.
The key lesson: these pain points are process issues, not AI capability limits. Better workflows solve most of them.

6. Key Takeaways

Eight lessons, distilled:
  1. Code without docs is tech debt. Documentation is the requirement — the unfinished task. Code is merely the result. Missing docs = invisible debt.
  2. Process > AI code generation. The refactoring workflow and standards you design matter more than letting AI write code. Process is the real product.
  3. Best model for docs, cheaper for code. Use the strongest model for documentation generation. For code writing, a standard model is sufficient and more cost-effective.
  4. Review docs > review code. Reviewing documentation catches more issues than reviewing code. Docs reveal logical gaps that code alone hides — and an error in the docs propagates everywhere, while an error in one function stays local.
  5. Don't rush to manual analysis. When bugs appear, let AI analyze first and output full call chains as docs. Read docs, not code, to locate the problem — then let AI make the fix. Your eyes are the scarce resource; spend them on the map, not the terrain.
  6. Your taste sets the ceiling. AI generates code at the level of your code taste. Better code taste → higher AI output quality. Invest in your own standards.
  7. Attitude determines outcomes. People with a positive attitude toward AI coding find ways to help AI succeed; neutral-to-negative people find an endless list of faults. Both are correct observations of the same tool — the difference is the outcome.
  8. Unreasonable becomes reasonable. Once AI removed the implementation cost from the equation, previously unreasonable product demands suddenly became feasible. A surprising amount of what we called "unreasonable" was actually "unaffordable."

Closing Thought

We started with a production service nobody fully understood, zero documentation, three coordinated platforms, and a red line that said "never break production." We finished with a refactored service, a 98%-coverage test suite, a living knowledge base, a 20-minute first integration that validated 90% of functionality, and two bugs — both human.
The uncomfortable conclusion is not "AI writes great code." It does, but that was never the bottleneck. The conclusion is that the process around the AI — the distillation, the standards, the separated verification agents, the human gates — is what made the outcome safe. The AI was the engine; the 13 steps were the steering, brakes, and seatbelt.
And the 13 steps themselves were not ours. They were Kiro's design philosophy — specs, steering, hooks, custom agents — translated, step by step, to fit a zero-doc service with a production red line. The philosophy gave us the blueprint; our constraints gave it its final shape. One last note for anyone copying this process: nothing here is tool-specific. Where Kiro provides these primitives natively, other competent coding agents can run the same process — you just build the scaffolding by hand. The value is in the workflow, not the vendor.
Refactor your process first. The code will follow.

Have you refactored a production service with AI agents — or are you still weighing whether to trust one? I'd love to hear how it went, especially the parts that didn't work.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article