「功能倒是沒錯,就是看不順眼」- 樸實無華的 Clean Architecture 日常

--

一個平凡無奇的下午,筆者打開專案隨意看著,突然感到一陣不舒適,頭暈目眩的,定神一看,原來是結構有問題啊!已經 Code Review 過也運行好一陣子的 code,能有什麼大不了的問題呢?請待我娓娓道來。

Fantasy 是我們的重要產品之一,當比賽結束,自然要有對應的處理行為。在我們的系統中,因為「比賽結束」這個事件有興趣的元件不止一個,基於維持低耦合的原則,我們是以「發出事件供其他元件自行訂閱」的方式設計的。

如下圖的左邊藍色部分,Scheduler 定時通知 Publisher 去發送事件,而因為我們探用 Spring Boot 框架,於是就使用了框架提供的 ApplicationContext 來發 Event,一切看起來挺自然的,但幾個月後的今天,筆者才發現其實有個結構上的問題。

問題其實在於 Clean Architecture 的分層。Uncle Bob 的 Clean Architecture 明白告訴我們,依賴要「由外而內」,要讓 I/O 與框架依賴於我們的核心邏輯,而不要反過來由內而外依賴。

上圖我們可以看到,Publisher 身為 Use Case 層的一份子,竟然「大逆不道」地跑去依賴於 Spring Boot 框架提供的 ApplicationContext,造成一個向外的依賴。

「向外依賴就向外依賴,功能正確不就好了嗎?」

重點來了,誰告訴你 Event 一定要用 Spring Boot 的 ApplicationContext 發送?我能不能用 Kafka 發送?能不能用 GCP 的 Pub/Sub 發送?

一旦核心的商業邏輯被框架「綁架」了,以後要做實作的技術轉型就會很麻煩,這就是為什麼 Uncle Bon 要求我們不可以反過來由內而外依賴的最主要原因。

「那麼,要怎麼治療呢?」

倒也不難,只要像上圖右邊紅色的一樣,在 Service 要跟 I/O 溝通時,用個 Interface 做個控制反轉,就能解決上述的問題。

套用 Clean Architecture 是我們一貫策略,套了以後出現過不少次 I/O 框架需要更換的場景,最後核心的商業邏輯都完全沒動到,不論長期或短期來看,都是蠻划算的投資。

藉機與各位分享。

--

--