Technical Design
In the previous section, we wrote a detailed PRD that specifies exactly what our JSON Formatter should do — formatting, minifying, validating, tree view, and more. Now it's time to turn that PRD into a technical design — defining the component structure, data flow, and architecture before we write any code.
Why Understand the Design?#
You might think: if Claude Code is writing the code, why do I need to understand the technical design? Can't I just let the AI handle it?
AI coding agents are remarkably good at generating working code — but they're not perfect. When something breaks, the agent might go in circles: trying fix after fix without understanding the root cause. This is where your understanding of the design becomes critical. If you know how data flows from the editor to the formatter, how the Web Worker communicates with the main thread, or how the tree view recursively renders nested objects, you can:
- Diagnose bugs faster — Instead of waiting for the AI to debug, you can pinpoint whether the issue is in parsing, rendering, or state management.
- Guide the AI effectively — A prompt like "the bug is in how the worker posts formatted results back to the main thread" is far more useful than "it's broken, fix it."
- Fix issues yourself — Sometimes the quickest path is a manual two-line fix. You can only do that if you understand the architecture.
Think of the technical design as your map. Claude Code is a powerful driver, but when the GPS loses signal, you need to be able to read the map yourself.
Writing the Design#
Before starting, clear your conversation history — in Claude Code, use the /clear command. This matters because the previous conversation about writing the PRD leaves behind context (drafts, revisions, review feedback) that can bias the AI's design decisions. A fresh conversation forces the AI to work from the PRD file itself — the finalized version — rather than half-remembered earlier drafts or discussion tangents. Clean context in, clean design out.
We'll ask Claude Code to read the PRD and produce a DESIGN.md that covers the architecture, UI layout, and key implementation decisions. Having this as a separate file keeps concerns clean: the PRD says what to build, and the design says how to build it.
Ask AI to generate a technical design document based on the PRD.
Here's an example of what Claude Code might produce. The design covers four main areas: the high-level architecture showing how the app shell, input/output panels, and Web Worker fit together; the UI design with layout wireframes for desktop and mobile, toolbar actions, and interaction details like drag-and-drop and error highlighting; the file structure mapping every component, hook, and utility to a specific file; and the Web Worker design explaining what runs off the main thread, the message protocol, and how stale results are discarded.
Revising the Design#
The generated design is solid — it covers the architecture, UI layout, file structure, and worker protocol in a way that's ready to implement. But just like with the PRD, it's worth reviewing with a critical eye before we start coding. A design doc that's too complex or includes unnecessary abstractions will lead the AI to generate over-engineered code.
If you read through the design carefully, you'll notice several issues worth fixing:
- Status bar placement — The status bar sits at the very bottom of the page, but it should be directly below the input and output panels. It should show both validation status (valid/invalid with error details) and stats (size, keys, depth) in one row — no need for a separate StatsPanel.
- Toolbar placement — The action buttons (Upload, Paste, Clear, Copy, Download, Minify) are split between the input and output panels. They should live in a single toolbar row above both panels, keeping the UI cleaner and the actions easy to find.
- Stats panel — The "collapsible via a chevron toggle" interaction adds unnecessary complexity. Stats are small enough to always show — just display them in the status bar.
- Settings as a popover — A full slide-over drawer is overkill for three settings. A popover dialog triggered by the gear icon is lighter and keeps the user in context.
You could fix these one at a time — chat with the AI, explain one issue, review the change, then move to the next. That's a perfectly valid workflow, and it's often better for complex or ambiguous changes where you want to verify each step. But here, for clarity, we'll batch all four fixes into a single prompt:
Ask AI to fix the UI layout and simplify the design.
The design also doesn't mention testing. The pure functions in lib/ — parsing, formatting, minifying, validation, stats computation — are the core logic of the app and are easy to test in isolation. Adding a test plan to the design ensures the AI generates testable code from the start, rather than bolting tests on after the fact.
Ask AI to add a testing section to the design.
Here's the revised design with all the fixes applied. The toolbar now sits above both panels as a single row, the status bar moved directly below the panels and merges validation status with stats (removing the separate StatsPanel), the settings drawer was replaced with a lightweight popover, and a new testing section covers unit tests for all lib/ functions using Jest.
Reviewing the Design#
Just as we did with the PRD, the final step is to let Claude Code review the design for any issues we might have missed — contradictions between sections, missing details that would block implementation, or unnecessary complexity that slipped through.
Ask AI to check for conflicts or gaps in the design.
Here's what Claude Code flagged — 3 contradictions, 3 missing details, and 2 ambiguities:
These are all valid catches. Let's ask Claude Code to resolve them:
Ask AI to fix the flagged contradictions and gaps.
Here's the final design with all issues resolved:
You can repeat this review-and-resolve cycle as many times as needed until no issues remain. A design with no loose ends means fewer surprises when we start building.
With the design finalized, we're ready to move on to implementation.