摘要: 當(dāng)我們需要考慮類、類的內(nèi)部細(xì)節(jié)、類之間的關(guān)系時,這時我們已經(jīng)開始做詳細(xì)設(shè)計了。詳細(xì)設(shè)計不一定是一份文檔,也不一定是Word文檔,詳細(xì)設(shè)計也不一定叫“詳細(xì)設(shè)計”,有時候“編碼就是設(shè)計”也是未嘗不可的。對于MIS類型系統(tǒng)來說,架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計做好的前提下,詳細(xì)設(shè)計的難度其實是比較小的了,但MIS系統(tǒng)會有一些特殊的需求點,我們需要識別出來并想清楚應(yīng)對辦法。如果你做的軟件是高技術(shù)含量的非MIS系統(tǒng),情況將會更加復(fù)雜。 大綱: 1.什么是優(yōu)秀的設(shè)計? 本文章是系列文章之一,如果你還沒有看過之前的文章,建議先看完前面的文章再看本篇,這樣效果更好。 8.細(xì)節(jié)決定成敗——詳細(xì)設(shè)計8.1 什么是詳細(xì)設(shè)計? 當(dāng)我們需要考慮類、類的內(nèi)部細(xì)節(jié)、類之間的關(guān)系時,這時我們已經(jīng)開始做詳細(xì)設(shè)計了。詳細(xì)設(shè)計不一定是一份文檔,也不一定是Word文檔,詳細(xì)設(shè)計也不一定叫“詳細(xì)設(shè)計”,有時候“編碼就是設(shè)計”也是未嘗不可的。下面是我的一些最佳實踐: 實踐一:模塊設(shè)計 我早期的一些項目會寫一份詳細(xì)設(shè)計文檔,但后來的項目我會將詳細(xì)設(shè)計文檔分拆為N份模塊設(shè)計文檔了,這樣做的兩大好處是: 1)一份詳細(xì)設(shè)計文檔太大,不利于閱讀,不利于指導(dǎo)編碼工作,分拆后就好多了; 2)N個模塊設(shè)計的任務(wù)可以分派給不同的軟件設(shè)計師(或程序員)來負(fù)責(zé)。 實踐二:代碼就是設(shè)計 有時候我會“偷懶”,我覺得沒有必要再寫什么設(shè)計文檔,直接在開發(fā)工具中定義好類,寫好類的公開接口,寫好注釋等等,這時我其實就是在做詳細(xì)設(shè)計的工作,我將代碼框架寫好后,才寫具體的實現(xiàn)代碼。這種工作模式其實就是將詳細(xì)設(shè)計與編碼實現(xiàn)融合在一起了,效果和效率更好!當(dāng)然不是說不再需要寫Word文檔格式的詳細(xì)設(shè)計了,對應(yīng)比較復(fù)雜的詳細(xì)設(shè)計,一般還是需要通過另外的文檔來描述一下比較好。 但可能會有一種比較詳見的“特殊”情況:你可能會遇到開發(fā)人員死活寫不出Word文檔格式的詳細(xì)設(shè)計,你和他溝通多次后,他還是寫不出有質(zhì)量的Word文檔格式的詳細(xì)設(shè)計,這時你不如讓他直接寫代碼,先寫個框架看看,然后你通過評審代碼來修正他的設(shè)計。 實踐三:Demo就是設(shè)計 設(shè)計邏輯復(fù)雜時,可能需要文檔來應(yīng)對,但文檔畢竟是紙上談兵,可能最切實的辦法是做一個 Demo 實現(xiàn)你的算法和設(shè)計思路。只要 Demo 是 Work 的,就可以將這個 Demo 的代碼重用到實際的項目中。 舉一個例子:曾經(jīng)某項目中需要寫代碼解決判斷一個點是否在多邊形內(nèi),算法有點麻煩,光寫文檔說算法沒有實質(zhì)的價值,于是我用了半天時間寫了實現(xiàn)的代碼和測試的代碼,將這個Demo提交給項目組。 實踐四:“無”詳細(xì)設(shè)計 無詳細(xì)設(shè)計的意思不是真的不考慮詳細(xì)設(shè)計了,而是對于這種情況我們已經(jīng)駕輕就熟了,幾乎是閉著眼睛都會做了,所以我們就“無”詳細(xì)設(shè)計直接編碼了。 8.2 詳細(xì)設(shè)計的基礎(chǔ) 我曾經(jīng)評審過一份設(shè)計文檔,該文檔內(nèi)容詳細(xì)、思路清晰,清楚描述了某些技術(shù)環(huán)節(jié)的實現(xiàn)辦法,而且實現(xiàn)辦法都是可行和有效的,這個文檔可以算是一份比較好的詳細(xì)設(shè)計文檔了。但可惜的是,整個項目只有這樣的一份設(shè)計文檔,從全局來看這個文檔只解決了局部問題,缺失了一些核心內(nèi)容: 1)沒有架構(gòu)設(shè)計的的內(nèi)容; 2)沒有數(shù)據(jù)庫設(shè)計的內(nèi)容; 3)系統(tǒng)的需求很復(fù)雜,大部分的需求沒有對應(yīng)的設(shè)計考慮。 前面的文章曾提到,我做過的項目一般至少會有一份概要設(shè)計文檔,詳細(xì)設(shè)計文檔不一定是必須的。詳細(xì)設(shè)計固然重要,但針對整個系統(tǒng)的全面考慮更加重要,詳細(xì)設(shè)計之前應(yīng)該具備以下條件: 1)應(yīng)針對全部需求(包括功能性和非功能性的需求),系統(tǒng)需要有整體上的考慮,也就是前文提到的架構(gòu)設(shè)計。 詳細(xì)設(shè)計需要考慮類、類的內(nèi)部細(xì)節(jié)、類之間接口等,這些是需要符合系統(tǒng)的總體架構(gòu)和分層架構(gòu)的。 2)應(yīng)有數(shù)據(jù)庫設(shè)計。 如果沒有數(shù)據(jù)庫設(shè)計,建筑在數(shù)據(jù)庫之上的代碼是很難寫的。當(dāng)然如果你是用“由中間到上下”的設(shè)計方法的話(什么是“由中間到上下”?請參考前面的文章),數(shù)據(jù)庫設(shè)計沒有,只要有中間層的建模的話,表現(xiàn)層和邏輯層的代碼還是可以寫的,但數(shù)據(jù)庫操作層的代碼還是依賴于數(shù)據(jù)庫設(shè)計的。 3)部分情況下,還應(yīng)該有部分或全部的用戶體驗設(shè)計(用戶體驗設(shè)計下一篇會分享)。 用戶體驗設(shè)計主要考慮的是軟件的表現(xiàn)層,最能充分體驗“由頂而下”的設(shè)計思路,將會直接影響具體的代碼實現(xiàn)。 一般情況下我們應(yīng)該在架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計的基礎(chǔ)上進(jìn)行詳細(xì)設(shè)計,否則很可能會讓我們僅僅關(guān)注了局部的問題,而沒有抓住其他更加重要的問題和全局的問題。如果沒有架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計,直接詳細(xì)設(shè)計是不是一定不可行呢?有以下的一些特殊情況(不限于此噢): 1)如果果你的情況是在原有系統(tǒng)上升級改造,系統(tǒng)原有的架構(gòu)和數(shù)據(jù)庫設(shè)計基本不變,那么直接進(jìn)行詳細(xì)設(shè)計是合適的做法; 2)有時候有些局部問題雖然很“局部”但又相當(dāng)特殊或重要,哪怕沒有來得及完成架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計,也可以先進(jìn)行詳細(xì)設(shè)計的。 后文我們先從正常思路介紹詳細(xì)設(shè)計,也就是先有架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計再有詳細(xì)設(shè)計,然后再分享一些上面第2)點的情況。 8.3 詳細(xì)設(shè)計是架構(gòu)設(shè)計的延續(xù) 前文的架構(gòu)設(shè)計提到我們要對系統(tǒng)進(jìn)行兩個層次的拆解,分別是: 第一層拆解:思考系統(tǒng)需要開發(fā)什么軟件和數(shù)據(jù)庫等; 第二層拆解:考慮組件(Component)、代碼包、某個分層等等,可能是“物理分拆”也可能是“邏輯分拆”。 不太記得或者看不懂的朋友,請先看看前面的文章啦。 而詳細(xì)設(shè)計其實就是: 第三層拆解:進(jìn)一步細(xì)化出類、類對外接口、類的內(nèi)部細(xì)節(jié)等。 通常我會用UML的順序圖(Sequence Diagram)來表達(dá)“第三層拆解”,請看一個簡單一點的圖,了解一下順序圖。 圖8.1 詳細(xì)設(shè)計-順序圖1 我們通過這個圖了解兩個事情: 1)順序圖的基本語法; 2)順序圖如何表達(dá)詳細(xì)設(shè)計。 這個圖表示的是用戶在某個查詢頁面輸入查詢內(nèi)容、點擊查詢按鈕等這些用戶交互及背后的程序設(shè)計。通常順序圖最左邊畫的是用戶,僅次之是軟件的表現(xiàn)層的某個頁面(界面),用戶與表現(xiàn)層的之間的交互,會導(dǎo)致表現(xiàn)層后面的類的一系列動作。這個圖還算比較簡單,請看下面這個我在N年前完成的某項目中的其中一個順序圖: 圖8.2 詳細(xì)設(shè)計-順序圖2 架構(gòu)設(shè)計需要考慮全部需求后設(shè)計出來,也就是說”全部需“求驅(qū)動架構(gòu)設(shè)計,當(dāng)然某些特殊的需求點需要特別關(guān)照;數(shù)據(jù)庫設(shè)計主要是業(yè)務(wù)概念模型驅(qū)動的,業(yè)務(wù)建模及進(jìn)一步提煉可以幫助我們設(shè)計出更有彈性的設(shè)計。那詳細(xì)設(shè)計是不是仍然需要”需求驅(qū)動“呢?這是必須的! 我們可能用用例(UseCase)、用戶故事(User Story)或者是功能點等方法表示需求,不管怎樣的表示辦法,最終都會拆解為一條條比較細(xì)的需求。每一條需求具體如何實現(xiàn)呢?順序圖就是表達(dá)這個實現(xiàn)方法的好工具!圖8.1 和 圖8.2 分別說明的都是某個需求點的實現(xiàn)方法,圖8.1 是查詢用例的詳細(xì)設(shè)計, 圖8.2 是修改材料設(shè)備信息的詳細(xì)設(shè)計。一個系統(tǒng)的詳細(xì)設(shè)計,就可以用類似圖8.1和圖8.2的圖逐一表示出來。 我們通過下圖再充分理解一下需求如何驅(qū)動詳細(xì)設(shè)計: 圖8.3 詳細(xì)設(shè)計-順序圖3 上圖紅色框框部分的內(nèi)容是需求,用戶和系統(tǒng)界面之間的交互設(shè)計是對需求的進(jìn)一步細(xì)化;藍(lán)色框框部分是在需求驅(qū)動下的程序?qū)崿F(xiàn),此圖實現(xiàn)部分比較簡單,大部分的程序?qū)崿F(xiàn)邏輯都會比上圖復(fù)雜,會涉及到邏輯層、數(shù)據(jù)操作層還有一些共用模塊之間的調(diào)用等等。詳細(xì)設(shè)計除了要需求驅(qū)動,同時也要需要符合架構(gòu)設(shè)計,代碼也需要基于已有的數(shù)據(jù)庫設(shè)計,換句話說就是詳細(xì)設(shè)計是需求、架構(gòu)設(shè)計及數(shù)據(jù)庫設(shè)計三者同時驅(qū)動的。 本小節(jié)所列舉的詳細(xì)設(shè)計的例子都是MIS類型系統(tǒng)的例子,基本上圍繞數(shù)據(jù)庫的增刪改查進(jìn)行,設(shè)計難度其實并不是很大。前面已經(jīng)提到,如果對于已經(jīng)很熟悉的情況,你沒有必要再用順序圖來畫一次了,直接可以”無”詳細(xì)設(shè)計;但如果你的團(tuán)隊成員還不是很熟悉數(shù)據(jù)庫的增刪改查,或者實現(xiàn)邏輯比較復(fù)雜,這樣就很有必要進(jìn)行詳細(xì)設(shè)計了。 本小節(jié)的例子比較“常規(guī)”,老鳥可能覺得沒啥難度,下小節(jié)的難度將會增加。 8.4 詳細(xì)設(shè)計是解決局部問題的良方 前面提到,有些局部問題雖然很“局部”但又相當(dāng)特殊或重要,哪怕沒有來得及完成架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計,也是需要先進(jìn)行詳細(xì)設(shè)計的。 舉三個例子: 案例1:針對網(wǎng)絡(luò)負(fù)載平衡的特殊考慮 某客戶的Web服務(wù)器采用網(wǎng)絡(luò)負(fù)載平衡,有兩臺Web服務(wù)器,這與我們慣常的一臺Web服務(wù)器場景很不一樣。我們打算使用公司的框架來開發(fā)這個系統(tǒng),但這個框架的其中一個地方很可能會出問題??蚣苁褂昧遂o態(tài)變量用來記錄數(shù)據(jù)庫中ID的最大值,當(dāng)增加一條記錄時就 ID_Max = ID_Max + 1,將新的 ID_Max 作為新增加記錄的ID。這樣在兩臺Web服務(wù)的場景下,就會有兩個靜態(tài)的 ID_Max,兩邊都很可能會出現(xiàn)不準(zhǔn)確的情況,導(dǎo)致數(shù)據(jù)插入到數(shù)據(jù)庫中時出錯。本身這個修改并不算復(fù)雜,但我們需要同時考慮兼容框架,因為這個框架是同時支持 SQLServer 和 Oracle 數(shù)據(jù)庫的,我們的首席設(shè)計師很厲害,在框架層面解決了這個問題,不僅可以繼續(xù)保持框架的兼容性,還擴(kuò)大了框架的適應(yīng)面。 案例2:點是否在多邊形內(nèi)的求解 這個幾何問題是由業(yè)務(wù)問題轉(zhuǎn)化而已來的,這是一個某移動通訊公司的系統(tǒng),先簡單介紹一下業(yè)務(wù)。 我們的手機(jī)是通過基站進(jìn)行通訊的,如果附近沒有基站,就會出現(xiàn)手機(jī)沒有信號的情況。我們所居住的城市當(dāng)中,一般會有上百成千的基站,保證我們通訊暢通?;九c基站之間形成的通訊網(wǎng)絡(luò),會劃分為以基站為中心的多個“多邊形”,形成一個好像蜂窩的樣子,這就是我們經(jīng)常聽說的蜂窩網(wǎng)絡(luò)。但有可能會出現(xiàn)某個地方打電話有問題的情況,這個出問題的地“點”位于哪個“多邊形”呢,系統(tǒng)需要通過點的坐標(biāo)找到這個點在哪個多邊形范圍內(nèi),進(jìn)一步定位到是哪個基站可能出問題。 上述就是原始的業(yè)務(wù)背景,我們將這個需求演化為一個幾何問題,當(dāng)時我參考了“放射線”的算法,直接通過“Demo法”來完成這個設(shè)計。前文的”實踐3:Demo就是設(shè)計“中提到的例子,就是這個例子了! 案例3:讓程序支持 Undo 和 Redo 如果要求你的系統(tǒng)支持 Undo 和 Redo,不知道你會如何考慮呢?支持 Undo 和 Redo 是非??岬模y度是相當(dāng)之高的,你會先完成架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計才考慮嗎?23設(shè)計模式中的命令模式可以幫助我們,但命令模式僅僅是給出了解決問題的框架而已,你還需要演化為更實際的內(nèi)容,否則又犯了”放之四海而皆準(zhǔn)“的毛病了。命令模式很有難度,但很有意思和很有用,我們這里不詳解命令模式,大家可以參考我的設(shè)計模式方面的文章。 這里舉這個例子是想說明:某些需求看上去好像是僅僅很小的一個點的要求,有可能影響面很大,你可能需要先針對這個點去思考詳細(xì)的實現(xiàn)辦法,然后才能幫助你想清楚架構(gòu)設(shè)計及數(shù)據(jù)庫設(shè)計。 小結(jié)一下詳細(xì)設(shè)計解決局部問題的兩種特殊情況:框架未確定之前的技術(shù)預(yù)研,案例1、3屬于這個情況;框架確定與否都不影響的局部問題求解,案例2屬于這個情況。一般認(rèn)為詳細(xì)設(shè)計是概要設(shè)計之后的,大部分情況確實如此,但通常我們進(jìn)行概要設(shè)計之前還很可能需要針對某些需求點進(jìn)行技術(shù)預(yù)研,這些技術(shù)預(yù)研是需要用詳細(xì)設(shè)計的程度來進(jìn)行。 需要補(bǔ)充說明的是:某些技術(shù)難點的設(shè)計,通常僅僅靠順序圖是搞不定的,甚至不能用順序圖,我還會用到類圖、對象圖、活動圖和狀態(tài)機(jī)圖等等,類圖用到的機(jī)會最大,你看看23設(shè)計模式,設(shè)計思路基本上都是用類圖來表達(dá)的。UML圖僅僅是一種工具,前文提到的“實踐二:代碼就是設(shè)計”和“實踐三:Demo就是設(shè)計”,對于難度高的詳細(xì)設(shè)計是經(jīng)常需要用到這兩招的。 8.5 需要從詳細(xì)設(shè)計中提煉出需要全局考慮的內(nèi)容 前文提到”詳細(xì)設(shè)計是架構(gòu)設(shè)計的延續(xù)”,其實還需要補(bǔ)充的是“詳細(xì)設(shè)計需要持續(xù)完善架構(gòu)設(shè)計”。詳細(xì)設(shè)計過程中,我們會發(fā)現(xiàn)很多共性的內(nèi)容,需要提煉為整個程序需要遵循的設(shè)計規(guī)范。下面是一些例子: 1)用戶體驗設(shè)計;(下一篇再詳細(xì)介紹) 2)輸入合法性判定; 3)批量數(shù)據(jù)的傳輸約定; 4)實體類的生命周期; 5)邏輯類的生命周期; 6)并發(fā)沖突的處理原則,包括判定辦法、提示辦法; 7)連接打開、關(guān)閉原則; 8)采用事務(wù)的原則; 9)異常處理機(jī)制; 10)日志記錄機(jī)制; …… 8.6 詳細(xì)設(shè)計小結(jié) 對于MIS類型系統(tǒng)來說,架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計做好的前提下,詳細(xì)設(shè)計的難度其實是比較小的了,你可以用順序圖來完成設(shè)計,注意做到需求驅(qū)動詳細(xì)設(shè)計,注意要滿足架構(gòu)設(shè)計和數(shù)據(jù)庫設(shè)計。不過不少MIS會有一些特殊的需求點,我們需要識別出來并想清楚應(yīng)對辦法,某些特殊的需求點還需要進(jìn)行前期的技術(shù)預(yù)研。 如果你做的不是MIS類型的系統(tǒng),而是設(shè)計難度很高的軟件,比方說技術(shù)含量很高的CAD軟件、人工智能很牛逼的某些家用游戲,要解決這些軟件的詳細(xì)設(shè)計,你需要設(shè)計模式、工程繪圖、數(shù)學(xué)、物理、人工智能等很多知識支撐才能搞得掂了! 本文是系列文章的其中一篇,要做軟件設(shè)計師一點都不簡單啊,請留意后續(xù)文章! 活動信息: 我們即將在深圳舉辦的一個活動“敏捷遇上UML”,為你分享需求分析及軟件設(shè)計的最佳實踐。 詳情請猛點這個鏈接:http://blog.csdn.net/fireball1975/article/details/19550771 本活動已經(jīng)在CSDN社區(qū)活動發(fā)布,詳見:http://huiyi.csdn.net/module/meeting/meeting/info/706/community 作者:張傳波 創(chuàng)新工場創(chuàng)業(yè)課堂(敏捷課程)講師 軟件研發(fā)管理資深顧問 CMMI首席專家 《火球——UML大戰(zhàn)需求分析》作者 www.創(chuàng)辦人 |
|