當技術遇到商業—漂亮的設計模式如何造成營運混亂


Posted by altheachu on 2025-05-03

「又出錯了?」
「要不要直接叫入帳模組的人過來 debug?」

專案負責人連夜打電話叫人上線支援,在會議室裡,我們經歷了一場場無止盡的檢討。
程式碼乾淨,設計模式正確,但現場卻一片混亂。

那一刻我突然明白——漂亮的設計模式,恰恰造成了營運的混亂。

這是我工作上實際遇到的困難,為了保護公司的商業機密,我用一個虛構的例子來說明:工程師認為構思良好的設計模式為何在實際商業環境中寸步難行。

有一家大型餐廳開發了訂餐系統,支援3種點餐方式:

  • 內用點餐
  • 外帶點餐
  • 外送點餐

這3種點餐方式在流程上有一些共通步驟,像是點餐、付款,但也有各自不同的業務規則,比如內用需要指定桌號、外帶需要指定取餐時間及外送需要聯絡地址。

由於這3種點餐方式僅有少部分業務處理邏輯不相同,因此資訊部決定使用工廠模式進行開發。

工廠模式 Factory Design

工廠模式是一種建立物件的設計模式,它的核心目的是:整理原先分散在各處負責實體化物件的代碼,將其集中於工廠管理,讓工廠就能決定實體化物件類別。使用工廠模式可以避免各點餐方式共有業務邏輯(像是付款)被重複撰寫,也便於未來新增不同的訂單類型(比如說外膾)。

基於這個概念,資訊部工程師建構了訂單工廠 OrderFactory 跟 4個代表訂單的類別,分別為:

  • 用於定義方法的訂單模板(Order)
  • 內用訂單(EatInOrder)
  • 外帶訂單(TakeAwayOrder)
  • 外送訂單( DeliveryOrder)。

參考上圖,訂單模板 Order 中,有3個方法:

  • confirm 確認訂單
  • payment 付款
  • orderRule 訂單檢查規則

內用訂單(EatInOrder)、外帶訂單(TakeAwayOrder)和外送訂單(DeliveryOrder)都繼承了訂單模板(Order)。目前假定訂單跟付款是共用邏輯,不因訂單類型而變,所以在子類別的3個訂單類別中,就不再複寫。但各類型訂單的檢查規則不同,如分別需要桌號、取餐時間及外送地址,所以在子類別中各自實作邏輯。

interface Order {

    default void confirm(){}
    default void payment(){}
    boolean orderRule();

}

class EatInOrder implements Order{
    @Override
    public boolean orderRule() {
        boolean hasTableNo = true;
        return hasTableNo;
    }
}

class TakeAwayOrder implements Order{
    @Override
    public boolean orderRule() {
        boolean hasTakeTime = true;
        return hasTakeTime;
    }
}

class DeliveryOrder implements Order{
    @Override
    public boolean orderRule() {
        boolean isAddressValid = true;
        return isAddressValid;
    }
}

而所有訂單的最終檢查,例如付款核對,由於規則不因訂單類型而異,因此工程師將代碼集中在一個「訂單驗證類別(OrderValidator)」裡共同處理。

class OrderValidator {
    public boolean validate(Order order){
        boolean commonProcessResult = true;
        return commonProcessResult;
    }
}

看起來既合理又很漂亮,對吧?但是上線後debug是場惡夢......

營運管理的痛點

想像一下,這是一個大型系統,3種訂單類型各自成為一個模組,訂單驗證則獨立成一個模組,而每個模組都有1個工程師負責維護。

當訂單桌號錯誤時,內用組工程師需要與中央驗證模組工程師協力檢查。
當取餐時間錯誤時,外帶組工程師需要與中央驗證模組工程師相互配合。
當外送地址錯誤時,外送組工程師需要與中央驗證模組工程師共同確認。

也就是說,訂單正確與否的壓力,最後都會累積在驗證模組團隊。當訂單大量產生時,bug也會一一浮現,但中央驗證模組人力有限,無法對每個問題都即時反應,內用、外帶、外送訂單的bug修復也隨之癱瘓。

工程師從「邏輯共用性」出發,設計出看似完美的中央驗證系統;但實際上,這讓所有的營運壓力集中在一組人身上,成為維運效率的瓶頸。

解決方法:封裝

即使訂單驗證的業務邏輯在每種訂單類型都相同,也將其回歸到訂單類別。

interface Order {

    default void confirm(){}
    default void payment(){}
    default boolean validate(){
        boolean commonProcessResult = true;
        return commonProcessResult;
    }
    boolean orderRule();

}

訂單驗證類別則封裝了訂單(Order)類別的validate方法。

class OrderValidator {
    public boolean validate(Order order){
        return order.validate();
    }
}

於是,訂單各組的工程師,可以在自身負責的模組內檢查驗證邏輯;訂單驗證模組的工程師,也不需要在短期內消化大量的bug。如果未來有天不同訂單種類需要不同的驗證邏輯,這樣讓訂單類別自行管理驗證邏輯的方式,也保留了修改的彈性。

interface Order {

    default void confirm(){}
    default void payment(){}
    boolean validate();
    boolean orderRule();

}

class EatInOrder implements Order{
    @Override
    public boolean validate() {
        boolean processResult = true;
        return processResult;
    }

    @Override
    public boolean orderRule() {
        boolean hasTableNo = true;
        return hasTableNo;
    }
}

class TakeAwayOrder implements Order{
    @Override
    public boolean validate() {
        boolean processResult = true;
        return processResult;
    }

    @Override
    public boolean orderRule() {
        boolean hasTakeTime = true;
        return hasTakeTime;
    }
}

class DeliveryOrder implements Order{
    @Override
    public boolean validate() {
        boolean processResult = true;
        return processResult;
    }

    @Override
    public boolean orderRule() {
        boolean isAddressValid = true;
        return isAddressValid;
    }
}

設計程式時,不僅要考慮某段邏輯是否共用,也要根據營運的人力分配作對應的處理。
畢竟,程式寫得再漂亮,一線撐不住也是徒然。


#工廠模式 #營運思維







Related Posts

JAVA筆記 _ OOP的三大特性

JAVA筆記 _ OOP的三大特性

Explore-Binary Tree

Explore-Binary Tree

Day05 git 柳暗花明

Day05 git 柳暗花明


Comments