System Design
System Design is such a broad topic, with many different styles adopted by different people. It only became popular recently when it became a requirement during interviews for software engineering roles. This blog is not about tips & tricks for passing half-hour session interviews, but a more realistic take on building systems that lasts.
Every system is built to solve a problem faced by someone or a business, and people tend to lose sight of that when the team or organisation starts growing. This could be because of how workers are hired for a specific role within a problem but are not directed to solve the business problem. As it is human nature to want to suceed and improve, these individual workers start implementing and improving onto their individual areas in isolation, which Inevidently, results in creating a more complicated and messy system over time.
That is where Domain Driven Design (DDD) comes in, as it brings the problem-solving focus back to the actual issue at hand. It starts by formalizing the language used by the domain-experts and stakeholders, such that engineers can actually use those terminologies during their design and implementation. This solves a huge communication gap between the non-technical and technical folks. As conversations regularly take place between stakeholders, DDD provides a framework for capturing important details in the domain. These details are also commonly known as Objects & Events in the software engineering world (more on that later).
I will not be diving deep into what DDD is in this blog, but will cherry-pick concepts from it to apply to my approach to System Design.
To give you a glimpse of what I am talking about, below is a simple System Design document leveraging DDD for building an authentication service for XYZ startup. These System Design documents are living documents that gets updated over time, and what is shown below is just a snapshot in the whole system life cycle.
XYZ Auth
Company XYZ requires a secure way to authenticate its users accessing its app. To keep costs low, and not be subjected to GDPR related policies, passwords cannot be stored within the system. Consulting with the Security Engineer in the team, he advises to use Magic Links as a quick and simple way to authenticate users.
Table of Contents
- DDD Strategic Design
- DDD Tactical Design
- Non-Functional Requirements
- API Endpoints
- Capacity Estimation
- Cost Estimation
- System Architecture
System Design
DDD Strategic Design
The expected interactions with XYZ Auth are as follows:
| Persona | Interaction |
|---|---|
| User | User enters email and requests for Magic Link. |
| User | User clicks on Magic Link and navigates to the Home page of the App. |
| User | User clicks on expired / invalid Magic Link and navigates to the HTTP 401 page of the App. |
| Admin | Admin enters email and requests for Magic Link. |
| Admin | Admin clicks on Magic Link and navigates to the Admin App. |
| Admin | Admin adds Users to the system by entering their emails. |
| Admin | Admin removes Users from the system by deleting their emails. |
The domain of XYZ Auth is as follows:
| Events | Objects | Transactions |
|---|---|---|
| UserAdded | User | AddUser |
| UserRemoved | RemoveUser | |
| UserRequestsMagicLink | RequestMagicLink | |
| UserLogin | LoginUser |
DDD Tactical Design

Based on the events and objects identified in the Strategic Design stage, the above Entity-Relationship diagram is drawn.
Non-Functional Requirements
- The Magic Link will only work on the same browser that was used to generate the Magic Link. This is enforced using CSRF tokens.
API Endpoints
POST /api/v1/login
POST /api/v1/login?magic={string}
POST /api/v1/users
POST /api/v1/users/{id}
GET /api/v1/users
GET /api/v1/users/{id}
Capacity Estimation (Data Storage)
Referencing the data structures for Postgres, the estimation is as follows:
id: 16 bytes
event_type: 1 byte * size = 16 bytes
user_id: 16 bytes
created_at: 16 bytes
email: 128 bytes
is_admin: 1 byte
Hence, an AuthEvent is estimated to be at most (16 + 16 + 16 + 16 + 128 + 1) = 193 bytes.
With a 1GB Postgres instance, we can store approximately ~5.1 million auth events.
Cost Estimation

System Architecture

- ← Previous
Hello Me! - Next →
Magic Links