其實以前寫過 YAGNI 的碎碎念,所以這是第二次...Orz
針對介面寫程式的確是降低耦合的好方法,可是,任何場合都不加思索地先寫介面,很容易讓整個應用程式架構變得太過累贅鬆散。舉例來說,若我們評估五年內有九成以上的機會不可能替換實作類別,而且也不需要跟第三方程式碼介接,那麼事先定義了一大堆介面,再撰寫實作類別,甚至還透過 Service Locator 來建立物件實體,如此大費周章的用意是什麼呢?
評估將來需要替換實作類別的機率大約多少,是很主觀沒錯,其結果因人而異,by case 不同。但它仍是一個值得想一下的問題。因為,相較之下,maintainability 更重要——我覺得啦!
不太確定採用哪一種設計、寫法比較好的時候,我傾向考慮 maintainability 多一些,而過度設計的架構會增加程式的複雜度,亦即更難維護。想像一下,有一天你接手維護一個 case,裡面包含十幾個 .csproj,上百個介面和類別。你想要先閱讀某部份的程式碼,以了解某個操作從前端 UI 到後端服務的大致流程。於是你用 Visual Studio 開啟了這些專案,嘗試以 F12 或 Alt+F12 追查線索。然而卻發現,應用程式各 layer 之間都有類似下面這行的程式碼:
this.MyService = ServiceLocator.Resolve<IMyService>();
而且碰到這裡就卡住了,必須利用其他方法(如搜尋關鍵字或產生相依關係圖)來找到實際使用的類別。這只是引進無謂複雜性所帶來的麻煩之一(如果它真的對你有用,那就不是無謂的複雜性)。
回到前面說的,如果將來要動態切換 MyService 類別的可能性微乎其微,用 Service Locator 的意義是什麼?不要只因為某個模式或寫法聽起來很酷,或因為我們有辦法那樣寫,就把它寫進程式裡,而不管它能否真正產生實質效益。
所以,我想斗膽說一句:
過度設計的架構就是不好的架構,無論我們套用什麼設計模式或原則。
這樣聽起來好像我很行,都不會犯這種毛病?不是耶,我也常常自己打臉,程式碼改來改去。舉個例子,我原本習慣讓應用程式具有「可任意切換 logging framework」的能力(例如可隨意切換成 NLog、Log4N 或其他類別庫),可是最近開始不這麼做了,甚至把提供此機制的相依組件和程式碼移除。因為經過一段時間之後,我慢慢發現,我根本一直都在用 NLog,完全沒需要切換,可是卻為了這個不太可能需要的功能而替專案引進了數個相依的第三方組件(當然不是說你也一定不需要)。
那麼,還是換個比較輕鬆、正面的說法吧:
別忘了,我們還有 YAGNI 這個好朋友。
然後,讓實際的開發與維護經驗來告訴你怎麼做才是最好的。
Happy coding!
針對介面寫程式的確是降低耦合的好方法,可是,任何場合都不加思索地先寫介面,很容易讓整個應用程式架構變得太過累贅鬆散。舉例來說,若我們評估五年內有九成以上的機會不可能替換實作類別,而且也不需要跟第三方程式碼介接,那麼事先定義了一大堆介面,再撰寫實作類別,甚至還透過 Service Locator 來建立物件實體,如此大費周章的用意是什麼呢?
評估將來需要替換實作類別的機率大約多少,是很主觀沒錯,其結果因人而異,by case 不同。但它仍是一個值得想一下的問題。因為,相較之下,maintainability 更重要——我覺得啦!
不太確定採用哪一種設計、寫法比較好的時候,我傾向考慮 maintainability 多一些,而過度設計的架構會增加程式的複雜度,亦即更難維護。想像一下,有一天你接手維護一個 case,裡面包含十幾個 .csproj,上百個介面和類別。你想要先閱讀某部份的程式碼,以了解某個操作從前端 UI 到後端服務的大致流程。於是你用 Visual Studio 開啟了這些專案,嘗試以 F12 或 Alt+F12 追查線索。然而卻發現,應用程式各 layer 之間都有類似下面這行的程式碼:
this.MyService = ServiceLocator.Resolve<IMyService>();
而且碰到這裡就卡住了,必須利用其他方法(如搜尋關鍵字或產生相依關係圖)來找到實際使用的類別。這只是引進無謂複雜性所帶來的麻煩之一(如果它真的對你有用,那就不是無謂的複雜性)。
回到前面說的,如果將來要動態切換 MyService 類別的可能性微乎其微,用 Service Locator 的意義是什麼?不要只因為某個模式或寫法聽起來很酷,或因為我們有辦法那樣寫,就把它寫進程式裡,而不管它能否真正產生實質效益。
所以,我想斗膽說一句:
過度設計的架構就是不好的架構,無論我們套用什麼設計模式或原則。
這樣聽起來好像我很行,都不會犯這種毛病?不是耶,我也常常自己打臉,程式碼改來改去。舉個例子,我原本習慣讓應用程式具有「可任意切換 logging framework」的能力(例如可隨意切換成 NLog、Log4N 或其他類別庫),可是最近開始不這麼做了,甚至把提供此機制的相依組件和程式碼移除。因為經過一段時間之後,我慢慢發現,我根本一直都在用 NLog,完全沒需要切換,可是卻為了這個不太可能需要的功能而替專案引進了數個相依的第三方組件(當然不是說你也一定不需要)。
那麼,還是換個比較輕鬆、正面的說法吧:
別忘了,我們還有 YAGNI 這個好朋友。
然後,讓實際的開發與維護經驗來告訴你怎麼做才是最好的。
Happy coding!
沒有留言: