Loading content...
A design exists in two forms: the design-in-your-head and the design-on-paper. The first is rich with context, reasoning, and nuance. The second is what survives after you've moved to other projects, left the company, or simply forgotten the details.
The gap between these two forms is where projects fail. Brilliant designs become incomprehensible systems when the reasoning behind them is lost. Future maintainers make changes that violate assumptions they never knew existed. What seemed like a robust architecture becomes a fragile mess because no one remembers why things were built this way.
This page teaches you to bridge that gap—to produce documentation that captures not just what your design is, but why it is that way, preserving the insight and reasoning that made it successful.
By the end of this page, you will understand the different purposes design documentation serves, the essential components of comprehensive documentation, techniques for writing clear and maintainable documents, and how to balance thoroughness with practicality.
Before creating documentation, understand who will read it and why. Different audiences have different needs, and effective documentation addresses all of them.
The Core Audiences:
| Audience | What They Need | How They Read | Key Questions They Ask |
|---|---|---|---|
| Implementers (now) | Clear enough to build from | Carefully, looking for details | What classes do I create? What methods? What data types? |
| Code Reviewers | Context for why the design is shaped as it is | Quickly, looking for rationale | Does this approach make sense? What alternatives were considered? |
| Future Maintainers | Understanding to make safe changes | Reference when confused | Why was it built this way? What are the assumptions? What shouldn't I break? |
| Onboarding Engineers | Orientation to the system | Top-down, seeking overview | What are the main components? How do they fit together? Where do I start? |
| Architects/Tech Leads | Strategic fit and quality assurance | Scanning for patterns and anti-patterns | Does this align with our standards? Are there scaling concerns? Is it maintainable? |
| Your Future Self | What you were thinking | When debugging or extending | What was I thinking? What did I assume? What are the edge cases? |
The Useful Lifespan of Documentation:
Different parts of your documentation have different lifespans:
Understanding these lifespans helps you invest appropriately. Spend more effort on documentation that will remain relevant; accept that detailed implementation docs will need updates.
Documentation is only valuable if it's read. Ask yourself: 'Will someone actually reference this when they need it?' If the answer is 'probably not,' either make it more useful or don't write it. Unread documentation is worse than no documentation—it creates the illusion of knowledge without delivering it.
Comprehensive design documentation includes several components. Not every design needs all of these, but knowing the full toolkit helps you choose what's appropriate.
Component 1: Executive Summary / Overview
A high-level description that anyone can understand in 2-3 minutes. This is often the only part that executives, product managers, or engineers from other teams will read.
1234567891011121314151617181920212223242526272829
# Order Processing System - Design Overview ## PurposeThe order processing system handles the complete lifecycle of customer orders,from placement through fulfillment. It is the core of our e-commerce platform. ## Key Entities- **Order**: A customer's request to purchase products- **OrderItem**: Individual products within an order- **Payment**: Financial transaction associated with an order- **Shipment**: Physical delivery of order items ## Core Capabilities- Accept and validate new orders- Process payments through multiple gateways- Manage inventory reservations- Track fulfillment and shipping- Handle cancellations and refunds ## Key Design Decisions- Strategy pattern for payment processing (extensibility)- State machine for order lifecycle (auditability)- Event-driven notifications (loose coupling)- Immutable order items (data integrity) ## Constraints and Limits- Synchronous payment processing (latency-sensitive)- Single-currency support initially- Maximum 50 items per orderComponent 2: Architecture Diagram(s)
Visual representations of the design at appropriate levels of abstraction. Diagrams are often the first thing people look for.
Essential diagrams for LLD:
Diagram quality guidelines:
Component 3: Entity/Class Specifications
Detailed descriptions of each significant class/entity. This goes beyond what's visible in a diagram.
123456789101112131415161718192021222324252627282930313233343536373839404142
## Order ### PurposeRepresents a customer's intent to purchase products. The Order is the centralentity around which the entire processing flow revolves. ### Responsibilities- Maintain the list of items being purchased- Track order lifecycle state (placed, paid, shipped, delivered, cancelled)- Calculate totals with applicable discounts- Ensure invariants (e.g., cannot modify items after payment) ### Key Attributes| Attribute | Type | Description | Constraints ||-----------|------|-------------|-------------|| id | OrderId | Unique identifier | Immutable after creation || customerId | CustomerId | Who placed the order | Required, immutable || items | List<OrderItem> | Products being ordered | 1-50 items, immutable after payment || status | OrderStatus | Current lifecycle state | Transitions per state machine || createdAt | Timestamp | When order was placed | Immutable || paidAt | Timestamp? | When payment completed | Set once, immutable | ### Key Methods| Method | Purpose | Notes ||--------|---------|-------|| addItem(item) | Add product to order | Throws if already paid || removeItem(itemId) | Remove product | Throws if already paid || calculateTotal() | Compute order total | Includes discounts, taxes || markPaid(payment) | Transition to paid | Throws if not in pending state || cancel(reason) | Cancel the order | Only valid before shipment | ### Invariants1. Order must have at least 1 item unless cancelled2. Total must equal sum of item totals plus taxes minus discounts3. Status transitions must follow state machine rules4. Items cannot be modified after payment ### Related Entities- OrderItem (composition - owns lifecycle)- Customer (association - reference only)- Payment (composition for successful, association for attempts)- Shipment (association - created by fulfillment system)Component 4: Key Flows / Sequence Documentation
Narrative description of how major operations work, complementing sequence diagrams.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
## Flow: Order Placement ### TriggerCustomer clicks "Place Order" in checkout UI. ### Preconditions- Valid customer session- Cart with at least one item- Selected payment method- Selected shipping address ### Steps1. **Validate Cart**: CartValidator checks all items are in stock, prices are current, and customer is eligible for any applied discounts. 2. **Create Order**: OrderFactory creates Order entity from Cart, copying items and freezing prices at current values. 3. **Reserve Inventory**: InventoryService attempts to reserve all items. If any item cannot be reserved: - Rollback any successful reservations - Return error indicating which items are unavailable 4. **Process Payment**: PaymentProcessor (selected via Strategy) charges the customer's payment method. If payment fails: - Release inventory reservations - Return error with payment failure reason 5. **Persist Order**: OrderRepository saves the order with PAID status. 6. **Emit Events**: - OrderPlacedEvent for fulfillment system - InventoryReservedEvent for inventory tracking - PaymentReceivedEvent for accounting 7. **Send Confirmation**: NotificationService sends order confirmation via customer's preferred channel(s). ### Postconditions- Order exists with PAID status- Inventory reserved for all items- Customer charged for order total- Confirmation notification sent ### Error Handling| Error Type | Handling ||------------|----------|| Inventory unavailable | Rollback, inform customer of unavailable items || Payment declined | Rollback inventory, show payment error || Persistence failure | Rollback payment and inventory, retry logic || Notification failure | Log and continue (non-critical) |Static diagrams show structure. Flow documentation shows behavior. Both are needed. A developer who knows what classes exist but not how they interact is set up for failure.
Beyond describing what the design is, capture why it's that way. This is what distinguishes documentation that enables future success from documentation that merely records the present.
Component 5: Architecture Decision Records (ADRs)
We introduced ADRs in the previous page on trade-offs. Including them in your final documentation package provides crucial context for significant decisions.
Component 6: Assumptions and Constraints
Every design is built on assumptions. Document them explicitly so future readers can assess whether they still hold.
12345678910111213141516171819202122
## Design Assumptions ### Business Assumptions| Assumption | Impact if Invalid | How to Verify ||------------|-------------------|---------------|| Order volume < 10,000/day | Current sync payment won't scale | Review traffic analytics || 95% of orders have < 5 items | Bulk item handling is simplified | Analyze order history || Refunds are rare (~1%) | Refund path is not optimized | Check refund metrics | ### Technical Assumptions| Assumption | Design Impact | Mitigation if Wrong ||------------|---------------|---------------------|| Payment gateway latency < 3s | Synchronous processing is acceptable | Implement async with webhooks || Inventory service always available | Sync inventory check in order flow | Add circuit breaker, graceful degradation || Database handles current write volume | Single primary DB architecture | Sharding or CQRS if needed | ### Organizational Assumptions| Assumption | Relevance ||------------|-----------|| Team familiar with TypeScript | No language training needed || Payment team owns gateway contracts | We consume, don't define, gateway APIs || Separate fulfillment team | Order system hands off, doesn't own shipping |Component 7: Known Limitations and Future Considerations
No design is perfect. Document what you know isn't ideal and what might need to change.
12345678910111213141516171819202122
## Known Limitations ### Current Limitations| Limitation | Why It Exists | When to Address ||------------|---------------|-----------------|| Single currency only | Scope constraint for MVP | International expansion || No partial order fulfillment | Simplifies state machine | High-value/multi-supplier orders || No subscription support | Out of scope | Subscription product launch | ### Technical Debt| Item | Impact | Estimated Effort | Priority ||------|--------|------------------|----------|| PaymentProcessor has hardcoded retry | Less resilient | 1 day | Medium || OrderValidator not fully tested | Risk of edge case bugs | 2 days | High || Notification templates are inline | Hard to update | 3 days | Low | ### Future Considerations| Future Need | Current Design Support | Preparation Needed ||-------------|------------------------|-------------------|| Multi-warehouse shipping | Order items have warehouseId | Add warehouse routing logic || Marketplace model | Order has single seller | Introduce Seller entity || Real-time inventory | Currently sync | Event-based inventory updates |Don't hide limitations or pretend the design handles everything. Honest documentation of limitations builds trust with readers and helps them make informed decisions. Hidden limitations become surprise failures.
Even complete documentation fails if it's not clear. Writing clarity is a skill that improves with practice and attention.
Principle 1: Write for the Confused Reader
Assume your reader is intelligent but unfamiliar with your context. They don't know what you know. Write as if explaining to a smart colleague who just joined the team.
Practical techniques:
Principle 2: Structure for Scanning
Most readers won't read linearly. They'll scan for the section they need. Structure your document accordingly:
Principle 3: Prefer Concrete Over Abstract
Abstract descriptions are hard to understand. Concrete examples make concepts tangible.
Instead of:
"The system validates inputs according to configured rules."
Write:
"The system validates inputs using the ValidatorChain. For orders, this checks that items are in stock, customer is not blacklisted, and payment method is supported. Example: An order with an out-of-stock item returns a ValidationError listing the unavailable items."
Principle 4: Show, Don't Just Tell
Code examples, diagrams, and worked scenarios communicate more effectively than prose alone.
12345678910111213141516171819202122232425262728293031323334353637383940
/** * OrderService handles the core business operations for orders. * * ## Creating an Order * * Orders are created from a validated cart: * * ```typescript * const cart = await cartService.getCart(customerId); * const result = await orderService.createOrder(cart, paymentMethod); * * if (result.isError()) { * // Handle validation or inventory errors * handleOrderError(result.error); * } else { * // Order successfully created * notifyCustomer(result.value); * } * ``` * * ## Cancelling an Order * * Orders can be cancelled before shipment: * * ```typescript * const result = await orderService.cancelOrder(orderId, CancellationReason.CUSTOMER_REQUEST); * // Returns error if order already shipped * ``` * * ## State Transitions * * Valid state transitions: * - PENDING → PAID (payment succeeds) * - PENDING → CANCELLED (cart abandoned or customer cancels) * - PAID → SHIPPED (fulfillment picks up) * - PAID → CANCELLED (customer cancels before ship) * - SHIPPED → DELIVERED (carrier confirms) * * Invalid transitions throw OrderStateException. */Have someone unfamiliar with your design read your documentation and tell you where they got confused. This is the most effective way to find clarity gaps. What's obvious to you isn't obvious to them.
Documentation that isn't maintained becomes actively harmful. Outdated docs lead developers astray, causing them to build on false assumptions. Here's how to keep docs useful over time.
Strategy 1: Locate Documentation Near Code
Documentation maintained separately from code tends to drift. Keep documentation as close to the code as practical:
/docs folder within the repository/docs/adr folderWhen documentation lives with code, it's more likely to be noticed during code changes.
Strategy 2: Define Documentation Ownership
Someone needs to be responsible for documentation accuracy. Options:
Without ownership, documentation degrades by default.
Strategy 3: Include Documentation in Definition of Done
If documentation is optional, it will be skipped when deadlines press. Build it into your team's workflow:
Strategy 4: Prefer Evergreen Content
Some content ages better than others. Prioritize documentation that remains accurate longer:
For volatile content, consider generating it from code (e.g., API docs from annotations) rather than maintaining it manually.
Strategy 5: Delete Rather Than Neglect
If documentation can't be maintained, delete it. Outdated documentation is worse than no documentation because it misleads without warning. A clean, smaller set of accurate docs is more valuable than comprehensive but unreliable docs.
As documentation becomes outdated, developers trust it less, consult it less, and update it less—accelerating the decay. Breaking this cycle requires visible commitment: when docs are updated, publicize it; when docs help someone, celebrate it.
In LLD interviews, you won't produce formal documentation, but the principles of good documentation apply to how you present your design.
Whiteboard/Drawing Equivalent of Documentation:
| Documentation Component | Interview Equivalent |
|---|---|
| Executive summary | Start with 30-second overview of your approach |
| Class diagram | Draw clear boxes with class names and key methods |
| Relationship notation | Use arrows with labels (has-a, is-a, uses) |
| Flow documentation | Walk through a scenario step by step |
| ADR/Decision rationale | Explain why you made key choices |
| Assumptions | State assumptions out loud: "I'm assuming we don't need..." |
| Limitations | Acknowledge: "This design doesn't currently handle..." |
Articulation Quality Matters:
Interviewers assess not just your design but how clearly you can explain it. This is a proxy for how well you'd communicate with teammates.
Good practices:
What Interviewers Notice:
Practice explaining your designs out loud, even to yourself. You'll discover that clear thinking and clear articulation don't automatically come together—you need to practice converting your mental model into words.
Finally, a brief survey of tools and formats for creating LLD documentation. Choose tools your team will actually use.
For Diagrams:
| Tool | Strengths | Considerations |
|---|---|---|
| Mermaid (text-based) | Lives in Markdown, version-controlled, easy diffs | Limited styling options |
| PlantUML (text-based) | Comprehensive UML support, renders from text | Requires rendering step |
| draw.io / diagrams.net | Free, flexible, collaborative | Separate files from docs |
| Lucidchart | Polished, collaborative, templates | Paid, docs may drift from diagrams |
| Excalidraw | Sketch-like, informal, easy | Less structured, may look unprofessional |
| Whiteboard/paper (for interviews) | Universal, no tool learning | Not for permanent docs |
For Written Documentation:
Recommended Approach:
For most teams, a combination works well:
The key is that docs should be where developers look. If your team lives in GitHub, docs should be in GitHub. If your team uses Confluence daily, put docs there.
The best tool is the one your team will actually use. A simple Markdown file that gets maintained beats a sophisticated documentation system that's ignored. Start simple; add tooling only when the simple approach fails.
Documentation bridges the gap between the design in your head and the design that survives your involvement. Let's consolidate the key insights:
Module Complete:
With this page, we've completed Module 7: Iterating and Refining. You've learned that design is inherently iterative, how to gather and incorporate feedback, how to make trade-off decisions with confidence, and how to document your final design for implementation and future maintenance.
These skills transform you from someone who creates designs into someone who creates lasting designs—designs that can be understood, maintained, and evolved by the team over time.
Congratulations! You've completed Module 7: Iterating and Refining. You now have the complete toolkit for the design refinement process: embracing iteration, incorporating feedback, making trade-offs, and documenting for the future. These skills will serve you in every design challenge you face.