Clean Architecture 無暇程式碼

jerry80409
3 min readFeb 21, 2022

--

整潔的軟體架構與設計

因為中間的 CH3 ~ CH6 不太有興趣, 就不記錄了.

CH7. SRP 單一職責原則

在讀這本書之前, 我一直以為 SRP 就是一個 class 只針對某個業務做一件事, 或是一個 method 只要處理一件事之類的. 書上的解釋如下

一個模組應該只對唯一一個使用者或利益關係人負責。

這個單字 「cohesive」應該更適合解釋,

united and working together effectively

團結且讓某些事情凝聚在一起, 讓工作變得更有效率, 這應該就是 SRP 的精神了。

這當中, 我覺得最重要的 Keyman 應該就是這個模組的使用者或是利害關係人, 我很喜歡書中的例子, 一個 Employee 業務, 有 3 種需求, 分別是

  1. 計算薪水
  2. 工作時數
  3. 存入資料庫備查

這樣的需求描述其實是危險的, 如果忽略使用情境很容易違反 SRP, 為什麼呢?回顧 SRP 的精神「一個模組應該只對唯一一個使用者或利益關係人負責」, 沒有看到需求的利害關係人, 如果很隨意的寫成

// 用 spring boot 隨便設計的
@Service
class EmployeeService {
private EmployeeDao dao; BigDecimal calculatePay(Employee employee) {
// get hour
int hours = reportHours(employee);

// get role
Role role = employee.getRole();

// calculate salary by role
return hour.multiply(role.getSalaryFactor());
} int reportHours(Employee employee) {
// get employee work days
int days = employee.getWorkingDays();

// 這邊的 8 是一個不好的寫法, 舉例用而已
return days * 8;
} @Transactional
void save(Employee employee) {
// save
dao.save(employee);
}
}

但如果忽略了 「利害關係人」, 在需求裡面的話, 可能會像 Manager 要看員工的工作時數, 但 HR 要看薪水, 而工作時數的計算規則改變了, 所以連動到薪水計算結果… 這很明顯地違反了 SRP. (利害關係人 Manager)

或是 Employee 這個 entity (Spring boot 的 persisted 物件) 的欄位因為資料量切表處理, 所以部分欄位變動了, 導致 reportHours 跟 calculatePay 都被影響了… 這也明顯地違反 SRP. (利害關係人 DBA)

所以我們再根據 SRP. 的原則, 把業務根據不同的利害關係人拆成

  1. PayCalculator
  2. HourReporter
  3. EmployeeSaver

這樣彼此的業務變更, 衝突就更小了, 但缺點是檔案變多了, 在某些情境下 FACADE pattern 是可以把這些業務整理組織起來…

書上說 FACADE 可以讓開發者更好從 FACADE 去追蹤業務, 且可以隱藏 Calculator, Reporter, Saver 的私有函式, 算是提高封閉性, 讓使用上可以專注於業務就好, 而 FACADE 更可以再更進一步搬進 Employee 物件, 讓物件不在貧血。

但對於 FACADE 跟充血的 Employee 不就又違反了 SRP. 嗎?

感覺上這邊應該要再配合一些 DDD 的知識才能比較完整 (😓

--

--

jerry80409
jerry80409

Written by jerry80409

隨便記錄一些沒有整理很清楚的想法

No responses yet