l

2017年3月24日 星期五

BDD(20)使用者介面細節放哪裡

March 24 08:20~10:32

屏幕截图 2017-03-24 10.24.05

 

昨晚C. C. Agile活動Teddy分享「SBE、BDD、ATDD、TDD、DDD大亂鬥」,Teddy提到Scenario應該避免描述太多使用者介面的細節,會後有好幾位朋友都問到BDD和使用者介面描述的問題。今天先把時間倒轉,回憶N年前Teddy還在用Use Case描述需求的時候,遇到關於使用者介面的問題。

 

怎樣算使用者介面細節?

首先看一個ATM提款的例子:

Use Case: 提款

  1. 系統顯示歡迎畫面
  2. 使用者放入提款卡
  3. 系統驗證提款卡
  4. 系統顯示輸入密碼畫面
  5. 使用者輸入密碼
  6. 系統驗證密碼
  7. 系統顯示交易選單
  8. 使用者選擇提款
  9. 系統顯示提款金額畫面
  10. 使用者輸入提款金額
  11. 系統驗證使用者存款餘額,確認使用者存款大於提款金額
  12. 系統詢問提款後是否繼續交易
  13. 使用者選擇否
  14. 系統退出提款卡
  15. 使用者拿取提款卡
  16. 系統扣除使用者帳戶內的提款金額
  17. 系統吐出鈔票
  18. 使用者拿取鈔票

Use Case描述系統與使用者的互動關係,上面這個Use Case有18個步驟,請問它有包含使用者介面細節的描述嗎?

提款Use Case的確描述了使用者介面,例如「歡迎畫面」、「輸入密碼畫面」、「交易選單」、「提款金額畫面」,這些使用者介面有些扮演「操作流程串接」的角色,有些則是負責接收使用者提供的資料當作系統的輸入,但Use Case中並沒有提到特定的使用者介面元件,例如按鈕、文字框、顏色、元件位置、元件的ID等資料,初步看起來並沒有描述「使用者介面細節」。

但是,有些人卻認為光是「使用者放入提款卡」這個敘述就是一種使用者介面細節。What The Fxxx…李組長眉頭一皺,為什麼放入提款卡算是介面細節哩?

因為這個描述背後的目的其實是「使用者出示可代表其身分的辨識物」,這個物品可以是提款卡、指紋、眼睛虹膜、臉部辨識、聲紋辨識、QR Code、甚至是一串代碼,而提款卡只是其中一種選項,所以算是實作細節。當然也有人認為這樣子太吹毛求疵了,我家的提款機打死就只支援提款卡,其他的方法一概都不支援。Use Case裡面直接寫出示提款卡不是清楚明白多了,搞什麼抽象化描述哩。

***

需求 VS 設計

雖然提款這個Use Case清楚交代使用者與系統的互動流程,但並沒有包含詳細的畫面。不是都說用戶體驗很重要嗎,如果不提供UI畫面讓Product Owner或stakeholder確認,到時候系統出來才來打槍那不是浪費大家的時間。N年前Teddy的作法是寫好Use Case(需求)之後用VB拉出假畫面(設計),跟客戶討論需求的時候一邊讀Use Case內容一邊對照著假畫面,這樣子客戶比較有「即視感」。Teddy第一次用這種方式做案子的客戶是「洗衣業」,客戶以前從來沒有遇過這種討論需求的方式,但他們卻非常接受這種方式,透過Use Case與假畫面來驗證他們內心對於產品的期望。

使用者介面是一種設計,依據「規格」或「需求」所產生的設計。規格來自於目標,目標定義專案範圍,必須先釐清目標、協作探索規格與範例,再依據規格產生介面設計。如果用相反的方式來產生需求,也就是透過使用者介面來「規範需求」,很可能導致疏於探索使用者需要系統的真正目的(沒有做到do the right thing),而且商業邏輯和介面邏輯混在一起,無助於建立豐富的領域模型(domain model)

需求與設計的界線經常並不是那麼黑白分明,回顧一下《Specification By Example》書中的這張圖,步驟1~4屬於需求探索的階段,步驟5~6屬於實作。雖然思考實作的時候很可能會回頭調整需求,這是一個迭代的過程,但大體來說還是必須從使用者的目的開始思考,由上往下展開。直接從使用者介面(而不是從使用者目的)思考,因為這已經是在討論一種設計方式,很容易卡在介面細節上,例如,icon美不美觀、字要大一點、小一點、畫面layout與配色怎麼安排,而忘了原本想達到的目的是什麼。最後就算是產品的品質很高,畫面精美,但因為需求搞錯方向,變成do the wrong thing right也是白搭。

屏幕截图 2017-03-22 09.48.24

***

啊不然介面細節要放哪裡?

下圖節錄自《BDD in Action》,軟體開發的規格依據需求與實作可分成:

  • 需求規格:在BDD中用Feature檔案與Scenario來表達,這也對應到specification by example的概念,可以使用Cucumber或SpecFlow這類的工具來表達。
  • 實作規格:用單元測試或RSpec、Spock來記錄。

屏幕截图 2017-03-24 09.54.45

 

但是以上都沒提到使用者介面細節。沒錯,Teddy認為BDD與OOAD對於規範與紀錄使用者介面細節的助益不大,它主要關注系統行為與實作(domain model)的規格,而非使用者介面。使用者介面怎麼設計,應該用它自己的規格或設計方式與文件,這種文件的目的並不是期望開發人員撰寫類似Cucumber的step definition將其自動化,而是提供給人機介面設計師實作參考。至於驗證使用者介面的目的,則應思考:

  • 系統中大部分的自動化測試案例應該是單元測試,約佔70%。
  • 自動化GUI測試應該是最少的,介於1%~5%之間。
  • GUI儘量不要包含複雜的邏輯,可以簡單到不太可能出錯就不需要太多自動化測試。
  • 當人工測試的投資報酬率大於自動化GUI測試的時候,採用人工測試即可。

***

友藏內心獨白:是行為驅動(behavior driven)不是介面驅動(GUI driven)。

2017年3月23日 星期四

[還少一本書] BDD in Action

March 23 05:52~07:05

屏幕截图 2017-03-15 15.35.30

 

昨天介紹完《Specification By Example》今天緊接著介紹《BDD in Action》,這兩本書都是Manning出版社所出版。從約20年前買了一本Manning出版的Java網路程式設計的書之後,Teddy一直都很喜歡這個出版社的書。如果要學一樣新技術,Manning所出版的書一定是Teddy優先考量的對象。昨天提到《Specification By Example》書中介紹7個流程模式,並沒有介紹工具也沒有程式碼。《BDD in Action》剛好跟它互補,講了很多工具與程式碼。對於學習BDD的人來說,這兩本書一起服用效果更佳。

***

看圖說故事

▼下圖節錄與修改自《BDD in Action》。

屏幕截图 2017-03-23 06.12.01

 

圖中將BDD開發流程分成6個步驟,和昨天介紹SBE的7個流程模式很接近:

  • Business goal:這一步對應到昨天SBE提到的第1個流程模式Deriving scope from goals
  • Features:這一步可視為SBE第2個流程模式Specifying collaboratively的產出物。
  • Examples:相當於SBE第3個流程模式Illustrating using examples
  • Executable specifications:相當SBE第5個流程模式Automating validating without changing specifications
  • Low-level specifications:從這個步驟開始則是銜接到傳統以單元測試為主的TDD範圍,這裡的low-level specifications就是TDD中的第一個步驟,先寫一個失敗的測試案例作為production code(application code)的規格。
  • Application code:就是TDD的第二個步驟,撰寫production code。如果完全對應TDD應該還有第7個步驟Refactoring(重構)才對,但上圖並沒有把Refactoring特別獨立成一個步驟,所以這個步驟可以看成寫production code加上Refactoring。

上圖步驟1~4可以視為傳統上BDD/ATDD的主打範圍,而5~6則是傳統TDD的守備範圍,而步驟4銜接到步驟5則是Teddy在〈BDD(12) 第二個開發票Scenario:從BDD到TDD〉與〈BDD(13)新劇情找到新Bug〉所介紹的轉換過程。

***

把圖展開

上圖並沒有包含SBE其他三個流程模式:Refining the specification、Validating frequently、Evolving a documentation system,下圖是書中上圖的原圖,可以看到步驟4~5展開後,包含了:

  • Living documentation:對應到SEB的Evolving a documentation system
  • Real-time progress reports:對應到SEB的Evolving a documentation system
  • Technical documentation:對應到SEB的Evolving a documentation system
  • Automatic validation:對應到SEB的Validating frequently
  • Working feature:對應到敏捷宣言的Running software或Scrum的Potentially shippable product increment。

屏幕截图 2017-03-23 06.38.22

 

雖然圖中還是沒有特別標示SBE的Refining the specification這個流程模式,但只要把步驟2和步驟3解讀成來回探索的過程,就等於對應到Refining the specification流程模式。

***

如何閱讀

Teddy是先讀了《Specification By Example》(2011年出版)之後才讀了《BDD in Action》(2014年出版)。第一次閱讀《Specification By Example》的時候因為書中完全沒有程式範例,光是看到書中對於這7個流程模式的文字說明覺得稍嫌抽象。後來讀了《BDD in Action》之後,整個感覺的豁然開朗了起來,兩本書互相對照,幾乎可以說《BDD in Action》就是《Specification By Example》這本書的具體範例啊。

對於沒有讀過這兩本書的鄉民,看完這兩篇介紹之後,Teddy建議直接讀《BDD in Action》再回頭讀《Specification By Example》這種閱讀順序。但是,讀《BDD in Action》也有一點小門檻,因為書中所介紹的工具與程式範例非常多,真的要全部搞懂需要很有耐心學習。

***

友藏內心獨白:讀書也需要實例化範例參考比較容易理解啊。

2017年3月22日 星期三

[還少一本書] Specification By Example

March 22 09:00~10:54

屏幕截图 2017-03-15 15.39.38

 

今年因為在北科兼任的「軟體生命週期管理」課程中教BDD,加上明天晚上在C. C. Agile要分享「SBE、BDD、ATDD、TDD、DDD大亂鬥」這個題目,從農曆年後又把《Specification By Example》(以下簡稱SBE)這本書拿出來讀了一次。第二次讀這本書比較有感覺,趁著記憶猶新的時候介紹這本書的內容。

 

從封底開始看

這本書的內容在英文版的封底已經簡短提示四個重點:

  • Common process patterns:本書包含7個「process patterns」(流程模式),書中從Part 2開始用了7章的篇幅來逐一介紹這7個模式。雖然作者用「模式」這個詞彙來介紹他所提出來的7個套用SBE的流程,但書中並沒有使用大家熟知的模式格式。作者提到用模式來記錄SBE的知識還需要一段時間,所以他先把手邊有的資料用比較隨興的方式介紹。希望假以時日這些知識可以被整理成更正式一點的模式,造福像Teddy這種模式愛好者。
  • How to avoid bad practices:既然書中提到7個流程模式,自然就會提到那些不好的做法會偏離這些模式,以及如何避免誤踩雷區。
  • Fitting SBE in our process:書中介紹的7個流程模式並沒有綁定任何特定工具,讀者融會貫通之後可以自行吸納到自己的開發流程之中。例如,在Scrum、XP或Kanban中套用SBE。
  • 50+ case studies:模式之所以被稱為模式,是因為模式針對重複出現的問題提出一個通過驗證的解決方案。本書是作者訪談超過50個案例並加以研究之後所整理出的7個流程模式,書中有大量的業界實踐SBE的佐證資料。書中Part 3特別用了6章來詳細介紹6個不同的案例,值得參考。

***

7個流程模式

本書的7個流程模式為:

  • (1)Deriving scope from goals:專案的範圍要如何界定?如果沒有目標,在專案進行的過程中一下子業務說加入A這個功能產品絕對超級賣,行銷說沒有B這個功能無法跟別人競爭,老闆說A.B…Z這幾個功能優先權都是1。照單全收的情況下最後導致功能膨脹,但預計上市的時程又不能延後。開發人員只好加班趕工,想辦法讓系統「看起來可以動」先過了這一關再說。專案團隊成員爆肝也就算了,更慘的是東西好不容易做出來才發現並不是客戶心中所想要的。沒有人要對這一片混亂負責,最後又怪開發人員做太慢、bug太多。

以上慘劇每天都在發生,這當然是大家想要避免的。所以專案的範圍必須從目標作為出發點,思考這個專案到底要給客戶和公司帶來什麼好處,採用「以終為始」的思考方式,對於達成專案目標沒有直接貢獻的功能應該加以排除,以免做白工。

  • (2)Specifying collaboratively:目標確定之後專案的規格要由誰來定?剛學Scrum的朋友可能會說:「需求是Product Owner負責的啊」需求是由PO排定優先順序這是沒錯,但並不是說所有需求都是PO一個人寫出來的。從敏捷開發的角度來看,需求是團隊一起討論出來的,這當然包含團隊與stakeholder的互動。SBE更加強調這一點,因此提出協作制定需求規格的建議。
  • (3)Illustrating using examples:規格不管是由一個人或是團隊討論而得出,不同的人對於相同規格總是有不同的解讀,這是因為語言與文字存在著模糊性。例如,雖然法律以及大法官對於警察臨檢有著明文規定與解釋令,但不同人對於「警察是否可要求穿拖鞋到小七買飲料的歐吉桑出示身分證」這件事卻很可能有著截然不同的見解。如果可以搭配案例(example)來輔助說明規格,如此不但可以減少對於規格的誤解,這些案例還可以做為日後相同事件發生時的檢驗標準(驗收測試)

屏幕截图 2017-03-22 10.25.40

 

  • (4)Refining the specification:理解與梳理規格是一個迭代的過程,隨著案例一個、一個出現,專案團隊與stakeholder對於規格越來越清楚,因此需要回頭整理原先的規格。
  • (5)Automating validating without changing specifications:等到規格與例子都整理得差不多了之後,就可以開始自動化。這個自動化的過程對應到Cucumber工具就是撰寫step definition,Teddy在BDD系列文章中已經舉過很多次例子。第5條流程模式的重點是:「自動化驗證而無須修改規格」,要做到這一點剛開始並不是很容易,實際做法可參考〈BDD(19)幫開發票功能加上使用者介面的三種方法〉。
  • (6)Validating frequently:既然已經把對於規格的驗收條件給自動化了,就必須要經常驗證這些條件,以確定系統進度與確保系統品質。
  • (7)Evolving a documentation system:最後,這些可自動執行與驗證的規格、例子與程式介面便成為系統的活文件(living documentation)。因為文件內容是由stakeholder與專案團隊共同討論,而且文件與程式碼隨時保持同步,因此是具備實際參考價值的活文件,而不像很多專案文件與程式已經不同步,變成沒有參考價值的死文件。

▼以上7個流程模式可以用下圖表示

屏幕截图 2017-03-22 09.50.59

***

讀中文版還是英文版?

經過Teddy這一番解釋,鄉民們先在腦袋裡面建立起這本書的概念圖,然後再去讀這本書應該比較容易看得懂。這本書有出正體中文版,Teddy也買了一本,內容翻譯的不錯。但是,Teddy對於正體中文版有一點覺得非常、非常的傻眼,那就是:「Specification By Example為什麼要翻譯成『Spec.實例化』?」把一個完整的名詞拆成兩半,前面用英文後面用中文讀起來真的不太習慣,讀正體中文版的時候每看到一次「Spec.實例化」就好像撞到一次牆一樣,思緒就被中斷一次。為什麼不用「實例化規格」、「規格實例化」或是直接用SBE都好。因為這個名詞貫穿整本書,用了「Spec.實例化」這個翻譯真的讓Teddy每看到一次心中就碎念一次啊。

***

友藏內心獨白:這是介紹SBE還是介紹Pattern啊。

2017年3月21日 星期二

【工商服務】看板方法:科技企業漸進變革成功之道(平日班)

March 21 07:50~08:13

屏幕截图 2017-03-21 07.59.54

 

你的專案遭遇到很多問題:一個團隊同時需要處理多個專案、時程延遲、團隊士氣低落、人員流動率高、加班情況嚴重、技術停滯不前、老闆或業務單位不斷地塞新需求。針對以上問題,Scrum敏捷開發法提供了不錯的解法,但是正所謂施政要「因地制宜」,治病要「對症下藥」,有時候Scrum這帖藥方可能不適合你的公司或團隊,因為:

  • 公司採用瀑布式(waterfall)開發流程,短時間不太可能改成Scrum這種敏捷方法。
  • 你是專門搶案子的資訊服務業者,你的團隊手上同時負責很多專案,而Scrum建議一個人最好同時間只處理一個專案,和你的現況衝突。
  • 你的團隊主要在開發新產品,但三不五時會有舊產品的維護需求跑出來,而且這些臨時性的需求都很急,必須要立即處理,因此打亂了Scrum的開發步驟。
  • 你的工作內容與「消防隊員」類似,專門處理突發事件,例如使用者回報的bug修正、客訴案件、公司IT維護與營運專案,不容易在固定的時間點(每個sprint開始的時候)朝開會議安排工作,而需要採用事件驅動的方式,即時的處理需求。
  • 你的團隊成員比較無法一下子接受過於激烈的組織與工作模式調整,依據Scrum的建議立即組成跨職能團隊(cross-functional team)。
  • 雖然可以從Scrum的工作看板(task board)得知每項工作狀態,但標準的工作看板只有「位施工」、「施工中」、「已完成」這三個狀態。你想要可視化更詳盡的工作流程,並從其中觀察出工作瓶頸以求改善之道。
  • 你是老闆、高階主管或專案經理,其實你不關心什麼敏捷不敏捷、精實不精實的,你只想要有一種比較好的方法來管理專案,方便你「切票(切割工作)」和「派票(分派工作)」,以及知道團隊的進度、工作效率和生產力。
  • 你已經採用Scrum,執行成效還不錯,但在開發流程與品質的持續改善方面遇到瓶頸。

 

如果你的專案具有以上任何一種「症狀」,都值得了解另外一種新的敏捷/精實開發方法:看板方法(Kanban Method)。看板以「可視化現有工作流程」為起點,先不要求團隊做出巨大的改變,以減少採用新方法的抗拒。接著,依據團隊的現有人力,設定每一個工作階段的同時施工項目上限,以協助團隊成員聚焦於「把工作完成」,而非不斷地製造「賣不出去的半成品」。 透過視覺化工具,看板方法可協助團隊找出工作瓶頸,並藉由五步驟聚焦法協助排除瓶頸,達到改善團隊工作效率,提升工作品質的目的。

看板可以應用在以下狀況:

  • 幫助新創公司要管理開發流程以便快速找到市場定位
  • 協助開發團隊有效管理手上同時進行的多個專案
  • 增進Scrum團隊的敏捷性與觀察問題的能力
  • 協助擴展大型敏捷開發團隊(例如Scaled Agile Framework, SAFe)
    • 管理IT維護與營運專案的事件驅動型工作
    • 以漸進且比較無痛的方式實施敏捷開發方法
    • 透過視覺化管理工作流程以便觀察與突破工作瓶頸

     

    螢幕截圖 2015-04-26 21.36.24

    ▲課程實況照片。

    ***

    報名網址在此:【看板方法與精實開發實作班】,上課日期2017年4月25、26日(二、三)。

    image

    ***

    友藏內心獨白:流程改善從此開始。

    2017年3月20日 星期一

    BDD(19)幫開發票功能加上使用者介面的三種方法

    March 20 08:01~10:08

    屏幕截图 2017-03-20 09.51.35

    ▲終於要幫開發票功能接上使用者介面了

     

    前言

    在〈BDD(18)這是一個End-To-End的Scenario嗎?〉提到scenario儘量不要描述太多使用者介面(UI)的細節,如果要透過UI做自動化驗收測試則可以把連結到UI的程式碼寫在step definition裡面。今天介紹在「開三聯式發票scenario」加上網頁介面的三種方法。

    ***

    直接修改Scenario

    ▼第一個最簡單的方式就是直接修改scenario,加上透過UI操作系統的描述。例如把原本的scenario從這樣:

    屏幕截图 2017-03-20 08.29.10

     

    ▼加上「Given I am on the invoice Web page」步驟,改成這樣:

    屏幕截图 2017-03-20 08.30.01

     

    ▼如此一來只要在「Given I am on the invoice Web page」的step definition中連結到操作invoice功能的網頁就可以透過UI讓這個scenario變成完整的end-to-end scenario。

    屏幕截图 2017-03-20 08.36.23

     

    ▼這種方法並沒有描述UI細節,只增加一個步驟描述這個scenario的入口點,其實是可以接受的方法。如果一個feature檔案中有多個scenario,也可以利用Cucumber的Background功能,統一把「Given I am on the invoice Web page」放在Background中,這樣就不用每一個scenario都重複描述。

    屏幕截图 2017-03-20 08.39.57

     

    如果覺得日後開發票功能可能會改成手機或桌機版本,到時候要把「Given I am on the invoice Web page」改成「Given I am on the invoice App screen」這樣很麻煩,也可以把這句改成更中性一點的敘述:「Given I am using the invoice function」,這樣子scenario要接Web、App、或桌上型應用軟體只要改step definition的內容就可以,不需修改feature檔案(不用改需求)。

    ***

    寫在Step Definition裡面

    ▼如果想維持原本的scenario敘述不變,但又想要透過UI來自動化這個scenario。

    屏幕截图 2017-03-20 08.29.10

     

    ▼第二種做法就是直接把連結到UI的程式碼寫在step definition裡面。這種做法的好處是scenario專心描述企業邏輯,當真的需要連結到UI的時候只需要修改step definition即可,不用動到scenario。

    屏幕截图 2017-03-20 08.51.01

     

    這種做法有兩個小缺點,首先從scenario檔案看不出每一個scenario的明顯「入口點」。第二個缺點是step definition內容變得有點亂,原本step definition是協助開發人員探索與定義系統實作的介面,現在夾雜了UI的自動化測試程式,很容易混淆原本的意圖。

    ***

    增加Support Layer

    ▼原本使用Cucumber的步驟由定義feature file開始,接著撰寫step definition,然後透過TDD的方式來完成domain object(production code)的設計與開發。因為step definition直接操作domain object,所以如果要加上透過UI來操作domain object就必須要修改step definition。

    屏幕截图 2017-03-20 08.09.40

     

    ▼為了讓step definition更乾淨,可以在step definition與domain object之間增加一個support layer(支援層),透過這一層來操作domain object。如此一來便可把UI的細節封裝在support layer。

    屏幕截图 2017-03-20 09.04.43

     

    ▼原本step definition直接操作domain object,現在改成透過KnowsTheDomain類別來操作domain object。

    屏幕截图 2017-03-20 09.18.59

     

    KnowsTheDomain類別很簡單,只是把原本step definition直接操作domain object的程式碼封裝在這裡而已。

    屏幕截图 2017-03-20 09.17.02

     

    現在思考一下如何重構(refactor)讓我們可以輕鬆切換有UI和沒有UI的自動化驗收測試。在原本的domain object中,開發票的責任由InvoiceBuilder類別負責,只要能夠提供兩種InvoiceBuilder的實作,一種是原本的實作,另外一種是包含UI的實作,如此一來只要讓KnowTheDomain類別的getInvoiceBuilder函數可以依據設定傳回不同的InvoiceBuilder類別實作,就可以達到「輕鬆切換有UI和沒有UI的自動化驗收測試」的目的。這種做法不需要修改scenario,也不用動到step definition。

     

    ▼首先套用Extract Interface重構,把原本InvoiceBuilder類別的介面抽離出來。

    屏幕截图 2017-03-20 09.38.18

     

    ▼原本的InvoiceBuilder類別改名為InvoiceBuilderImpl,並且實作剛剛抽離出來的InvoiceBuilder介面

    屏幕截图 2017-03-20 09.40.31

     

    ▼新增WebInvoiceBuilder類別,讓它繼承InvoiceBuilderImpl。複寫issue函數,在開發票的時候打開瀏覽器連到開發票系統的網頁畫面,透過網頁完成開發票的動作。

    屏幕截图 2017-03-20 09.42.37

     

    ▼最後透過dependency injection容器(在此使用picocontainer),讀取設定檔來判斷要注入WebInvoiceBuilder類別實例還是InvoiceBuilderImpl類別實例。

    屏幕截图 2017-03-20 09.46.12

     

    ▼如果要透過網頁測試,在設定檔中加入這一行。

    屏幕截图 2017-03-20 09.49.35

     

    ▼執行驗收測試,首先連結到開發票網頁,自動輸入含稅金額與稅率,按下開發票按鈕。

    屏幕截图 2017-03-20 09.51.58

     

    ▼接著看到計算後的稅額和未稅金額。

    屏幕截图 2017-03-20 09.51.35

     

    ▼當然驗收測試也是通過的。

    屏幕截图 2017-03-20 09.52.26

    ***

    結論

    今天介紹三種scenario串接UI的方法,各有其優缺點。第三種方法看起來最漂亮,但需要花多點設計與重構的功夫。如果鄉民們想要使用第三種方法但覺得scenario裡面沒有敘述功能起始點怪怪的,也可以結合第一種和第三種方法,把功能起始點描述在feature檔的Background裡面,scenario連結UI的實作方式則是用第三種方法來完成,這樣子應該就接近完美了XD。

    ***

    友藏內心獨白:什麼接近完美,明明就很麻煩…Orz。

    2017年3月17日 星期五

    BDD(18)這是一個End-To-End的Scenario嗎?

    March 17 08:58~10:40

    屏幕截图 2017-03-17 10.34.52

     

    考考你

    敏捷開發是一種「價值驅動」的方法,為了交付價值給用戶,user story應該要表達成end-to-end。當stakeholder、PO、開發團隊透過討論之後寫出user story,接著舉出這個user story具體的例子之後,就可以進入開發階段,透過Cucumber、SpecFlow、JBehave、Fit/FitNess、Robot Framework等工具將此scenario自動化。

    ▼下圖是一個Cucumber的例子,鄉民們先把feature類比成user story(概念上feature的粒度較大,可能包含一個或多個user story),scenario就是feature(user story)的一個例子(example,一種執行路徑)。

    屏幕截图 2017-03-17 09.02.06

     

    從敏捷開發的角度來看,既然user story應該寫成end-to-end,那麼身為user story的一種執行路徑的scenario理論上應該也是end-to-end比較合理。針對這個問題,昨天在北科上「軟體生命週期管理」的時候Teddy問學生:「上面這個Scenario是一個End-To-End的Scenario嗎?

    經過討論之後學生的看法分成兩派:

    1. 不是:這個scenario沒有描述使用者介面,使用者無法直接使用,所以不是end-to-end。
    2. 是:這個scenario描述「開三聯發票的系統行為」,雖然從字面上看起來並沒有提到使用者介面,但是使用者介面是一種實作細節,可以在step definition裡面描述。如此一來不管是透過網頁,或是透過手機App來實作這個scenario,都不用改修改它。

    ***

    看似無聊但很重要

    ▼這個問題好像很無聊但實際上卻非常重要,因為它會影響落實BDD的方向,甚至是成敗的重要因素之一。依據BDD發明人Dan North對於BDD的定義:

    屏幕截图 2017-03-17 09.35.30

     

    首先看到outside-in這個字:由外而內,或是用更傳統的說法,由上而下(top-down)。看到由外而內很自然會認為BDD在描述scenario的時候應該從系統最外面,「也就是使用者介面」開始。所以在網路上或書上經常會看到類似的例子:

    Scenario: Login

    Given I am on the login page

    And I input id as “John”

    And I input password as “pwd321”

    When I press the login button

    Then I should be directed to the welcome page

    接著在step definition裡面就看到實作程式碼呼叫Selenium開啟網頁,選擇DOM的某個元素,輸入Scenario中所描述的帳戶、密碼(在這裡是John/pwd321),然後再按下login按鈕,最後驗證網址跳到welcome 頁面。

    這種例子如果是從介紹「工具」,例如Cucumber、SpecFlow、Selenium的角度來看,是很簡單易懂的好例子,但從BDD的角度來看,就不是那麼合適。因為BDD強調透過stakeholder、PO、開發人員的溝通來建立起「通用語言(Ubiquitous Language)」,這個通用語言正是後續開發活動以及living documentation(活的文件)的核心基礎。如果scenario都是從使用者介面切入撰寫,這樣的scenario頂多只是「自動化驗收測試」的文字版本,離「specification by example」還有一大段距離。

    學過use case的鄉民可能還記得,撰寫use case的時候儘量不要相依於使用者介面,這個原則在BDD撰寫scenario的時候同樣適用。物件導向分析與設計(OOAD)透過use case來建立domain model(找出問題領域的重要概念,這些概念在設計階段會變成類別、介面、屬性、或關係)。同樣地,BDD透過scenario(例子)來建立domain model、介面、屬性、關聯。如果你的scenario都在描述使用者介面的元件,step definition裡面都在呼叫Selenium操作網頁元素,那十之八九你的BDD已經變成透過使用者介面驗證系統行為,你的「物件村(domain model)」很可能人丁單薄,很多商業邏輯不是寫在介面中,很可能就直接寫在資料庫中(stored procedure)。

    ***

    所以哩?

    針對以上的討論Teddy有幾點結論:

    • 為了專注於交付價值以及建立通用語言,BDD的scenario應該還是要保持end-to-end或是接近end-to-end。只不過end-to-end裡面關於前端,也就是使用者介面的細節,可以不要直接寫在scenario裡面,而是擺在step definition或是另外建立一層實作輔助層裡面
    • Outside-in(由外而內)並非一定要從使用者介面開始,它的意思應該是從任何你有興趣的事物外圍開始,然後逐步往內探索
    • Cucumber、SpecFlow、JBehave、Fit/Fitness這些工具只是支援BDD開發流程的一(小)環,並非全部。透過工具無法得知BDD的全貌。這也是為什麼《Specification By Example》這本書完全沒有從工具面去討論SBE/BDD要怎麼做,而是把重點放在7個流程模式( process pattern)
    • 你在撰寫use case所曾經犯過的錯誤,絕大部分在用Given-When-Then撰寫Scenario的時候也都可能再次出現。
    • 只要是以物件導向的方式開發軟體,modeling的技能都是重要的。採用BDD/TDD不會讓你自然產生好的domain model。

    ***

    友藏內心獨白:OOAD的知識還是很有用。

     

    延伸閱讀

    2017年3月16日 星期四

    使用Spock規範類別行為 (下):定義Stack行為

    March 14 16:50~18:50; 21:25~22:12

    屏幕截图 2017-03-14 22.00.08

    ▲節錄自Spock官網

     

    前言

    依據〈使用Spock規範類別行為 (上):在IntelliJ IDEA使用Groovy〉所介紹的步驟,現在已經可以在IntelliJ IDEA使用Groovy,但是要使用Spock還需要設定Maven的pom.xml檔案以及在IntelliJ IDEA安裝Spock外掛才算整個環境設定完成。

    ***

    在Java(Maven)專案中使用Groovy

    ▼確定Groovy安裝成功之後,Teddy最終的目的是要在Java專案中使用Spock來規範類別行為。首先新增一個Maven專案叫做SpockTutorial,在pom.xml檔案中加入。

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12version>
            <scope>test</scope>
        </dependency>
       <dependency>
           <groupId>org.spockframework</groupId>
           <artifactId>spock-core</artifactId>
           <version>1.1-groovy-2.4-rc-3</version>
       </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.9</version>
        </dependency>
    </dependencies>

    ▼在test目錄下新增groovy目錄,請注意此時groovy目錄還不是綠色的。

    屏幕截图 2017-03-14 17.48.17_thumb

    ▼這時候在groovy目錄按滑鼠右鍵,選擇New,只出現新增Groovy Script,並不能新增Groovy Class,表示還沒設定完畢。

    屏幕截图 2017-03-14 17.43.52_thumb[1]

     

    ▼在groovy目錄按滑鼠右鍵,選擇Mark Directory as—>Test Sources Root。

    屏幕截图 2017-03-14 17.45.47_thumb[1]

     

    ▼此時groovy目錄變成綠色,按下滑鼠右鍵出現Groovy Class。

    屏幕截图 2017-03-14 17.54.43_thumb[1]

    ***

    安裝Spock外掛

    ▼選擇IntelliJ IDEA—>Preferences…

    屏幕截图 2017-03-14 17.54.00

     

    ▼在Plugins分類中搜尋spock,沒找到任何東西因為還沒安裝。點選畫面中央的Search in repositories。

    屏幕截图 2017-03-14 17.55.29

     

    ▼找到Spock Framework Enhancements外掛,選擇Install。

    屏幕截图 2017-03-14 17.55.36

     

    ▼安裝完畢之後選擇Restart IntelliJ IDEA。

    屏幕截图 2017-03-14 17.55.46 

     

    ▼這時候選擇New就會看到Spock Specification選項。

    屏幕截图 2017-03-14 17.56.10

    ***

    Eiffel語言定義Stack的行為

    Design By Contract(DBC,依合約設計)是一種很知名用來定義類別行為的方法,在練習用Spock定義類別行為之前先看一下Eiffel語言對於Stack的push與pop這兩個函數行為的合約。其中require代表定義pre-condition,ensure代表定義post-condition,這就是合約(contract)。

    屏幕截图 2017-03-14 18.28.40

     

    ▼以下是pop函數的合約,invariant關鍵字定義class invariant,代表無論何時只要物件存在都必須要滿足的條件。Class invariant也是合約的一種。

    屏幕截图 2017-03-14 18.28.47

    ***

    用Spock定義Stack行為

    ▼以下是Teddy所寫的StackSpec類別,它繼承了Spock的Specification類別。StackSpec有兩個函數,分別用來定義push與pop的行為。請鄉民們仔細比對StackSpec與上面Eiffel語言範例,從定義行為的角度來看,此兩者是相近的(扣除掉class invariant不論,因為Teddy還不知道如何在Spock規範類似DBC的class invariant)。在StackSpec類別中Teddy特別用given-when-then格式來定義Stack的行為,讓鄉民們比較一下DBC和given-when-then的差異與相似處。

    屏幕截图 2017-03-15 10.05.38

     

    ▼執行結果,兩個測試案例(可執行規格)都通過。以上這兩個測試案例當然也可以用JUnit的單元測試來表達,只不過用Spock看起來比較接近自然語言,可讀性比較高一些。

    屏幕截图 2017-03-14 21.29.21

    ***

    延伸閱讀

    • Martin Fowler有一篇文章〈SpecificationByExample〉提到Specification By Example(在此可視為BDD同義字)和Design By Contract(DBC)之間的比較與應用時機。DBC的概念源自於傳統定義語意的正規方法(formal method),雖然DBC比起正規方法已經簡單很多但也還是比不上用例子來定義行為(規格)要來的簡單。DBC的倡導者對於用例子來定義行為有所批評,但物件的行為真的要全部都用合約(contract)來定義其實並不容易,有時甚至是不太可行。雖然Martin Fowler從來沒有機會用Eiffel語言來完整使用DBC,但他提到在定義介面(interface)的時候,他總是用合約來思考
    • 為什麼防禦性程式設計不好?〉討論DBC與防禦性程式設計的比較。
    • 最後,這裡有另一個用Spock定義的Stack行為,考慮到邊界條件,定義的範圍更加詳細,有興趣的鄉民可參考。

    ***

    友藏內心獨白:工具沒有唯一,依據時機使用合適的工具。