拒絕「義大利麵程式碼」!Laravel 10 專案架構最佳實務:資深工程師的重構與設計心法

2026/01/24 | Laravel技術分享, 全端與程式開發, 架構與效能優化

告別技術債:Laravel 10 專案架構的專業蛻變

您的 Laravel 專案是否正被「肥胖控制器」與「義大利麵程式碼」所困擾?資深工程師 Eric 將帶您跳脫傳統 MVC 迷思,直接切入實戰架構優化。本文將揭示資深工程師如何透過 Service Layer、Single Action Classes 及強型別 DTO(資料傳輸物件),將複雜的業務邏輯徹底解耦,打造出高可維護性與擴展性的「藝術品」。不要再讓混亂的程式碼成為您的技術債炸彈!立即學習這些重構與模組化設計心法,讓您的 Laravel 系統穩健如山,並聯繫我們,終結您的專案噩夢!

需要專業協助?

聯絡浪花專案團隊 →

拒絕「義大利麵程式碼」!Laravel 10 專案架構最佳實務:資深工程師的重構與設計心法

嗨,我是浪花科技的 Eric。身為一個在 Laravel 圈子打滾多年的工程師,這幾年我接手過無數個「年久失修」的專案。說真的,每次打開那些 `app/Http/Controllers` 裡塞了兩千行程式碼的檔案,我的心跳都會漏一拍。那種變數滿天飛、邏輯像義大利麵一樣糾纏不清的程式碼,不僅維護起來像在拆炸彈,要擴充功能更是難如登天。

Laravel 10(以及後續的 11)是一個非常強大且優雅的框架,但框架只是工具,它給你自由,卻不能阻止你寫出爛 Code。很多新手(甚至中階)開發者常常會陷入「MVC 迷思」,認為只要把程式碼塞進 Model、View 或 Controller 就好。但隨著業務邏輯變複雜,這種簡單的分類很快就會崩潰。

今天這篇文章,我想以「資深工程師」的角度,不談太虛幻的理論,直接切入實戰,聊聊在 Laravel 10 專案中,我們該如何規劃架構,才能讓專案從「技術債炸彈」變成可維護、可擴充的藝術品。

為什麼標準的 MVC 架構還不夠?

Laravel 預設的 MVC (Model-View-Controller) 架構對於小型專案或是簡單的 CRUD 應用來說非常完美。但現實世界的商業邏輯通常沒這麼簡單。試想一下,當一個「下訂單」的動作包含了:驗證庫存、扣款、發送 Email、通知倉儲系統、寫入 Log、更新會員等級……如果你把這些全部寫在 Controller 裡,那就會發生我們常說的 Fat Controller(肥胖控制器) 災難。

這不僅違反了 單一職責原則 (SRP),也讓單元測試變得幾乎不可能執行。你沒辦法單獨測試「扣款」邏輯,因為它跟 HTTP Request 綁死在一起。

Laravel 10 架構優化的三大心法

1. 引入 Service Layer(服務層)與 Action 模式

這是我最強烈建議的第一步。請把你的商業邏輯從 Controller 中剝離出來。Controller 的工作應該只有三件事:接收請求、呼叫邏輯、回傳回應。至於「怎麼做」,不關它的事。

在 Laravel 10 中,我們可以更進一步使用 Single Action Classes(單一行為類別)。比起傳統把一堆方法塞進 `OrderService`,我更喜歡將每個具體的商業行為拆分成獨立的 Class。

例如,與其寫一個龐大的 `ProductController::store`,不如建立一個 Action:

// app/Actions/Product/CreateProductAction.php

class CreateProductAction
{
    public function execute(ProductData $data): Product
    {
        // 這裡只專注處理建立產品的邏輯
        // 1. 資料庫寫入
        // 2. 圖片處理
        // 3. 觸發事件
        return Product::create($data->toArray());
    }
}

然後在 Controller 中這樣呼叫:

// ProductController.php

public function store(ProductRequest $request, CreateProductAction $action)
{
    $product = $action->execute(ProductData::fromRequest($request));
    
    return response()->json($product, 201);
}

這樣做的好處是顯而易見的:你的 `CreateProductAction` 可以在任何地方被重複使用(例如 CLI 指令、Job Queue 或 API),而且寫測試時,不需要模擬 HTTP 請求。

2. 拒絕關聯陣列,擁抱 DTO (Data Transfer Object)

這是我個人的堅持,也是 Eric 我在 Code Review 時最常退件的原因。請停止在你的 Service 或 Action 之間傳遞 `array`!

陣列是「無型別」且「不透明」的。當你看到一個 `$data` 陣列傳進來,你不看程式碼根本不知道裡面有什麼 key,是不是少了什麼欄位。在 PHP 8.1+ 和 Laravel 10 的環境下,我們可以使用 readonly 屬性來建立強型別的 DTO。

// app/DataTransferObjects/ProductData.php

readonly class ProductData
{
    public function __construct(
        public string $name,
        public float $price,
        public ?string $description = null,
    ) {}

    public static function fromRequest(Request $request): self
    {
        return new self(
            name: $request->validated('name'),
            price: $request->validated('price'),
            description: $request->validated('description'),
        );
    }
}

這樣做,IDE 會感謝你,接手你程式碼的同事也會感謝你。大家都清楚知道資料結構長什麼樣子,型別錯誤在編譯階段就能被發現。

3. Repository Pattern 的取捨

在 Laravel 社群中,Repository Pattern(倉儲模式)一直是個爭議話題。老實說,對於大部分使用 Eloquent ORM 的專案,我認為不要過度使用 Repository

Elouqent 本身已經實作了 Active Record 模式,本身就像個 Repository。如果你只是為了「包一層」而寫 Repository,例如 `findUserById` 裡面只是呼叫 `User::find($id)`,那是多此一舉,增加了複雜度卻沒帶來好處。

什麼時候該用 Repository?

  • 當你需要切換資料來源(例如從 MySQL 換到 ElasticSearch)。
  • 當你有非常複雜的查詢邏輯(例如多表 Join 加動態篩選),且多個地方都會用到。
  • 為了單元測試需要 Mock 資料庫層時(雖然 Laravel 的 `RefreshDatabase` trait 已經讓測試資料庫變得很簡單)。

目錄結構的整理術

Laravel 預設的 `app` 目錄雖然通用,但對於中大型專案,我建議依照「領域 (Domain)」或「模組 (Module)」來重新組織程式碼。

與其把所有的 Controllers 放在一起、Models 放在一起,不如試試看這樣的結構:

  • app/Modules/Order/
    • Actions/
    • DataTransferObjects/
    • Models/
    • Events/
  • app/Modules/User/

這種結構讓你的專案更具備「模組化」的特性。當你需要修改訂單邏輯時,你只需要專注在 `Order` 資料夾,而不用在整個 `app` 目錄裡跳來跳去。

嚴格型別模式 (Strict Types)

在 Laravel 10 專案中,我強烈建議在每個 PHP 檔案的開頭加上:

declare(strict_types=1);

這能強迫 PHP 在傳遞參數時進行嚴格的型別檢查。雖然剛開始寫起來會覺得「報錯變多了」,但這能大幅減少那種「字串數字自動轉換」帶來的隱性 Bug。這是一種「短痛換長痛」的划算交易。

結論:架構是為了人而服務

最後,Eric 想跟大家囉嗦一句:沒有絕對完美的架構,只有最適合當下團隊與業務的架構。

不要為了套用設計模式而套用。如果你的專案只是一個簡單的形象網站後台,那標準的 MVC 就很棒了。但如果你的系統承載著複雜的 B2B 邏輯、金流串接、ERP 同步,那麼引入 Service Layer、DTO 和模組化設計,絕對是讓你晚上能睡好覺的最佳投資。

程式碼是寫給人看的,偶爾才是給機器執行。保持程式碼的「可讀性」與「意圖清晰」,永遠比寫出炫技的 Code 更重要。

延伸閱讀

如果你想進一步優化你的 Laravel 專案,可以參考以下幾篇深度技術文章:

受夠了維護困難的舊系統嗎?

如果你的企業正面臨技術債的困擾,或是想要打造一個高擴充性、架構穩健的 Laravel 系統,浪花科技擁有最資深的開發團隊能為你解決難題。

立即聯繫我們,預約技術諮詢

常見問題 (FAQ)

Q1: 所有的邏輯都一定要移出 Controller 嗎?

不必矯枉過正。如果只是一行 `User::all()` 或簡單的 View 回傳,直接寫在 Controller 是完全沒問題的。架構模式是用來解決「複雜度」的,沒有複雜度時不需要引入額外模式。

Q2: DTO 和 Laravel 的 Form Request 有什麼不同?

Form Request 負責的是「HTTP 請求的驗證」(例如:欄位必填、格式要是 Email)。而 DTO 負責的是「系統內部的資料傳遞」。通常我們會先通過 Form Request 驗證,再將驗證後的資料轉成 DTO,傳遞給 Service 或 Action 使用,這樣能確保核心邏輯層不依賴 HTTP 請求物件。

Q3: Laravel 11 出來了,這些 Laravel 10 的架構還適用嗎?

完全適用。Laravel 11 雖然精簡了 `skeleton`(骨架),移除了部分 middleware 和 config 檔案,但核心的架構邏輯、Service Provider 機制以及 PHP 物件導向的原則是通用的。現在把 Laravel 10 專案架構整理好,未來升級 11 會更順暢。

 
立即諮詢,索取免費1年網站保固