【深入淺出物件導向分析與設計】第二 ~ 四章、需求收集、需求變更、需求分析

紀錄 O'REILLY 深入淺出物件導向分析與設計 (Head First Object-Oriented Analysis & Design) 的讀後心得,並將範例轉為 C#.Net Code。

什麼是「需求」?

【客戶所需之物】稱之為需求。

「需求」是【系統】為了正確運作所必須做的特定事。

「需求」是【設計】的原動力。

收集需求 - 給客戶所需之物

使用案例(Use Case):A use case describes what your system does to accomplish a particilar customer goal. (使用案例描述系統為達成特定客戶目標所要做的事)

  1. 清楚的價值
  2. 起點與終點
  3. 外部啟動者

每個系統都至少包含一個「使用案例」。「使用案例」除了用來收集需求外,另一個更重要的目的,是找出使用時的例外情況,並做替代路徑規劃,而且是在真實世界中確實可行的。

確認系統中所有的「使用案例」有涵蓋了系統的所有需求。

運用使用案例找出客戶忘了告訴你的事。

需求變更 - 山可移,此情永不渝...現在,情況有變

永遠不變的真理 - 就是【改變】

客戶永遠是對的,只要有付出對等的價格。

每個使用案例至少包含一個「使用情節」,每個使用情節的起點與終點都是相同的,只是路徑不同而已。

透過使用案例接露任何不完整、缺漏的需求,並須考是否需要將其加入系統中。

OO原則:將變化之物封裝起來。

分析 - 將你的軟體帶進真實的世界

本文分析(Textual Analysis):查看使用案例裡的名詞與動詞,並整理出類別與方法。

  1. 名詞:類別
  2. 動詞:方法

分析的目的在於確保軟體在真實世界的情境裡仍能正常運作,而不是只在完美的環境裡運行。

本文分析幫你將使用案例轉換成類別、屬性與操作。

範例

專案:介好鑽狗門

第一個客戶的需求:想要一個由按鈕控制的狗門。

第一次使用:狗狗吠著要出去 -> 主人聽到狗狗在吠 -> 主人按下遙控去按鈕 -> 狗門開啟 -> 狗狗順利出門 -> 狗狗完事後回來了 -> 狗狗順利進門 -> ... (過了一段時間) ... -> 家裡怎麼多了隻兔子??

第一次客訴:「@$&*#%(!^_...)」。

第一次檢討:「我的設計沒問題,是客戶在狗狗進門後,忘記再按一次遙控器將門關上。是客戶使用方式不正確,不是我的錯!

第一次結果:NG,退貨收場。

重新檢討,改變作法,請聽客戶的聲音,了解客戶的需求,建立需求清單,規畫主要路徑與替代路徑,完成第一個使用案例。

//使用案例:狗門(v1.0)
1. 狗狗吠著要出去
2. 主人聽到狗狗在吠
3. 主人按下遙控去按鈕
4. 狗門開啟
5. 狗狗跑出去
6. 狗狗辦它的事
7. 狗狗回來、進門
8. 狗門自動關閉

思考例外情況:萬一狗狗在回來之前,狗門已關上了怎麼辦?

//使用案例:狗門(v1.1)
...
6. 狗狗辦它的事
   6.1 狗門自動關閉
   6.2 狗狗吠著要進來
   6.3 主人聽到狗狗在吠
   6.4 主人按下遙控器按鈕
   6.5 狗門開啟
7. 狗狗回來、進門
...

【需求新增】

第二個客戶的需求:狗狗每次出門都弄得髒兮兮,希望狗狗每次一出去就關門,直到我將它清理乾淨後按下按鈕讓它進來。

第三個客戶的需求:狗狗經常在吠,根本搞不清楚是不是要出去,能設計狗狗抓門時就打開嗎?

//使用案例:狗門(v2.0)
1. 狗狗想出去
case 1 : (for customer #1&2)
	1.1.1. 狗狗吠著要出去
	1.1.2. 主人聽到狗狗在吠
	1.1.3. 主人按下遙控去按鈕
case 2: (for customer #3)
	1.2.1. 狗狗抓門
2. 狗門開啟
3. 狗狗跑出去
4. 狗門自動關閉(for customer #2,但強制擴大到所有用戶)
5. 狗狗辦它的事
6. 狗狗回來
case 1 : (for customer #1)
	6.1.1. 很乾淨、吠著要進來
	6.1.2. 主人聽到狗狗在吠
	6.1.3. 主人按下遙控器按鈕
case 2 : (for customer #2)
	6.2.1. 弄得髒兮兮
	6.2.2. 主人把狗狗清理乾淨
	6.2.3. 主人按下遙控器按鈕
case 3 :(for customer #3)
	6.3.1. 狗狗抓門
7. 狗門開啟
8. 狗狗進門
9. 狗門自動關閉

【需求變更】

第一個客戶的需求變更:由於經常沒注意到狗狗在吠,或找不到遙控器,導致來不及開門,狗狗就直接在家裡完事了。如果能讓狗狗吠的時候,狗門自動開啟就太好了。

新增了「吠聲偵測器」

//使用案例:狗門(v3.0)
1. 狗狗想出去
case 1 : (for customer #1&2)
	1.1.1. 狗狗吠著要出去
	case 1 :
		1.1.1.1.1. 主人聽到狗狗在吠
		1.1.1.1.2. 主人按下遙控去按鈕
	case 2 : (for customer #1 new require)
		1.1.1.2.1. 吠聲偵測器「聽見」吠聲
...
6. 狗狗回來
case 1 : (for customer #1)
	6.1.1. 很乾淨、吠著要進來
	6.1.2. 主人聽到狗狗在吠
	case 1 :
		6.1.2.1.1. 主人按下遙控器按鈕
	case 2 : (for customer #1 new require)
		6.1.2.2.1. 吠聲偵測器「聽見」吠聲
...

實際測試後發現,「吠聲偵測器」在真實世界使用上會有個問題,就是其他狗狗的吠聲,也一樣會出發狗門的開啟與關閉,這並不是客戶所希望的,所以我們需要將其升級為「吠聲辨識器」,來正確辨識客戶狗狗的吠聲。

//使用案例:狗門(v3.1)
1. 狗狗想出去
case 1 : (for customer #1&2)
	1.1.1. 狗狗吠著要出去
	case 1 :
		1.1.1.1.1. 主人聽到狗狗在吠
		1.1.1.1.2. 主人按下遙控去按鈕
	case 2 : (for customer #1 new require)
		1.1.1.2.1. 吠聲辨識器「聽見」"主人的狗狗"的吠聲
...
6. 狗狗回來
case 1 : (for customer #1)
	6.1.1. 很乾淨、吠著要進來
	6.1.2. 主人聽到狗狗在吠
	case 1 :
		6.1.2.1.1. 主人按下遙控器按鈕
	case 2 : (for customer #1 new require)
		6.1.2.2.1. 吠聲辨識器「聽見」"主人的狗狗"的吠聲
...

因此,我們需要為「吠聲辨識器」新增使用案例。

//使用案例:吠聲辨識器(v1.0)
1. 主人的狗對著吠聲辨識器吠
2. 吠聲辨識器儲存主人的狗的吠聲

比較底下三人 Randy、Sam 與 Maria 的類別圖設計,看得出其中差異嗎?孰優孰劣呢?

顯而易見的,Sam 設計了 Mark 類別的方式,比 Randy 單純以 string 做比較的設計更符合低耦合的要求,而 Maria 的設計不但保有 Sam 的優點,更符合現實世界的應用,支援了多種吠聲。

所以,孰優孰劣應該已經很明顯了。