Nếu bạn đang cảm thấy code của mình sau 6 tháng phát triển bắt đầu biến thành một "nồi lẩu thập cẩm" – nơi mà Logic Business trộn lẫn với SQL Query, và Controller thì phình to như người khổng lồ – thì bài viết này dành cho bạn.
Hôm nay, mình sẽ giới thiệu "Domain-Driven Hexagon" của tác giả Sairyss. Với hơn 12.000 ngôi sao trên GitHub (tính đến đầu 2026), đây không chỉ là một boilerplate (khung mẫu), nó là chuẩn mực giáo dục về cách xây dựng Backend hiện đại.
1. Tại Sao Repo Này Lại Là "Số 1"?
Trong thế giới TypeScript và NestJS, có hàng ngàn repo mẫu. Nhưng domain-driven-hexagon khác biệt ở chỗ nó giải quyết bài toán khó nhất: Sự phức tạp (Complexity).
Nó kết hợp nhuần nhuyễn 3 tư tưởng lớn của kỹ nghệ phần mềm:
- Domain-Driven Design (DDD): Tập trung vào nghiệp vụ cốt lõi, không để công nghệ chi phối nghiệp vụ.
- Hexagonal Architecture (Ports & Adapters): Giúp ứng dụng của bạn "bất tử" trước sự thay đổi của Database hay External API.
- Clean Architecture: Phân chia tầng lớp rõ ràng, dễ test, dễ bảo trì.
Tư duy của Sairyss: "Mục tiêu không phải là viết code chạy được. Mục tiêu là viết code mà 2 năm sau, người khác đọc vào vẫn hiểu và mở rộng được mà không cần đập đi xây lại."
2. Giải Phẫu Kiến Trúc (Anatomy)
Trước khi đi vào cài đặt, hãy nhìn vào cách repo này tổ chức. Nó không chia theo kiểu controllers, services thông thường, mà chia theo Modules (Nghiệp vụ).
Trong mỗi Module (ví dụ: UserModule), cấu trúc sẽ như sau:
- Domain: Nơi chứa Business Logic thuần túy. Không phụ thuộc vào Database hay Framework.
- Application: Các Use Cases (ví dụ:
CreateUser,ChangePassword). Đây là nơi điều phối công việc. - Infrastructure: Nơi giao tiếp với thế giới bên ngoài (Database, Redis, Mail Server).
- Interface (Controller): Nơi nhận request từ người dùng (HTTP, GraphQL, CLI).
- Shutterstock
An isometric infographic showing the Hexagonal Architecture layers: The central core is 'Domain' (glowing warm light), surrounded by 'Application' (cool blue), and the outer ring is 'Infrastructure' with connectors to Database icons and Cloud icons, white background, clean lines, --ar 3:2
3. Hướng Dẫn Cài Đặt Thực Chiến (Docker Hóa)
Mặc định repo này sử dụng yarn để chạy trực tiếp. Nhưng để chuẩn chỉnh cho anh em deploy hoặc dev team, mình sẽ hướng dẫn bọc nó vào Docker.
Bước 1: Clone Repository
Bash
git clone https://github.com/Sairyss/domain-driven-hexagon.git
cd domain-driven-hexagon
cp .env.example .env
Bước 2: Tạo Dockerfile (Multi-stage Build)
Tạo file Dockerfile ở thư mục gốc để tối ưu dung lượng ảnh:
Dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
# Stage 2: Run
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/.env ./.env
EXPOSE 3000
CMD ["node", "dist/main"]
Bước 3: File Docker Compose "Thần Thánh"
Repo gốc thường yêu cầu bạn cài Postgres ở ngoài. Dưới đây là file docker-compose.yml trọn gói (App + DB):
YAML
version: '3.8'
services:
api:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=postgres
- DB_PASSWORD=root
- DB_NAME=ddh_db
depends_on:
- postgres
networks:
- ddd-network
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=root
- POSTGRES_DB=ddh_db
ports:
- "5432:5432"
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- ddd-network
networks:
ddd-network:
volumes:
pg_data:
Bước 4: Chạy thôi!
Bash
docker-compose up -d
Chờ khoảng 1 phút, API của bạn đã sẵn sàng tại http://localhost:3000.
A close-up, high-angle shot of a mechanical keyboard and a monitor displaying TypeScript code with clean indentation and syntax highlighting, a cup of coffee on the side, focused lighting, bokeh background, --ar 16:9
4. Học Gì Từ Repo Này? (Deep Dive)
Đây là những "viên ngọc quý" bạn nên soi kỹ trong source code:
- Value Objects: Xem cách tác giả định nghĩa
Email,Addresstrong thư mụcdomain/value-objects. Nó giúp validate dữ liệu ngay từ trứng nước. - CQRS (Command Query Responsibility Segregation): Tách biệt việc Ghi (Command) và Đọc (Query). Điều này giúp app scale cực tốt khi lượng user tăng vọt.
- Repository Pattern: Xem cách
user.repository.tstronginfrastructuremap dữ liệu từ Database về Domain Model. Đây là nghệ thuật của sự tách biệt.
Kết Luận
Domain-Driven Hexagon không dành cho các dự án "mì ăn liền" (CRUD đơn giản). Nó dành cho những dự án xác định đi đường dài, cần sự bền vững và khả năng mở rộng (Scalability).
Nếu bạn muốn nâng tầm từ một Junior/Middle Dev lên Senior, việc đọc hiểu và áp dụng repo này là một bài tập bắt buộc.
Next Step: Hãy thử tạo một Module mới tên là Product dựa trên cấu trúc của User có sẵn trong repo. Đó là cách học nhanh nhất!
- Tác giả: Sairyss
Chia sẻ bài viết này nếu bạn thấy nó hữu ích cho cộng đồng NestJS Việt Nam nhé!
Discussion