|
設(shè)計(jì)真是件奇妙的事情,能造就璀璨的明珠,也能帶來一堆萬年不去核廢料;能讓人享受釋放智慧的樂趣,也能品嘗挫敗的沮喪。Why?
設(shè)計(jì)的過程
工程角度,設(shè)計(jì)是一個(gè)過程,包含三種不同層次的活動(dòng):架構(gòu)設(shè)計(jì),概要設(shè)計(jì)和詳細(xì)設(shè)計(jì)。三者由全局到局部,依次展開,逐漸深入細(xì)節(jié),最終完成一個(gè)技術(shù)解決方案,給出可行的如何實(shí)現(xiàn)需求的答案。此三者的一般性過程如下:
架構(gòu)設(shè)計(jì)
目標(biāo):定位全局,確定技術(shù)方案的方向、后續(xù)技術(shù)活動(dòng)策略。
輸入:需求文檔。敏捷過程常常是是一組用戶故事。
輸出:架構(gòu)設(shè)計(jì)文檔。敏捷過程稱之為應(yīng)用全局視圖Application Overview。
角色:架構(gòu)師
任務(wù):
1.分析需求,識(shí)別關(guān)鍵功能、質(zhì)量需求和約束
2.分析目標(biāo)系統(tǒng)為達(dá)成以上目的,需要哪些流程,流程中有多少環(huán)節(jié),各環(huán)節(jié)涉及哪些角色,這些角色的職責(zé)及他們之間的協(xié)作關(guān)系。
3.將角色按邏輯分類抽象,變成子系統(tǒng)。角色的職責(zé)即是子系統(tǒng)的接口,角色間的協(xié)作關(guān)系即為各子系統(tǒng)間的關(guān)系。
4.各子系統(tǒng)內(nèi)部,根據(jù)職責(zé)拆分模塊,確定它們的交互方式。
5.針對(duì)關(guān)鍵功能,確定完成這些功能的流程,在時(shí)序上由各子系統(tǒng),模塊協(xié)同工作的順序。
6.考慮各子系統(tǒng)的部署方式。
7.將各子系統(tǒng)、模塊轉(zhuǎn)換成實(shí)現(xiàn)語言的元素。如對(duì)于.NET,規(guī)劃各子系統(tǒng)有哪些namespace,namespace如何分配到assembly,assembly之間的依賴關(guān)系。再將assembly分配到project中。期間需要注意避免循環(huán)依賴,明確接口(作為接口的assembly和project)。
8.規(guī)劃project在SCM中的組織結(jié)構(gòu)。
9.根據(jù)質(zhì)量需求確定全局性的技術(shù)策略(方案):如線程控制,錯(cuò)誤處理,數(shù)據(jù)存儲(chǔ)等。
10.分析其余需求,驗(yàn)證當(dāng)前方案是否能支持,根據(jù)發(fā)現(xiàn)的問題做必要調(diào)整。
概要設(shè)計(jì)
目標(biāo):在具體實(shí)現(xiàn)語言層面上展開工作,確定每個(gè)project的主要類及交互過程和總體算法。
輸入:架構(gòu)設(shè)計(jì)文檔和需求。
輸出:概要設(shè)計(jì)文檔。
角色:高級(jí)程序員
任務(wù):
1.設(shè)計(jì)提供暴露服務(wù)的接口的具體實(shí)現(xiàn)類,補(bǔ)充所需的相類,通常可按界面(接口)、活動(dòng)和存儲(chǔ)三方面考慮。進(jìn)一步落實(shí)對(duì)項(xiàng)目外接口的依賴關(guān)系和位置。
2.設(shè)計(jì)算法實(shí)現(xiàn)接口暴露的相關(guān)功能。
詳細(xì)設(shè)計(jì)
目標(biāo):確定概設(shè)提出的每個(gè)方法的具體實(shí)現(xiàn)。
輸入:概要設(shè)計(jì)
輸出:偽代碼。
角色:程序員
任務(wù):用偽代碼描述每個(gè)方法。
這里看到的是一個(gè)按需求->系統(tǒng)->子系統(tǒng)->模塊->類->方法,自頂向下逐步求精的過程。
設(shè)計(jì)的技術(shù)
技術(shù)角度,設(shè)計(jì)是一系列方法和工具,通過應(yīng)用這些方法和工具給出一個(gè)可行解決方案的描述。常用方法有:
OO:面向?qū)ο蠓椒āF淠康氖墙y(tǒng)一問題的描述與解決方法,通過一致的抽象提高開發(fā)效率。核心思想是,將問題空間映射到計(jì)算機(jī)模型上,在計(jì)算機(jī)中建立一個(gè)同我們?nèi)粘8兄澜缦嗤哪P停鉀Q問題。實(shí)踐中,通過類描述問題空間的概念,通過類的消息描述這些概念的交互形成一個(gè)模型,再將模型落實(shí)到OOP的語言中,如C++,C#,Java等。
AOP:面向方面的方法。期望將主要業(yè)務(wù)同這些業(yè)務(wù)中散落的支撐功能(服務(wù))如日志,權(quán)限等分離。結(jié)合OOP應(yīng)用時(shí),通過橫切點(diǎn)定義跨多個(gè)類的支持服務(wù),由方面(特殊類)實(shí)現(xiàn)這些服務(wù),再通過切入點(diǎn)連接方面與橫切點(diǎn),達(dá)到運(yùn)行時(shí)自動(dòng)提供服務(wù)的目的。
DDD:領(lǐng)域驅(qū)動(dòng)的設(shè)計(jì)。采用傳統(tǒng)OO方法時(shí),一般的需求分析結(jié)果是用自然語言描述的與OOD存在脫節(jié),容易生造出問題域中不存在的概念,建立與實(shí)際需求不一致的模型。因此,從需求分析起,首先為問題域即領(lǐng)域建模,完全不考慮如何設(shè)計(jì)、實(shí)現(xiàn),用客戶能理解的方法僅描述問題現(xiàn)狀。常用的建模方法是OOA,模型可用UML表達(dá),也可以用類似框圖聯(lián)系,總是以能讓用戶明白這就是問題的描述,方便溝通為原則。
在不斷使用這些方法的過程中,一些大師們發(fā)現(xiàn)了某些經(jīng)常重復(fù)的解決方案,便對(duì)它們進(jìn)行了提煉和總結(jié),以便后來者這能利用這些經(jīng)驗(yàn),提高工作效率和質(zhì)量,少走彎路。這些經(jīng)驗(yàn)有:架構(gòu)風(fēng)格,架構(gòu)模式,設(shè)計(jì)模式和反模式。
架構(gòu)風(fēng)格
架構(gòu)層次的,根據(jù)系統(tǒng)的架構(gòu)呈現(xiàn)出的總體特點(diǎn)進(jìn)行架構(gòu)分類的方式。主要的風(fēng)格有:
1.客戶-服務(wù)器:系統(tǒng)分為客戶與服務(wù)端兩部分,客戶端發(fā)送請(qǐng)求,服務(wù)端執(zhí)行并響應(yīng)。
2.分層(級(jí))架構(gòu):系統(tǒng)按關(guān)注點(diǎn)水平分層,每一層為上層提供一個(gè)抽象。近一步,可將層分布到不同計(jì)算機(jī)上。
3.面向?qū)ο螅合到y(tǒng)分成單獨(dú)的可重用的對(duì)象,每個(gè)對(duì)象包含數(shù)據(jù)及處理它們的行為。
4.基于消息(事件):系統(tǒng)各部分通過發(fā)送和接收約定格式的消息工作,無需關(guān)心實(shí)際的收發(fā)者。
5.面向服務(wù)(SOA):系統(tǒng)通過約定的契約暴露功能,并根據(jù)這些契約工作。
6.基于組件:系統(tǒng)分解為邏輯的可重用位置透明的組件,通過明確定義的通信接口工作。
7.管道-過濾器:由管道連接過濾器一組,處理流經(jīng)的數(shù)據(jù)。
8.微內(nèi)核:分離最小功能核心和可擴(kuò)展部分。
它們?cè)谧罡邔哟胃鶕?jù)問題的類型給出了一般的解決方向。如:
1.通信問題:基于消息、管道-過濾器
2.部署問題:客戶/服務(wù)器、分層架構(gòu)
3.重用與可擴(kuò)展:OO、基于組件、SOA
但是,不同風(fēng)格并不是互相排斥的,相反,一個(gè)實(shí)際系統(tǒng)通常同時(shí)呈現(xiàn)出多種風(fēng)格。如一個(gè)分布系統(tǒng),功能可通過語言無關(guān)的契約暴露,用OOP實(shí)現(xiàn)這些契約,實(shí)現(xiàn)對(duì)象又被組織成一個(gè)個(gè)組件,每個(gè)組件定義了彼此的通信接口,而通信又可是基于消息的,組件本身運(yùn)行在一個(gè)支持插件的容器中,可隨時(shí)添加新組件,提供新服務(wù)。這里表現(xiàn)出了SOA、OO、Component、Messaging和Mico-Kernel多種風(fēng)格。
架構(gòu)模式
一系列可重用的架構(gòu)設(shè)計(jì)方案,每個(gè)方案在滿足適用場(chǎng)景的前提下,解決一種或一類問題。經(jīng)典的POSA給出了一些常用的模式分類:
1.服務(wù)訪問和配置:包裝器(Wrapper Facade)、組件配置器(Component Configurator)、截取器(Interrceptor)、擴(kuò)展接口(Extension Interface)
2.事件處理:反應(yīng)器(Reactor)、主動(dòng)器(Proactor)、異步完成標(biāo)記(ACT)、接收-連接器(Acceptor-Connector)
3.同步:界定枷鎖(Scoped Locking)、策略化加鎖(Strategized Locking)、線程安全接口(Thread-Safe Interface)、雙檢查加鎖優(yōu)化(Double-Checked Locking Optimization)
4.并發(fā):主動(dòng)對(duì)象(Active Object)、監(jiān)視器對(duì)象(Monitor Object)、半同步/半異步(Half-Sync/Half-Asynce)、領(lǐng)導(dǎo)者/追隨者(Leader/Followers)、線程特定存儲(chǔ)器(Thread-Specific Storage)
5.資源獲取:查找(Lookup)、懶加載(Lazy Acquistion)、預(yù)加載(Eager Acquistion)、分步加載(Partial Acquisition)
6.資源生命周期:緩存(Caching)、池(Pooling)、協(xié)調(diào)器(Coordinator)、資源生命周期管理(Resource Lifecycle Manager)
7.資源釋放:租約(Leasing)、清除者(Evictor)
此類模式給出了全局性問題的一般處理方案,大都是關(guān)于子系統(tǒng)、模塊及相互之間關(guān)系的粗粒度的描述。
設(shè)計(jì)模式與反模式
設(shè)計(jì)模式指OO的設(shè)計(jì)模式,是可反復(fù)使用的代碼經(jīng)驗(yàn)總結(jié)。通過GoF經(jīng)典的《設(shè)計(jì)模式》廣為人知。GoF將它們分類為:
1.創(chuàng)建型:簡單工廠(Simple Factory)、工廠方法(Factory Method)、抽象工廠(Abstract Factory)、創(chuàng)建者(Builder)、原型(Prototype)、單例(Singleton)
2.結(jié)構(gòu)型:外觀(Facade)、適配器(Adapter)、代理(Proxy)、裝飾(Decorator)、橋接(Bridge)、組合(Composite)、享元(Flyweight)
3.行為型:模板方法(Template Method)觀察者(Observer)、狀態(tài)(State)、策略(Strategy)、職責(zé)鏈(Chain of Responsibility)、訪問者(Visitor)、調(diào)停者(Mediator)、備忘錄(Memento)、迭代器(Iterator)、解釋器(Interpreter)
它們?cè)诖a層面給出解決上述三類問題的一般做法及使用場(chǎng)景。
設(shè)計(jì)模式如紅日般普照大地,光芒萬丈,導(dǎo)致做OO的言必稱設(shè)計(jì)模式,不用上幾個(gè)都不好意思拿去見人。免不了被亂用、誤用,明明需要避光保存的,偏偏加個(gè)LED增加照明,還曰節(jié)能、低碳。所以不得不需要反模式來撥亂反正。反模式說明了,當(dāng)在錯(cuò)誤的時(shí)間,錯(cuò)誤的地點(diǎn),使用了錯(cuò)誤設(shè)計(jì)模式后,出現(xiàn)的嚴(yán)重后果,提醒人們過猶不及。
設(shè)計(jì)的人員
今天,從人員角度,設(shè)計(jì)是一系列扮演不同角色的人員的協(xié)作,他們通過某種過程,應(yīng)用某些技術(shù),相互配合,共同完成一個(gè)解決方案。一個(gè)采用傳統(tǒng)設(shè)計(jì)過程的大型系統(tǒng)涉及的角色通常有:
1.架構(gòu)師:一個(gè)人或者一個(gè)團(tuán)隊(duì),負(fù)責(zé)將系統(tǒng)分解成子系統(tǒng)和模塊,去頂它們之間的關(guān)系(開發(fā)期、運(yùn)行期)并制定相關(guān)的技術(shù)決策,如部署、開發(fā)、性能等。
2.高級(jí)程序員(設(shè)計(jì)師):負(fù)責(zé)完成一個(gè)或多個(gè)子系統(tǒng)、模塊的概要設(shè)計(jì)。
3.程序員:負(fù)責(zé)詳細(xì)設(shè)計(jì)。
4.項(xiàng)目經(jīng)理:負(fù)責(zé)整個(gè)活動(dòng)的任務(wù)協(xié)調(diào),并根據(jù)架構(gòu)安排開發(fā)任務(wù)。
其中,架構(gòu)師是核心,其工作成果是后續(xù)管理和實(shí)現(xiàn)的基石。有什么樣的架構(gòu),便會(huì)有什么樣的開發(fā)組織結(jié)構(gòu)。如分層架構(gòu),必然會(huì)存在界面、業(yè)務(wù)、持久化及公共模塊的開發(fā)職責(zé)分配,由不同人(團(tuán)隊(duì))完成不同層的工作。
現(xiàn)代軟件,因?yàn)橐?guī)模和復(fù)雜性,再也無法由個(gè)人獨(dú)立完成所有工作,必須依靠協(xié)作。協(xié)作首先需要分工,明確各工種的職責(zé),個(gè)人依照職責(zé)行事。分工之后便有了工作的先后次序,不同次序的串聯(lián)需要一定規(guī)則,便形成了一些過程規(guī)范,大家依照規(guī)范協(xié)同。所以,才有了那么多的軟件工程方法論,開發(fā)才有了架構(gòu)師,設(shè)計(jì)師和程序員的細(xì)分。不能簡單的認(rèn)為架構(gòu)師>設(shè)計(jì)師>程序員,他們主要的區(qū)別在于工作范圍的廣度和深度的側(cè)重點(diǎn)不同。架構(gòu)師更廣,程序員工作的更深入。
為了使用一致的思維考慮問題與問題的解決方法,誕生了OOP。為了分離業(yè)務(wù)與支持服務(wù),讓不同的人在不同的時(shí)間和地方分別解決不同問題,誕生了AOP。為了便于開發(fā)人員與用戶達(dá)成待解決問題的一致認(rèn)識(shí),誕生了DDD。
設(shè)計(jì)時(shí)無論采用何種種過程、技術(shù)和人員組織方式,根本目的只有一個(gè):給出關(guān)于需求的技術(shù)解決方案。
實(shí)際工作中還會(huì)碰到一個(gè)嚴(yán)重的問題,常常發(fā)現(xiàn),要解決的問題,并不是地上的石頭,靜靜的躺在那兒,等你照劍譜揮劍的。經(jīng)常是,哦,我要砍的不是這塊,是那塊,甚至不是碎石而是需要劈柴,一身武藝無處使。不由怒從心頭,不時(shí)問候需求人員或者客戶,干嘛不一次說清楚,寫的仔細(xì)點(diǎn)。害我改這改那兒的。對(duì)此,Brooks在《設(shè)計(jì)原本》說:設(shè)計(jì)的本質(zhì)是幫助客戶發(fā)現(xiàn)他們想要的需求。
設(shè)計(jì)的本質(zhì)!
根本上,解決方案和問題是共同變化的,甚至?xí)嗷ビ绊憽,F(xiàn)實(shí)中,需求階段給出的需求,往往是初始需求,隨設(shè)計(jì)過程的推進(jìn),它會(huì)奇妙的發(fā)生一些變化:
1.需求描述更精確了:隨著設(shè)計(jì)深入,發(fā)現(xiàn)原來的描述存在模糊的方,需要更精確才能做出設(shè)計(jì)決策。
2.需求描述錯(cuò)了:設(shè)計(jì)著,突然,卡住了,一交流,發(fā)現(xiàn),哦原來這不是用戶要的,他們要那樣的,其實(shí)很簡單。
3.出現(xiàn)新需求:會(huì)發(fā)現(xiàn)之前不曾注意的需求,會(huì)加入系統(tǒng)性的需求,如緩存等。
設(shè)計(jì)必須能適應(yīng)這些變化,有些需要通過技術(shù)方法,柔性的容納新變化,將變化點(diǎn)抽象成接口,隔離變化,新需求只要設(shè)計(jì)成新的實(shí)現(xiàn)了即可。有些則只能通過總體過程來適應(yīng),如敏捷過程的高迭代,分批交付,在每個(gè)迭代間能響應(yīng)變化。企圖一次就做出美妙的設(shè)計(jì)是不現(xiàn)實(shí)的,設(shè)計(jì)必須具備響應(yīng)變化的能力。因此,設(shè)計(jì)人員需要:
- KISS:時(shí)刻注意保持簡單性,簡單的方法往往也是最正確高效的。
- 關(guān)注需求:時(shí)刻注意什么是真正的需求,遇到困難,不妨先想想,真的需要解決這個(gè)問題嗎,能換種方式嗎?
- 適度的遠(yuǎn)見:預(yù)見同類需求發(fā)生的可能性,并提前考慮對(duì)策。如看到報(bào)表需要導(dǎo)出成excel,想想是否有生成pdf的可能性,如有必要盡早隔離這種變化。
- 系統(tǒng)性思維:時(shí)刻注意用需求去驗(yàn)證設(shè)計(jì),確認(rèn)設(shè)計(jì)是否滿足需求,滿足的是否牽強(qiáng),是否因假想了需求而增加了額外的復(fù)雜性。
- 全局性思維:思考設(shè)計(jì)會(huì)對(duì)開發(fā)、測(cè)試和部署運(yùn)營造成什么樣的影響,因?yàn)檫@些方面往往存在致命的隱含需求。
- 提升抽象層次:從一次一個(gè)系統(tǒng)轉(zhuǎn)換到一次一個(gè)系統(tǒng)族,考慮所有同類系統(tǒng)的共性和可變性,將共性做成框架,可變性提煉成配置,DSL留到具體項(xiàng)目實(shí)施時(shí)完成。
it知識(shí)庫:研發(fā)的那些事2—設(shè)計(jì)之惑,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。