26. Design Principles - Others


Posted by WayneCheng on 2021-02-03

關於 Design Principle 本篇將討論以下幾個問題

1. 關於 Others

2. Keep it simple, stupid

3. You aren’t gonna need it

4. Don't Repeat Yourself

5. Law of Demeter / The Principle of Least Knowledge


1. 關於 Others

避免誤會先說明一下,Others 並不是什麼新的原則,而是指 SOLID 以外的常見原則,本篇將會介紹以下四種原則

縮寫 名稱 中文
KISS Keep it simple, stupid (略)
YAGNI You aren't gonna need it (略)
DRY Don't Repeat Yourself (略)
LoD Law of Demeter
The Principle of Least Knowledge
迪米特法則
最小知識原則

2. Keep it simple, stupid

保持簡單, 笨拙

簡單是個很抽象的概念,什麼樣的程式才算是簡單?

舉例來說,使用 Autofac 將服務註冊進 ContainerBuilder 的時候,使用 Reflection 取得 Assembly 內所有 Service & Component 來註冊,省去一一列出 Service & Component 的麻煩,之後新增 Service & Component 都不必修改 ContainerBuilder。

上面說到使用 Reflection 實作這段程式本身不算簡單,但使用上卻很簡單很方便,甚至什麼都沒做就會自動將 Service & Component 加到 ContainerBuilder 中了,一直到這邊都沒什麼問題,不過其實 Autofac 有一個RegisterAssemblyTypes()方法,提供 Assembly Scanning 的功能,比起自己用 Reflection 來說,使用 Autofac 提供的方法更加簡單,也更好維護。

關於保持簡單有以下幾點可以參考

  • 不要為了單純縮短程式碼而使用平常少見到的寫法(e.g. 位元與移位運算子)
  • 不要重複造輪子(e.g. 如上述例子中已經有方法可以呼叫就不要自行實作)
  • 不要為了不知道什麼時候才會擴充的功能預留擴展點(e.g. 硬要套用 Design Pattern 造成過度設計)

3. You aren't gonna need it

你不會需要它

可以把 YAGNI 看作是 KISS 的子集,YAGNI 主要是專注在要不要做上,而關於 YAGNI 有以下幾點可以參考

  • 不要實作不知道什麼時候才會用到的功能
  • 不要預留不知道什麼時候才會用到的擴展點

真的有需求再來花時間重構也不遲,除了不用為了當初預留擴展點的架構煩惱之外,還更符合實際需求。


4. Don't Repeat Yourself

不要重複

常見的重複有以下幾種

  • 程式碼重複
  • 功能重複
  • 執行重複

程式碼重複最主要的原因應該是開法者必備的複製貼上大法了,遇到相同需求時應該避免複製貼上,而是將相同的部分抽離出來改為共用方法。

功能重複但實作細節不同(e.g. 相同的參數 & 回傳值),這部分通常是開發者間缺少溝通造成重複造輪子的狀況,除了加強溝通外,發現時也應該將重複的功能排除,只保留一份共用。

執行重複常見於取資料(e.g. 先到資料庫取得UserName,之後又再取UserId,但其實是同一筆資料)跟驗證時(e.g. 呼叫的每一層都重複的驗證 is null),這部分也許開發過程中沒注意到,但在 commit 之前可以再次順過程式邏輯,確認是否有執行重複的問題。


5. Law of Demeter / The Principle of Least Knowledge

迪米特法則 / 最小知識原則

Law of Demeter / The Principle of Least Knowledge 提倡

  • 每個單元對其他單元的知識應該有限,只與當前單元密切關連
  • 每個單元只與朋友交談,不和陌生人說話
  • 只與直系朋友交談

舉例來說,有一個定時處理資料的排程,每次執行排程就會寫開始執行時間 & 結束時間的 log 到資料庫。

理想情況是透過_log將時間寫入資料庫,而處理資料排程()不會知道存入資料庫的邏輯,完全交由_log來處理

public void 處理資料排程()
{
    _log.Info(DateTime.Now, StatusType.Start);

    // 處理資料實作

    _log.Info(DateTime.Now, StatusType.End);
}

但若是今天我們透過_log取得 Context 並由處理資料排程()自己 Insert 資料,則是一次將 LoD 的三個規則都打破了,甚至還違反了 DRY 的執行重複,重複呼叫_log取得 Context

public void 處理資料排程()
{
    _log.GetContext.Insert(new Log { Time = DateTime.Now, Status = StatusType.Start });

    // 處理資料實作

    _log.GetContext.Insert(new Log { Time = DateTime.Now, Status = StatusType.End });
}

總結

要讓現有的程式更符合 Design Principles 就脫離不了「重構」,而重構範圍可大可小,大到整個專案架構調整,小到兩個 class 之間解耦,都可以算是重構,且持續重構能讓專案保持擴充彈性與維護性,不過重構若是沒有充足的單元測試與重構者扎實的程式基礎為依靠,那就真的是在製造工作機會了。


參考資料

  1. Wikipedia KISS
  2. Wikipedia YAGNI
  3. Wikipedia DRY
  4. Wikipedia LoD

新手上路,若有錯誤還請告知,謝謝


#DesignPrinciples







Related Posts

[day 06] yield & yield*: 生成器

[day 06] yield & yield*: 生成器

React 的 controller component 與 uncontrolled

React 的 controller component 與 uncontrolled

Day06:從經典案例看 bytecode

Day06:從經典案例看 bytecode


Comments