[Architecture 101] Layered Architecture: Bí kíp thoát khỏi "nồi lẩu" Spaghetti code
Hãy tưởng tượng bạn vào một quán ăn mà anh chủ quán vừa là người trông xe, vừa là người chạy bàn, vừa là đầu bếp kiêm luôn tạp vụ. Khi quán chỉ có 2 khách, mọi thứ vẫn ổn. Nhưng khi có 50 khách ập vào, anh chủ quán sẽ loạn cào cào, quên đơn, nấu mặn và khách sẽ bỏ đi hết.
Trong phần mềm cũng vậy. Nếu một đoạn code đảm nhận quá nhiều trách nhiệm (Responsibility), khi hệ thống phình to, việc sửa một dòng code có thể gây lỗi ở 10 chỗ khác. Layered Architecture ra đời để chia dự án thành các lớp riêng biệt, mỗi lớp chỉ lo đúng việc của mình.
1. Cấu trúc 4 lớp kinh điển (The 4-Layer Pattern)
Dù có nhiều biến thể, nhưng thông thường một kiến trúc phân lớp chuẩn sẽ gồm 4 tầng chính xếp chồng lên nhau:
1.1. Presentation Layer (Tầng hiển thị/Giao diện)
Đây là nơi tiếp nhận yêu cầu từ người dùng (Web UI, Mobile App, hoặc các API Endpoints).
- Nhiệm vụ: Nhận request, validate dữ liệu đầu vào cơ bản và chuyển tiếp xuống tầng dưới. Nó không được phép biết về Database hay cách tính toán tiền bạc phức tạp.
- Trong Laravel: Chính là các Controllers.
1.2. Business/Service Layer (Tầng nghiệp vụ)
Đây là "trái tim" của ứng dụng, nơi chứa mọi quy tắc kinh doanh.
- Nhiệm vụ: Thực hiện các tính toán, logic kiểm tra (ví dụ: áp dụng mã giảm giá, tính phí vận chuyển, kiểm tra điều kiện đăng ký).
- Trong Laravel: Thường là các Services.
1.3. Persistence/Data Access Layer (Tầng truy cập dữ liệu)
Tầng này đóng vai trò trung gian giữa logic và dữ liệu thô.
- Nhiệm vụ: Thực hiện các câu lệnh SQL (CRUD) để lấy hoặc lưu dữ liệu. Nó giúp tầng Business không cần quan tâm dữ liệu đang nằm ở MySQL, PostgreSQL hay một file Excel.
- Trong Laravel: Chính là Eloquent Models hoặc Repositories.
1.4. Database Layer (Tầng dữ liệu)
Nơi dữ liệu thực sự nằm đó (MySQL, Redis, v.v.).
2. Quy tắc "Bất biến": Luồng đi của dữ liệu
Trong Layered Architecture, có một quy tắc sống còn: Dependencies chỉ được hướng xuống dưới.
- Tầng Presentation chỉ được gọi tầng Business.
- Tầng Business chỉ được gọi tầng Persistence.
- Cấm tuyệt đối: Tầng Persistence gọi ngược lên tầng Presentation hoặc tầng Business gọi trực tiếp vào Database mà không qua Persistence.
Tại sao? Vì nếu các tầng gọi loạn xạ, việc thay thế một tầng (ví dụ chuyển từ MySQL sang MongoDB) sẽ buộc bạn phải sửa code ở tất cả các tầng khác.
3. Tại sao anh em nên dùng Layered Architecture?
- Dễ bảo trì (Maintainability): Muốn sửa logic tính thuế? Chỉ cần tìm đến Business Layer. Muốn đổi giao diện từ Web sang Mobile? Chỉ cần viết lại Presentation Layer.
- Dễ viết Unit Test: Bạn có thể test riêng biệt tầng Business mà không cần quan tâm đến việc có Database thực sự hay không (bằng cách Mocking tầng Persistence).
- Làm việc nhóm hiệu quả: Một người có thể tập trung thiết kế UI, một người tập trung xử lý Logic, và một người tối ưu Database mà không "đá" vào chân nhau.
4. Mặt trái của tấm huy chương
Không có gì là hoàn hảo. Layered Architecture cũng có nhược điểm:
- Mã nguồn bị phình to (Boilerplate): Đôi khi một chức năng đơn giản (chỉ là lấy data hiện ra) cũng phải đi qua 3-4 lớp, khiến anh em có cảm giác mình đang "vẽ việc" ra làm.
- Hiệu năng: Việc chuyển tiếp dữ liệu qua quá nhiều lớp có thể gây ra một chút độ trễ nhỏ (tuy nhiên trong đa số trường hợp Web app thì không đáng kể).
5. Áp dụng thực tế (Dành cho anh em Laravel)
Thay vì viết mọi thứ trong Controller:
// CÁCH TỆ (Spaghetti)
public function store(Request $request) {
// 1. Validate
// 2. Tính toán giảm giá (Logic nằm đây)
// 3. Query DB trực tiếp: DB::table('orders')->insert(...)
// 4. Trả về view
}
Hãy tách lớp:
// CÁCH TỐT (Layered)
public function store(Request $request) {
// Controller gọi Service
$order = $this->orderService->createOrder($request->all());
return response()->json($order);
}
// Trong OrderService (Business Layer)
public function createOrder($data) {
$discount = $this->calculateDiscount($data);
// Service gọi Repository/Model
return $this->orderRepository->save($data, $discount);
}
Lời kết
Layered Architecture là bước khởi đầu để anh em tiến tới những kiến trúc cao cấp hơn như Hexagonal hay Clean Architecture. Nó giúp code của anh em "sạch" hơn, chuyên nghiệp hơn và quan trọng nhất là giúp anh em giữ được sự bình tĩnh khi dự án phình to gấp 10 lần.
Anh em có đang áp dụng phân lớp rõ ràng trong dự án hiện tại không, hay vẫn đang "tiện đâu viết đó"? Cùng chia sẻ cấu trúc folder dự án mà anh em tâm đắc nhất nhé!
Hy vọng bài viết này giúp anh em có cái nhìn tổng quan về cách tổ chức code. Đừng quên Upvote để ủng hộ mình ra thêm các bài về Design Patterns nhé!
All rights reserved