農場計畫 Week #1:Behavior-Driven Development
Abstract
Behavior-Driven Development(BDD)是以故事情節做為基礎,因此 BDD 的核心在 user story。從 user story 來發展 software prototype 的過程可以單純是 coding,並且使用開發者界的手法「code is document」,來讓代碼與文件合而為一。Code is document 的關鍵,首先取決於二個層面:
- 代碼品質(code quality)
- 專案管理(Git)
現在是一個軟體開發的先進時代,只要代碼品質夠好,它就是一份文件,所以你不必要另外花時間,就只是為了寫 Documentation。好的開發者,閱讀 code is document 的效率,是讀傳統文字文件的數十倍。
有了 code is document 的觀念,就可以明白為什麼在完成一個 user story 後,就可以直接撰寫程式碼、製作第一個 Prototype。這是又直接、又有效率的做法:user story -> prototype。
要測試這個 prototype,可以想辦法將 user story 直接轉化(code generation)為測試步驟(step definitions)。以上介紹的 user story 與 step definitions,可以透過一些 BDD framework 工具來實現。
cucumber 是目前很受歡迎的 BDD framework,它採用 Gherkin 語法來撰寫 user story,並且將 user story 編譯為 step definitions 的 code stub(程式碼骨架)。
User Story
用「故事情節」的方式,來表達、描述與表現你的功能(features),而不是用規格(spec)的方式。如果你想知道什麼叫「規格描述」,台灣 ODM / OEM 廠裡,應該隨地都可以撿到這種文件。
這個部份,BDD 用到很多方式跟軟體工具,不過從 Startup 的角度來看,其實一開始採用 story board 的方式,再搭配一段 story template 就夠了。一份典型的 story template 如下:
In Order To <biz value is derived>
As a <role>
I want <some feature>
從這個 template 的句型來看,story 的敍述應該是「value first」,而不是 function first。一份簡單的 user story 可以極簡到使用「記事本」來撰寫,不過,為了易於管理,選用一個適合的 BDD 寫作架構還是有必要的。
Cucumber and Gherkin
Cucumber1 是目前頗受歡迎的寫作框架,它原本是為 Ruby 語言所打造,不過現在也有 JavaScript 的版本:cucumber-js2 。Cucumber 採用 Gherkin 語法來描述 user story。Gherkin 語法所描敍出來的文件結構稱為 'Give-When-Then[3]',這裡有一個簡單的例子:
1 #
2 # features/unsplash.feature
3 #
4
5 Feature: Unsplash feature
6 As a traveler of photographer
7 I want to post photos on website
8 So that I can share with my excitings
9
10 Scenario: Post photo
11 Given User login
12 Given Use Facebook account
13 When Interact with upload element
14 Then You see the photo
以 user story 來表示 spec 是 BDD 的核心精神。同樣地,你可以用記事本、用自已的語意來撰寫 user story,然後用瀏覽器,以及「工人瀏覽」方式來測試。但有一個 BDD 框架,還是最省時省力的。
Cucumber-js 就提供了這樣的測試框架。要測試你的 features,要再加入二個東西:
- Support files
- Step definitions
Support files 要定義一個 World 類別,裡面要實作 visit method。Step definitions 就是測試 user story 的步驟,這個部份的程式碼骨架,可以透過 cucumber-js 來產生。
以下是 support files 與 step definitions 的例子,下一個階段再說明程式碼實作細節。
Support Files
1 // test/features/support/world.js
2
3 module.exports = function() {
4 var zombie = require('zombie')
5 , HTML5 = require('html5');
6
7 this.World = function World(callback) {
8 this.browser = new zombie.Browser(/* {runScripts:true, debug:false, htmlParser: HTML5}
9 */);
10
11 this.page = function(path) {
12 return "http://localhost:3000" + path;
13 };
14
15 this.visit = function(path, callback){
16 this.browser.visit( this.page(path), function(err, browser, status) {
17 callback(err, browser, status);
18 });
19 };
20
21 callback(); // tell Cucumber we're finished and to use 'this' as the world instance
22 };
23 };
Step Definitions
1 // test/features/support/world.js
2 'use strict';
3
4 module.exports = function() {
5 var zombie = require('zombie')
6 , HTML5 = require('html5');
7
8 this.World = function World(callback) {
9 this.browser = new zombie.Browser(/* {runScripts:true, debug:false, htmlParser: HTML5}
10 */);
11
12 this.page = function(path) {
13 return "http://localhost:3000" + path;
14 };
15
16 this.visit = function(path, callback){
17 this.browser.visit( this.page(path), function(err, browser, status) {
18 callback(err, browser, status);
19 });
20 };
21
22 callback(); // tell Cucumber we're finished and to use 'this' as the world instance
23 };
24 };
實作
實作的方式當然是使用 HTML5 技術,也就是 HTML5/CSS/JS。從能力上來看,Full Stack Web Development 的技能是必備的。雖然 Full Stack Web Developer 的工作看似包山包海,要學習的主題也很廣泛,但有架構思維,也有主軸的話,其實學習可以很有效率;否則,學習再多,都是「碎片化」的學習方法,感覺學到或看過的東西很多,但每一種都只有「Hello World」等級。
這裡提到的架構思維就是 Single-Page Application - SPA。
Feature: Unsplash Story
一份 .feature 檔描敍一個 user story。底下是一個例子,故事的主題叫做「Unsplash」。
1 #
2 # test/features/unsplash.feature
3 #
4
5 Feature: Unsplash feature
6 In order to share my enjoys
7 As a traveler of photographer
8 I want to post photos on website
9
10 Scenario: Post photo
11 Given User login
12 When Interact with upload element
13 Then I should see "my photo"
14
15 Scenario: Slideshow
16 Given The latest photo gallery
17 When Tap to next photo
18 Then I see one photo
19 And Full page
第 5 行的「Feature:」是 Gherkin 的語法,說明故事標題。標題底下的縮排區段,是故事敍述,請使用先前介紹的 user template 句型,來寫故事:In order to ... As a ... I want ...。
緊接著用「Scenario:」語法,來定義「功能」。Scenario 的寫法是使用「Given-When-Then」句型:
- Given:系統的狀態,例如:User login,表示系列要處在登入狀態
- When:使用者的動作,例如:Interact with upload element,表示使用者與上傳介面互動
- Then:outcomes,也就是輸出。例如:I should see "my photo",表示畫面顯示使用者上傳的照片
一個 user story 可以包含數個 scenario,也就是多個功能。除此,Gherkin 也有「And, But」語法,例如第 18-19 行。Unsplash story 的 prototype:
http://innoboard.cc/unsplash
Feature: Slidenow Story
設計一個使用 Markdown 語法的簡報服務,力求極簡易用。
1 #
2 # test/features/slidenow.feature
3 #
4
5 Feature: Slidenow feature
6 In order to lively introduce something
7 As a coder, developer and instructor
8 I want to make slides in Markdown
9
10 Scenario: Read slides
11 Given Landing page showing slides items
12 When Click the slide item
13 Then I should see full screen "slide"
14
15 Scenario: Submit a slide
16 Given The submit page
17 And User login
18 When Commit markdown document
19 Then I send a new slide
20 And Use CC4.0 license
Prototype 實作:
http://booklog.io
特別說明:Solution Storyboard vs User Story
Solution Storyboard(或簡稱 Story Board)是 101 Design Methods 的一個流程,一般是採用漫畫的方式呈現。這是非常有幫助的設計思考方法,細節請看 Leon 老師的摘要文件;以及 101 Design Methods 的 Model 6.7。
Story board 的範例說明裡,將 Mokoversity Farm 的思考,製作成簡報後,再實作為 landing page。但是請注意,這個 landing page 呈現的是一份「簡報」;但 user story 要實作的是 Prototype(App)。
Leon 老師在 hackpad 有一份 story board 說明,這個例子先將想法做成簡報(Presentation),再將簡報內容實作為 landing page。請注意,這份 landing page 是 idea 的「簡報」,而不是 idea 的實作。
同時也要注意,BDD 的 user story 屬於軟體工程的一環,它的目標是書寫 Scenario(也就是軟體功能),然後實作 prototype;BDD 不是用來製作 business plan 簡報的方法論,所以不能把 BDD 的 user story 跟 Design Thinking 或 Lean Startup 畫上等號。實際上,BDD 的 user story 是屬於數學上的 finite state machine(FSM)。
BDD 的 User story 要達到的目的是實作,也就是想法的實作;即 Prototype。
關於 Mokoversity 農場計畫
Mokoversity 農場計畫(Farm Team)是一個 Pre-Startup 的訓練場(Play Ground)。在農場裡可以學習 Coding、打造 Prototype 與建構 Entrepreneur Mindset,這裡更是一個 Entrepreneur 黃金圏(Golden Circle)。更多資訊,請訪問:https://www.mokoversity.com/farm/zh-tw
References
[3]: Given When Then, https://github.com/cucumber/cucumber/wiki/Given-When-Then
[4]: BDD in JavaScript: CucumberJS, http://custardbelly.com/blog/blog-posts/2014/01/08/bdd-in-js-cucumberjs/
