Laravel – Folder Structure & Clean Architecture

2 min read


Vì sao Laravel folder structure mặc định không đủ cho project lớn?

Laravel sinh ra với cấu trúc đơn giản:

app/
 ├── Http/
 ├── Models/
 ├── Providers/
 ├── Console/

Cấu trúc này rất tốt cho project nhỏ, nhưng khi:

  • Project có 30+ controller
  • Business logic phức tạp
  • Team 5–10 dev
  • Microservice hoặc multi-domain

Thì bạn sẽ bắt đầu thấy:

❌ Controller quá to
❌ Logic business nằm rải rác
❌ Khó test
❌ Khó refactor

Laravel không ép bạn giữ nguyên cấu trúc mặc định. Framework đủ linh hoạt để bạn tổ chức lại kiến trúc.

Tài liệu chính thức về structure:
👉 https://laravel.com/docs/structure


1️⃣ Khi nào nên thay đổi Laravel folder structure?

Bạn nên cân nhắc restructure khi:

  • Business logic nhiều hơn CRUD
  • Có nhiều domain (User, Order, Payment…)
  • Bắt đầu xuất hiện duplicate logic
  • Test trở nên khó viết

Nếu bạn vẫn đang ở mức CRUD app nhỏ, không cần phức tạp hóa vấn đề.


2️⃣ Vấn đề lớn nhất: Controller bị “phình to”

Ví dụ anti-pattern:

public function store(Request $request)
{
    $user = User::create($request->all());    Mail::to($user->email)->send(new WelcomeMail());    event(new UserRegistered($user));    Log::info("User registered");    return response()->json($user);
}

Controller đang làm:

  • Validation
  • Business logic
  • Event
  • Logging
  • Response formatting

Đây là dấu hiệu bạn cần tách layer.


3️⃣ Clean Architecture trong Laravel

Clean Architecture chia hệ thống thành các layer:

Controller
   ↓
Application (Use Case)
   ↓
Domain
   ↓
Infrastructure

Đọc thêm về Clean Architecture:
👉 https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html


Áp dụng vào Laravel như thế nào?

Bạn có thể tổ chức lại app/:

app/
 ├── Domain/
 │     ├── User/
 │     ├── Order/
 │
 ├── Application/
 │     ├── User/
 │     ├── Order/
 │
 ├── Infrastructure/
 │     ├── Repository/
 │     ├── Services/
 │
 ├── Http/

Domain Layer

  • Entity
  • Business rule
  • Value object

Không phụ thuộc framework.


Application Layer (Use Case)

Ví dụ:

class RegisterUser
{
    public function execute(array $data)
    {
        // business orchestration
    }
}

Controller chỉ gọi:

public function store(RegisterUser $useCase)
{
    return $useCase->execute(request()->all());
}

Controller giờ cực sạch.


Infrastructure Layer

  • Eloquent model
  • External API
  • Mail service
  • Queue

Layer này phụ thuộc Laravel.


4️⃣ Modular Structure – Tổ chức theo Domain

Thay vì chia theo technical layer, bạn có thể chia theo feature:

app/
 ├── User/
 │     ├── UserController.php
 │     ├── UserService.php
 │     ├── UserRepository.php
 │
 ├── Order/
 │     ├── OrderController.php
 │     ├── OrderService.php

Ưu điểm:

✔ Team làm song song không conflict
✔ Dễ scale
✔ Dễ tách microservice sau này


5️⃣ Repository Pattern Có Cần Thiết?

Laravel đã có Eloquent ORM.

Bạn chỉ nên dùng Repository khi:

  • Muốn abstract database layer
  • Có nhiều data source
  • Cần mock repository để test

Nếu chỉ dùng MySQL đơn giản, đôi khi thêm repository chỉ làm code phức tạp.


6️⃣ Tối ưu Performance Khi Restructure

Khi bạn tách layer:

  • Đừng resolve service nhiều lần
  • Sử dụng singleton cho service nặng
  • Tránh over-engineering

Laravel container documentation:
👉 https://laravel.com/docs/container


7️⃣ Những Sai Lầm Khi “Theo Clean Architecture”

❌ Copy-paste mô hình từ blog mà không hiểu
❌ Tạo quá nhiều layer không cần thiết
❌ Viết interface cho mọi thứ
❌ Over abstraction

Clean Architecture không phải để “cho đẹp”.
Nó để giúp bạn scale.


8️⃣ Folder Structure Gợi Ý Cho Production App

Một cấu trúc cân bằng:

app/
 ├── Domain/
 ├── Application/
 ├── Infrastructure/
 ├── Http/
 ├── Providers/

Giữ:

  • Controller mỏng
  • Business logic tách riêng
  • Domain độc lập

Kết luận

Laravel folder structure mặc định phù hợp cho:

  • CRUD app nhỏ
  • MVP
  • Startup sớm

Nhưng khi project lớn lên, bạn cần:

  • Tách domain
  • Tách use case
  • Giảm phụ thuộc vào framework
  • Giữ controller mỏng
Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *