iT邦幫忙

2021 iThome 鐵人賽

DAY 2
1
自我挑戰組

馬克的軟體架構小筆記系列 第 2

30-2 之軟體架構設計原則 1 - SRP 單一職責原則

  • 分享至 

  • xImage
  •  

軟體架構設計原則 1 - SRP 單一職責原則

在軟體設計有個 『 SOLID 原則 』的幾個原則,它是由 5 個原則所組成,而這 5 個原則所想要達的的事情為以下兩點 :

  • 低耦合
  • 高內聚

接下來這篇文章我們將要談談第一個原則 SRP 單一職責原則

SRP ( Single-Responsibility Principle ) 是什麼呢 ?

SRP 單一職責原則,最一開始是由一位叫 Robert Cecil Martin 在他的 《敏捷軟體開發,原則,模式和實踐》一書中所提到的『 物件導向設計原則 』

一個 『 類別 』只對一個『 原因 』引起變化 ( A class should have only one reason to change )

然後這位作者在之後出版的一本書《 Clean Architecture 》又將定義修改成如下 :

一個 『 類別 』只有一個『 角色 』引起『 變化 』

那這一個『 角色 』指的是什麼呢 ? 而 『 變化 』 又是什麼呢 ? 我這裡自已的想法為 :

『 角色 』代表這個類別的使用者 ( 想成實體化後執行方法的地方 ),而『 變化 』代表『 因為這角色某個需求,而需要去修改程式碼。

然後 DDD 裡面有提到的 Context 概念,我也覺得很符合 SRP 想表達的觀念。

上面這句話,我們接下來用下面的範例,來簡單說明。

範例 - 訂單計算直播人數

假設我們有個類別,計算直播的觀看數,就是簡單的去資料庫拿資料 ( 這只是範例,我知道有些情況不適合去 DB 拿這個數字 )。

// Bad SRP
class LiveViewCountCalculator{
    constructor(){
        // 假設每個筆單只有一種類型的產品
    }

    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount
    }
}

然後目前會使用這個方法的兩種角色『 前台給觀眾看 』、『 後台給直播主、工作人觀看 』,在需求沒有變動的情況下沒什麼問題。

但如果這時前台給觀眾看的決定灌水怎麼辦呢 ?

如果這時改了,『 就同時會影響到後台給直播主看的實際數字 』,所以如果修改成如下會比較好點,根據『 角色 』來拆,這樣一個角色的改變,就不會影響到另一個角色。

// Good SRP

class AdminLiveViewCountCalculator{
    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount
    }
}

class GeneralLiveViewCountCalculator{
    calcFee(){
        let viewCount = 0
        viewCount = await _getViewCountFromDB()
        return viewCount * 2
    }
}

然後上述的範例是以『 角色 』為概念來取分,但是在 DDD 中它還會在用 Context 來取分,以上述的範例你可以『 直播前台直播中、直播前台直播結束、後台直播時 』這樣分 context 的情況下,更能預防因為 context 情況變而所需要的調整。

那是不是一切都要『 根據角色 』切分呢 ?

事實上是不一定,在《敏捷軟體開發,原則,模式和實踐》裡有提到 :

If the application changes in ways that affect the signature of the connection functions, then the design will smell of Rigidity... In that case the two responsibilities should be separated. If, on the other hand, the application is not changing in ways that cause the two responsibilities to change at different times, then there is no need to separate them.

這個是我自已的理解的想法,如果每一次的改動對不同的角色事實上都是連動的,那就沒必要拆開,而如果是一個角色動,會影響到另一個角色使用,則拆。

小總結

SRP 單一職則原則,雖然定義上為如下,但事實上我覺得還有很多東西也適合這個原則。

一個 『 類別 』只有一個『 角色 』引起『 變化 』

像是在《 架構師的自我修鍊中 》有提到建議一個實踐 :

一個 class or function 打開來以後,不要超過一個螢幕

我覺得這是個不錯的建議,畢竟一個太長的 class 或 function 雖然不能說是一定,但基本上就有一定等級的壞味道,可以考慮往不同角色用他的情況,會不會世界炸掉。

下面這一段是我最近從某個 youtbue 上看到的學到的方法,也就是每一次學習完,問這三個問題,就可以加深記憶,對我這種老人腦袋 ~ 希望有點幫助

這個知識點可以用來解釋什麼現象

  • 我覺得分層架構的出現,事實上也符合 SRP 原則,都是為了達到高內聚與代耦合
  • 記得我有一次在改一個 function ,結果其它地方也有使用到他結果導致世界炸掉。

這個知識點可以和以前的什麼知識連結呢 ?

記憶中和 clear code 這本書中有提到,一個方法只做一件事情,這點我覺得也算是 SRP 原則

我要如何運用這個知識點 ?

  • 每一次在開發一個方法或類別時,記得要想像使用它的角色,會不會和其它地方打架
  • 假設一個叫 Get 的方法中,不要在加什麼 Update 或 Set 啥的會改變的東西
  • 一個類別只做自已分內的事情,例如購物車類型,不要處理付款與訂單相關的東西
  • 一個方法名為 getXXX 時就別偷偷的再裡面進行狀態改變。

參考資料


上一篇
30-1 之 前言
下一篇
30-3 之軟體架構設計原則 2 - OCP 開放封閉原則
系列文
馬克的軟體架構小筆記29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言