研發的那些事2—設計之惑

作者: Chaos  來源: 博客園  發布時間: 2011-03-10 17:11  閱讀: 1160 次  推薦: 0   原文鏈接   [收藏]  

     設計真是件奇妙的事情,能造就璀璨的明珠,也能帶來一堆萬年不去核廢料;能讓人享受釋放智慧的樂趣,也能品嘗挫敗的沮喪。Why?

  設計的過程

     工程角度,設計是一個過程,包含三種不同層次的活動:架構設計,概要設計和詳細設計。三者由全局到局部,依次展開,逐漸深入細節,最終完成一個技術解決方案,給出可行的如何實現需求的答案。此三者的一般性過程如下:

  架構設計

  目標:定位全局,確定技術方案的方向、后續技術活動策略。

  輸入:需求文檔。敏捷過程常常是是一組用戶故事。

  輸出:架構設計文檔。敏捷過程稱之為應用全局視圖Application Overview。

  角色:架構師

  任務:

  1.分析需求,識別關鍵功能、質量需求和約束

  2.分析目標系統為達成以上目的,需要哪些流程,流程中有多少環節,各環節涉及哪些角色,這些角色的職責及他們之間的協作關系。

  3.將角色按邏輯分類抽象,變成子系統。角色的職責即是子系統的接口,角色間的協作關系即為各子系統間的關系。

  4.各子系統內部,根據職責拆分模塊,確定它們的交互方式。

  5.針對關鍵功能,確定完成這些功能的流程,在時序上由各子系統,模塊協同工作的順序。

  6.考慮各子系統的部署方式。

  7.將各子系統、模塊轉換成實現語言的元素。如對于.net,規劃各子系統有哪些namespace,namespace如何分配到assembly,assembly之間的依賴關系。再將assembly分配到project中。期間需要注意避免循環依賴,明確接口(作為接口的assembly和project)。

  8.規劃project在SCM中的組織結構。

  9.根據質量需求確定全局性的技術策略(方案):如線程控制,錯誤處理,數據存儲等。

  10.分析其余需求,驗證當前方案是否能支持,根據發現的問題做必要調整。

  概要設計

  目標:在具體實現語言層面上展開工作,確定每個project的主要類及交互過程和總體算法。

  輸入:架構設計文檔和需求。

  輸出:概要設計文檔。

  角色:高級程序員

  任務:

  1.設計提供暴露服務的接口的具體實現類,補充所需的相類,通常可按界面(接口)、活動和存儲三方面考慮。進一步落實對項目外接口的依賴關系和位置。

  2.設計算法實現接口暴露的相關功能。

  詳細設計

  目標:確定概設提出的每個方法的具體實現。

  輸入:概要設計

  輸出:偽代碼。

  角色:程序員

  任務:用偽代碼描述每個方法。

     這里看到的是一個按需求->系統->子系統->模塊->類->方法,自頂向下逐步求精的過程。

  設計的技術

     技術角度,設計是一系列方法和工具,通過應用這些方法和工具給出一個可行解決方案的描述。常用方法有:

     OO:面向對象方法。其目的是統一問題的描述與解決方法,通過一致的抽象提高開發效率。核心思想是,將問題空間映射到計算機模型上,在計算機中建立一個同我們日常感知世界相同的模型,解決問題。實踐中,通過類描述問題空間的概念,通過類的消息描述這些概念的交互形成一個模型,再將模型落實到OOP的語言中,如C++,C#,Java等。

     AOP:面向方面的方法。期望將主要業務同這些業務中散落的支撐功能(服務)如日志,權限等分離。結合OOP應用時,通過橫切點定義跨多個類的支持服務,由方面(特殊類)實現這些服務,再通過切入點連接方面與橫切點,達到運行時自動提供服務的目的。

     DDD:領域驅動的設計。采用傳統OO方法時,一般的需求分析結果是用自然語言描述的與OOD存在脫節,容易生造出問題域中不存在的概念,建立與實際需求不一致的模型。因此,從需求分析起,首先為問題域即領域建模,完全不考慮如何設計、實現,用客戶能理解的方法僅描述問題現狀。常用的建模方法是OOA,模型可用UML表達,也可以用類似框圖聯系,總是以能讓用戶明白這就是問題的描述,方便溝通為原則。

     在不斷使用這些方法的過程中,一些大師們發現了某些經常重復的解決方案,便對它們進行了提煉和總結,以便后來者這能利用這些經驗,提高工作效率和質量,少走彎路。這些經驗有:架構風格,架構模式,設計模式和反模式。

  架構風格

     架構層次的,根據系統的架構呈現出的總體特點進行架構分類的方式。主要的風格有:

  1.客戶-服務器:系統分為客戶與服務端兩部分,客戶端發送請求,服務端執行并響應。

  2.分層(級)架構:系統按關注點水平分層,每一層為上層提供一個抽象。近一步,可將層分布到不同計算機上。

  3.面向對象:系統分成單獨的可重用的對象,每個對象包含數據及處理它們的行為。

  4.基于消息(事件):系統各部分通過發送和接收約定格式的消息工作,無需關心實際的收發者。

  5.面向服務(SOA):系統通過約定的契約暴露功能,并根據這些契約工作。

  6.基于組件:系統分解為邏輯的可重用位置透明的組件,通過明確定義的通信接口工作。

  7.管道-過濾器:由管道連接過濾器一組,處理流經的數據。

  8.微內核:分離最小功能核心和可擴展部分。

     它們在最高層次根據問題的類型給出了一般的解決方向。如:

  1.通信問題:基于消息、管道-過濾器

  2.部署問題:客戶/服務器、分層架構

  3.重用與可擴展:OO、基于組件、SOA

     但是,不同風格并不是互相排斥的,相反,一個實際系統通常同時呈現出多種風格。如一個分布系統,功能可通過語言無關的契約暴露,用OOP實現這些契約,實現對象又被組織成一個個組件,每個組件定義了彼此的通信接口,而通信又可是基于消息的,組件本身運行在一個支持插件的容器中,可隨時添加新組件,提供新服務。這里表現出了SOA、OO、Component、Messaging和Mico-Kernel多種風格。

  架構模式

     一系列可重用的架構設計方案,每個方案在滿足適用場景的前提下,解決一種或一類問題。經典的POSA給出了一些常用的模式分類:

  1.服務訪問和配置:包裝器(Wrapper Facade)、組件配置器(Component Configurator)、截取器(Interrceptor)、擴展接口(Extension Interface)

  2.事件處理:反應器(Reactor)、主動器(Proactor)、異步完成標記(ACT)、接收-連接器(Acceptor-Connector)

  3.同步:界定枷鎖(Scoped Locking)、策略化加鎖(Strategized Locking)、線程安全接口(Thread-Safe Interface)、雙檢查加鎖優化(Double-Checked Locking Optimization)

  4.并發:主動對象(Active Object)、監視器對象(Monitor Object)、半同步/半異步(Half-Sync/Half-Asynce)、領導者/追隨者(Leader/Followers)、線程特定存儲器(Thread-Specific Storage)

  5.資源獲取:查找(Lookup)、懶加載(Lazy Acquistion)、預加載(Eager Acquistion)、分步加載(Partial Acquisition)

  6.資源生命周期:緩存(Caching)、池(Pooling)、協調器(Coordinator)、資源生命周期管理(Resource Lifecycle Manager)

  7.資源釋放:租約(Leasing)、清除者(Evictor)

  此類模式給出了全局性問題的一般處理方案,大都是關于子系統、模塊及相互之間關系的粗粒度的描述。

  設計模式與反模式

     設計模式指OO的設計模式,是可反復使用的代碼經驗總結。通過GoF經典的《設計模式》廣為人知。GoF將它們分類為:

  1.創建型:簡單工廠(Simple Factory)、工廠方法(Factory Method)、抽象工廠(Abstract Factory)、創建者(Builder)、原型(Prototype)、單例(Singleton)

  2.結構型:外觀(Facade)、適配器(Adapter)、代理(Proxy)、裝飾(Decorator)、橋接(Bridge)、組合(Composite)、享元(Flyweight)

  3.行為型:模板方法(Template Method)觀察者(Observer)、狀態(State)、策略(Strategy)、職責鏈(Chain of Responsibility)、訪問者(Visitor)、調停者(Mediator)、備忘錄(Memento)、迭代器(Iterator)、解釋器(Interpreter)

它們在代碼層面給出解決上述三類問題的一般做法及使用場景。

     設計模式如紅日般普照大地,光芒萬丈,導致做OO的言必稱設計模式,不用上幾個都不好意思拿去見人。免不了被亂用、誤用,明明需要避光保存的,偏偏加個LED增加照明,還曰節能、低碳。所以不得不需要反模式來撥亂反正。反模式說明了,當在錯誤的時間,錯誤的地點,使用了錯誤設計模式后,出現的嚴重后果,提醒人們過猶不及。

  設計的人員

     今天,從人員角度,設計是一系列扮演不同角色的人員的協作,他們通過某種過程,應用某些技術,相互配合,共同完成一個解決方案。一個采用傳統設計過程的大型系統涉及的角色通常有:

  1.架構師:一個人或者一個團隊,負責將系統分解成子系統和模塊,去頂它們之間的關系(開發期、運行期)并制定相關的技術決策,如部署、開發、性能等。

  2.高級程序員(設計師):負責完成一個或多個子系統、模塊的概要設計。

  3.程序員:負責詳細設計。

  4.項目經理:負責整個活動的任務協調,并根據架構安排開發任務。

  其中,架構師是核心,其工作成果是后續管理和實現的基石。有什么樣的架構,便會有什么樣的開發組織結構。如分層架構,必然會存在界面、業務、持久化及公共模塊的開發職責分配,由不同人(團隊)完成不同層的工作。

     現代軟件,因為規模和復雜性,再也無法由個人獨立完成所有工作,必須依靠協作。協作首先需要分工,明確各工種的職責,個人依照職責行事。分工之后便有了工作的先后次序,不同次序的串聯需要一定規則,便形成了一些過程規范,大家依照規范協同。所以,才有了那么多的軟件工程方法論,開發才有了架構師,設計師和程序員的細分。不能簡單的認為架構師>設計師>程序員,他們主要的區別在于工作范圍的廣度和深度的側重點不同。架構師更廣,程序員工作的更深入。

     為了使用一致的思維考慮問題與問題的解決方法,誕生了OOP。為了分離業務與支持服務,讓不同的人在不同的時間和地方分別解決不同問題,誕生了AOP。為了便于開發人員與用戶達成待解決問題的一致認識,誕生了DDD。

     設計時無論采用何種種過程、技術和人員組織方式,根本目的只有一個:給出關于需求的技術解決方案。

     實際工作中還會碰到一個嚴重的問題,常常發現,要解決的問題,并不是地上的石頭,靜靜的躺在那兒,等你照劍譜揮劍的。經常是,哦,我要砍的不是這塊,是那塊,甚至不是碎石而是需要劈柴,一身武藝無處使。不由怒從心頭,不時問候需求人員或者客戶,干嘛不一次說清楚,寫的仔細點。害我改這改那兒的。對此,Brooks在《設計原本》說:設計的本質是幫助客戶發現他們想要的需求

  設計的本質!

     根本上,解決方案和問題是共同變化的,甚至會相互影響。現實中,需求階段給出的需求,往往是初始需求,隨設計過程的推進,它會奇妙的發生一些變化:

  1.需求描述更精確了:隨著設計深入,發現原來的描述存在模糊的方,需要更精確才能做出設計決策。

  2.需求描述錯了:設計著,突然,卡住了,一交流,發現,哦原來這不是用戶要的,他們要那樣的,其實很簡單。

  3.出現新需求:會發現之前不曾注意的需求,會加入系統性的需求,如緩存等。

     設計必須能適應這些變化,有些需要通過技術方法,柔性的容納新變化,將變化點抽象成接口,隔離變化,新需求只要設計成新的實現了即可。有些則只能通過總體過程來適應,如敏捷過程的高迭代,分批交付,在每個迭代間能響應變化。企圖一次就做出美妙的設計是不現實的,設計必須具備響應變化的能力。因此,設計人員需要:

  1. KISS:時刻注意保持簡單性,簡單的方法往往也是最正確高效的。
  2. 關注需求:時刻注意什么是真正的需求,遇到困難,不妨先想想,真的需要解決這個問題嗎,能換種方式嗎?
  3. 適度的遠見:預見同類需求發生的可能性,并提前考慮對策。如看到報表需要導出成excel,想想是否有生成pdf的可能性,如有必要盡早隔離這種變化。
  4. 系統性思維:時刻注意用需求去驗證設計,確認設計是否滿足需求,滿足的是否牽強,是否因假想了需求而增加了額外的復雜性。
  5. 全局性思維:思考設計會對開發、測試和部署運營造成什么樣的影響,因為這些方面往往存在致命的隱含需求。
  6. 提升抽象層次:從一次一個系統轉換到一次一個系統族,考慮所有同類系統的共性和可變性,將共性做成框架,可變性提煉成配置,DSL留到具體項目實施時完成。
0
0
 
標簽:研發
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()