OCP: 開放-封閉原則
軟體的行為應該是可以擴展的,而且在擴充功能的同時,是沒有必要修改原來的地方
簡單的想法是,當增加新功能時, git diff 不會有或僅一兩行的「減少」行數,剩下都是增加行數
一個構想實驗
試想一下,有一個財務系統,要在網頁上顯示資料,而後來利益相關者需要此系統也能將資訊印出來做報告。顯然增加了新的功能,那需要修改修改多少舊程式碼呢?
首先透過應用 SRP,可以導出一個數據流:將財務數據轉換成報告數據,然後再將報告數據格式化成 web 形式或是 printer 形式。
在這個例子中,作者展現了 OCP 在架構層級的工作方式。把元件切分成 Views / Presenters / Controllers / Interactor
Interactor 擁有這樣的特權,因為它包含了商業邏輯在其中,我們要保護他免受任何其他元件變化的影響。
再往外一層是 Controllers,我希望保護他,免受 Presenters 的改變的影響。而 Presenters 我們希望它免受 Views 改變的影響。
因此,功能分離後,開始組織原始碼的依賴關係,以確保對於其中一個職責的變更,不會導致另一個職責的變更。
注意元件和元件間的方向只有一個,這些箭頭的方向位於修改而言,就是我們想要保護的元件。
「如果元件 A 應該被保護免於受到『元件 B 的改變』的影響,那麼元件 B 應該依賴於元件 A」
架構師會根據如何、為什麼以及何時發生變化來分離功能,因此他控制了「依賴的方向」「資訊隱藏」
當這兩者達到時,也就是 OCP 在架構上的目標「使系統易於擴展而不會因修改而產生較大的影響」
低語
如果照著 structured programming 的思維來想,
- 「UI 層」呼叫「商業邏輯 Manager」,
- 「商業邏輯 Manager」呼叫了大量的「Data Manager」、「Function Manager」或「Utils」,
整體的相依就會大大不同
但是我覺得這裡的關鍵是「什麼是最容易改變的」?因為每個職位的關注點是不相同的。
舉例來說,
對 UI/UX Designer 會想要調整使用介面或流程,來達到商業數值的提升,所以「UI 層」也就會有比較大的變動。
對 PM or PO 來說,想要調整「商業邏輯」來增加營收或是商業獲利,因此「商業邏輯 Manager」或需要被調整。
對 Engineer 來說,有新的底層工具,或新版本的功能,可以使用,來增加工作效能,減少錯誤,以減低維運的成本,因此「Data Manager」、「Function Manager」或「Utils」就會被變動到。
但是要注意的一點,當商業邏輯被調整時,通常 UI / Data 也會需要有所調整,才能因應增加的資訊或商業流程。但是 UI 變動,應該是不會對到商業邏輯。同樣的,換了一個 Data 的儲存實作 (e.g. SQLite -> Realm),也不應該動到商業邏輯。
因此以架構的角度,UI / Data 元件應該依賴於商業邏輯元件
過去,當一些套件想要升級時,卻因為擔心商業邏輯是否變動,而綁手綁腳,成為了「硬體」