初學軟體程式設計的新鮮人,在撰寫程式的同時,幾乎都會將功能性擺在第一位,畢竟功能的完成,是撰寫程式的最關鍵目標。所以,諸如:妥善處理各種異常情況、提高程式的可讀性,以及注意系統的可擴充性及彈性,以便為日後的修改或維護做準備等等議題,通常不會被視為是何等重要的事情。但隨著開發的經驗愈多,程式人會逐漸體驗到撰寫程式時的重心,不單追求功能的達成,其餘的議題,倘若沒有同時兼顧,在系統的開發過程或系統發行之後,便會有許多苦頭得吃。有心的程式人便會開始重視這些在功能面之外的其餘議題。

在這些議題當中,像是提高系統的可擴充性及彈性,時常讓許多程式人深深著迷,甚至陷於其中而無法自拔。這是因為各種能夠提高系統的可擴充性及彈性的設計技巧,幾乎都充滿著十足的美感,程式人多半可以透過簡約的設計,賦予系統極高的彈性,來處理各種可能的情況,因應改變。也因為這樣令人著迷的美感,更使得許多程式人一旦接觸,在設計系統時,便會無時無刻希望將這樣高度的彈性擺到系統中。

工程化的過與不及
不重視軟體架構、不在意系統未來可能會需要的彈性及擴充性,時常為了求速成,因而未在基礎架構及建設上耗費心思。一旦面臨了功能需求的新增或變更,原先舊有脆弱的基礎建設就承受不住,最後的命運不是大改、重寫,就是繼續疊床架屋,在危樓上再蓋危樓。而這種情況就是所謂的「under-engineering」。

但是,一味追求系統彈性的極致,又是另一種極端,能夠盡可能的為日後的各種變化預先做好準備,讓自己的系統能夠放諸四海皆準,無論日後遭遇到什麼樣的變化,系統高度通用的設計,都已經將這樣的變化納入考量。

這立意固然良善,但是現實的情況往往是,這些為了高度彈性而生的設計,往往考慮過了頭。許多預先設想好的可能情境,最終往往都不會發生,我們常用「想太多」來形容這種情況,而這就是所謂的「過度工程化(over-engineering)」。

under-engineering並沒有為可見的未來提前做準備,而over-engineering則是做了太多的準備。高度通用的形式,無論是在物理或數學等科學理論上,都是研究者所一心追求的。高度通用的設計,對軟體設計來說,時常也意謂著高度的彈性。高度的彈性形式簡約優美,每個熱血的程式人,都會打從心底喜歡。但是,對軟體設計而言,任何效益都需要付出代價交換,才能夠取得。軟體設計就是一連串設計決策的過程,在這個過程中,我們會有很多設計上的限制條件存在,而設計者的任務,就是在這些限制條件的約束下,盡力達到最好的結果。魚與熊掌不可得兼是千古不變的道理,想要節省空間,往往就得耗費時間,想要有高度彈性,就得拿系統效能來交換。

從系統運行的面向上來看,過度工程化帶來的彈性,多半是以系統效能換取得來。為了賦予系統彈性,系統的效能時常會因此受到影響。而且,更重要的是,倘若所換來的彈性,真能發揮作用的話,那效能犧牲得也不算白費,但是,之所以稱為「over-engineering」,就是因為這增加彈性的動作做過頭。

設計者為了追求過度的彈性(或美感),做了額外設想的設計,這些彈性及擴充性,卻是這個系統自始至終都不會需要的。額外設想的設計,免不了帶來繁瑣,提高系統的複雜程度。而且更重要的是,這些額外設計的機制,根本就用不到,但卻得耗費開發團隊的時間,造成專案時程的延遲。過度工程化的團隊或團隊成員,對生產力造成的傷害,並不是源自於未能為系統貢獻程式碼,而是在於他們為系統貢獻了不必要的程式碼,使得他們多耗費了時間於程式碼的撰寫,也使得測試人員必須設計更多的測試案例,花費更多的測試時間,才能確保這些額外撰寫的程式碼,能夠正常的運作。

以可預見的未來為限
許多設計者初嘗軟體設計彈性之美,明白了投資在軟體架構的基礎建設是很重要的。於是,便會處心積慮去打造看起來很優美的架構。但是,建立一個無懈可擊幾近完美的一般化設計,除了美感外,別無用處。但軟體設計的目標並不在展現美感,而是要解決真實的工程問題。過度的工程化,讓系統變複雜,也讓開發專案必須投入更多的資源,衝擊專案的時程,最後得到的,只是完全發揮不了作用的彈性。

過度工程化告訴我們的,並非在設計系統時不為系統預留彈性,而是告訴我們凡事都有個限度,適可而止。因為未來可能會有的需求其實捉摸不定,很難在最初設計系統的時候,就對未來可能會有的變化了然於心。看似通盤的考量,也時常與最後的事實相背離。

一些輕量化的開發方法論(例如eXtreme Programming),都強調「先開火再瞄準」的道理。設計者的責任,就是在over-engineering和under-engineering之間拿捏分寸,過與不及都不對。設計者並不是完全不做設計,也不是設計過了頭。

一位夠稱職的設計者,會試著打造一個具演化能力的設計,讓這個設計能夠隨時依照可見到的迫切需求,在很短的時間內滿足這個迫切的需求,同時繼續為下一次的演化而做準備。讓每一次的改變,除了滿足目前的需要之外,也能做為下一次改變的基石。

設計者的確有如下棋布局的棋手,每步棋不僅是在解決眼前的關卡,同時也在為接下來的局勢鋪陳。棋力愈高的棋手,能預見對手愈多在未來可能會下的棋步走法。有經驗的設計者,自然就如下棋高手一般,更能精確的預見對手可能會有的變化,而預先做好準備。然而,每個設計者,都有其思慮的限制邊界。企圖超越自己思考上的限制範圍,最後產生的就是近乎猜測的結果。

一次只強化一個等級的彈性設計
設計者應該將焦點擺在可預見的未來,而不是企求千百年後,自己所精心構築的設計,依舊一體適用。

需求的變化不僅快速而且難以捉摸,面對快速變化的需求,最好的方式就是讓你的軟體架構,具有好的體質,足以快速的反應。具有彈性,又不會過度擴張彈性。初期只有基礎的彈性,而在每次的變化之後,都再加強一個等級的彈性,使得它足以通過下一次變化的考驗。

不可否認的,現代軟體的開發,首重的還是開發的生產力。過度工程化時常造成開發生產力的降低,卻又對系統帶來不了什麼好處,有的只是複雜度的提升。或許美的事物真的迷人,但軟體工程要的是真實、確切可用的系統。過度工程化是設計者開始重視設計的症狀,這是必經的過程,所以是件好事。有過度工程化傾向的設計者,要試著克服自己的心魔,在能夠壓抑自己心中總是想將設計做到無比彈性的念頭後,就會回到見山是山、見水是水的境界。在這個時候,你已經更能夠分辨,自己需要的究竟是什麼。

在設計上我們所稱呼的over-engineering,和在效能最佳化上的「過早的最佳化(premature optimization)」。其實都是差不多的心態,為了不可知的未來,耗費了力氣,事後卻起不了太多的作用。事情,有時候等快發生再做準備,反而會比較好。

《作者簡介》王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。

相關閱讀:
物件導向程式設計常見的錯誤(1)抽離作用重複的程式碼,重構品質
物件導向程式設計常見的錯誤(2)責任分配均衡才是健康的系統
物件導向程式設計常見的錯誤(3)立體的系統架構,可降低修改的影響
物件導向程式設計常見的錯誤(4)Facade畫分子系統,可加速開發

熱門新聞

Advertisement