---
title: "Nền tảng về Design Patterns, Layered Architecture, Hexagonal và Clean Architecture"
description: "Khoá nền tảng về design pattern và kiến trúc ứng dụng, xoay quanh câu hỏi: phần nào sẽ thay đổi, và phần code nào đang phụ thuộc vào phần code nào. Bạn học cách chọn hoặc gỡ một pattern, đặt ranh giới theo Layered, Hexagonal, Clean Architecture, và yêu cầu AI tổ chức code theo cấu trúc bạn kiểm tra lại được."
canonical: "https://200lab.io/courses/nen-tang-ve-design-patterns-layered-architecture-hexagonal-va-clean-architecture"
type: "course"
course_type: "course"
learning_type: "free_form"
published: "2026-09-28T04:01:44Z"
students: 0
---

## Khoá học này mang lại gì cho bạn

Khoá học bắt đầu từ một cảm giác nhiều developer đã quen: code vẫn chạy đúng, nhưng yêu cầu sau tốn công hơn yêu cầu trước. Design pattern và kiến trúc ứng dụng là những cách sắp xếp code để một thay đổi không lan vào phần logic không liên quan; khoá học cung cấp cách chọn chúng theo đúng vấn đề, kèm cái giá của từng lựa chọn. Khi AI viết phần lớn code, kiến thức này càng cần thiết: code theo một cấu trúc quen thuộc thì AI dễ đọc và sửa đúng chỗ hơn, còn bạn dù không tự tay viết pattern vẫn cần hiểu nó để yêu cầu đúng và kiểm tra lại kết quả.

- **Gọi tên áp lực thay đổi** — Bạn chỉ ra được phần hay thay đổi đang viết lẫn với phần ít thay đổi, trước khi nghĩ tới pattern nào.
- **Đoán phạm vi một thay đổi** — Bạn lần theo chiều dependency để biết file nào phải sửa theo, và đo coupling bằng số chỗ phải sửa thay vì cảm giác.
- **Chọn hoặc gỡ một pattern** — Bạn quyết định dựa trên áp lực mà pattern giải quyết và cái giá nó thêm vào, kể cả khi if/else vẫn là đủ.
- **Đọc kiến trúc từ import graph** — Bạn thấy chiều phụ thuộc thật qua các lệnh import thay vì tin vào sơ đồ, rồi giữ luật về chiều phụ thuộc bằng architecture check.
- **Đặt ranh giới đúng chỗ** — Bạn đặt port, adapter, use case hay repository ở nơi có thay đổi thật, để đổi database hay service bên ngoài mà không mở file chứa luật nghiệp vụ.
- **Phân biệt Hexagonal, Onion và Clean** — Bạn thấy ba kiến trúc cùng dựa trên một luật phụ thuộc, và biết chỗ chúng thật sự khác nhau.
- **Yêu cầu AI tổ chức code** — Bạn dùng tên pattern và tên cấu trúc để yêu cầu coding agent sắp xếp code, rồi kiểm tra lại kết quả qua chiều import.

Đây là khoá nền tảng cơ bản về design pattern và kiến trúc ứng dụng, độc lập với ngôn ngữ và framework: code minh họa bằng TypeScript chỉ để đọc.

## Khoá học cung cấp những nền tảng nào

Cả khoá học dựa trên một câu hỏi: phần nào sẽ thay đổi, và phần code nào đang phụ thuộc vào phần code nào. Phần A đặt câu hỏi ấy ở cấp vài object, nơi nó dẫn tới design pattern; phần B nâng nó lên cấp cả ứng dụng, nơi câu trả lời nằm ở chiều import giữa các tầng và module. Mỗi lời giải đều có cái giá phải trả, như lời khuyên của Martin Fowler trong [Is Design Dead?](https://martinfowler.com/articles/designDead.html): pattern nào không đáng với độ phức tạp nó thêm vào thì đừng ngại gỡ ra. Phần kiến trúc bám theo hai bài viết gốc, [Hexagonal Architecture](https://alistair.cockburn.us/hexagonal-architecture/) của Alistair Cockburn và [The Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) của Robert C. Martin.

### 1. Tìm chỗ code khó sửa, rồi học ba khái niệm nền

Nhóm đầu tiên đặt vài yêu cầu thay đổi lên một đoạn code checkout đang chạy đúng, xem mỗi yêu cầu bắt bạn sửa những chỗ nào, và đọc code smell như tín hiệu để hỏi tiếp. Tiếp theo là ba khái niệm nền: dependency (A dùng B thì khi B đổi, A có thể phải sửa), coupling và cohesion (đo bằng số chỗ phải sửa cho một thay đổi), và decoupling bằng interface. Trên một service chỉ cộng hai số, interface cho phép đổi cách nhận dữ liệu, cách trả kết quả và cách lưu mà không đụng vào phép cộng.

### 2. Design pattern theo từng tình huống thay đổi

Các pattern được sắp xếp theo tình huống bạn hay gặp: nhiều cách tính cho cùng một kết quả (Strategy), một khung chung có vài bước khác nhau (Template Method), hành vi đổi theo trạng thái (State), hành động cần xếp hàng hoặc hoàn tác (Command), thêm một bên cần nhận thông báo (Observer) và dữ liệu dạng cây (Composite). Rồi đến thư viện ngoài không khớp với code (Adapter, Facade), thêm log, cache, retry mà không sửa code gốc (Decorator, Proxy), chỗ quyết định tạo object nào (Factory, Builder, Abstract Factory) và object toàn cục làm khổ lúc viết test (Singleton, dependency injection). Mỗi pattern có một bản gọn bằng TypeScript, kèm cái giá và dấu hiệu cho thấy chưa nên dùng.

### 3. Pattern mà ngôn ngữ đã làm giúp, và lúc nên gỡ pattern

Iterator, Visitor, Prototype hay Memento hiếm khi cần dựng thành bộ class, vì ngôn ngữ đã có `for...of`, generator, tagged union và các cách sao chép dữ liệu. Chain of Responsibility và Mediator bạn chủ yếu gặp trong code của framework, còn Bridge, Flyweight và Null Object thì hiếm khi cần đến. Phần A khép lại bằng chiều ngược lại: pattern là khoản đầu tư cho một thay đổi được đoán trước, và khi thay đổi đó không đến thì gỡ nó ra bằng refactoring giữ nguyên hành vi.

### 4. Chia tầng, import graph và các mẫu để dựng phần lõi

Phần B mở đầu bằng layered architecture và câu hỏi vì sao một thay đổi ở database vẫn lan lên dù đã chia tầng. Bạn học đọc import graph để thấy kiến trúc thật, rồi giữ luật về chiều phụ thuộc bằng architecture check. Tiếp theo là các mẫu trong Patterns of Enterprise Application Architecture của Martin Fowler: Transaction Script, Domain Model, Active Record, Data Mapper, Repository, Unit of Work và Service Layer.

### 5. Dependency Inversion và Hexagonal architecture

Dependency Inversion đặt interface ở phía cần nó, để mũi tên import đổi chiều trong khi chiều gọi vẫn giữ nguyên. Hexagonal architecture dựa trên đó để tách phần nghiệp vụ khỏi mọi thứ bên ngoài, như khi phần tìm kiếm sản phẩm chuyển từ Postgres sang Elasticsearch mà luật tìm kiếm không phải viết lại. Driving adapter cho phép gọi cùng một nghiệp vụ từ web, CLI, job hay test. Driven adapter đổi mã lỗi hay timeout của service bên ngoài thành kết quả mà lõi hiểu. Còn composition root là nơi ứng dụng được lắp ráp khác nhau cho test, dev và production.

### 6. Onion, Clean Architecture và một luật phụ thuộc chung

Layered architecture theo cách của Eric Evans cho thấy application service, domain service và infrastructure service thuộc ba tầng khác nhau. Onion architecture đưa database ra vòng ngoài, còn Clean Architecture phát biểu thành dependency rule: mọi phụ thuộc trong source code chỉ hướng vào trong. Nhóm này còn đi qua input và output boundary, Humble Object, partial boundary, rồi đặt ba bộ nhãn Hexagonal, Onion và Clean lên cùng một import graph để thấy chỗ chúng thật sự khác nhau.

### 7. Chia code theo hướng thay đổi, và biết khi nào dừng

Nhóm cuối hỏi code nên chia theo tầng hay theo tính năng, và khi nào đáng dùng vertical slice hay modular monolith. Rồi đến chiều ngược lại: khi nào ba tầng và bốn interface là quá nhiều cho một app. Khoá học kết bằng một case study: service đặt hàng viết theo layered phải chuyển phần hỏi tồn kho sang kho của đối tác, và bạn quyết định ranh giới nào đáng tách thành port, làm theo thứ tự nào, dừng ở đâu.

## Vì sao 200Lab tạo ra khoá học này

AI giờ viết cả một module trong vài phút, và code thường chạy đúng ngay lần đầu. Cái khó đến ở yêu cầu thứ ba, thứ tư, khi thêm một cách thanh toán hay đổi nơi lưu dữ liệu lại phải mở những file tưởng như không liên quan. Viết code đã nhanh hơn nhiều, còn mỗi lần sửa tốn bao nhiêu công thì vẫn do cấu trúc quyết định.

Muốn thiết kế tốt hơn, nhiều người học thuộc 23 pattern từ sơ đồ UML hoặc chép nguyên một template Clean Architecture, tức là đặt lời giải lên trước vấn đề. Chính những người viết sách về pattern cũng nhắc điều ngược lại: năm 2009, các tác giả GoF tự xếp lại nhóm pattern cốt lõi và Erich Gamma muốn bỏ Singleton, còn Joshua Kerievsky kể ông từng dùng Strategy ở chỗ một câu điều kiện là đủ.

Khoá học này đặt lại thứ tự: yêu cầu thay đổi đến trước, tên pattern đến sau. AI viết khung một pattern rất nhanh; còn có nên dùng, dùng ở đâu và gỡ khi nào là những quyết định bạn mang theo vào mọi codebase.

## Những vấn đề thường gặp khi áp dụng design pattern và kiến trúc

Phản xạ tự nhiên khi thấy code khó sửa là tìm một pattern hay kiến trúc có tên để gắn vào. Có lúc đúng, nhưng nhiều khi lời giải được chọn trước khi vấn đề được gọi tên.

- Mỗi lần thêm một cách thanh toán hay đổi phí ship, bạn lại phải sửa cùng một hàm checkout ngày càng dài — phần hay đổi đang viết lẫn với phần ít đổi, nên yêu cầu nào cũng mở lại cả khối logic.
- Bạn tách khối if/else ba nhánh thành Strategy, code dài ra mà lần sửa sau không nhẹ hơn — pattern được đưa vào trước khi có áp lực thay đổi thật, và khi các nhánh ít đổi thì if/else vẫn gọn hơn.
- Code đã dùng interface và dependency injection mà đổi thư viện gửi email vẫn phải sửa phần nghiệp vụ — interface được viết theo hình dạng của thư viện, trong khi nó phải do phía nghiệp vụ đặt ra.
- Test với mock xanh hết, lên production vẫn hỏng — mock chỉ giữ hình dạng của lời gọi, còn mã lỗi hay timeout của service thật phải được adapter xử lý và được contract test đối chiếu với bản thật.
- Một app CRUD nhỏ dựng theo template Clean Architecture, mỗi tính năng đi qua rất nhiều file — mỗi tầng và mỗi interface là thêm một chỗ phải đọc qua, và chỉ đáng giá khi phía sau có thay đổi thật.

Mỗi tình huống trên được phân tích trong một bài riêng, trên một ví dụ nhỏ.

## Bạn sẽ học theo cách nào

- **Vấn đề trước, tên gọi sau** — Mỗi bài thường bắt đầu từ một ví dụ nhỏ như service cộng hai số, kèm theo một yêu cầu thay đổi; pattern chỉ được gọi tên khi bạn đã thấy yêu cầu chạm vào đâu.
- **Hình vẽ cấu trúc code** — Hình minh họa cho thấy file, chiều import và chỗ yêu cầu thay đổi chạm tới, trước và sau khi sắp xếp lại.
- **Trước và sau trên cùng một yêu cầu** — Bạn so sánh code trước và sau trên chính yêu cầu đó, kèm cái giá phải trả.
- **Quiz ngắn sau mỗi bài** — Vài câu hỏi yêu cầu bạn dự đoán hoặc quyết định trên một đoạn code.
- **Luyện tập cùng coding agent** — Mỗi bài có một kit để coding agent của bạn dựng ví dụ thành repo nhỏ có test, bằng ngôn ngữ bạn chọn; bạn tự làm yêu cầu thay đổi, rồi agent chấm theo tiêu chí của kit.

## Khoá học dành cho ai

1. **Developer đã viết ứng dụng thật** — Code chạy được nhưng càng về sau càng khó sửa, và bạn muốn tự quyết định cấu trúc thay vì học thuộc pattern.
2. **Người viết code cùng AI** — Bạn cần tên gọi chính xác để yêu cầu coding agent tổ chức code, và cách kiểm tra lại code nó viết.
3. **Người thấy lý thuyết còn xa vời** — Bạn từng đọc về SOLID, GoF hay Clean Architecture nhưng thấy chúng xa code mình viết.

## Những điều cần lưu ý

- **Không dạy ngôn ngữ hay framework** — Code TypeScript có chú thích và chỉ để đọc; bạn cần đọc được function, class, interface ở một ngôn ngữ bất kỳ, và mang cách nhìn sang ngôn ngữ của mình.
- **Không đi hết 23 pattern** — Bạn đi sâu vào những pattern ứng với áp lực thay đổi hay gặp, và nhận ra pattern mà ngôn ngữ đã làm giúp.
- **Không bàn kiến trúc cấp hệ thống** — Microservices, event sourcing hay DDD ở cấp chiến lược nằm ngoài khoá học; bạn nhận được cách tổ chức bên trong một ứng dụng.
- **Không có cấu trúc chuẩn để chép** — Bạn nhận được cách quyết định cho từng áp lực, kể cả quyết định không thêm tầng nào.

## Bắt đầu từ đâu

Bài đầu tiên trả lời vì sao mỗi yêu cầu mới lại làm code khó sửa hơn, dù code không sai. Bài này đứng đầu vì nó đặt ra câu hỏi cả khoá học dựa vào: phần nào sẽ thay đổi, và phần code nào đang phụ thuộc vào phần code nào. Có câu hỏi đó, mỗi pattern và kiến trúc bạn gặp sau này là một cách trả lời bạn tự cân nhắc được.

## Chương trình

- Từ design patterns tới architecture: vì sao mỗi yêu cầu mới lại làm code khó sửa hơn (miễn phí)
- Code smell và áp lực thay đổi: tìm chỗ code khó sửa trước khi nghĩ tới pattern (miễn phí) · quiz
- Dependency: A dùng B thì khi B đổi, file nào phải sửa theo (miễn phí) · quiz
- Coupling và cohesion: đổi một file thì phải sửa thêm mấy file · quiz
- Decoupling bằng interface: đổi cách nhận, cách trả, cách lưu mà không đụng logic · quiz
- Strategy pattern: khi nào if/else vẫn là đủ · quiz
- Template Method và composition: giữ khung xử lý chung ở lớp cha hay truyền các bước từ ngoài vào · quiz
- State pattern: đổi hành vi theo trạng thái mà không thêm mãi if/else · quiz
- Command pattern: khi một hành động cần được xếp hàng, ghi lại hoặc hoàn tác · quiz
- Observer pattern: thêm một bên cần nhận thông báo là phải sửa hàm phát thông báo · quiz
- Composite pattern: dữ liệu dạng cây mà code cứ phải kiểm tra đâu là lá, đâu là nhánh · quiz
- Adapter và Facade: khi thư viện ngoài không khớp với code, hoặc bắt bạn gọi quá nhiều bước · quiz
- Decorator và Proxy: thêm log, cache, retry mà không sửa code gốc · quiz
- Factory và Builder: quyết định tạo object nằm ở đâu, và khi nào object literal đã đủ · quiz
- Abstract Factory: khi nhiều thành phần phải đi cùng một bộ · quiz
- Singleton và dependency injection: tiện lúc viết, khổ lúc test · quiz
- Iterator, Visitor, Prototype, Memento, Interpreter: những pattern mà TypeScript đã có sẵn cách viết gọn · quiz
- Chain of Responsibility, Mediator, Bridge, Flyweight, Null Object: có sẵn hay hiếm khi cần · quiz
- Gỡ pattern thừa: khi pattern không còn đáng giữ · quiz
- Layered architecture: chia tầng rồi mà một thay đổi vẫn lan qua mọi tầng · quiz
- Import graph và architecture check: sơ đồ một đằng, code import một nẻo · quiz
- Transaction Script và Domain Model: luật nghiệp vụ nằm trong hàm hay trong object · quiz
- Active Record và Data Mapper: object tự lưu xuống database hay giao việc lưu cho mapper · quiz
- Repository: interface đã giấu database mà vẫn làm mất nghĩa của dữ liệu · quiz
- Unit of Work: một thao tác sửa ba bảng, lỗi giữa chừng thì sao · quiz
- Service Layer và use case: khi luật nghiệp vụ nằm rải rác trong controller và câu SQL · quiz
- Dependency Inversion: đã inject rồi mà nghiệp vụ vẫn phụ thuộc thư viện ngoài · quiz
- Hexagonal architecture: phần nghiệp vụ không cần biết mình được gọi từ đâu và đang gọi ra hệ thống nào · quiz
- Driving adapter: cùng một nghiệp vụ, gọi từ web, CLI, job hay test · quiz
- Driven adapter và test double: test với mock thì xanh, lên production thì vẫn hỏng · quiz
- Composition root: ứng dụng được lắp ráp ở đâu, và lắp khác nhau cho test, dev, production thế nào · quiz
- DDD layered architecture: cùng gọi là service mà thuộc ba tầng khác nhau · quiz
- Onion architecture: khi database không còn nằm ở tâm · quiz
- Clean Architecture: luật phụ thuộc và vì sao database, web, framework chỉ là chi tiết · quiz
- Use case interactor: kết quả đi ra ngoài thế nào mà lõi không phụ thuộc giao diện · quiz
- Humble Object: tách logic ra khỏi phần code khó test · quiz
- Partial boundaries: khi làm ranh giới đầy đủ quá tốn kém, nên dừng ở mức nào · quiz
- Hexagonal, Onion, Clean: ba cái tên, một luật phụ thuộc · quiz
- Vertical slice: thêm một field mà phải sửa năm folder · quiz
- Modular monolith: đã chia module mà module nào cũng gọi thẳng vào bên trong module khác · quiz
- Module data ownership: module này join thẳng vào bảng của module kia · quiz
- Over-layering: khi ba tầng và bốn interface là quá nhiều cho một app · quiz
- Layered sang Hexagonal: đổi cấu trúc từng bước trên một codebase, và biết dừng ở đâu · quiz
