文章目錄
緒論
不要單獨建模…小組成員要輪流畫草圖,以使每個人都參與其中
並行地創建模型.例如在一塊白板勾勒UML動態視圖的交互圖,同時在另一白板上勾畫出補充性的UML靜態視圖的類圖
開發者應該爲自己進行OO設計建模,而不是創建模型圖後交給其他編程者去實現–這是非敏捷的面向瀑布的方法
在白板上通過繪製UML草圖來建模是我(和衆多開發者)多年來熱衷的方式.然而,本書中大多數UML圖給人的印象並非如此,因爲這些圖是爲了提高可讀性而使用工具精心繪製的.
看來作爲圖的目的有兩種,便於表達和便於接受,這樣看來對於思考過程中的圖應該就不應該有CAD這樣精確的繪製,所以有sketchup
初始階段
在早期迭代中解決高風險和高價值的問題
這樣看來,消除風險也是很有價值的
不斷地讓用戶參與評估,反饋和需求.
在書中理想的情況下,每次發佈就很快得到反饋,從而知道下一個迭代,實際情況恐怕沒這麼快,只能間隔迭代
從上圖可以看出,在一個項目的不同階段,工作內容比例是不一樣的,但是對於endless的產品迭代而言,當進入穩定期後就持續不變了.
設計包裝練習: vision box exercise是Jim Highsmith在Cutter Summit中描述的用於設想陳述的一種有效方法.即團隊分組對產品的包裝盒進行設計,包括包裝盒正面的產品名稱,圖案和關鍵賣點,以及背面的詳細特性描述和運行需求.
記點投片表決: dot voting是一種設置優先級的技巧…通常每人獲得的選票爲列表選項數量的四分之一…其缺點是採納了主流意見,而疏遠了持非主流觀點的成員,可能在今後的溝通中遺留危機
下列列出的是一些跡象,表明你並沒有理解以敏捷精神采用迭代開發和UP的真正含義
- 在開始設計或實現之前試圖定義大多數需求.
- 在編程之前花費數日或數週進行UML建模
- 認爲初始階段=需求階段,細化階段=設計階段,構造階段=實現階段
- 認爲細化的目的是完整仔細地定義模型,以能夠在構造階段將其轉換爲代碼
- 堅信合適的迭代時間長度爲三個月之久,而不是三週
- 認爲採用UP就意味着要完成大量可能的活動和創建大量的文檔
- 試圖對項目從開始到結束制定詳細的計劃
在石油行業中,勘探一個新地域時要經歷以下幾個步驟:
- 確定是否已有足夠的證據或業務案例來證明可以進行勘測鑽探
- 如果有,則進行測量和鑽探
- 提供油田範圍和預算信息
- 其他更多的步驟…
初始階段製品的樣例
- 設想和業務用例
- 用例模型
- 補充性規格說明
- 詞彙表
- 風險列表和風險管理計劃
- 原型和概念驗證
- 迭代計劃
- 階段計劃和軟件開發計劃
- 開發案例
注:在本階段,只完成部分製品.後續迭代中將反覆對其精化
不難想到,按照敏捷的思想,上面交付的產物略顯多了點
總的來說初始階段不是用來做規整需求或者設計,這些都是在細化的過程中逐漸完善的.初始階段更像是一個交接儀式,從外部的,大環境的訴求內化爲系統的要求,其目的是讓各種外部人員不再參與(或者不再作爲主體參與)
用例
這也正是敏捷建模的觀點:建模的最大價值是增強理解,而非記錄可靠的規格說明.正如艾森豪威爾將軍所說:“在即將進行作戰的時候,我經常發現之前制定的計劃根本排不上用場,但制定計劃這項工作卻是必不可少的”
文中用了大量篇幅講解用例,畢竟這是讓用戶參與的重要途徑,而用戶參與又是軟件開發成功的保證.令人驚訝的是作爲一個將作圖的書在這裏降低了圖的價值而強調文字的作用,並且指出(也許是譯者)圖形化的用例使得溝通變得困難.而文字的用例更加結構化
用例有幾種,首先最重要的是主成功場景,比如出售商品,其次是非正式場景,比如退貨,最後是各種奇葩情況的處理,往往是各種如果,比如信用卡失效.
fully dressed use case
- 用例名稱
以動詞開始- 範圍
要設計的系統- 級別
“用戶目標"或者是"子功能”- 主要參與者
調用系統,使之交付服務- 涉衆及其關注點
關注該用例的人及其需要- 前置條件
開始前必須爲真的條件- 成功保證
成功完成必須滿足的條件- 主成功場景
典型的,無條件的,理想方式的成功場景- 擴展
成功或失敗的替代場景- 特殊需求
相關的非功能需求- 技術和數據變元表
不同的IO方法和數據格式- 發生頻率
影響對實現的調查,測試和時間安排- 雜項
例如未決問題
一個完整的例子可以參見書,裏面提到了受衆展現出真實軟件需求的一面
用例的幾個部分的具體含義
- 範圍
範圍界定了所要設計的系統.文中把用例分爲兩類系統用例和業務用例,文中強調的是系統用例,而按照我的理解,系統用例的範圍就是系統的名稱 - 級別
按照文中說法,級別可以有用戶目標級別和子功能級別兩類,user-goal leve是常規的級別,而subfunction-level只是將公共部分抽取出來而已.文中認爲user-goal level=Elementary Business Process - 主要參與者
- 涉衆及其關注點列表
文中非常強調這一點,但是我認爲這一點是困難的.因爲這裏陷入了一個經典的死循環:如果你不通知我我怎麼知道是否需要,如果你不告訴我你是否需要我怎麼知道是否要通知你,這裏恐怕要頭腦風暴下想下所有涉及的人.只有有了所有涉及的人(有些人是隱藏起來的,有些是在後面的流程中才參與進來)才能把他們的訴求都考慮進來.
使用參與者的目標而不是系統的任務可以更加明確,避免遺漏.
而最終,這一切的關注點都要以涉衆可以感知的形式明確
詢問工作目標比詢問工作本身更爲適宜 - 前置條件
這裏是一些需要注意的地方,有些不言自明的地方無需指出(例如電力供應),更一般的情況應當將前置條件理解爲另一個系統的後置條件 - 後置條件
- 主成功場景
- 擴展(替代流程)
擴展是重要的,並且通常佔據了文本的大部分篇幅
擴展連同主成功場景主要描述了執行路徑,對於一些額外的要求(例如顧客要求顯示商品描述和價格)屬於可用性需求
UI vs Essential
文中建議對目標(例如登錄)本身的目標(例如標識身份並被認證)進行思考,目標是有目標,目標的目標也有目標,那麼盡頭是哪裏?無UI的情況.下面是本質風格的準則:屏除用戶界面並且關注參與者的意圖
但是這個是有難度的,每一次向本質的追尋,往往意味着我們有了更多的外延用例.例如出現了生物識別的方式後也許我們纔想到使用口令登錄不是必須的.文中比較了兩種風格的用例
- 本質風格
- 管理員標識自己的身份
- 系統對此身份進行認證
- 具體風格
- 管理員在對話框輸入ID和口令(見圖3)
- 系統對管理員進行認證
- 系統顯示"編輯用戶"窗口(見圖4)
黑盒
black-box use case強調的是職責.對比下面兩種
- 黑盒風格
系統記錄銷售
- 非黑盒風格
系統將銷售信息寫入數據庫(或者更糟糕的:系統執行insert語句)
從這裏可以看出,用例更加的面向業務,更加的抽象與高層,從這個角度上來看如果一個開發人員面對用例時是有很大的自主權的,這樣整個UP過程就更加的清晰,而不是一股腦的希望將各種決策前置從而避免走彎路.
系統邊界
在我看來系統的邊界更像是右邊的情況而不是左邊的情況,系統的邊界難以一開始就劃分清楚,而是不斷精確的.這一點倒是和圍棋很像
有效性
- 老闆測試
你的老闆問:"你整天都做了些什麼?"你回答"登錄系統!"你的老闆會高興嗎?
這也並不意味着要忽略在老闆測試中失敗的用例.用戶認證可能不會通過老闆測試,但卻是重點和難點
- EBP測試
這裏和價值鏈很類似,去尋求小的task然後考察他們的價值 - 規模測試
用例很少有單獨的活動或步驟組成,相反,用例通常包含多個步驟,在詳述形式的用例通常需要3~10頁的文本
下面是一些demo
- 就供應者合同進行協商
比EBP更廣泛,用時更長.更適合作爲業務用例而非系統用例- 處理退貨
能通過老闆測試- 登錄
難以通過老闆測試- 在遊戲板上移動棋子
單一步驟,無法通過規模測試
用例圖
區分人和系統
主要參與者在左側,支持性參與者在右側.看上去就是調用方在左側,被調用的在右側
特性列表
使用用例而非功能列表的一大好處是提供了場景,從而便於理解.
某些商業化銷售的軟件(例如新版本加入某種特性)可能更適合特性列表
另外書中舉例遊戲不太適合用例的形式
總的看來使用哪種方式來描述系統取決於客戶如何認知系統
除了用例
應用專用的領域(業務)規則
例如如何計算商品折扣
詞彙表
術語 | 定義和信息 | 格式 | 驗證規則 | 別名 |
---|---|---|---|---|
UPC | …www.uc-ouncil.org | 分爲幾部分的12位數字代碼 | 第12位是校驗位 | 通用產品代碼 |
另外還可能有與其他元素關係,值域
業務規則
ID | 規則 | 可變性 | 來源 |
---|
一般來說,業務規則不侷限與當前軟件
領域模型
association vs attribute
association 用於實例之間關係,attribute則用於需要記住的信息
一般來說人們會比較實例的址而比較屬性的值
value object更像是data type
ID
考慮這樣的productId,由countryCode+manufacturaterCode+id組成,但是我覺得這樣的情況應該視爲邏輯編碼,除了用來查詢外不應當做唯一id使用,更加不能解析該id,因爲countryCode有可能改變(換了國家),另外manufacturaterCode沒有包含countryCode也是令人奇怪.
number attribute
一般來說涉及到數量的時候會有單位,典型的就是Money
示例
s:開始 r:精化
科目 | 製品 | 初始 | 細化 E1->En | 構造 C1-Cn | 移交 T1->Tn |
---|---|---|---|---|---|
業務建模 | 領域模型 | s | |||
需求 | 用例模型 | s | r | ||
設想 | s | r | |||
補充性規格說明 | s | r | |||
詞彙表 | s | r | |||
設計 | 設計模型 | s | r | ||
軟件架構文檔 | s | ||||
數據模型 | s | r |
從理論的角度來看,理論與實踐應當是一致的
從實踐的角度來講,實踐與理論其實是不同的
System Sequence Diagram
對於用例中一系列特定事件,SSD展示了直接與系統交互的外部參與者,系統(作爲黑盒)以及由參與者發起的系統事件.
不用爲所有場景創建SSD…相反,只需要爲下次迭代所用的場景繪製SSD.同時,不應該花費太長時間來繪製SSD,用幾分鐘或者半小時來繪製即可
SSD是用例模型的一部分,將用例場景隱含的交互可視化
SSD與其他UP製品的關係
可以看出,SSD像是一個更概括的時序圖,它屏蔽了內部的各種交互而將這個系統視爲一個整體.
準則:應爲每個用例的主成功場景,以及頻繁發生的或者複雜的替代場景繪製SSD
爲系統事件和操作命名
scan(itemID)和enterItem(itemID)這兩個名字,哪個更好?
系統事件應該在意圖的抽象級別而非物理輸入設備級別來表達
因此,enterItem要優於scan,因爲前者既捕獲了操作的意圖,又保留了抽象性
如此看來,不同IO設備帶來的不同輸入方式不應作爲SSD中的劃分,簡單來看SSD就只有兩列,用戶和系統
UP階段
- 初始
通常不會在該階段引入SSD- 細化
大部分SSD在細化階段創建
操作契約
後置條件
契約中重要的是後置條件,以下爲一個契約的示例
操作: enteritem(itemID:ItemID,quantity:integer)
交叉引用:用例:處理銷售
前置條件:正在進行的銷售
後置條件:
- 創建了SaleLineItem的實例sli(創建實例).
- sli與當前Sale關聯(形成關聯).
- sli.quantity賦值quantity(修改屬性)
- 基於itemID的匹配,將sli關聯到ProductDescription(形成關聯).
可以看出,其後置條件有些囉嗦,並且是無UI關聯的.
另外用過去時態表達後置條件從而強調他們是觀察結果
概括來說,後置條件可以分爲以下三種類型:
- 創建或刪除實例
- 屬性值的變化
- 形成或消除關聯(精確的講,是UML鏈接)
消除關聯會比較少見,有的時候會以刪除來體現
而刪除也會比較少見,這與法律及各種規定有關
下面再講另一個例子:
操作:makeNewSale()
交叉引用:用例:處理銷售
前置條件:無
後置條件:
- 創建了Sale的實例s(創建實例)
- s被關聯到Register(形成關聯)
- s的屬性被初始化(修改屬性)
在上面的例子中最後一個後置條件是模糊的,這是取決於具體場景下是否能夠理解
系統操作
從上面可以看出,系統操作是用戶的所有操作,即使這些操作並沒有形成前端向後端的調用(這個時候還未考慮前後端交互問題)
對領域模型的修改
考慮下面一個契約
操作:enterSale()
交叉引用:用例:處理銷售
前置條件:正在進行中的銷售
後置條件:
- Sale.isComplete被置爲真(修改屬性)
上面的契約導致了領域模型新增了isComplete字段
個人的一點感悟,詳盡的文檔感覺是把一件事做了兩遍,雖然這樣保證你第二次做這件事的正確但是也導致了更大的工作量並且時間上也不允許
UP階段
- 初始
初始階段不會引入契約,因爲過於詳細.- 細化
…只對最複雜和微妙的系統操作編寫契約