Clean Architecture là gì?

Clean Architecture là gì?

Clean Architecture là mô hình kiến trúc phần mềm do Robert C. Martin (Uncle Bob) tổng hợp từ các trường phái trước: Hexagonal Architecture của Alistair Cockburn, Onion Architecture của Jeffrey Palermo, Screaming Architecture của chính Uncle Bob, DCI và BCE. Mục tiêu chung của tất cả các trường phái này là tách biệt rõ ràng các tầng sao cho business logic không phụ thuộc vào framework, database hay UI cụ thể — thứ thay đổi nhanh nhất trong vòng đời phần mềm.

Clean Architecture đưa ra 5 tính chất hệ thống mong muốn: độc lập framework (dùng frameworks như công cụ, không bị chúng ràng buộc), khả năng test (business rules test được không cần UI/DB/web server), độc lập UI (swap web console mà không đổi business rules), độc lập database (swap Oracle sang MongoDB tự do), và độc lập external agencies (business rules không biết gì về outside world).

Bốn tầng chính

Clean Architecture sử dụng mô hình các vòng tròn đồng tâm (concentric circles). Mỗi tầng bên trong không biết gì về tầng bên ngoài. Số vòng có thể nhiều hơn 4 — đây là schematic, không phải quy định cứng.

  • Entities (Layer 1): enterprise-wide business rules — Product, Order, User. Lớp này ít thay đổi nhất, không import framework nào. Đây là các object có methods hoặc data structures kết hợp functions.
  • Use Cases (Layer 2): application-specific business rules — CreateOrder, CancelOrder, Checkout. Orchestrate flow giữa entities, chỉ thay đổi khi application operation thay đổi. Không phụ thuộc DB hay web framework.
  • Interface Adapters (Layer 3): converters giữa format use case/entity và format bên ngoài. Chứa controllers, presenters, views, repositories. SQL được giới hạn ở đây — domain không biết gì về database.
  • Frameworks & Drivers (Layer 4): database, Flask/Django/FastAPI, UI framework, third-party services. Phần lớn là glue code. “The web is a detail. The database is a detail.”

Trình soạn thảo code với syntax highlighting nhiều màu

Dependency Rule — quy tắc cốt lõi

Mọi source code dependencies chỉ được phép hướng vào trong (point inwards). Tầng trong không import tầng ngoài. Khi control flow cần hướng ra ngoài — use case gọi presenter — sử dụng Dependency Inversion Principle (DIP): inner circle định nghĩa interface (port), outer circle implements nó. Dù control flow hướng ra ngoài, source dependency vẫn hướng vào trong.

Data vượt qua boundary phải là simple data structures: dicts, tuples, dataclasses. Không bao giờ truyền Entity hay ORM row qua interface — nếu làm vậy, inner circle sẽ phụ thuộc vào outer framework.

Cấu trúc project Python thực tế

Dựa trên Cosmic Python và kinh nghiệm thực tế từ sản phẩm production, cấu trúc khuyến nghị:

my_project/
├── domain/                    # Layer 1: pure Python
│   ├── __init__.py
│   ├── models.py              # dataclasses: Order, Product
│   └── rules.py               # enterprise business logic
├── use_cases/                 # Layer 2: application rules
│   ├── __init__.py
│   ├── interfaces.py          # ABC/Protocol: OrderRepository
│   └── order_service.py       # CreateOrder, CancelOrder
├── adapters/                  # Layer 3: glue
│   ├── __init__.py
│   ├── repositories.py        # SQLAlchemyOrderRepo
│   ├── api_controllers.py     # Flask/FastAPI endpoints
│   └── mappers.py             # ORM ↔ domain mapping
└── frameworks/                # Layer 4: tech details
    ├── __init__.py
    ├── flask_app.py           # Flask setup
    ├── database.py            # SQLAlchemy engine
    └── config.py              # settings, env vars

Lập trình viên gõ code trên laptop tại bàn làm việc

Code thực tế — Repository Pattern

Dưới đây là ví dụ Python triển khai tối giản nhưng đúng Dependency Rule:

# domain/models.py
from dataclasses import dataclass

@dataclass
class Order:
    id: int
    items: list[str]
    total: float

# use_cases/interfaces.py
from abc import ABC, abstractmethod

class OrderRepository(ABC):
    @abstractmethod
    def get_order(self, order_id: int) -> Order: ...

class OrderService(ABC):
    @abstractmethod
    def create(self, items: list[str]) -> Order: ...

# use_cases/order_service.py
from domain.models import Order

class CreateOrder:
    def __init__(self, repo: OrderRepository):
        self.repo = repo

    def execute(self, items: list[str]) -> Order:
        order = Order(id=None, items=items,
                      total=sum(10.0 for _ in items))
        self.repo.save(order)
        return order

# adapters/repositories.py
import sqlalchemy as sa
from sqlalchemy.orm import Session
from use_cases.interfaces import OrderRepository
from domain.models import Order

class SqlAlchemyOrderRepo(OrderRepository):
    def __init__(self, session: Session):
        self.session = session
    def save(self, order: Order) -> None:
        row = sa.OrderRow(items=order.items,
                          total=order.total)
        self.session.add(row)
        self.session.commit()

# frameworks/flask_app.py (composition root)
from flask import Flask, request, jsonify
from use_cases.order_service import CreateOrder
from adapters.repositories import SqlAlchemyOrderRepo
from sqlalchemy.orm import Session
from sqlalchemy import create_engine

app = Flask(__name__)
engine = create_engine("postgresql:///myapp")
session = Session(engine)
create_order = CreateOrder(repo=SqlAlchemyOrderRepo(session))

@app.route("/orders", methods=["POST"])
def create():
    items = request.json["items"]
    order = create_order.execute(items)
    return jsonify({"id": order.id, "total": order.total})

So sánh với các pattern khác

Pattern Độ phức tạp Testability Framework coupling Phù hợp
MVC thuần (Django) Thấp Trung bình Chặt CRUD đơn giản
Fat Models Thấp Trung bình Chặt (Django) Django-only
Clean Architecture Cao Rất cao Lỏng Dài hạn, phức tạp
Hexagonal Cao Rất cao Lỏng Tương tự CA

Khi nào dùng, khi nào dùng lại

Clean Architecture phù hợp khi app sống nhiều năm, business logic phức tạp, cần swap framework (Django → FastAPI), nhiều delivery mechanism (CLI + API + web) hoặc team lớn cần rõ ràng trách nhiệm. Tuy nhiên, nó overkill cho CRUD app đơn giản, script nhỏ hay prototype cần tốc độ — trong những trường hợp đó, Django views hay FastAPI router trực tiếp đủ tốt.

Ưu và nhược điểm

Ưu điểm Nhược điểm
Business logic testable không cần framework Nhiều boilerplate (interfaces, DTOs, mappers)
Framework-agnostic domain Steep learning curve cho junior
Domain sống sót qua thay đổi UI/DB Có thể dẫn đến anemic domain nếu làm sai
Tách biệt rõ trách nhiệm Thiếu magic từ framework (DI thủ công)
Tuân thủ SOLID Nhiều file cần navigate

Tổng kết

Clean Architecture không phải công thức bắt buộc — mà là guideline giúp bạn đặt business logic ở vị trí trung tâm, framework ở ngoài. Đối với Python project dài hạn, tách biệt domain khỏi adapter thực sự đáng giá. Xem thêm blog gốc của Uncle BobCosmic Python book.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Drizzle ORM là gì? ORM TypeScript hiệu năng cao thay thế Prisma

Drizzle ORM là gì? Drizzle ORM là thư viện ORM (Object-Relational Mapping) kiểu headless cho TypeScript và JavaScript, tập trung vào hiệu năng cực cao và trọng lượng thấp. Khác…

Xem thêm

SQLAlchemy 2.0 là gì? Cải tiến ORM Python hiệu năng 2024

SQLAlchemy 2.0 là gì? SQLAlchemy 2.0 là bản cập nhật lớn của thư viện ORM và SQL toolkit nổi tiếng nhất cho Python, phát hành năm 2023. Nó cung cấp…

Xem thêm

Bun vs Deno: So sánh hai JavaScript runtime thay thế Node.js

Tại sao Bun và Deno là hai JavaScript runtime đáng chú ý nhất hiện nay JavaScript runtime là nền tảng thực thi mã JavaScript bên ngoài trình duyệt. Node.js đã…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất