Dan North

兩個程式碼庫的對比#

想像兩個程式碼庫。在第一個中,你看到這樣的程式碼:

if (portfolioIdsByTraderId.get(trader.getId())
    .containsKey(portfolio.getId())) {...}

你抓破頭想理解:從 trader 物件取得 ID,用它從一個 map-of-maps 中取得資料,然後在內層 map 中檢查另一個 ID 是否存在。你找到 portfolioIdsByTraderId 的宣告:

Map<int, Map<int, int>> portfolioIdsByTraderId;

在另一個程式碼庫中,你看到的是:

if (trader.canView(portfolio)) {...}

不需要抓頭。你不需要知道交易員內部如何運作。這是交易員的事,不是你的。

你更想在哪個程式碼庫中工作?

使用者自定義型別改變了一切#

從前,我們只有基本的資料結構:位元組、字元、陣列、堆疊、佇列、雜湊表等——這些在真實世界中並不存在的資料結構。然後我們有了使用者自定義型別(user-defined types)

如果你的領域包含交易員(traders)和投資組合(portfolios),你可以用 TraderPortfolio 這樣的型別來建模。更重要的是,你可以用領域術語來建模它們之間的關係(relationships)

不用領域語言寫程式碼的後果#

如果你不使用領域術語來寫程式碼,你就是在創造一個隱含的(讀作:秘密的)理解——這裡的 int 代表交易員的識別方式,而那裡的 int 代表投資組合的識別方式。(最好別把它們搞混了!)

如果你用演算法片段——比如 map-of-keys 的存在性檢查——來代表一個商業概念(「某些交易員不被允許查看某些投資組合——這是違法的」),你不是在幫稽核和合規部門的忙。

下一個接手的程式設計師可能不知道這個秘密,所以為什麼不把它明確化呢?用一個 key 去查另一個 key 來做存在性檢查,並不是很直觀。怎麼有人能猜到這就是利益衝突商業規則的實作?

讓領域概念顯而易見#

在程式碼中明確使用領域概念,可以讓其他程式設計師更容易理解程式碼的意圖(intent)——比試圖把演算法逆向工程回他們對領域的理解要容易得多。

這也意味著當領域模型演進——隨著你對領域的理解增長——你的程式碼處於一個有利的位置來跟著演進。加上良好的封裝(encapsulation),規則很有可能只存在於一個地方,你可以在不影響其他相依程式碼的情況下修改它。

幾個月後來維護程式碼的那個程式設計師會感謝你。而那個人,可能就是你自己。