iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Software Development

AI時代下的軟體工程系列 第 24 篇

Day24: Information Hiding:藏的不是 code,而是 decision

  • 分享至 

  • xImage
  •  

昨天談 Cohesion 時,我們從 change 的角度重新看 decomposition。

我們學會了如何分辨哪些東西該聚集、哪些該拆開:

  • 當今天相同功能的改動散落在各處 > 需要聚合起來
  • 當今天不同功能的改動卻聚集在一處 > 則需要把它們拆開

隨著同個 boundary 底下的 component 越來越多,其擁有的 “功能” 也隨之增加,那我們到底該把哪些功能從 boundary expose 出去給 clinet 使用呢?

這裡可以很直觀的到,如果一個 client 直接依賴的東西之後很容易改變,那每次它改變,client 也可能被迫跟著改。

所以在決定 public interface 之前,我們得先知道一件事:到底什麼東西會變?

決策

假設現在有一個「滿 2000 折 100」的活動:

THRESHOLD = 2000

def discount_hundred(amount: Price) -> Price:
    if amount >= THRESHOLD:
        return amount - 100
    return amount

如果下一次只是改成「滿 3000 折 100」,只需要修改 THRESHOLD, client 也不需要做出額外的改動。

但如果下一次活動變成「全面九折」,真正改變的就不只是某個數字,而是整套折扣的做法。

所以 code 背後通常存在一個更高層次的東西:decision。
例如:

決策 當下的選擇 其他可能
資料存在哪裡 SQLite PostgreSQL、remote API
使用者如何登入 Password LDAP、OAuth
折扣怎麼計算 滿額折抵 百分比、會員價
訂單如何通知 Email LINE、Push notification

我們現在使用的 implementation,只是某個 decision 當下的答案。而不同 decision 的改動則會增加

Volatility 易變性

部分 Decision 是很容易變動的,主要原因大致有三種:

  1. 需求會繼續演進:現在只提供簡單版本,但已知未來會加入更多能力。
  2. 本來就存在多種選擇:當下只是先實作其中一種,之後可能替換成另一種 implementation。
  3. 不同環境需要不同答案:同一個功能,在不同平台、地區或 provider 上需要不同做法。

這種「一個 requirement、assumption 或 design decision 有多容易因為時間或情境而改變」的性質,可以稱為 volatility。

Information Hiding

知道哪些 decision 比較 volatile 之後,就可以回到開頭的問題。

先想一件事:一個 decision 改變的時候,哪些地方要跟著改?

答案是所有知道它目前答案的地方。 而知道的地方越多,這次 change 就越貴。

所以方向很清楚:volatile 的 decision,知道的地方越少越好,最好只有一個 boundary。

這就是 Information Hiding:

把 volatile 的 decision 留在一個 boundary 裡,不讓 client 依賴它目前的答案。

被留在裡面的 decision,稱為這個 boundary 的 secret。

回到折扣的例子。如果 pricing 提供給 client 的是:

pricing.discount_hundred(amount)

每一個呼叫它的 client,都知道「現在的活動是折 100」。活動換成九折,這些 client 全部要改。

如果提供的是:

pricing.total_of(items)

client 只知道一件比較穩定的事:這些商品最後要付多少錢。

至於裡面用的是滿額折抵、百分比還是會員價,是 pricing 的 secret。

其實在階段二提到的 Abstraction 就是一種Information Hiding的手段;我們將底層 Decision 的實作細節藏起來,只 expose 更 general 的 function 出來使用。

藏的是 decision,不是 code

Information Hiding 很容易被理解成「把 variable 設成 private」,或是「不要讓 client 看到 implementation」。

但在上面兩種寫法裡,THRESHOLD 與 function 的內容都沒有 expose 出去。Code 藏得一樣好,差別只在於 client 知不知道那個 decision。

所以這裡的 information,指的不是 code,而是關於 decision 的知識。

而這份知識最常洩漏的地方,就是 public interface 本身:

  • 名稱:描述的是目前的做法,而不是 client 要的結果。
  • 參數:要求 client 提供某一種做法才需要的東西。
  • 回傳的型別與錯誤:把底層的型別或 exception 直接交給 client。
  • 沒寫出來的假設:contract 沒有提到,client 卻照著目前的行為依賴它。

要檢查一個 decision 有沒有藏好,可以問:

只看 public interface,猜得出裡面目前選了什麼嗎?

猜得出來的,就是已經洩漏的 decision。

不是所有 decision 都值得藏

Information Hiding 不是「能藏就藏」。它有三個限制。

一、要有證據。

理論上,任何 decision 都可能改變。

如果一句「以後可能會改」就足以把它藏起來,我們會為大量不存在的需求提前支付 complexity。
昨天的證據排序在這裡同樣適用:已經發生過的 change,強過已知的需求來源,再強過想像中的 change。Volatility 是依據前兩者做出的判斷,不是對未來的想像。
而需要多少證據,取決於要付多少成本。在既有的 boundary 上少 expose 一樣東西,幾乎不花成本;為了還沒出現的選擇先建立新的 abstraction,需要的證據就多得多。後者之後再談。

二、藏了之後,client 能做的事會變少。

Public interface 越窄,implementer 能自由改動的空間越大,client 能依賴的東西也越少。
當 client 真的需要某個被藏起來的東西,它只剩兩條路:請 boundary 多 expose 一個功能,或是繞過 boundary 自己來。
這就是 Day15 談過的拉扯:implementer 需要空間,client 需要保證。

三、Public interface 本身也是 decision。

我們可以把 decision 藏進 boundary,卻藏不了 boundary 對外的那一面。
Public interface 上的每一樣東西,都是所有 client 一起知道的 decision,也因此最難改。
所以 Information Hiding 並沒有讓 decision 消失。它做的是一次交換:

用一個比較穩定的 decision,擋在一個比較不穩定的 decision 前面。

如果擋在前面的 interface 自己也不穩定,問題只是換了位置,而且換到更貴的地方。

Information Hiding 真正想表達的事

回到開頭的問題:

boundary 裡的東西,哪些應該 expose 給 client?哪些應該留在裡面?

昨天與今天,其實在處理同一件事的兩半:

  • Cohesion:知道同一個 decision 的 code,放在一起。
  • Information hiding:放在一起之後,別讓外面也知道。

只做前一半,change 還是會沿著 interface 傳出去。

Boundary 藏的不是 code,而是 decision。一個 decision 只有一個地方知道,它改變的時候,就只有那裡需要改。

對 coding agent 而言,decision 特別容易洩漏,因為最省事的做法,就是把手上現成的東西直接往外傳:照著目前的做法命名,底層回傳什麼就回傳什麼,底層丟出什麼錯誤,就讓它一路往上丟。這樣的 code 能通過 type check 與 test,boundary 也都還在,階段一與階段二的工具都不會提醒我們。

所以與 agent 合作時,可以多做兩件事:

  • 檢查時,先讀 interface:只看名稱、參數、回傳的型別與錯誤,猜得出裡面目前選了什麼嗎?
  • 交代任務時,把 secret 說出來:例如「通知怎麼送,只有 notification 可以知道」。這比「請注意封裝」具體得多,agent 也才知道該守住什麼。

階段二教我們把 boundary 守住。但守得再好,如果 decision 早就寫在 interface 上,change 還是會一路傳出去。

Reference


上一篇
Day23: Cohesion:會一起變的,放在一起
系列文
AI時代下的軟體工程 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言