本節書摘來自華章計算機《需求設計:建構使用者想要和需要的産品》一書中的第1章,第1.2節,作者:[英] 克裡斯·布裡頓(chris britton) 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
設計是個很常見的說法,沒有幾個人會深挖它的含義,但如果仔細想一想it應用程式的設計與一般的設計的差別,你就會發現,it應用程式其實是很特殊的。這種特殊性促使我們思考一個問題:應用程式的設計真有這麼特殊嗎?或者說,我們是不是将它看得太過特殊,以緻忽視了一些最為基本的共性?
首先,我們來定義設計這個詞。設計,是對想要建構的事物或系統所做的概念化處理。設計(design)既是名詞,又是動詞。剛才定義的是名詞,現在我們給出動詞的定義:(作為動詞的)設計,就是指建立設計方案。
筆者故意把這個定義下得比較寬泛。你可能既沒有給自己所構想的最終産品繪制一份圖表,也沒有給自己所要建構的事物或系統撰寫一份描述,但隻要你腦中有它的概念,就仍然可以說是在做設計。
設計當然可以有很多種不同的方式,但就其基本結構來看,所有的設計都有着深刻的相似之處。筆者的這種說法,以前還沒有别人提過,但我想大多數的設計者都應該能了解這個意思吧?(有一次我看到過一種類似的說法,但它講得太過隐晦,我無法确定和自己說的是不是一個意思。)
設計的結構,可以像下面這樣分成3步或4步:
1.了解(understanding)。了解自己想要達到的目标(也就是想要開發的東西),以及需要克服的困難。這一步的成果是一份需求清單。
2.猜想(hypothesis)。這一步需要有一些創意,需要依靠直覺并做出一些有理由的猜測。我們從諸多想法中挑選一個或幾個,并進行下一步。
3.細化(elaboration)。要確定所有的需求都得到覆寫,并確定所有已知的弱點都得到解決,以便使設計更加充實。
4.分析(analysis)。對設計進行檢查、測試或運算,看看當初的猜想有沒有不對的地方。
其中的第4個步驟是可選的,或者說,很多人都不做這一步。
我們以橋為例來說明這4個步驟。需求很簡單,就是建造一座每小時可以通行x輛車的橋,該橋在y點跨越一條河,橋的單程長度是半英裡,橋的成本不超過z。由于成本限制,我們必須把隧道方案排除。設計猜想,指的是要建構什麼橋,是懸索橋、箱梁橋、傳統的日式木橋、典型的石拱橋,還是其他類型的橋。細化階段,指的是确定橋的樣子,橋柱的位置,以及橋的材質,換句話說,就是确定橋的各種細節。分析階段,可能指的是我們需要計算橋的承重能力,并判斷當河水流得比較快時,會不會把橋沖垮,此外可能還要做其他一些檢查。
上面這個例子可以把這4個步驟劃分得非常清晰,但現實工作中的設計流程,其各個步驟之間一般都沒有這麼分明。尤其要注意的是,分析步驟有可能融入細化步驟中,而我們在敲定整個設計之前,還有可能需要再度進行分析。有的時候,我們有可能剛提出一個猜想,就立刻要對其進行迅速的分析檢查,以判斷這個想法是否合理。為了從某些方面推進設計的細化,我們需要尋找設計中的弱點,并尋找彌補這些弱點的方式,而分析,正是一種可以用來尋找弱點的工具。
it界有一個流行的概念,叫做模式(pattern)。它有點像預先提出的一些設計猜想。這個概念其實并不新穎,它固然可以就近追溯到建築師christopher alexander所提出的設計理念,但早在18世紀,就已經出版了很多模式方面的書籍,這些書可以幫助那些訓練較少的建築者去建造古典風格的房屋。模式本身是好的,但是大家要注意:設計者必須發揮出自己的創意,必須用創新的态度去思考并尋找解決方案。

由于設計過程中會有回報,是以設計者可能需要跳回早前的步驟。在細化階段,你可能發現當初所做的設計猜想是行不通的,于是必須回頭去嘗試另外一種辦法,換句話說,就是要傳回猜想環節,去提出另外一種想法。此外,還有一點也非常重要,那就是:我們有可能會在細化環節之中,發現當初所提的需求有所遺漏,或是有互相不一緻之處,此時,必須回頭去修改需求。當設計猜想發生變化時,需求的重點也會随之改變。例如,在設計橋梁的時候,如果我們決定把設計猜想由原來的懸索橋,改為一種像倫敦的塔橋或武漢的轉體橋那樣,能夠提升或移動路面的橋,那麼就必須定出一套全新的需求,并在其中指出這座橋多長時間需要做一次提升或旋轉。是以,在整個設計流程之中,即使是早已定好的需求,也依然有可能會發生變化。圖1-1示範了流程之中的回報情況。
在分析環節中,我們當然有可能發現錯誤。有的時候,可以通過調整細節來修複該錯誤,也就是說,可以回到細化環節去重做其中的某一部分。還有一些時候,則需要傳回第2步,也就是重新提出另外一種猜想。
成本因素,很有可能會出現在項目的需求之中。如果在細化或分析階段發現成本過高,那有可能必須重新考慮整個設計方案。
筆者刻意選擇了猜想這個詞,來指出做設計與推進科學理論之間的相似點。這種提出假說并試圖證僞的辦法,與karl popper的主張有關,現在大家基本都把它當作一條科研準則來看待。在popper提出該主張之前,很多人都以為科學的進步依賴于事實的積累,事實積累到一定程度,科學定律自然就會展現出來。很多人對設計的看法也和這種積累及湧現模型類似,而且筆者認為,大部分人在開發應用程式時也是這樣想的,我們總是去收集需求,然後等着設計方案自己湧現出來。科學界已經抛棄了這種錯誤的想法,而我們今天在設計應用程式時,也同樣應該放棄這個想法。筆者之是以這樣說,主要原因有兩個。第一,我們要處理的并不是确定的問題,而是一些通過猜測和直覺所提出的想法,在這些方面,是沒有唯一答案可言的,于是,我們就需要通過細化及分析來確定這些猜測和直覺是有理有據的,并把它們建構在堅實的基礎之上。第二,正如前面所講,我們有可能需要在猜想環節和細化環節中去修改早前的需求,這說明早前的需求與最終要執行的解決方案之間有着某種互動關系。
由于這些步驟之間會發生回報,是以設計活動不應該鎖定在某個固定的時間段内。我們唯一能指望的,就是設計活動所花的時間應該遠遠少于實作活動所花的時間。然而這對it應用程式的設計來說卻很成問題,因為程式設計本身也是在做設計。本書中的很多内容,都是想幫助大家盡早(而不是過早地)做出重要的決策,進而使得程式設計活動變得相對有規律一些。
筆者認為,優秀的設計者會本能地完成這四個步驟。他們身上的兩項優點是糟糕的設計者所不具備的。第一,他們不會頻繁地返工,而是會在腦中畫有一幅設計全景圖,這張圖的内容領先于目前正在做的内容。換句話說,他們确實也會想到返工,但這種返工,指的是在思維層面上反複推演,而不是在手頭工作上來回折騰。第二,他們會花時間來處理一些主要的決策,比如在諸多猜想中進行選擇等。他們并不急于得出結論,而是願意傾聽建議,并樂于探索各種替代方案。筆者在本書中會多次建議大家像設計者一樣去思考。所謂像設計者一樣去思考,是說你應該仔細思考這些猜想,思考它們将會細化成何種模樣,并且應該考慮設計與需求之間的互動。此外,還應該尋求一些對設計進行分析的方式。
設計有很多種做法。筆者将這些做法分為專項的設計、有計劃的設計以及工程化的設計這三大類,并在下面三個小節中分别讨論它們。
1.2.1 專項的設計
專項的設計(ad hoc design)是從一張草圖或一個想法開始建構的。在推進過程中,你很可能會發現設計方案裡面有一些疏漏或問題,并會對其做出調整。有的時候,這種調整的幅度相當大,以緻你必須把某些已經完工的部分重新做一遍。
專項設計在it項目裡面很常見,筆者自己就多次做過這種設計。它很适合應對那種例行的項目,也就是說,那些項目與你原來做過的項目相似,而且你也大概知道自己應該怎麼做。更準确地說,這種設計方式通常适用于具備下列特征的項目:
項目規模較小。設計者一個人就能把設計方案構思好,并且可以相當明确地給團隊中的其他成員指派任務。有些情況下,如果可以精确地厘定其中某一部分設計工作的範圍和需求,那麼設計者還可以把這部分設計工作轉交給項目團隊之中的另外一個人來做。
項目本身是獨立的。也就是說,在開發該項目的同時,沒有别的項目需要依賴于本項目。一般來說,如果某個項目依賴于另外一個項目,那我們就必須把這種依賴關系精準地确定下來。比如,我們必須準确指出項目所要接收及發送的資料,或是指出項目需要在資料庫之共享的資料。采用專項設計方式所開發的項目,是很難做到這一點的,因為這種項目的設計者經常會改變自己的構想,而對于依賴本項目的其他項目來說,其設計者可能會對這種頻繁的改動感到惱火。
設計者與利益相關者之間的關系很密切。這種項目的利益相關者,即便沒有看到太多證據,也依然必須相信項目的設計者确實能做出他們想要的東西。為了緩解這種憂慮,項目團隊可以經常為利益相關者展示目前已經完成的某一部分功能。如果利益相關者在項目的開發過程中确實有時間和精力去反複地評審這個程式,那麼這種方式就是可行的。
除了上述三種情況,還有一種情況也适合做專項設計,那就是你在開始做項目的時候,并不知道它最終會做成什麼樣子。實際上這相當于通過嘗試來進行設計。筆者在本書中要提到一個自己所建構的範例程式,該程式會根據資料來繪制一些圖表。我之是以用專項設計的方式來建構這個程式,一部分原因在于本程式的利益相關者就是我自己,還有一部分原因則是當初我并不清楚這個産品的最終樣貌。
要想采用專項設計的方式來做項目,你最好一開始就有心理準備:項目過程中有可能要把已經做好的一部分内容丢掉,因為在開發過程中可能會碰到障礙,或是會發現更好的解決方案。筆者在編寫那個繪圖程式時,曾經放棄了20%已經寫好并測試好的代碼。藝術工作也可以視為一種設計,它通常是采用專項設計的方式來完成的。有些藝術家之是以優秀,是因為他們敢于把不夠好的作品丢掉重做。更進一步地說,即便你要面對的是一個相當複雜而且有挑戰性的問題,也依然可以采用專項設計的方式去制定解決方案,但是你必須做好準備:項目在最終完成之前,有可能要丢棄大量的内容。也就是說,你可能已經寫完了一些代碼,但是卻發現還有更好的解決辦法,于是要把早前的代碼再寫一遍。
我們經常聽到有人說:軟體産品的第二版或第三版,要比最初那一版好得多。沒錯,如果已經有一個系統擺在那裡,那我們自然可以更好地了解其各個部分之間的關系,而且也可以更容易地指派多位設計者去協調處理系統中的不同部分。第二版或第三版之是以會比第一版好,一部分原因在于公司的營銷政策,因為公司想盡快推出一個能用的版本來打入市場,這個版本可能做得有點草率。(盡管如此,筆者從來沒有發現哪個優秀的程式員會用草率的态度來寫代碼,即便在時間比較緊的情況下,也不應該這樣做,因為這通常會對開發工作造成不利的影響。)然而筆者卻認為,出現這種情況的主要原因,還在于開發者面對第二版或第三版的時候,更願意抛棄舊版本中的代碼,而他們在制作第一版的時候,則不太願意把自己編好的代碼丢掉。
想用專項設計的方式來做大型項目,其中一個辦法是把項目分成很多小的版本來釋出。複雜的設計方案會随着這些小版本的釋出而逐漸浮現出來,等到它完全出現在我們面前的時候,實作團隊中的每一位成員就都應該能夠了解這套設計方案了。可是這裡面有一個奇怪的問題:為什麼我們能夠在心中了解一個龐大而複雜的軟體,卻沒辦法用大家都能看懂的方式把它落在紙面上呢?本書中有很多内容都會談到怎樣解決這個問題。
1.2.2 有計劃的設計
如果你采用有計劃的設計(planned design)方式來做項目,那麼你會用圖紙把自己想要設計的産品繪制出來,或是用文字将其描述出來。我們今天能看到的很多優秀的曆史建築,都是有計劃地設計出來的,建築師會把建築的樓面和外牆用圖紙繪制出來,并指出其材質或需要使用的技術。筆者覺得歐洲很多雄偉的哥特式教堂,都應該是采用這種有計劃的設計方式設計出來的,否則你很難想象建築者怎麼可能把它建得這麼好,尤其是要把一塊石頭刻得恰到好處,使其剛好能夠放到花飾窗格之中的特定位置上面。不過,這些哥特式教堂的建造者在建造柱子的時候,使用了一些經驗法則來決定其厚度,而且他們還可以依賴一些工匠,這些工匠知道應該怎樣把圖紙上的東西建造出來。
如果你确實可以調動一些優秀的手藝人來完成項目,那麼這種有計劃的設計方式,就可以展現出一個極大的優勢,也就是說,我們不需要再像專項的設計方式那樣,整天盯着他們幹活,因為他們完全可以根據圖紙把所要制作的内容建構出來。
在建構複雜的項目時,我們可以看出設計方案的層次感。例如,要設計一座中世紀風格的教堂,那麼最宏觀的設計應該是教堂的基本形狀,這需要我們确定柱子和牆面的位置,但目前,我們還不需要考慮柱子或屋頂的内部結構,因為這些内部結構屬于更為詳細的設計,需要留給其他人去做,或者說,更有可能是留給工匠去做,這些工匠可以按照幾百年來一直流傳的設計風格把這些内容建構出來。此外,可能還需要有人來設計石雕窗格與彩色玻璃,并規劃聖壇與唱詩班座位的布局。
有計劃的設計方式是一種較為保守的方式,因為它必須依賴于手藝人所具備的知識和技能體系,如果要脫離這套熟悉的做法,那就需要培養一套新的知識與技能體系。
it界經常采用這種有計劃的設計方式來做項目,尤其是會用它來做大型的項目。筆者覺得,這種有計劃的設計方式,确實在應用程式的設計方面取得了一定的成功。
1.2.3 工程化的設計
工程化的設計與有計劃的設計很相似,它們都需要表示成圖紙或文本,然而兩者的差別在于:工程化的設計是一種經過測試的設計。我們早前講過一套帶有4個步驟的設計流程,分析環節是其中的一個步驟。在本節所講的這三種設計方式裡面,隻有工程化的設計方式才會包含正規的分析環節,然而這并不是說專項的設計方式和有計劃的設計方式就絕對不做分析。筆者覺得,優秀的設計者通常會在心裡做一些簡單的分析,例如,他們可能會構想一下本産品将會在哪些場景中使用。筆者甚至覺得,中世紀那些哥特式教堂的設計者,應該花了很長的時間去思考教堂的使用情況,甚至有可能想到應該怎樣留出一定的靈活空間,以友善信徒們列隊行進并舉辦儀式。令人遺憾的是,教堂的建築者并不懂得去做一些力學和承重方面的計算,有很多教堂的鐘塔,在建造後不久就坍塌了。工程化的設計與前兩種設計的不同點正在于它會進行正規的分析,并且會用一套知識體系來确定合适的分析方式。現代的建築工程師都會計算建築物的承重能力,隻要建築物建造正确,他就可以确信:該建築在結構上是穩固的。除了純粹的計算,我們還可以用其他一些形式來進行分析。例如,可以通過計算機模組化來分析建築物中的人在火災發生時的逃生時間,或是通過風洞來分析汽車設計方案的防風能力。
除了那種非常簡單的東西,工程化的設計一般都會展現出設計的層次感。比如,要設計一種新的噴氣式客機,那麼最頂層的設計,就應該是從各元件的組合情況着眼來描述飛機的形狀。其中的每個元件都有各自的小設計,而且像發動機這種複雜的元件,還會分成很多子元件,每個子元件都具備各自的設計。圖1-2抽象地展示了這種階層化的設計。
圖中的每個小方塊表示一個元件,包圍着小方塊的每個大方塊表示一種設計。最頂層的設計圖,展示了飛機的機身、機翼、發動機、起落架等部件的拼接情況,而發動機的設計圖,則展示了發動機裡面各個小部件之間的拼接情況。
對于元件的設計來說,其需求可以分為兩類,一類是宏觀的設計方案對該元件所提出的需求,另一類是外界對該元件所提出的需求。比如,在飛機的發動機所應滿足的各項需求之中,發動機的功率以及重量和大小方面的限制來自宏觀的設計方案,而噪聲限制及可服務性則來自外界。圖1-3示範了這兩種需求。
在工程化的設計之中,每個元件的設計都是經過測試的。
工程計算中有兩個很重要的地方。首先,這種計算要算的是元件能不能滿足其需求。比如,飛機設計者會通過計算來判斷這架飛機是否能夠飛行。要想完成這樣的計算,就必須先知道發動機的重量以及它的輸出功率。在分析元件的過程中所用到的每一個因素,都必須由元件設計中的一項需求來支撐。如果發動機所輸出的功率無法應對預定的重量,那麼宏觀設計就必須重做。換句話說,元件設計與宏觀設計之間會形成回報回路,如圖1-4所示。
https://yqfile.alicdn.com/558444cac847c073819028a17a4c797d85dd3f82.png" >
第二個要注意的地方是,工程計算并不能證明産品一定成功,它們隻能保證産品在一系列預先定義的情景之中不會失敗。以建築為例,結構工程師可以算出建築的承重能力,確定人們在走進建築物或是在其中添設家具之後,該建築不會坍塌。但是如果想保證建築物可以抵抗強風,那麼還需要再做另外一些計算。建築物的抗震和抗洪能力,也需要通過其他一些計算來了解。換句話說,工程計算隻能證明産品可以應對目前所涉及的這個問題,而并不能證明它可以應對尚未指出的那些問題。之是以要說明這一點,是因為很多it人士都追求一種境界,他們想要設法證明程式是正确的。工程師想要證明的,并不是設計方案的正确性,而是該方案可以應對一系列預先想到的問題。是以,我們在驗證程式的時候,應該更像工程師,而不是更像數學家。
我們要在出問題之前就預料到某些問題,而不是等出了問題之後再去修複,1940年的塔科馬海峽吊橋垮塌事件[2]說明了這一點。當時有一陣中等強度的風引發了共振,使橋開始搖擺。這種共振,把小幅度的上下運動變成大幅度的上下運動,并且令橋面扭曲,最終使其崩塌。當代的工程師已經能夠了解這種共振現象,他們可以通過計算來確定建築物的結構不會是以而受損。但有時還是會出錯,如倫敦的千禧橋,這座橋也出現了共振,但不是由風引發,而是由過橋的行人所引發。該橋在開放後不久,就因為要解決這個問題而關閉。
我們總是會發現,有的時候必須重新做設計,才能把某個問題解決好,而且有的時候,要想重新設計某個元件,就必須重新設計與之相關的其他一些元件,甚至需要重新設計整個産品。這兩種風險,在有計劃的設計方式中表現得會比工程化的設計方式更為嚴重,因為工程化的設計可以通過分析來盡早發現問題。
https://yqfile.alicdn.com/82db240ec48b31928f9ed5bf5ceaa9275ee115bc.png" >
1.2.4 設計方法小結
前面幾個小節講了很多概念,這裡有必要回顧一下:
設計可以看成一套含有4個步驟的流程,這4個步驟分别是:了解、猜想、細化和分析。
複雜的設計可以分成很多個元件,這些層次不同的元件可以分别進行設計。
設計方式可以分成三大類:
專項的設計。這種設計沒有正規的形式,它完全是在設計者的頭腦中構想出來的。該方式适用于規模較小而且了解較為充分的産品,此外,如果某産品的設計方案已經做出來了,但是設計者現在又想重新設計産品中的大部分元件,那麼也可以用這種設計方式來進行探索。
有計劃的設計。這種設計方式具有正規的形式,設計者不用一直督導其他人來完成工作。任何規模的項目(甚至是那種很大的項目,如金字塔)都可以用這種方式來做。該方式不包含正規的分析環節,是以産品的表現要依靠設計者的直覺。
工程化的設計。它與有計劃的設計方式很像,但是還包含一個正規的分析環節。如果産品較為複雜,有較多的内部依賴關系,或是其表現很難預測,那麼我們就應該用工程化的設計方式來做這個項目。
為了解說後面兩節中的觀點,筆者繪制了圖1-5來示範工程化的設計。
我們能不能像工程學那樣來開發應用程式呢?如果可以,那是不是應該這麼做?