實例化需求:讓團隊溝通無障礙,交付無差錯

實例化需求:讓團隊溝通無障礙,交付無差錯

在多年的IT生涯中,發現一個有趣的現象。項目或者產品出現問題的時候,大家痛定思痛總結教訓,第一個被拎出來說事的,總是需求——需求不明確,需求總變更,需求不全面。我們寫過大而全的需求文檔,也用過敏捷的故事卡片,卻總是無法將需求問題消弭於無形之中。近來有機會接觸到了《實例化需求》的方法論,才真正感覺看到了一絲曙光。所學所練所想,分享於此。

1 什麼是實例化需求

實例化需求這個概念來自於一本書《實例化需求:團隊如何交付正確的軟體》(Specification by Example: How Successful Teams Deliver the Right Software)。

書的作者叫Gojko Adzic,是一名英國的戰略軟體交付顧問。在近十幾年來,一直在各種行業領域(例如財務和能源交易平台、移動定位、電子商務、在線遊戲、複雜配置管理系統等等)從事著程序員、架構師、技術指導和顧問等工作。

就是這位大叔

實例化需求就是Gojko在這十多年的軟體生涯中總結出來的一套行之有效方法。對於它的介紹是這樣的:實例化需求是一組方法,它以一種對開發開發團隊有所幫助的方式(理想情況下表現為可執行的測試)描述計算機系統的功能和行為,讓不懂技術的利益相關者也可以理解,即使客戶的需求在不斷變化,它也具有很好的可維護性,可以保持需求的相關性。從而幫助團隊交付正確的軟體產品。

在我看來,這就是這套方法最牛的地方——幫助團隊交付正確的軟體產品正確這個詞,說起來簡簡單單,但實現起來卻真的很難。

2 我們為什麼使用實例化需求

我們都明白,需求是一切軟體開發的源頭。有了需求,開發才能開始。但,實際情況往往是,當項目發生延期,或是項目測試投產出了問題的時候,第一個被揪出來當替罪羊的也往往是需求——需求不明確!需求總變更!需求不全面!需求沒寫對!

需求人員心裡苦

你們開發也逃脫不了干係!不是應該搞明白了需求才開始開發的嗎?怎麼還會錯?

造成這個問題的無非下面幾種情況。

1)真的沒好好搞清楚需求就開始了開發。

在需求的討論溝通中,很常見的一種情況就是,剛開始說的是要做什麼,為什麼要做,講著講著,大家的探討焦點就變成了怎麼做,如何實現,然後迫不及待地投入到軟體開發之中。很多團隊都會有這樣的誤解:只有開始寫代碼才是真正的幹活,澄清需求的時間並不多。 也許輸入的需求並不足以具體到支撐起一個系統的開發,但卻沒人發現,大家只管埋頭苦幹,這為之後的問題埋下了很大的隱患。

2)項目干係人並沒有對需求有著一致的理解。

常規的需求通常是用自然語言編寫而成的文檔,自然語言本身就會存在著一千個人有一千個漢姆雷特這樣的理解偏差。如果團隊使用的是需求-開發-測試這樣的瀑布流程,需求在產生階段並沒有整個團隊的介入,僅由需求人員負責,在開發之初才移交給開發團隊,即使需求人員和開發人員有理解偏差也很難在第一時間發現。

3)不是我不明白,是這世界變化快。

互聯網時代,軟體致勝只有一個法寶——快。很多人慨嘆,現在的時代過於浮躁,精雕細琢的東西不復存在。而事實是,整個IT界的業態變化得如此之快,如果你再按照從前的項目節奏走下去,當你的產品交付之時,也將是被淘汰之時。如今,大多相互的項目周期是按月來衡量的,項目階段則是以周甚至是天來計數的。 需求變更是常態。 如果團隊期待的是一份大而全,且永不變更的需求文檔,並以此為依據進行開發,那項目延期或者出問題簡直是必然的情況。

4)過於依賴個人的認知結構。

需求從哪裡來?

有的團隊的做法是把用戶提出的需求當做用戶故事的源頭,竭盡全力去實現。但是用戶對於系統和軟體開發並無概念,所以他所說的有可能超過了系統的範疇。再加上用戶也許並不真的像他以為的那麼了解自己,往往把真實的需要隱藏在一個他自以為的解決方案中提出。如果真的照他說的做,那就慘了,只有在交付的時候才能聽到他說——這不是我想要的。

另一種做法是由產品人員把用戶的需求翻譯過來。但是在翻譯的過程中只有產品人員孤軍奮戰。而每個人總有每個人思維的局限性,一定會有想不到的地方。

除了上面的需求問題,還有一些問題也是讓軟體開發團隊深惡痛絕的。

5)可怕的文檔。

傳統需求文檔的養成過程是這樣的:雖然極力想在開發之前全面描繪出軟體理想中的樣子,怎奈各種局限,只有寥寥數筆。此時的需求身材單薄,長相有些刻板但算整潔。

開發中不斷發現需求問題,甚至於到了不改需求沒法開發下去的地步,於是需求被改得日漸臃腫,從瘦弱少女變成身材走樣的中年大媽。

到了開發完成進入測試,測出來bug但趕工期沒時間回歸,這時的法寶又是——改需求!誰讓需求和測試結果一致就不算bug呢?可憐的需求再次挨刀,一副整容手術失敗的沮喪模樣。

這樣的需求可讀性差,可維護性更差。讀的人一頭霧水,寫的人苦不堪言。但非常不幸的是,我們面對的需求文檔卻大多是這副醜陋模樣。

而在所有的需求文檔中,最可怕的莫過於遺留系統的需求。尤其是在你要改造或是重建遺留系統的時候,你徒勞地想從它浩如煙海又不說人話的需求文檔中揪出蛛絲馬跡,最後卻只能仰天長嘆。

6)返工危機

無論是傳統的瀑布模型,還是敏捷的Sprint中,趕在工期之前把代碼寫完,再瀟洒地丟給測試,都是能令程序員開心的事情。

什麼會令程序員不開心呢?那就是測試工程師測出bug,再瀟洒地丟給程序員。

如此往複,沒完沒了。

程序員向測試工程師大喊:你們就不能一次發現所有問題嗎?

測試工程師向程序員大喊:你們就不能早點發現問題改了再交給我嗎?

而項目經理向所有人大喊:再改就要延期了!!!

讓我們來看看實例化需求可以做什麼吧。

實例化需求的核心是,讓項目的所有干係方進行有效的協作和溝通,用實例的方式說明需求,用自動化測試的方式頻繁地驗證需求,從實例化的需求說明和自動化測試用例中演進出一套「活文檔系統」。這套「活文檔系統」既可以有效地對系統進行說明,又可以當做交付驗收的標準

  • 有效的交流溝通確保有足夠的時間澄清需求。
  • 使用舉例的方法澄清需求能在第一時間識別出需求是否足以支撐開發。
  • 所有的干係方參與需求討論,可以確保大家對於交付哪些東西有一致的理解。
  • 具有不同領域背景的干係方一同參加需求討論,可以規避因個人認知局限帶來的需求問題。
  • 」活文檔系統」對於變更有著先天優勢,可以以最少的維護成本維持文檔的相關性和可靠性。又能避免過度說明需求而產生浪費,避免花時間在開發前有可能發生變化的細節上,對於變更天然友好。
  • 採用自動化測試的方法實現業務實例,代碼開發出來即可以驗證,無須經過冗長的手動回歸測試,降低返工。

完美解決上述問題。

3 實例化需求怎麼做

Gojko在書中提出了實例化需求的主要過程模式,包含以下幾個環節:

1、從目標中獲取範圍。

與客戶溝通協作,以用戶的業務目標為起始,通過團隊協作找出可以實現目標的範圍。

Tip1:不要把用戶自以為的解決方案當做系統需求。問他為什麼,想解決什麼問題。由你的團隊討論解決方案,劃定範圍。

Tip2:需要牢記業務目標,為什麼做這件事情,因為開發團隊很容易把關注焦點轉移到怎麼做上。

2、從協作中制訂需求說明。

協作是關鍵詞。目的是讓項目的干係人,包括產品、設計、開發以及測試都參與進來,發揮整個團隊的知識和經驗,排除理解的不一致性,盡量減少個人認知造成的局限。

Tip1:只有團隊準備好實現的時候才開始實例化需求,例如迭代開始時。如果提前開始實例化,有可能在真正開發的時候需求已經發生了變更,又要重來。

Tip2:在協作的過程中需要大家共同建立起項目的領域模型,並在討論中嚴格遵循領域模型,這樣能確保大家對於術語和概念的認知是一致的,討論是在共同的語境中進行。

Tip3:在外部需求不明朗的情況下(例如遺留系統的遷移項目),可以從系統的工作流入手,梳理需求。在梳理系統工作流的時候,不僅關注系統間的調用關係,也要識別出系統間的數據傳遞,識別得越明確,對於舉例越有幫助。

Tip4:需求說明描述的是系統和用戶之間的交互,不應該描述系統流程。也不應該和代碼綁定緊密,陷入技術細節。也不應該過度關注界面。

3、舉例說明。

舉例說明是項目需求交流過程中不可或缺的,團隊中的人領域背景不同,對同一個事物的理解也可能不盡相同,通過舉例說明的方式可以讓目標更一致

在書中,作者提出,功能模塊的例子必須具有精確性(不是簡單的是或否的答案,使用具體的例子)、真實性(使用真實數據,從客戶那兒獲取真實的例子)、完整性(使用不同的數據組合去試驗,利用其他方式去檢驗和測試),並易於理解(不用試驗所有組合,尋找隱含的概念)。

Tip1:例子應該關注用戶和系統之間的交互,而非關注系統本身的處理流程。因此,例子應該包含前置條件、輸入、輸出。前置條件指的是場景發生時,未作為輸入傳遞到本系統中,但是已經存在,且對業務產生影響的數據。

Tip2:當大家用說的方式解釋不清的時候,舉例子是自然而然的選擇。事實上,即使你覺得能說清楚,也應該舉例,以免大家的理解有誤差。例子應該具體而精確,避免使用範圍。例如,不要用某一值「小於10」這一表述,而應該用某一值等於「9」來舉例。

Tip3:在場景特別複雜的情況下,還可以使用流程圖來輔助舉例。使用什麼樣的方式不重要,重要的是這種方式能夠達到在團隊中澄清需求的目的。

Tip4:如果發現實例太複雜,就把它的複雜度降低,分解成若干個實例。例如,對於「如果數量大於10件,或者重量大於50kg,則收取50元運費」這個規則,可以拆分為「數量大於10件」和「重量大於50kg」兩個規則,再來舉出數量為20件和重量為60kg兩個實例。

Tip5:在舉例說明的過程中極有可能會發現之前未能識別出來的潛在概念。當潛在概念出現時,應當把它加入到領域模型之中。

4、提煉需求說明。

雖然協作過程中的需求討論可以建立大家對相關領域的共識,但得到的實例往往包含很多不必要的細節。關鍵實例是從這些實例中提煉出來的,雖然精簡但足以說明業務的實例。並且這些提煉好的實例本身就可以當作交付的驗收條件。

Tip1:摒棄對業務走向沒有影響的實例。例如,當輸入中的購買者欄位是「中學生」「小學生」「大學生」時,如果它們的區別僅在於名稱不同,系統對業務的處理完全一樣,此時應該只保留其中一個實例作為代表。

Tip2:提煉實例可以由簡入繁。可以先把基本的成功情況提煉出來,再逐步推及到各種異常和失敗。關注影響業務規則的實例,關注邊界條件的實例。

Tip3:實例應當有正反兩個方面。比如,有一條業務規則是:對於購買重量在10kg以上的訂單,才收取6元運費。所舉出的實例就應該有正反兩個:一個是重量是11kg,收取運費6元;一個是:重量為5kg,收取運費0元。

5、在不修改需求的前提下,用自動化測試來驗證需求。

自動化測試工具Cucumber

Tip1:測試是為了驗證需求,因此不可以只偏重於測試本身,而忽略了測試和需求之間的聯繫。過度飽和的數據和測試用例的大爆炸是不可取的。

Tip2:還是那句,測試是為了驗證需求,因此不要在測試代碼中引入業務流程或者業務邏輯,不要驗證系統是怎麼做的,而要驗證系統做的事對不對。

Tip3:自動化測試有很多種優秀的工具,但不要執著于于特定工具,認為工具才是解決問題的王道。工具是為了測試服務的。

6、頻繁驗證。

在傳統的流程中,龐大的需求說明往往跟不上實際開發中的需求變更,導致需求文檔在交付之時就已經過時。代碼才是唯一能真正信任的。但是,如果對於需求說明進行頻繁驗證,我們就能及時發現需求說明和系統代碼之間的差異,及時解決它們,從而保證需求說明和代碼是一直同步的。可以像信任代碼一樣信任需求說明。

頻繁驗證的方法有很多,自動部署,持續集成,排除不確定性,對外部系統使用Mock,等等,作者在書中給出了很多建議。

7、利用工具,提取組織良好的、易於尋找的、前後一致的活文檔。

維護需求文檔,通常是件讓人頭疼的事情。過於繁瑣的需求文檔會讓人喪失維護的動力。可是,系統的重構和更新又偏偏需要這樣一份文檔。怎麼辦呢?所幸的是,實例化需求為我們提供了這樣一種省時省力的方式——從自動化測試用例中提取文檔!

提煉出來的需求實例是對系統做了什麼事最有力、最準確、最新鮮的描述。而自動化測試用例又使用了可執行的方式實現了這些需求實例,我們再使用一些工具把自動化測試用例提煉為HTML或是PDF的文本,那麼,砰!一份簡單易懂的活文檔就產生了!水到渠成,簡單易懂,永不過時!

文檔提取工具Relish

在作者的書中關於活文檔有句話我特別喜歡——如果沒有活文檔,任何重大的重構都是自尋死路。

Tip1:活文檔和敏捷中的用戶故事卡有什麼區別嗎?好像很類似的樣子。當然有所不同。用戶故事是用故事的形式描述需求,活文檔則是運用實例。另一個不同是,敏捷的故事卡在Sprint結束之後就沒有用了,通常不會長久保存,而活文檔則是易於保存,同步更新的。

寫到這裡,實例化需求的主要環節已經結束了。毫無疑問,實例化需求是一個好方法。但是,再好的方法也需要人的有力實施才能發揮效果。這其實也是本書作者的一種態度——實例化需求的方法更多的是確保團隊成員之間的協作和溝通,而非推廣工具。希望看到本文的人能讓好方法發揮效用,令產品經理、程序員、測試工程師們的世界變得更美好。

推薦閱讀:

TAG:產品需求 | 軟體開發 | 軟體項目管理 |