論壇文章
漫談軟體設計能力的培養

筆者過去曾從學界投入軟體產業,從事軟 體開發的工作數年。返回學界後,第一 個學期在構思所要開設的課程時,首先 就想到要開一門〝軟體設計〞的課。為什麼呢? 因 為從實務的工作經驗中,我深深體會到產業界對學 校課程在這一方面有很大的期待,而我任教的科系 也沒有這樣的課程,所以雖然很多朋友都說這種設 計類的課程很難講授,我覺得還是值得一試,就開 了,而且還連續開了好幾年。特藉此園地,跟大家 陸續分享我開設這門課的一些想法與經驗。

首先先就課程定位說明一下。從軟體系統開發的角 度而言,軟體設計通常指的是依據系統需求規格, 發展出系統建構藍圖(blueprint)的一系列活動, 是系統發展過程中一個承上轉下的重要階段。一般 業界常簡稱擔任此項工作的人員為SD(系統設計 師),他們與所謂的SA( 系統分析師) 配合,界定 系統的內部元件、結構與運作方式,並製作詳細的 建構藍圖供PG ( 程式開發人員) 作為開發系統的 依據(系統的使用介面設計不在我們的討論範圍)。

在大型系統日益普及與重要的今日,資深的SD 人員 不見得要往領域專家的SA 職涯發展,而可以深化自 己的設計能力與視野,進而成為架構師(architect)。 當初我想要開設的,就是一門幫助PG 朝SD 與架構 師角色邁進的基礎課,對象是有程式設計基礎,且 有心提昇自己軟體設計技能的同學。

從事軟體設計的工作需要哪些技能呢?大致說來, 跟其它的設計行業一樣,軟體設計除了要具備關於 〝軟體〞這個主題的專業知識外,也要對〝設計〞 這項具創造性活動有一定的認識與體驗。

軟體設計除了要具備關於〝軟體〞這個主題的專業知識外,也要對〝設計〞這項具創造性活動有一定的認識與體驗。

先談設計部分,設計的過程中為滿足使用者的需 求與限制,必然要做很多的取捨與決定。例如: 系統不同模組間的資料傳遞格式要用XML 還是 JSON ?新系統與現有系統之間的Web Services 整合要用SOAP 或是REST ?做這些決定的背後, 必然要有依據,不管是使用者的要求還是環境的 限制,設計者必須要充分掌握,並從而以專業經驗 與創意,設計出滿足要求與符合限制的解決方案, 所以清晰的決策脈絡必然是設計者必須內化的工作 技能之一。更進一步,要成為設計師,師字輩的人 物,還要能為自己的設計辯護,清楚地說出自己的 設計理念(design rationale)。所以不管在各種媒 體上,因設計出名的人物在接受專訪時,幾乎都會 被問到這個問題:『當初你設計A 的時候,為什麼 會想到使用x 這樣的作法?』

要如何培養這樣的說理的能力?這裡提供一個分為 四步驟的思考訓練方針供大家參考:what,how, why,why not。首先,what 跟how 就是要先了 解所面對的議題(需求與限制),設想解決方案。 這部份比較單純,一般的程式設計課程與日常工作 都會訓練這些能力。接下來的why 的部分也不難理解,對自己或他人提出的設計決定,自然會想要 問為什麼。但很多時候,不只是要問為什麼選擇A 方案,還要探究有沒有其它方案,進一步問為什麼 不是B 方案,甚至要問why not B or C !唯有 這樣,才會督促自己或他人去考慮所有可能的解決 方案,避免疏漏。久而久之,還可以開拓自己的視 野,成為一個深思熟慮的設計師。

後面這兩個why 跟why not 的訓練尤其重要。很 多工程師非常擅於what 跟how 的部分,但常以自 身口才不好,拙於言詞為由,而不習慣為自己的決 定(做比較正式的)說明,因而缺乏why 與why not 的訓練,但這其實是個迷思!我們要的不是華 麗的言詞,只是要將決定背後的想法與理由,以平 時或平實的言詞適當地表達出來即可。不這樣做, 反而可能無法發現自己其實並未對所下的決定有周 詳的考慮與設想。很多時候,腦海中對選擇的方案 只有概括性、甚至模糊的想法,這時候更應該透過 筆寫下來,或是簡報方式,將自己的想法整理出 來,經由這個寫下來或說出來的過程來檢視(以及 修正)自己做決策的依據與理念,這樣不但可以增 強自己的分析與說理能力,更是培養自己設計功力 的不二法門。這也是為什麼 design review 是SD 的養成訓練中極為重要的步驟之一。

接著我們回到軟體的專業上來談,這次我們先談軟體 的本質與特殊性,比較軟體設計與其它類型設計的基 本差異,以及因此而衍申的基礎技能。後面幾次的專 欄,我們再細談軟體設計的議題與技能的培養。

很多工程師非常擅於what 跟 how 的部分,但常以自身口才不 好,拙於言詞為由,而不習慣為 自己的決定(做比較正式的)說 明, 因而缺乏why 與why not 的訓練,但這其實是個迷思!

軟體設計大不同於其它產品的設計之處就在於軟體 是抽象的。不管是服裝,建築物或是3C 商品,它們的產品都是由實體的材料組成,所以它們的設計 都是可以用實體模型,或對應的幾何圖形(建構 藍圖),作為標的來構思與討論的。反觀軟體產 品,既不需要實體材料,也看不到、摸不到,完 全是虛擬的,只能靠SD 以抽象思維方式來構思其 設計。不僅增加其在構思其設計時的困難度,也 讓如何跟他人(其他SD 或是要負責實作的PG) 溝通自己的設計變成一件更具挑戰的工作。基本 上,〝結構〞是我們認識許多產品設計的重要步 驟;所有實體產品都具備有明顯可辨識的(幾何) 結構,但是軟體則不然。我們要如何描述一個軟 體產品的結構呢?透過類似UML( 統一塑模語言 Unified Modeling Language) 的視覺化工具固然 可以幫助,但UML 文件作為軟體的建構藍圖不 是沒有爭議的( 註一:Jack Reeves 曾為文論辯 軟體設計的產出藍圖應該是原始碼,其它文件只 能視為設計過程中的輔助文件,詳請參閱http:// www.developerdotstar.com/mag/articles/reeves_ design.html);姑且不論恰當性的問題,UML 文 件跟其它行業的建構藍圖比起來還是抽象的多,要 PG 人員『按UML 圖施工』開發軟體產品的想法, 在實務上依然是困難重重的。所以軟體這種高度抽 象化的本質,自然讓抽象思維的能力(以下簡稱抽 象力)成為SD 必備的能力之一。

那抽象力要如何培養?先從抽象的一般意義談起。 作為動詞,抽象(化)指的是就特定對象,找出與 目的相關的重要處,略去比較無關的細節,很類似 我們中文裡常用的一個詞語:『去蕪存菁』。說的 更具體一點,抽象化的核心就是抓重點或是找特 徵,一個直接的應用就是〝分類〞─針對不同的事 物找特徵加以區分,而且可以按差異的程度去建立 分類架構,生物學上〝界門科目綱屬種〞的分類架 構就是一個典型的抽象化範例。在抽象化的過程 中,少不了分析與歸納的步驟,所以培養抽象化能 力的同時就是在建立自己分析與歸納的能力。

一般說來,數學理論是高度抽象化的產物,多讀一 些數學的理論,像是代數結構等,通常是可以提高自 己的抽象力。除此之外呢?畢竟多數的程式開發人員 並不見得喜歡數學或是受過很多數學的訓練。我的 建議如下,首先可以透過學習抽象程度教高的函數 式程式語言(functional languages)來深化自己的 抽象感受力。這些語言不僅在資料結構面提供高度 抽象化的串列(lists)來簡化程式的繁瑣性,也提供 了像高階函數(higher-order functions)這樣重用 性高的抽象化機制,讓程式變得更簡潔有力。高階 函數跟一般函數副程式的主要差別在於參數化的抽 象程度,一般函數只能接受簡單的參數,而高階函 數可以接受含函數當參數,大幅提高函數的抽象層 級。正因其抽象層級高,它們的重用性也高:因為 透過套用不同的函數當參數,可適用於多種不同情 境,使用上甚至可以類比所謂的框架(framework)。 最近20 年來出現的程式語言, 如Java、Ruby、 Python、C# 與JavaScript 都有函數式語言的影子。

此外, 設計樣式(design patterns) 的學習也可 以增加我們對抽象結構的領悟。因為號稱樣式,就 代表是從許多個案抽象而來;既是經過專家洗煉而 來的抽象體,自然有一定的內涵可供我們學習。再 來,多觀摩好的抽象體與抽象機制也是一個重要的 抽象力培養途徑。尤其現在有開放源碼的資源,更 容易從它山之石鍛鍊我們的功力。這裡要特別推薦 Unix, 尤其是Unix 的file 抽象體與pipe 機制。 Unix 裡各式各樣的輸出入媒介都可視為〝file〞, 而享有一致的介面,大大簡化了關於輸出入程式的 撰寫。透過pipe 我們則可以輕鬆地完成許多原本要 寫程式的工作,這是一個跟程式語言設計有著一樣 內涵的抽象機制─提供使用者自定命令的機制,就 好像類別讓我們自定型態一樣。

軟體這種高度抽象化的本質, 自然讓抽象思維的能力(以下 簡稱抽象力)成為SD 必備的 能力之一。

最後,抽象化是有層級性的,所以要練習可以自在 的遊走於抽象階梯的各個樓層, 快速聚焦的能力。 打個比方,我們從1000 公尺的高度往下看地面, 跟從500 公尺處往下看,看到的景觀一定是不一 樣的。或是說,拍照時,隨距離不同,我們也要透 過調整焦距來取得最清晰的畫面。這種能力可以透 過寫摘要與簡報來培養,例如:對同樣的主題,寫 150 字與500 字的摘要,或是給10 分鐘與40 分鐘 的簡報,練習在各種限制下如何去抓重點,體會與 培養上下抽像化階梯的能力。

pipe 機制
大家都知道UNIX 是個多工的作業系統,使用 者可以同時執行多個程式,在UNIX 執行中的 程式稱為process 。為處理process 間大量的 資訊傳送,UNIX 提供了一個稱為pipe 的機 制,它是將一個process 與另一個 process 連 接起來,其方式就是使pipe 前面process 之標 準輸出導引至pipe 後面process 之標準輸入。