5

分離式客製化開發:兼顧模組化與客製化的 Laravel 彈性架構

 3 years ago
source link: https://blog.turn.tw/?p=3697
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
分離式客製化開發:兼顧模組化與客製化的 Laravel 彈性架構

接案的時候,常常很想把一套系統寫完之後,一口氣賣給多個客戶。

偏偏每個客戶都有各自不同的客製化需求,沒辦法真的都拿同一個專案去佈署。

只好把一個專案複製成好幾份,然後分別客製化給不同客戶。

但這樣又會出現維護問題:各專案的差異越變越大。

之後就算更新了核心功能、修理了核心 bug,也很難一口氣替所有客戶升級。

如果各專案的差異是無法避免的,那有沒有辦法至少,讓核心系統與客製化的程式碼分開來放呢?

最好能讓各專案的檔案結構都像這樣:

System/
Customization/

如此一來,雖然 Customization/ 內的 code 不能重複使用,至少 System/ 內的 code 可以。

可以將 System/ 內的 code 更新進其他專案,也可以拿強化後的核心系統去接未來的新案子。

我把這種檔案結構稱為「分離式客製化架構」,下文用 SCA (Separated Customization Architecture) 代稱。

這篇文章跟大家分享在 Laravel 底下如何使用這種 SCA 架構。

使用 SCA 架構非常簡單,只要安裝 laravel-modules 套件就可以了。

laravel-modules 套件非常單純,它只是運用了 Laravel 原生的 Package Development 觀念,幫助你把 app/ 與 resources/ 資料夾底下的程式碼移進另外的 Modules/ 資料夾而已。

Modules/ 內可以有一或多個資料夾,每個資料夾就跟一個獨立 laravel app 一樣,有自己的 controllers, views, entities, routes, migrations… 等等內容。

laravel-modules 套件就只是幫你讀取各個模組的內容而已,沒有其他黑魔法。

如此一來,你的 Laravel 專案的檔案結構會變成這樣:

Modules/
resources/

注意到了嗎?它剛好對應到前面說的檔案結構:

System/
Customization/

Modules/ 就是 System/,而 app/ 與 resources/ 就是 Customization/。

那麼實際上該如何開發呢?以下直接舉例說明。

情境:你開發了一套 Awesome 通用系統來接案

首先你根據過去的經驗開發了一套 Awesome 電商官網模組,打算用它來接許多案子,賺大錢。

你的 laravel 檔案結構長這樣:

Modules/Awesome/
resources/

Awesome 模組的 controllers, views, entities, routes, migrations… 等等內容都在 Modules/Awesome/ 裡面,就跟一個獨立 laravel app 一樣。

而 app 與 resources 資料夾內目前只有 laravel 預設檔案,你沒寫半行 code 在裡面。

你拿 Awesome 系統開始接案,接著客戶出現。他們有以下的客製化需求。

情境:客戶想修改 UI

客戶要求對首頁畫面微調。

這個時候請利用 laravel 原生的 Overriding Package Views 機制,你直接新增一個檔案:

resources/views/vendor/awesome/homepage.blade.php

就在這個檔案內隨心所欲的重寫或是亂寫吧!它會直接取代原本的這個檔案:

Modules/Awesome/Resources/views/homepage.blade.php

如果不只是畫面微調,這種模板覆蓋不夠用,那就可以視為修改系統的 business logic,請接著往下讀。

情境:客戶想修改系統的 business logic

客戶想修改結帳前的購物車頁面與功能。

此功能原本的 routing 定義在 Modules/Awesome/Http/routes.php 內:

Route::group(['middleware' => 'web', 'namespace' => 'Modules\Awesome\Http\Controllers'], function()
    Route::get('/shopping/cart', 'ShoppingController@cart');
    // blah blah...

請在原本 laravel 預設的 routes/web.php 內新增:

Route::get('/shopping/cart', 'ShoppingController@cart');

接著建立 app/Http/Controllers/ShoppingController.php 檔案,去繼承原先在 Modules/Awesome/ 內的 controller:

namespace App\Http\Controllers;
use Modules\Awesome\Http\Controllers\ShoppingController as BaseController;
use Illuminate\Http\Request;
class ShoppingController extends BaseController
    function cart(Request $request)
        // 隨你修改商業邏輯 ...
        // 繼續用原有模板與覆蓋機制
        // return view('awesome::shopping.cart');
        // 或是在 resources/views/ 內建一個新的也行
        return view('the-new-cart');

這樣就會直接取代原本的功能了!

最棒的是,這只是用上了基本的 OOP 類別繼承觀念,以及 laravel 的特性:「重複的話,後定義的 route 會覆蓋先定義的 route」。

有需要的話,domain model 內的類別也可以用同樣手法繼承來擴充。

比如說原本有個 Modules/Awesome/Cart.php 類別:

namespace Modules\Awesome;
use Illuminate\Database\Eloquent\Model;
class Cart extends Model
    // blah ...

你可以建立 app/Cart.php 這樣的子類別:

namespace App;
use Modules\Awesome\Cart as BaseCart;
class Cart extends BaseCart
    // blah ...

在新建立的 controller 內就可以使用這些擴充後的新 domain model 類別。

用這種手法可以自由新增程式碼!而且全是在 app/ 或 resources/ 資料夾內新增,完全沒碰到 Modules 內的東西。

情境:客戶想開發新功能

開發全新功能就更簡單了,直接在 routes/web.php 內增加 routing 後,在 app/ 與 resources/ 內增加你需要的檔案就行了。

就跟平常開發 laravel 專案一樣!

有需要的話,就在新的檔案裡面引入或是繼承 Modules/ 內的類別就行了。

情境:需要更新資料庫 schema

laravel-modules 有提供指令幫忙產生 migration 檔案。

所以屬於 Awesome 系統的 migration 檔案會在 Modules/Awesome/Database/Migrations/ 底下。

如果客製化時需要更新 schema ,就用 laravel 原生的 migration 指令在 database/migrations/ 內建立 migration file 即可。

連 migration file 都可以完全分離在 System/ 與 Customization/ 裡面!

SCA 的特色在於它不預設你打算把專案模組化或是客製化到哪種程度。

你可以為了客戶在 Customization/ 內先寫完功能。之後有空再完全重構或是部份重構進 System/。

也可以遇到需求就先強化 System/,寫到不適合的地方再開始從 Customization/ 接手客製化。

你可以視情況來來回回,以一種混合的方式寫 code。

你可以邊寫邊決定,事後隨時反悔也沒問題,所以 SCA 非常適合接案類型的軟體開發。

針對 SCA 還有許多進階議題可以討論,本文只談最基本的觀念與技巧,但應該足以解決大部份的問題。

我自己用這種方式接案開發了幾個月,效果非常不錯,分享給各位參考。

有任何問題歡迎留言讓我知道,或是寄信到 [email protected] 與我討論。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK