Detailed Design: Turning Big Ideas into Clean Components
High-Level Design gives you a cool diagram with boxes like “Authentication Service” or “Rate Limiter”. But what actually goes inside those boxes? Detailed Design (or Component Design) is where the rubber meets the road. In this guide, we walk through how to design an actual production-ready software component from scratch — algorithms, interfaces, thread-safety, and edge cases.
👉 Macro Blueprint: Want to see where components sit in the larger system? Read our guide on High-Level Design (HLD).
What is Detailed Design?
Imagine you are an architect designing an office building. You have drawn the floor plans showing where the conference rooms and elevators go. But when the electrician shows up, they need to know:
- What voltage runs through this conduit?
- Where does the circuit breaker panel live?
- How many amps can this plug handle before a fuse blows?
That is Detailed Design. It takes one box from your high-level architecture diagram and zooms in until there is zero ambiguity left about how to write the code.
The Core Rule: Treat Your Component Like a Black Box
A well-designed component has a clear boundary. The rest of your application should only ever see a clean, public interface. Everything else — the internal state, the specific data structures, the helper methods — is strictly private.
flowchart TD
Caller["Upstream Code / Controllers"]
subgraph BlackBox["Component Boundary (Strictly Encapsulated)"]
Interface["1. Public Interface Contract\n(Simple method calls: tryAcquire())"]
Logic["2. Core Algorithmic Logic\n(Calculates time elapsed & token refills)"]
State["3. Private Internal State\n(Thread-safe counters & timestamps)"]
Outbound["4. Outbound Provider Interface\n(Pluggable Redis / Memory cache)"]
Interface --> Logic
Logic <--> State
Logic --> Outbound
end
Caller -->|"Only talks to public interface"| Interface
Outbound -->|"Talks to"| Redis[("External Redis Cache")]
Why this matters: If you decide tomorrow to swap an in-memory hash map for a distributed Redis cache, not a single line of caller code needs to change. Your component boundary protects the rest of the codebase from your internal refactoring.
A Concrete Example: Designing a Rate Limiter Component
Let's build something every senior backend engineer needs: an API Rate Limiter that restricts users to 60 requests per minute.
Step 1: Pick the Right Algorithm
A beginner might say: “Let's just keep an array of every timestamp the user makes a request, and check how many happened in the last 60 seconds!”
If you have 100,000 active users making thousands of requests, that array will eat gigabytes of RAM in no time.
Instead, we use the Token Bucket Algorithm:
- Every user gets a virtual bucket holding up to 60 tokens.
- Tokens refill smoothly over time (1 token every second).
- When a request arrives, we don't store a list of timestamps — we just calculate tokens accrued since the last request, subtract 1 token, and update the timestamp.
- The result: Memory consumption is strictly O(1) — just two numbers (token count and timestamp) per user!
sequenceDiagram
autonumber
actor Client as API Request
participant Limiter as RateLimiter Component
participant Store as State Storage (Redis / RAM)
Client->>Limiter: 1. tryAcquire(user_id="user_42")
activate Limiter
Limiter->>Store: 2. Fetch {tokens: 15, last_refill: 1715000000}
activate Store
Store-->>Limiter: Return state
deactivate Store
Note over Limiter: Tokens refilled = (now - last_refill) * rate
Total available = min(60, 15 + refilled)
alt Available Tokens >= 1
Limiter->>Store: 3. Save new state: {tokens: available - 1, last_refill: now}
Limiter-->>Client: 4. Allowed! (HTTP 200 OK)
else Bucket is Empty
Limiter-->>Client: 4. Blocked! (HTTP 429 Too Many Requests)
end
deactivate Limiter
Step 2: Write the Interface Contract
Keep the contract minimal and easy to test:
// Public Interface: simple, clear, and focused
public interface RateLimiter {
RateLimitResult tryAcquire(String clientId);
}
// Immutable Return DTO: gives callers exactly what they need
public record RateLimitResult(
boolean isAllowed,
long remainingTokens,
long retryAfterSeconds
) {}
Concurrency: Where Component Design Usually Breaks
In production, two HTTP requests from the same user often arrive at the exact same millisecond. If your code is not designed for concurrency, here is what happens:
- Thread A reads: “User has 1 token left.”
- Thread B reads at the same instant: “User has 1 token left.”
- Thread A decrements to 0 and allows the request.
- Thread B decrements to 0 and allows the request.
Both requests slipped through! The user just cheated the rate limit.
How to fix it:
- On a single server: Use atomic variables (like Java's
AtomicReference) or lock-free compare-and-swap (CAS) loops. Avoid putting coarsesynchronizedlocks around the whole method, which slows down all other users. - Across a distributed cluster: Run the token calculation inside an atomic Redis Lua script so that checking and decrementing tokens happen in a single uninterruptible step on the Redis server.
Detailed Design Review Checklist
Before you start writing code, ask yourself these four questions:
- Is the interface clean? Does it hide the internal implementation details from callers?
- What is the worst-case memory footprint? If 100,000 users hit this at once, will it run out of memory?
- Is it thread-safe? Can two requests mutate the state simultaneously without race conditions?
- Can I test it in memory? Can you test this component in a unit test in 5 milliseconds without needing a real database or network connection?
- To turn component designs into clean classes, read Low-Level Design (LLD).
- To learn how components communicate over the network, read System Integration & API Design.
- To understand macro application architecture, read High-Level Design (HLD).
Final Thoughts
Detailed Design is where good intentions become real, resilient software. By clarifying your component boundaries, choosing space-efficient algorithms, and thinking about concurrency before writing code, you save yourself hours of frantic debugging in production.