在專案上的新功能開發,團隊都盡量以 Clean Architecture 為指導原則,從 Domain、Use Case 到 Handler 層層分離。這種分層確實帶來了更清楚的職責界線,但也不是每次都這麼順利,有時還是會遇到實作上的「卡點」。
最近實際遇到的問題,就是 某一 Use Case 依賴了另一個 Use Case,這其實違反了 Use Case 間應各自獨立的精神。 這篇就來記錄當時主要遇到的問題,以及最後如何用 Pub/Sub Pattern 重構解決。
問題:Use Case 之間的依賴長什麼樣子?
以某個 domain 下的 Notification Use Case 為例:
它會根據傳入的 orderID、userID 呼叫外部 API 發送推播通知。
假設有兩個 Use Case:(A)初始化參加活動資料、(B)根據訂單狀態更新活動資料
這兩個 Use Case 都需要在處理後通知用戶,所以他們各自都依賴 Notification Use Case 介面,像這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 用戶參加活動,A Use Case
typeActivityUsecasestruct{notificationUsecaseNotificationUsecase// ...其他依賴...
}func(uc*ActivityUsecase)InitActivity(ctxcontext.Context,reqInitActivityRequest)error{// ...初始化活動資料...
// 業務完成後直接呼叫 NotificationUsecase 發通知
returnuc.notificationUsecase.SendActivityCreated(ctx,req.UserID,req.OrderID)}// B Use Case 同理
// ...
雖然 A, B Use Case 已經把「通知」這件事委託出去了,依賴的是抽象的 Notification Use Case 介面,但仍然需要知道 Notification Use Case 的存在。這違反了 Use Case 各自獨立、單一職責的原則。
Uncle Bob 在《The Clean Architecture》中強調,依賴應該指向內層,Use Case 應保持獨立,避免相互依賴,以維持系統的可維護性和靈活性。
重構思路
既然目標是讓 Use Case A, B 完全不知道 Notification Use Case 的存在,Pub/Sub Pattern 就是很適合的選擇。核心做法是: