l

2017年3月31日 星期五

5月【例外處理設計與重構】平日班

March 31 07:40~08:16

螢幕快照 2013-09-13 下午9.07.53

▲看到這樣的網路銀行畫面用起來心裡會不會毛毛地?

 

有一句閩南語俗話是這樣說的:「生吃都不夠,哪還有多的可以曬乾?」這句話很確切的點出例外處理的處境—「開發正常功能的時間都不夠,哪還有多餘的時間去處理例外狀況?

沒有多餘的食物拿來曬乾不打緊,但軟體系統沒有好好地處理例外狀況卻是很嚴重的問題。不穩定的系統輕則無法提供正常服務給使用者,重則造成使用者時間、金錢甚至是生命安全的危害。強調使用者體驗的今日,系統穩定度不良的問題,絕對不是請使用者重開機或是不斷地重新載入(reload)網頁就可以輕鬆帶過

螢幕快照 2014-01-02 下午11.48.05

▲Facebook錯誤畫面,大拇指受傷比讚就不好看了啊XD

***

身為專業軟體開發人員的各位鄉民,從小到大一定學過各式各樣的軟體設計技術與方法。從最基礎的程式語言、資料結構與演算法,到物件導向分析與設計、設計模式、軟體架構,以及各種敏捷開發實務做法,包含自動化測試、測試驅動開發、行為驅動開發、持續整合、敏捷設計原則等。以上,所有的大師費盡一生心力,都在告訴各位一件事:「如何設計軟體的光明面,也就是『正常行為』(normal behavior)」。而Teddy要告訴鄉民們,如何對付軟體的黑暗面,也就是『異常行為』(abnormal behavior)。唯有正常與異常的行為「陰陽調和」,軟體才可以提供正常且穩定的服務給客戶。

***

例外處理設計與重構實作班】專治例外處理疑難雜症,適合以下人士:

  • 經常因為系統當機,而被主管、老闆與客戶痛罵者…Orz
  • 對設計高強健度軟體系統有興趣者。
  • 想深入並徹底了解例外處理設計者。
  • 因為例外處理不良導致系統一直當機者。
  • 想知道如何在敏捷開發中,以逐步成長的方式來增進系統強健度者
  • 想開發出穩定的軟體,借此賺大錢者。

***

課程介紹與報名網址在此【看板方法與精實開發實作班】,上課日期2017年5月2、3日(二、三)。

image

***

友藏內心獨白:想成為絕地武士須先克服黑暗力量。

2017年3月29日 星期三

BDD(21)從測試金字塔看BDD的自動化驗收測試

March 28 23:40~24:00; March 29 00:00~00:58

屏幕截图 2017-03-29 00.57.19

▲畫面節錄自Google搜尋結果

 

前輩的測試金字塔

在〈BDD(18)這是一個End-To-End的Scenario嗎?〉、〈BDD(19)幫開發票功能加上使用者介面的三種方法〉和〈BDD(20)使用者介面細節放哪裡〉Teddy花了三集討論了使用者介面和BDD的關係,故事還沒結束,今天從「測試金字塔」(Test Pyramid)的角度來思考這個問題。測試金字塔的概念由Mike Cohn描述在《Succeeding with Agile》書中,多年來已經有各方人馬提供各自版本的測試金字塔。

▼Mike Cohn原始版本。

屏幕截图 2017-03-28 23.52.27

 

▼下圖節錄自Martin Fowler的版本,左邊用烏龜和兔子用來代表不同類型測試執行速度快慢,右邊用錢來代表對使用者的價值,UI測試的價值最高,單元測試的價值最低(因為使用這看不到)。

屏幕截图 2017-03-28 23.54.50

 

▼下圖取自agilefaqs網站的〈Inverting the Testing Pyramid〉文章,左手邊為傳統專案中的測試金字塔,大部分為人工手動測試,其次為自動化GUI測試,再來則是整合測試,單元測試所佔比例最少。但這是不健康的現象,因為占比最多的人工測試與自動化GUI測試的執行很耗時,且維護成本高,找到問題之後debug的時間也很長。執行速度最快,且最容易避免系統缺陷的單元測試反而最少,所以應該把左手邊的測試金字塔反轉過來,變成右手邊這樣。

image08

 

上圖的測試種類分得十分詳細,而且還包含每種測試所佔的比例。基本上從Biz Logic Acceptance Tests到End to End Flow Tests之間的測試都可以視為傳統軟體測試所說的整合測試(Integration Tests),或對應到Mike Cohn版本的Service測試。

***

Teddy的測試金字塔

▼綜合上述說明,加上網路上找到的資料以及這一陣子讀的書,Teddy把測試金字塔畫成下圖。
屏幕截图 2017-03-29 00.27.55

 

首先看到中間的金字塔本體,一樣是三大層,Teddy把中間層叫做驗收測試(Acceptance Test)原本Teddy是採用傳統軟體測試中整合測試這個名稱,但後來想一想,從「目標導向」的角度思考,這中間層的整合測試,其目的應該是要「驗收」一群軟體物件或元件之間的協作是否如預期,所以改成驗收測試覺得目標比較明確。

圖的右方把驗收測試展開之後,是沿用〈Inverting the Testing Pyramid〉的分類,驗收測試細分之後包含商業邏輯驗收測試、傳統的整合測試、工作流程的驗收測試、以及在GUI下一層的End-To-End流程驗收測試。用這種方法分類,和BDD的流程與工具就可以配合得很好。為什麼,請看以下說明。

圖的左邊是從工具觀點來看金字塔的三層,最底層是單元測試,可以用xUnit系列工具或Spock與RSpec。往上一層驗收測試層,這一層的最頂層「End-To-End流程驗收測試」,可以用BDD工具像是Cucumber或Fitness來開發,其他下層的測試則可以沿用單元測試工具。 這樣的對應關係恰好是Teddy在〈BDD(18)這是一個End-To-End的Scenario嗎?〉文章中所討論內容,一個位於GUI下一層的End-To-End流程測試,這是一種驗收測試,用來驗收Scenario(或 User Story)的測試。

至於最頂層的GUI測試,通常是從使用者的角度所執行的測試。因為自動化GUI測試建置、維護與執行的成本高,為了減少這類測試案例的數量,在設計上應該考量使用者最關注的系統重要功能開始撰寫。自動化的工具如果是網頁則可以採用Selenium,桌面程式與手機APP也有相對應的GUI自動化測試工具。

在這裡要提醒一點,上圖中的驗收測試(Acceptance Test)與使用者驗收測試(User Acceptance Test;UAT)不同,UAT需透過GUI來執行,而這裡的驗收測試則是採用「目標導向」的觀點對於傳統整合測試的另一種稱呼。

***

結論

如果採用Teddy所介紹的測試三角形觀點,則BDD的驗收測試就可以「名正言順」的和GUI脫鉤,而在需要掛鉤的時候參考〈BDD(19)幫開發票功能加上使用者介面的三種方法〉文章中介紹的方法。在此Teddy要強調這只是Teddy自己的觀點,並不是說BDD一定採取這種做法。實際上在《Growing Object-Oriented Software, Guided by Tests》(GOOS)書中就主張驗收測試一定要跨越應用程式的每一層,也就是需要從GUI開始進入系統,如此方可達到兩種不同的End-To-End效果:

  • User Story
  • Process

但Teddy認為就算是採用本文建議的作法,也還是可以吸納GOOS書中的好建議,讓BDD的Scenario串起End-To-End Process,只不過Scenario的入口點採用「可插入」(Pluggable)的方式,不一定是哪一種特定的UI,可以是Web UI、Console UI、手機UI。因此,稍微延緩一下定義UI的時間點對於End-To-End Process的建立所造成的負面影響應該可以想辦法降到最低。

***

友藏內心獨白:感覺快要可以寫一篇論文了…Orz。

2017年3月28日 星期二

Fail Fast不是這樣用的吧?!

March 28 09:12~10:53

屏幕截图 2017-03-28 10.34.39

▲畫面節錄自Google搜尋結果

 

認識Teddy的人都知道Teddy是一個講話非常不中聽的人,也因此在有意、無意中經常得罪人。記得有一年Teddy去拜訪一位朋友,朋友說他們正在跟某公司合作,該公司已經跑Scrum三年多了,成效斐然。聽到台灣有這麼棒的團隊,Teddy很好奇的問:「請問他們的自動化測試和持續整合做到怎樣的程度?」聽到這個問題朋友突然顧左右而言他,快速轉到其他話題上。

文化上的改變先不談,一個跑了三年多的Scrum團隊自動化測試和持續整合都做不好,你說這個團隊好棒棒實在很沒說服力。

***

有位鄉民和Teddy聊BDD(Behavior Driven Development,行為驅動開發),他說他們導入BDD已經一年多了,Teddy非常有興趣,想多了解對方這一年多來實踐BDD的經驗。但聊來聊去都聊不出個所以然,問他如何在BDD中落實DDD(Domain Driven Design)他說從來沒聽過DDD,再問他開發團隊如何和PO或stakeholder協作討論規格與範例,他說他們的規格是「別人」給的。講到最後才發現原來這個朋友口中的BDD是「功能做好之後用Selenium補寫(錄製?)自動化驗收測試」。

這是九二共識的軟體版嗎?

一個BDD各自表述。

***

某位鄉民和Teddy聊到User Story Mapping(使用者故事對照,USM),對方說他參加公司內部的讀書會,把書讀過一遍之後的感想就是使用者故事對照只適合用來管理循序(有單一時間操作順序)的功能,對於多重路徑(有選擇條件)或時間順序不一定的功能無法用使用者故事對照來表示。Teddy第一次讀這本書的時候也是有同樣的疑惑,把使用者的歷程依據時間軸展開,這不是把真實世界中,系統平行、重複或多重選擇路徑硬簡化成單一時序的使用情境嗎?這種方法有用嗎?要表達時間順序不是用UML裡面的sequence diagram (循序圖)就好了,何必再學另一種工具呢?

經過更仔細的閱讀之後,才發現自己一開始只看到使用者故事對照的形,根本沒看懂它的精髓。時間順序只是一種讓你講故事的方法,因為從時間順序來思考最直覺也簡單。有了故事之後,引發團隊討論,驗證大家腦袋中的想法,最後獲得共識,這才是背後的目的。試想,一個產品或服務,你說它時間順序不明顯,無法說故事,那你產品做好之後要怎麼賣?最後還不是要用說故事的方式賣給客戶,總不能把所有規格一條、一條列出來就要客戶買單吧:

4個USB Type C、15” 2K螢幕、觸感不佳的二代鍵盤、超大觸控板、無三小路用Touch Bar、16GB RAM、512GB SSD

如果只看規格,誰想買「貴森森」的MacBook Pro(MBP),類似規格價格便宜的產品選擇很多。相信很多人是因為被產品背後的「故事」—以及故事所帶來的用戶體驗,不管是真實體驗還是自行腦補後的想像體驗—給吸引。功能不是不重要,相反地功能很重要,但必須能夠串起來幫助使用者達成任務(解決問題)才可以傳遞價值。

如果無法說故事,會不會是因為還沒把產品的價值想清楚,還停留在比規格、比功能數量的思維上面呢?

***

敏捷、敏捷,大家都想要求快,就算這個快是很膚淺的快也無所謂,反正先丟出去再說,先說先贏。敏捷不是說fail fast嗎?人是很奇妙的生物,大家經常抱怨政府推出的政策都在炒短線,口號喊著漫天價響,很少做長遠規劃。但輪到自己做事的時候才發現,原來做長遠規劃這麼辛苦,而且又不能時時刷存在感,這樣子怎麼提高民調數字哩?算了,還是也來學政府開放「現股當沖」,先把交易額炒高再說。

學習原本就沒有說一定要「全學會」才可以,學一點、用一點是很正常的現象。怕就怕「學一點」卻以為全部學會,「守、破、離」三個階段都還沒開始「守」就已經不知道「離」到哪裡去了。學習的「量」(廣度)和「質」(深度)之間應該取得平衡,才不至於淪為口號收集器。

俗話說:「滾石不生苔,轉業不聚財。」學習還沒到守的階段就已經換題目,大概離詐神不遠矣。

***

友藏內心獨白:詐騙手法也是要推陳出新。

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行為,考慮到邊界條件,定義的範圍更加詳細,有興趣的鄉民可參考。

    ***

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