過度設計的陷阱

你開始著手開發了一款新的遊戲。作為一個初出茅廬的軟體工程師,你覺得你應該要事先規劃好軟體架構,才能讓專案開發順利的完成。

你看了看設計師(可能是你自己)的需求,決定先套用State Pattern到遊戲主流程和戰鬥單位上(包括了玩家與敵方單位),然後分別為它們各做一份管理器,就取名為GameManager、PlayerManager和EnemyManager,你覺得這樣也很符合單一職責原則(SRP)。

你認為GameManager要協調其它系統的運行,因此讓它套用了Mediator Pattern。

Enemy需要透過PlayerManager來獲得所有玩家單位的資料,這樣它們才知道要去追逐哪個玩家單位,所以你讓PlayerManager套用了Singleton Pattern。

接著,你認為應該要套用Observer Pattern,讓UI能夠顯示Player的狀態。

專案或許順利的完成了,但幾個月後,你又收到了這個專案的維護與功能需求,這時候回來看看專案,會不會覺得架構複雜又難懂呢?

單純因為可以使用SOLID原則或設計模式而使用

SOLID原則與設計模式在使用時,其實都是透過增加架構的複雜度,來獲得對特定變動的修改彈性。所以實際上,當你一頭熱的套用各種原則與設計模式時,實際上是增加了未來維護的困難性。

你可能會不同意上述的論點,你可能會覺得你已經對於設計師可能會提出的需求瞭若指掌,為了省下未來修改需求的時間,因此當下有時間就針對這些未來可能出現的需求進行一些事前準備,我聽過其他人稱這種準備為hook(中文翻譯是掛鉤)。

但是仔細想想,這些準備到底有多少是實際用上的呢?我相信是不會全部用上,可能有用到一半就不錯了。而且沒有用到的鉤子,你也還是要花時間去進行功能支援與維護。我以前曾經在專案結案前,清除了一些自己加上的鉤子,刪除了一些不必要的繼承與介面,清完後發現,有些功能根本不需要弄得這麼複雜就能完成,自己為什麼要白做工。

解決方法

我建議,在進行專案開發時,一次只針對一個功能做處理,而且只用最簡單的方式來處理。這樣做的原因是,避免為未來設想的太多,而寫出多餘的東西。當你未來在處理相關的新功能時,會比較好做修改,因為你當時只用最簡單的方式來處理。

要注意的是,最簡單的方式並不是讓你破壞軟體架構或是其它的暴力解決辦法,而是讓你找到最符合當前架構與需求的最小工作量

不要忘記隨時重構你的程式碼,尤其是當你完成目前的功能,準備提交之前。如果你的架構出現了設計臭味的時候,就進行重構,這時候才是應用SOLID原則與設計模式的時機點。

軟體開發的迴圈:
  1. 編寫新功能
  2. 測試
  3. 確認有沒有設計臭味,如果沒有,則提交,並回到1.編寫新功能
  4. 如果有設計臭味,思考是違反了那些SOLID原則
  5. 選擇要套用的設計模式,並進行修改,然後回到2.重新進行測試與確認
  6. 回到2.,重新進行測試與確認
設計臭味

設計臭味(design smell)與程式碼的臭味(code smell)不太相同,設計臭味的層級比較高,是屬於架構型的臭味,而程式碼的臭味只屬於一小段程式碼。

  • 僵化性:很難做修改,像是一個簡單的修改結果需要到處找相關散落的程式碼
  • 脆弱性:容易被改壞,像是改了A,結果B壞掉了,然後把B修好了,結果C又壞了
  • 頑固性:很難抽取出來做重複使用
  • 粘滯性:很難做正確的事情
  • 不必要的複雜性:過度設計,像是「為什麼這個功能要寫的這麼複雜?」
  • 不必要的重複:通常是由「Copy/Paste Pattern」造成的
  • 晦澀性:難以理解

發佈留言