喲哪桑提出為了軟體維護的二種設計策略,在設計的彈性策略方面,提到了我的〈專案成本估算之軟體價格的迷思〉某種程度上也說明了為何開發者難以達到彈性這個理想。既然學長提到了,我也好藉這個機會表達我在這方面的看法與經驗。
《易經.繫辭傳》有言:「天下事一致而百慮,殊途而同歸」。在不同產業中,設計所呈現出的面貎也許不盡相同,但是其策略本質卻是不會輕易改變的,亦即為未來可能發生的變動提供適應變化的能力。然而,開發者想要讓軟體具備足夠的彈性,以符合未來可能會面臨的需求改變,抽象化思考與設計能力會是關鍵因素,加上專案成本估算之軟體價格的迷思所形成的動態模型,當我們愈想要加入有彈性在我們的軟體設計上時,就更難以面對市場的競爭壓力,於是只好放棄設計彈性的理想。記得我和吳宗成教授曾經討論過國內軟體設計的議題,依照吳教授的觀察,他告訴我:"台灣的軟體開發者大部分都在做 concrete design 而非 concept design,有用的設計是 concept design 而非 concrete design"。由此可知,在台灣軟體開發環境不重視設計的情勢下,大部分的人多抱持著:今天先把功能寫出來,明天再求最佳化往往是軟體專案以時間換取空間的常見做法;我並不反對這種看法,但設計者必須培養持續改善的專注力,好的設計其實源自於紀律。
設計真的沒辦法堅持彈性的理想嗎?如果我們願意換一種思維方式,是不是就可以堅持理想,試圖打破軟體價格的迷思。於是,我們換一種做法,不以降低軟體開發成本為目標,而是藉由邊際效益的提昇來展現設計的附加價值,強調高品質的軟體設計及好的軟體來自於軟體工程的想法,不再自廢武功落入削價競爭瘀惡性循環中。換句話說,當我們體認到軟體維護的重要性時,就必須為未來可能的改變而設計,以保有系統修改及維護的彈性。那要如何做呢?我們可以學習別人良好的設計範例,先從臨摩就座開始,慢慢提昇我們的設計能力。於是,我們向 design patterns 取經,學習如何為不確定來設計、體會務虛的設計藝術。
然而,design pattern 的學習看似簡單,但學了之後,要真正用在軟體開發上,卻又不是那麼一回事。看得懂是一回事,要實際去用卻是另外一回事:為什麼那些大師可以「化腐朽為神奇」,運用 design pattern 使設計變得更有彈性,而我們常把能用的 pattern 都用上了,不但沒讓設計變簡單,反而讓設計變得相當繁複,要了解它都很困難了,更不用說實作與維護了。〈由招熟漸悟懂勁〉告訴我們設計招式與心法搭配的其中奧妙所在:
設計技巧如何,因人而異,面對相同問題,每個人可能會有不一樣的設計手法,程式寫得愈多,對設計愈有不同的體會,如果你對程式如何解決問題沒有深切的體認,很難設計出彈性及功能兼具的系統。所以以個人的心得來說,業務流程、演算邏輯及程式語言的技巧是招式的運用,而內化的領域知識、OOAD 的分析設計原則、封裝、抽象化乃至於 Pattern 的運用則是心法的展現。這兩者互相反覆搭配、增長。
運用 design pattern 雖然是增加設計彈性的利器,但為了維護這些設計彈性,卻必須付出開發成本,當我們的設計充斥了「沒有用的彈性」時,就會浪費許多無謂的時間與資源,而不會再有足夠時間回應軟體需求的變化,及足夠的空間來容納真正需要的功能。以經濟學的角度而言,設計者須重視設計的機會成本,要為現實需求而設計,避免想太多而造成軟體設計的過度工程化的後遺症,而在設計上充斥著沒有必要的複雜度。以物件導向設計原則而言,抽象性愈高的套件,穩定度就要愈低,否則它就會沒有什麼用處,穩定度愈高的元件,抽象性就要愈低,否則它就會很難被重複使用抽象性的度量是套件中套件所有類別或界面數量除以抽象類別或界面的數量;而穩定度的度量則是向外關聯性-套件內類別關聯至套件外類別的數量,加上向外關聯性-套件內類別與套件內其它類別關聯的數量,然後再將相加的總合除以向外關聯性。相關內容請參考林昆穎與吳京子譯(2005),《敏捷軟體開發》。。總之,要設計彈性與功能兼具的系統,其實最關鍵的是務實與務虛兩種設計策略能夠相互達到均衡,以達成設計與實作觀點的兩分之形,如下棋般,讓不同觀點皆能發展出最佳的著手。
太強調抽象的設計思維,系統很容易失焦而徧離主題,做出功能不符合客戶需求的軟體;太強調具體的實作而缺少設計,系統會缺乏彈性而難以適應需求的變更,不斷地增加軟體開發的成本與風險。所以設計其實是一種權衡與適應變化的能力,而不應企求設計一次到位,想要以不變應萬變是不切實際的。想當年,克明兄曾針對可迅速維修保養的坦克車提到模組化的思維,有網友回應認為軟體和坦克不同,所以不能相提並論;而我卻認為這是取決於設計的出發點為何,我當時曾提出:
整合並非不可行,重點您是以什麼觀點來看設計。如果您把方便整合的觀念溶入設計中,您會設計減震點(Decouple point),把模組化與差異化的部分巧妙地隔開,這種設計策略就是所謂的延緩策略(Postponement),好處是可能待需求確認後才開始實始生產差異化的部分,而共用的模組則可以重覆使用增加開發績效,縮短開發時間及成本。其實就是所謂的(DFx,Design for xxx),例如克明兄所說坦克的例子就包含了 Design for maintenance 的設計概念。
所以軟體開發能如果做到元件模組化,服務差異化,那整合一點都不困難。可惜大部分的公司都是反其道而行-元件差異化,服務模組化。結果反而造成系統變得更複雜,整合更加困難。
其實不做整合的主要的原因還是市場利基及公司策略方向,如果人家很容易把我整合進去,那我還有什麼搞頭,當然要把系統弄得別人很難整合進去。但標準化,同步工程及整合是不可擋的趨勢,如果忽略它們,那未來將被新的浪潮所淹没。
其實,design pattern 就是一種軟體設計之延緩設計策略的促成技術(Enabling Technique),但設計者也要小心 design pattern 的誤用所造成過度設計會讓設計變得更複雜,這中間該如何拿捏呢?單純地為當下而設計且讓設計儘量簡單吧!Qing 認為:"建立一個具演化能力的設計,讓這個設計能夠隨時依照可見到的迫切需求,在很短的時間內滿足這個迫切的需求,同時繼續為下一次的演化而做準備。就是這樣,每一次的改變,除了滿足目前的需要之外,同時也為下一次的改變而做準備"。喲哪桑也說:"簡單未必容易。為了同時修掉既有的問題、又讓軟體隨著需求而演化,開發者的設計技藝得更純熟,而開發者往往還要更密切地與使用者互動、快速回應、人際溝通要更強。從我經驗來看,這通常是成熟開發者才辦得到。"。我則認為:"軟體專案的規劃比較適用於反覆與漸近式開發(IID, iterative and incremental development),它強調用適應性計劃(adaptive planning)來取代預測性計劃(predictive planning),把規劃設計與承諾完成的水準與資訊品質等量齊觀,是一種面對現實的規劃。雖然不做事先的設計,但開發者所做事就是在做設計,一種面對現實的設計,因此軟體設計並不昧於專案現實。"
喲哪桑認為,設計的簡單策略需要「成熟」開發者才能辦得到,但我覺得成熟這個字容易帶有對某種特定開發能力高下的偏見,所以認為這個詞如果修正為「有紀律」會更為貼切。一個有紀律的開發者必須不斷地專注在面對「現實」,認清問題,用「目前最合適」的解決方法來解決。「現實」代表解答問題的目標是顯而易見的,所以我們可以輕易地寫程式來驗證目標是否真的可以達到;而「目前最合適」則代表我們馬上可以把設計實作出來,並且用先前的驗證程式驗證出來,這就是設計的紀律的具體呈現。而在設計實務上,我則用三種工具來促成設計開發團隊的紀律,那就是:
- 測試先行,以測試驅動來開發功能。
- 必要時,在增加功能前先重構。但增加功能時不重構;重構時,亦不增加功能。
- Daily build,持續不斷整合,確保所開發的軟體是可運作的。
這些工具,都是十分簡易的,設計者並不需要很高的設計能力,但當建立起設計者之紀律時,設計能力會與日俱增,除了能快速回應需求改變化,軟體也會更具有彈性,其實好的設計源自於紀律呀!
Powered by ScribeFire.
自動引用通知: 同人的生活派對 » 羅馬不是一天造成的