~/blog/laravel-10-project-architecture-refactoring-guide-2026.md
Laravel 與後端開發 · 2026 / 02 / 07

技術債滾成雪球之前:Laravel 10 潔淨架構重構與維護指南

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
技術債滾成雪球之前:Laravel 10 潔淨架構重構與維護指南
目錄 table-of-contents.md

當初讓老闆讚不絕口的「快速功能」,現在自己重讀一次要花多久才看得懂?許多企業級系統為了求穩還停在 Laravel 10,時間一拉長,那些走捷徑的程式碼全滾成了義大利麵與技術債雪球。這篇分享我替舊專案導入潔淨架構的重構與維護心法,趕在雪球壓垮團隊之前把它拆掉。

雖然 Laravel 10 在當年是個長期支援版本(LTS),引入了 PHP 8.1+ 的強型別特性,但工具再好,架構還是得靠人來維護。我看過太多專案,Controller 寫得比聖經還厚,Model 裡面混雜著商業邏輯和視圖邏輯。今天,我們不談那些虛無飄渺的理論,我會以 2026 年的工程標準,回頭檢視「Laravel 10 專案架構最佳實務」,教你如何把手中的技術債,重構成可擴展的資產。

1. 拒絕「肥大 Controller」:擁抱 Action 模式

這是老生常談,但直到 2026 年的今天,我 Review 程式碼時還是會血壓升高。Controller 的職責只有三個:接收請求、呼叫邏輯、回傳回應。它不應該知道你的商業邏輯細節。

在 Laravel 10 時代,雖然 Service Pattern 很流行,但後來我們發現單一職責的 Action Pattern(或稱 Single Action Controller 風格的類別)更容易測試與維護。

糟糕的寫法(The Bad Way):

// StoreController.php
public function store(Request $request)
{
    // 驗證邏輯混在 Controller
    $request->validate(['email' => 'required|email']);

    // 商業邏輯直接寫死
    $user = User::create($request->all());
    
    // 發送信件邏輯也塞在這裡
    Mail::to($user)->send(new WelcomeEmail($user));

    return response()->json($user);
}

2026 年推薦的架構(The Clean Way):

將邏輯抽離到 Action 類別中。這在 Laravel 10 完全適用,且符合未來的升級路徑。

// app/Actions/RegisterUserAction.php
class RegisterUserAction
{
    public function execute(UserData $data): User
    {
        $user = User::create($data->toArray());
        // 這裡可以放更多複雜的邏輯,例如觸發事件
        UserRegistered::dispatch($user);
        return $user;
    }
}

// StoreController.php
public function store(RegisterRequest $request, RegisterUserAction $action)
{
    // 使用 DTO (Data Transfer Object) 傳遞資料,更加嚴謹
    $user = $action->execute(UserData::fromRequest($request));
    
    return UserResource::make($user);
}

這樣做的好處是,這個 RegisterUserAction 可以在 API、CLI 命令列、甚至排程任務中重複使用,而不需要複製貼上程式碼。

2. 強型別與 DTO:別再用陣列傳遞資料

Laravel 10 支援 PHP 8.1/8.2,這意味著我們有很好的型別系統。但在舊專案中,我常看到工程師喜歡把 $request->all() 或是關聯式陣列(Associative Array)到處傳。這在小專案沒問題,但在企業級架構中,這是災難。

如果你在 2026 年還在維護 Laravel 10 專案,請引入 Data Transfer Objects (DTO)。你可以使用 Spatie 的 `laravel-data` 套件,或是 PHP 8.2 的 `readonly` 類別來實作。

為什麼要這麼做? 因為 $data['email'] 沒有 IDE 自動補全,如果你拼錯成 $data['emial'],程式要跑起來才會報錯。但 $data->email 在你寫程式的當下,靜態分析工具就會告訴你錯了。

3. 模型(Model)瘦身計畫:Scope 與 Accessor 的應用

很多工程師會把查詢邏輯直接寫在 Controller 裡,導致重複查詢。請善用 Laravel 的 Local Scopes

// Bad: 在 Controller 到處寫 where
$activeUsers = User::where('active', 1)->where('last_login', '>', now()->subDays(30))->get();

// Good: 在 Model 定義 Scope
// User.php
public function scopeActive(Builder $query): void
{
    $query->where('active', 1);
}

public function scopeRecent(Builder $query): void
{
    $query->where('last_login', '>', now()->subDays(30));
}

// Use in Controller
$activeUsers = User::active()->recent()->get();

這不僅讓程式碼具有「語意化」(讀起來像英文句子),如果未來「活躍用戶」的定義改變了(例如從 30 天變成 7 天),你只需要改 Model 一個地方,不用全專案搜尋取代。

4. 依賴注入與介面(Interface)

雖然 Laravel 的 Facade(如 Log::info())很方便,但在大型架構中,過度依賴靜態呼叫會讓測試變得困難。在 Laravel 10 專案重構時,試著使用依賴注入(Dependency Injection)。

定義一個 PaymentGateway 介面,而不是直接在程式碼中 `new StripeService()`。這樣在 2026 年,當業務端突然說要從 Stripe 換成 HitPay 或 ECPay 時,你不需要改動核心商業邏輯,只需要抽換 Service Provider 綁定的實作類別即可。

5. 資料夾結構的演進:從 App 到 Modules

Laravel 預設的 app/Http, app/Models 結構適合中小型網站。但如果你的專案包含「電商」、「部落格」、「論壇」等多個複雜領域,我建議採用 模組化(Modular) 結構。

你可以建立 src/Domains/ECommerceapp/Modules/Blog,將相關的 Controller, Model, Policy, Service 都放在同一個領域資料夾下。這就是所謂的 Domain-Driven Design (DDD) 的輕量化實踐。這樣當你要拔除或修改某個功能模組時,不會牽一髮動全身。

6. 相關閱讀與資源延伸

架構優化是一條漫長的路,以下這幾篇文章可以幫助你在 2026 年更好地掌握 Laravel 與系統設計的精髓:

老實說,沒有所謂「完美」的架構,只有「適合當下團隊與業務」的架構。但在 Laravel 10 這樣成熟的框架下,遵循 SOLID 原則、善用強型別與自動化測試(別忘了 PHPUnit 或 Pest!),絕對能讓你的工程師生涯少掉很多半夜被叫起來修 Bug 的機會。

你的 Laravel 專案已經變成了難以維護的怪獸嗎? 或者你需要將舊版的 Laravel 10 系統升級並重構為現代化架構?浪花科技擁有豐富的 Laravel 企業級開發經驗,讓我們幫你把技術債變成技術資產。

立即聯繫浪花科技 Eric
// FAQ

常見問題

Laravel 專案的 Controller 應該負責哪些事?
Controller 的職責只有三個:接收請求、呼叫邏輯、回傳回應。它不應該包含商業邏輯細節,例如資料驗證以外的處理、寄信或第三方串接等都應抽離到 Action 或 Service 類別中,以便在 API、CLI、排程任務等不同場景重複使用。
為什麼在 Laravel 專案中應該用 DTO 而不是陣列傳遞資料?
用關聯式陣列傳資料時,像 $data['email'] 這種寫法沒有 IDE 自動補全,拼錯成 $data['emial'] 也要等程式執行才會報錯。改用 DTO(Data Transfer Object)後,存取 $data->email 在撰寫當下靜態分析工具就能抓出錯誤,資料格式更嚴謹可預測。可使用 Spatie 的 laravel-data 套件或 PHP 8.2 的 readonly 類別實作。
Laravel 的 Local Scope 有什麼好處?
把重複的查詢條件定義成 Model 上的 Local Scope,可讓程式碼語意化、讀起來像英文句子,例如 User::active()->recent()->get()。更重要的是當查詢定義改變時(例如活躍用戶從 30 天改為 7 天),只需修改 Model 一處,不必在全專案搜尋取代。
2026 年該繼續維護 Laravel 10 舊專案還是直接重寫?
取決於專案規模與技術債嚴重程度。如果專案邏輯尚可理解且有測試覆蓋,建議用「絞殺者模式(Strangler Pattern)」逐步重構並升級到較新版本,可搭配 Laravel Shift 等工具輔助。若核心已腐爛且無法擴充,重寫可能長痛不如短痛。
大型 Laravel 專案的資料夾結構該怎麼安排?
預設的 app/Http、app/Models 結構適合中小型網站。當專案包含電商、部落格、論壇等多個複雜領域時,建議採用模組化結構,依業務領域建立資料夾(如 app/Modules/Blog),把相關的 Controller、Model、Policy、Service 集中在同一領域下,這是 DDD 的輕量化實踐,修改或拔除功能時不會牽一髮動全身。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?