Two Different Questions
When engineers sit down to build software, they face two fundamentally different kinds of design questions:
- High-Level Design (HLD): “What are the major components, and how do they interact?”
- Low-Level Design (LLD): “How does each component work internally?”
These map directly to traditional engineering. In structural engineering, HLD is the schematic design — deciding that a building will have a steel frame with a concrete core, where the lateral system goes, and how loads transfer to the foundation. LLD is the detail design — specifying the bolt sizes, weld details, rebar spacing, and connection types.
You would never specify bolt sizes before deciding on the structural system. Yet in software, engineers routinely jump to writing functions (bolt-level decisions) without establishing the system architecture (structural system decisions). This lesson is about understanding why that order matters and how to work at both levels.
High-Level Design (HLD): The Architecture
High-Level Design answers the “what” and “where” questions:
- What are the major components (services, modules, subsystems)?
- How do they communicate (APIs, message queues, shared databases, file I/O)?
- Where does data live (databases, file systems, caches)?
- What are the system boundaries (what’s inside vs. outside the system)?
- What are the key constraints (performance, security, scalability, compliance)?
An HLD does not specify:
- Which programming language to use for each module (usually)
- Specific data structures or algorithms
- Function signatures or class hierarchies
- Database table schemas
What HLD Produces
- Component diagrams: Boxes and arrows showing major pieces and their connections.
- Data flow diagrams: How data moves through the system from input to output.
- Deployment diagrams: Where components run (which servers, containers, cloud services).
- Interface contracts: What each component expects from and provides to other components (not how it provides it).
Low-Level Design (LLD): The Detail
Low-Level Design answers the “how” questions for each component identified in the HLD:
- What classes, functions, or modules will the component contain?
- What data structures will be used?
- What algorithms will implement the business logic?
- What is the database schema?
- What are the function signatures and return types?
- How will errors be handled?
- What design patterns apply?
What LLD Produces
- Class diagrams: Object hierarchies, methods, and relationships.
- Sequence diagrams: Step-by-step interaction between objects within a component.
- Database schemas: Table definitions, foreign keys, indexes.
- API specifications: Exact endpoints, request/response formats, error codes.
- Pseudocode or interface definitions: Precise enough to code from.
The Design Hierarchy in Practice
Here’s how HLD and LLD relate in a typical project:
System Architecture (HLD)
|
|-- Component A: Data Ingestion Service
| |-- Module A1: File Parser (LLD)
| | |-- class CSVParser
| | |-- class JSONParser
| | |-- class ParserFactory
| |-- Module A2: Validator (LLD)
| |-- class SchemaValidator
| |-- class RangeChecker
|
|-- Component B: Processing Engine
| |-- Module B1: Solver (LLD)
| | |-- class FEMSolver
| | |-- class MeshGenerator
| |-- Module B2: Results Aggregator (LLD)
| |-- class StatisticsComputer
| |-- class ReportBuilder
|
|-- Component C: Results API
|-- Module C1: REST Endpoints (LLD)
|-- Module C2: Authentication (LLD)
Notice how the HLD level (Components A, B, C) describes what the system does without saying how. The LLD level (individual modules and classes) describes how each component fulfills its role.
Why the Order Matters
Consider a common scenario: a team of engineers building a simulation pipeline. They need to read input files, run a solver, and generate reports.
Without HLD (the common mistake):
- Engineer A starts writing a file parser. It reads data and immediately runs the solver inline.
- Engineer B starts writing the report generator. It calls the solver directly to get results.
- Now the solver is tightly embedded in both the parser and the reporter. You can’t replace the solver without modifying both.
- Testing is painful — you can’t test the parser without running the solver, and you can’t test the reporter without running the solver.
- Adding a new input format means touching the solver code. Adding a new report format means touching the solver code.
With HLD first:
- The team agrees on three components: Ingestion, Processing, and Reporting.
- They define the interfaces: Ingestion produces a standard data structure. Processing consumes it and produces results. Reporting consumes results.
- Engineers A and B can work in parallel because the interfaces are defined.
- Each component can be tested independently with mock data.
- Replacing the solver means changing only the Processing component.
Architecture Diagrams: The Language of HLD
Architecture diagrams are the primary deliverable of HLD. They serve the same purpose as engineering drawings: communicating design intent to everyone involved. There are several common types:
Component Diagram
The most common HLD diagram. Shows major components as boxes and their relationships as arrows. Each arrow should be labeled with what flows along it (data, commands, events).
Sequence Diagram
Shows how components interact over time. Vertical lines represent components, horizontal arrows represent messages between them, and time flows downward. Useful for understanding request/response flows and identifying potential bottlenecks.
Data Flow Diagram (DFD)
Traces how data enters the system, gets transformed, stored, and output. Particularly useful for data-intensive engineering applications where the primary concern is “what happens to the data?”
Entity-Relationship Diagram (ERD)
Shows data entities and their relationships. Bridges HLD and LLD — it describes what data exists and how it relates, without specifying how it’s stored (that’s LLD).
Tools for Architecture Diagrams
- Draw.io (diagrams.net): Free, browser-based, integrates with VS Code. Good starting point.
- Mermaid: Text-based diagrams that live in Markdown files. Version-controllable. Great for documentation-as-code.
- PlantUML: Another text-based diagramming tool. More powerful than Mermaid but steeper learning curve.
- Excalidraw: Whiteboard-style diagrams. Good for brainstorming and informal communication.
- Lucidchart: Commercial tool with collaboration features. Common in enterprise environments.
Mermaid Example
Mermaid lets you define diagrams in plain text that can live alongside your code:
graph LR
A[Input Files] --> B[Parser]
B --> C[Validator]
C --> D[Solver Engine]
D --> E[Results DB]
E --> F[Report Generator]
F --> G[PDF/HTML Output]
This renders as a left-to-right flowchart showing the data pipeline. Because it’s text, it can be version-controlled, reviewed in pull requests, and updated alongside code changes.
Exercise 3.1: First Architecture Diagram
- Engineers upload structural models (IFC files) through a web interface.
- The system validates the model format and checks for common errors.
- A solver engine runs structural analysis on the model.
- Results are stored in a database.
- Engineers can view results, generate PDF reports, and compare results across model versions.
- An admin dashboard shows system usage and solver performance metrics.
Your task:
- Identify the major components (aim for 4–7).
- Draw a component diagram (boxes and labeled arrows). Use pen and paper, Draw.io, or Mermaid.
- For each arrow, label what flows along it (e.g., “IFC file,” “analysis results,” “report request”).
- Identify one design decision you had to make (e.g., “Should the solver be a separate service or part of the main application?”) and explain your reasoning.
Don’t worry about getting it “right” — the goal is to practice thinking at the HLD level. We’ll refine the skills in later lessons.
Quiz
Question: A team of three engineers starts building a data processing pipeline. They skip the architecture diagram and immediately begin coding. Each engineer writes their component independently. After two weeks, they try to integrate their code. What is the most likely problem they’ll encounter?
- The code won’t compile because they used different programming languages.
- Their components have incompatible interfaces — different data formats, different assumptions about inputs and outputs, and duplicated logic.
- They’ll discover that the problem doesn’t actually need software.
- The code will be too slow because they didn’t optimize early enough.
Answer
b) Their components have incompatible interfaces — different data formats, different assumptions about inputs and outputs, and duplicated logic.
This is the most common consequence of skipping HLD. Without agreeing on component boundaries and interface contracts upfront, each engineer makes independent assumptions. Engineer A outputs results as a list of dictionaries. Engineer B expects a pandas DataFrame. Engineer C expects a CSV file. Now integration requires writing glue code, which is exactly the kind of accidental complexity that HLD prevents. Options (a), (c), and (d) are possible but far less likely than interface mismatch, which is nearly guaranteed when HLD is skipped.