4 months ago

因為 LogDown 實在太多問題了,又沒有繼續在維護,
只好換到 Medium 去了

 
4 months ago

參與2天的AgileSummit後,覺得很有趣,很多經驗的分享都值得與高手們再深入討論,這裡先整理記錄幾點:

1. 台灣貌似有一大票想要做數位轉型的企業

老闆或高階管理都有來這場研討會(?)取經,而且以為以「敏捷轉型」進行,
就可以「快速」改善企業現在面臨的困境?
有這樣的感覺,是因為2天下來,幾乎每一場的講者都會強調:

  • Agile不是快,是靈活
  • 套用了Agile不會事半功倍,只是更專注於問題刀口上
  • 敏捷不是特效藥

之類的警語,所以,台下是否真的有那麼多人是衝著「我的公司、團隊只要敏捷轉型了,就能成功」而來的
如果真是這樣,那麼至少於台灣的科技業環境,現正經歷著一段「驗證著敏捷轉型是否有效」這樣的變革歷史

2. DevOps 似乎與 Agile 脫離不了關係

傳統的各施其職、個體獨立做事的團隊模式似乎惹人詬病,把「個人能力將成為團隊瓶頸」這個問題表露無遺
企業在未來所面對的,是市場上快速的產品迭代,別人改善產品或服務的變化速度難以估計
所以自身產品的開發與維運,也必需變得更「快」更靈活,更確切地說,是需要快速的應對問題能力
在開發維運上,那種恐龍體積與速度量級的產品已經來不及反應過來,
現在的國內外都有大企業大公司正積極把過去的包袱進行瘦身分解,利用 cloud, data pipe, mirco service, 分散式架構進行重組自己的產品世界觀
而且,比起小公司和新創,他們有更多的資源,來進行這樣的改革,用上適合的新技術來獲利,只是時間問題。

3. 把手弄髒的人才有資格說話

很欣賞Gipi分享的那段「把手弄髒的人才有資格說話」
對應 Taleb 的「Skin in the Game」
用講的都很容易,但在體制外大談怎麼改善體制,實在沒甚麼說服力
想要企業、公司賺錢,就先想辦法讓自己的產出能夠產能最大化
公司能夠賺錢存活,才能談好的企業文化

4. 柯市長想法十分敏捷

總括幾點聽市長這次演講的重點:

a. 市長想法很積極進取,創新不只是口號。
他認為是成功並不能被複製,默守成規不正視問題,政府只能走向失敗

b. 行為很實際。承認自己的不足,但重點是接受自己團隊做得不足的地方,並試圖改善
不像某些政客只開空頭支票,選前就五大保證之後怎樣怎樣,選後做不到卻搬出十大理由,
柯p沒聽到他做甚麼無緣由的保證,只見他針貶現狀,並提出具體的改善方案

c. 十分相信數據驅動
政策判斷都由數據和統計資料所驅動,他在告訴你他正要做甚麼政策前,先拿了數據出來告訴你現狀,你可以說數據說明不了箇中的原因,但你不能否認那表示了不爭的現狀

d. 希望建立一個容許犯錄的環境
透過小規模試錯,透過不斷改善政策讓社會變得更好。

需然柯P從頭到尾都沒有提供北市府現在正在使用Agile
但從他所表達的,我覺得他的想法非常符合Agile的宗旨
最欣賞的還是柯P的一句話「政府是來服務人市民的,不是來管理市民的」

小結

兩天下來聽到很多有興的論點與經驗之談,主題橫跨了公司組織、結構、文化、UX、開發流程等等
個人覺得的主題大部份是在談論敏捷轉型的mindset和背景,從這樣的內容主軸,
其實可以理解為何直至今年才有 AgileSummit 這樣的研討會出現,因為台灣科技業(至少是軟體業)正大量的進行變革,
而Agile似乎是現在最明亮的一座燈塔

期待明年會有更多實踐經驗的甘苦談,
每個組織都是不一樣,當然遇到的困境也不一樣
成功經驗無法複製,倒不如來談談有哪些坑值得被注意

以及更多針對技術(硬實力)與mindset(軟實力)的搭配之類的主題出現。

筆記

最近有個嘗試,試著用mind map來做一些筆記,方便建立脈落與關聯性,這次的議程也有記錄一些
如上面那張是我在聽Gipi分享時所記錄的,但有些場次比較難整理,我就挑我記錄到內容比較多的來分享了,有興趣的話可以連進去看看

 
4 months ago

經歷了幾個月的 User Story Mapping 讀書會終於結束。因為大家希望更有感,所以上周辦了一場給參與這次讀書會的同事來玩的workshop

Workshop 怎麼樣?

這次workshop主題是:

假設我們是一間高度客製化的旅行社,要為 Ian 這個用戶安排一次沖繩旅遊,希望透過使用 user story mapping方式安排出一個可行方案

結束後再回想整個workshop的過程,大家 engage 起伏程度大概如下圖所示
[進程內容 與 溝通熱度 關係圖]

講解如何進行這次工作坊後,整個workshop大概分為這樣的階段:

  • A. 手執便利貼和便,雀雀欲試了。大家直接開始想像各種旅行中可能會做的事,雖然不斷有一些不確定的事,但參與者互相討論與協商,然後就紛紛把這些提案直接貼到白板上,有些看起來可能是在講同一個使用者活動,但是有不同的提案,例如「開車」、「自駕」、「廉航」、「商務艙」等等。

  • B. 雖然大家很熱絡,但排烈出來的便利貼總有些不對勁:
    從中看不出來有時序性與重要性排列與書中提到幾種的user story方式不太相符各自發展,
    但卻不知道最終想要端出怎樣的目標提案,
    反倒是像一份使用者問卷所以我就忍不住兩三度的發表了一些意見跟提醒

  • C. 感覺大家已經抓不住方向,有些人已經冷了下來,直接坐在椅子上看其他人繼續,總體上大家的熱度也大幅減退,甚至到膠著的狀況。

  • D. 隨著我提醒與否定越來越明顯,氣氛已經凝結。我只好馬上喊停,希望讓大家先針對暫時遇到甚麼問題,提出一些點評,繼而可以修正回我預期中的航道上。

  • E. Richard 跳出來,一直重複問大家:「你們有跟user確認這是他想要的行程嗎? 你們有確認user的需求嗎?」用提問的方式引導大家把問題焦點回歸到user身上。再請大家重新開始。

  • F. 大家才意識到剛剛其實都是在沒有確認過需求的情況下進行發散性的討論,以個人的經歷來提案。所以接下來才開始與user互動,確認例如user在旅行中,對於食、住、行、預算之類的想法。
    確認了user的需求後,歸納出一個目標

    讓不吃牛的攝影控有一個5天4夜好的春夏沖繩遊,總花費不高於5萬
    

    有了目標後,討論確實比較聚焦,相對也把不符合目標的活動節目拿掉
    Richard也有提醒可以按時間順序來排列這些user activities,
    大家按照時間再進行整理,又發現缺少一些必要的activity

  • G. 看到整個旅行的規劃其實已經大部份完成,如下圖。時間有限也先在於暫停,讓大家描述一下最終的提案,與user進行確認。

  • I. 遊戲部份算是到此結束,結合中書的章節,進行歸納總結,highlight這次workshop中遇到的問題。

  • H. 接續請大家表述一下在這個活動中,有甚麼發現和感想,下圖中有打星號的項目就是大家針對這次workshop有提及到的內容:

    • 一開始沒有去了解user的需求,導致我們方向散亂不一
    • 我們一開始就focus 在礫石般大小的問題上,卻不知道我們原本要解決的是甚麼岩石級size的問題
    • 做產品的人會以自己的經歷和想像去設計,但卻忽略了甚麼才是使用者想要的、甚麼是使用者真正需要的
    • 把所有要做的事情都列出來了,但要決定哪些in哪些out,才能有效地執行
    • 討論的人數超過一定數量後,討論比較容易失焦與產生分歧,決策小組的做法或許適用

反省

在階段B到C這段時間,因為看產出與我心中期待的結果差距很大
雖然我一度想要引導大家向書中方向進行修正,提出了不少質疑和意見
但反而是讓大家更加搞不清楚我希望他們的產出是甚麼。

在這個點上我確實認為我的引導方式不是十分有效果,甚至當下我自己其實也是有點束手無策,
所以到C的時間點,才堅決喊停,希望釐清大家的問題後再重新整頓士氣
也還好有Richard在旁幫助漸漸回到任務的目標上。

所以事後便向Richard 討教這次workshop不足的地方,
畢竟這次其實我給自己的刻意練習,實作過後的專家回饋是必要的

討論後主要有以下幾點結論:

作為引導者,這次workshop的目標是甚麼?

在準備workshop之前,其實與我的第一組組員已經在一開始就「workshop的目標是甚麼?」進行討論,
而共識就是:
讀書只有概念,透過實作讓大家加深印象

Richard問到一個我完全沒有想過的問題:

「針對大家做出來的成果,你有沒有預計一個高標和低標,一個你覺得達到目標的範圍?」

確實,在workshop當下,我心中並沒有劃好一條 boundary,
誰越界才需要提醒,沒有越界時就任其自由發展
而在引導的過程中,我犯了一個毛病,就是太在意大家有否使用書中介紹的方式進行
卻忽略了缺乏動機這個問題,

因為不知道為甚麼要用USM,所以用起來更加迷惘。

強調最重要的觀點

讀完這本書,再結合平時的工作經驗與其他關於產品設計的知識,
我心中其實充斥著滿滿的想法想要跟大家分享
但最想要大家接受到的、最重要的是哪一點?

時間有限,甚麼都談反而容易讓大家失焦,接收到一堆自己還沒辦法內化的資訊,挑最重要的表達,反而能加深重點。


金字塔頂端就只有那麼一點空間,該放甚麼?

引導者需要把自己與參與者的資訊量進行同步,進行相同層次的溝同。
不知道參與者不知道甚麼,就沒有能力讓他們弄清楚他們不知道的事。

有反差才有感覺

大家一開始會偏離書中的方法,眾多原因中的一個,應該是一開始我端出了一個上次workshop的產物,
一個按照 good, better, best的方式把旅行要做的事劃分成三個版本的一張mapping。

但其實這應該是在whole picture產生之後,在切分release時才該來做的事。
可能有這個前例作為誤導,大家就往這個方向繼續發展了。

所幸的是,在F階段,大家重整之後,就依循兩個重點把接近書中的作法重新排出了 user story mapping

  • 是否能為user帶來價值
  • activities之間的時間順序性

對比起一開始比較雜亂,沒有時序性,不在乎是否user需要的那一版本
第二版實在讓人有感到滿意

也因為有了對比,大家對於為甚麼要用 user story mapping有了更深刻的體會,就是上面 I 環節列舉的。

何時該出手干預?

這是最難的議題,Richard也坦承很難可以明確去定義哪個時機點需要出手干預
干預總會打擊當下參與者的參與熱度,不同風格和方式的干預也會造成不同的影響。
Richard特別指出在這個workshop中,其實有3個人都進行了干預或是引導:

  1. 我:在剛開始就好幾次提醒大家該用哪種方式來進行mapping
  2. Richard:中期見大部份人已經無法 engage其中,於是提醒大家是否有跟user確認過、而又是否可以按時間來排列等,以提問的方式讓大家正視問題
  3. 布丁:發表感言時,針對我們端出一份5萬元的計劃書進行評論,更具體地指出我們角色定義模糊的問題。

有些干擾能修正方向,但也可能大大打擊參與熱度

我覺得這問題考驗了引導者幾個方面的能力:

  • 對目前各人參與熱度的覺察能力
  • 對書中內容的了解程度
  • 讓大家能自主發現問題的引導能力
  • 連結相關知識點的發掘能力
  • 指導發散思考的提問能力
  • 導致偏離的原因洞察能力

設計一個讓人有收獲workshop果然不是簡單的事,要做到面面俱到更是困難,
但最重要的問題,還是 - 想要帶給參與者甚麼樣的收獲
圍繞這個問題才不會失去設計workshop的主要目的。

 
5 months ago

前兩天16,17號,由提出海盜派測試的邰曉梅老師主持,
引領這個敏捷圈的大家聊一聊「隱藏的質量」這個問題

持續的探索

當曉梅老師解釋她自己實作的一個小程式是如何一步一步的進行「探索」時
我才晃然驚覺,她這兩天所講的探索,其實不只是我們一般在軟體開發中進行的測試

我們過往講的測試,就是做驗證,驗證已經做好的東西,是不是功能正確、能如預期般地運作

而她所講述的測試探索,我一開始還狹義的以為只是針對有可能發生的bug進行try and error
但其實她要表達的,是「真正的探索」

「探索」,對未知領域的伸探,盡可能發掘一些有用的資訊。
發掘未知的領域,把未知領域裡的資訊進行過濾,
但未知的資訊未必就能馬上變為已知,未知的有可能是風險,
往往要進行一些小規模的實驗才有辦法把風險中隱藏的訊息曝露出來,
而小規模的實驗其實也是探索的一部份

我試著用下面這個例子來解釋我的理解:


你正在做一個可以讓多個user同時線上使用的系統聊天系統
你發現系統回應的速度,因為user的數量規模日漸增加而有漸緩的趨勢
因此,user數量級的增長將會為系統的穩定服務帶來風險
這是一個 known unknown - 已知的未知之數

雖然知道這是一個風險,但手中卻沒有數據能推斷大概到哪個數量級時,系統就會無法運行
作為營運者現在也很難推測user的增長數目,是否會一直維持與現在相同的增長斜率

又假設為了維持良好的用戶體驗,你要求系統的request回應速度要在1秒之內
所以未知之數已經有:

  • 以現在的系統規模,app request能在1秒內回應的前提下,最多同時可容維上線的user為多少?
  • 同時在線的user數量的增長率為何?
  • 哪一天將會到達這個最多可容納上線人數?

就這樣一個被發現的問題點,就可以延展出這些問題,當然還存在著更多的問題、更多的風險
這是暫時機器無法取代人進行的動作,是一個探索風險、揭露未知的過程

當然,時間與市場不會允許你挖掘出所有的問題,我們也不可能完美解決所有的問題,
但揭露風險是能提高品質的過程,哪些風險需要馬上被解決,哪些可以繼續安放
會是團隊一起進行的決定,讓這些被揭露的風險資訊,為大家建立對這產品的品質共識

與 TDD (Test-Driven Development) 如出一轍

「我每找到一個錯誤,我就去改進我的程式,然後再去探索下一個問題」
曉梅老師介紹完她的實作過程後,我心想:「這就是TDD的思路呀」

永遠為現有的程式找到下一個可能會出錯的情況,圈出的risk boundary
我也並不認為一定要很制式地先寫一個 fail的test case作為開始才算是真正的TDD
死守這種方法論的定義,容易失焦於其能帶來的價值

「挖掘風險」這一精神,我覺得老師講的探索性測試與 TDD 其實是沒有同一種道理,
有時候我覺得TDD 是一種 mindset ,比作為一種方法更為適合。

所以聽完曉梅老師這次分享,讓我更加深信TDD在程式開發上對於風險發掘的影響之深
TDD對應的是開發程式本身
那麼 test and exploration 應該是對應到產品的品質提升

問題不只存在於程式中

曉梅老師一再強調 Checking 與 Testing 本質的不同
那些按著 SPEC, Plan上的驗證動作,填上一個接一個的勾勾,就只是checking 的概念

我當下能理解這個區別,但卻不明白為何曉梅老師要一再強調這個定義問題。
經過兩天的沉澱下來,回想起一路走來的開發經歷以及接上過 David的需求探索入門工作坊,有了一些想法:

checking 固然重要,因為那些是我們已經知道我們必需做好的事情。
但卻容易把產品的品質侷限在這樣的框框當中

以驗證一些UI的正確性為例,
假如在一個包含GUI的產品上,我們需要測試一個 text input field 的正確性,
能否在輸入值後得到預期中的結果,或者在輸入不正確的值後得到比較直覺的錯誤訊息回應
然後繼續把注意力集中在這個 input field中的輸入值當中
但可否會想到除了test case上表列的那些可能性之外的 input呢?
更甚者,這個input field是否有存在的必要?是否存在著別的操作可能也能為user達到同樣的目的?

或許正在進行這項驗證工作的 tester不認為這屬於自己的工作範疇內,那是 UX designer 該注意的
但 假若 developer 已經能為自己所開發的程式負上更多的責任,
而 tester 單純只著眼於程式 debug 層面上 test工作,對於有效提升產品質又能起到多少顯著的作用?

甚麼是隱藏的質量?

當我們開發出一項功能、乃至一個產品時,我們有辦法描述這個功能或產品的品質/質量如何嗎?
質量這個詞,非常抽象,在軟體開發這個領域中,

從開發期的軟體中找到的bug數、coding style一致度、程式的可延展性、可維護性
到產品上線後,遇到錯誤引起無法down time的次數、服務穩定度、修復錯誤所需之時間
再到使用者終端,使用者體驗、安全性議題、市場評價與商業價值等等都可以成為品質/質量的指標

察覺到那些隱藏在背後的品質問題,才能做出差別。

因為自己也還沒看讀過曉梅老師著作的 <<海盜派測試分析>>
或許還沒能正確詮譯曉梅老師對測試的中心思想
以上純粹這兩天聽了曉梅老師分享後,自己所得到的一些反思和見解
若有誤解,還望朋友作出指點糾正

 
about 1 year ago

在定義完MVP之後,接下來Sprint 開跑

Sprint#0

回想起來,其實第一個sprint (Sprint#0)是最累人,最難熬的,原因主要是:

1. Don't know what we don't know

不確定因素太多。萬事起頭難,我們要從0開始把地基先打出來,但卻不太確認我們還缺少些甚麼,諸如:

  • API到底能做甚麼事?
  • 是否需要以後端實作
  • UI 各頁面整合中需要傳遞甚麼資料

然而當眼前是一片空白時,我心裡面更多的懷疑是我們做這個產品是否真的有其存在的商業價值,但後來 S 君的一個動作其實解開了我們的疑慮,容我之後再補充。

2. It must be a long long night ...

大家都是工作完一整,天下班後直接殺過來的,其實當下開幹已經是晚上十一二點了,是蠻適合睡覺的時候了XD
可是偏偏「開始」應該是要最拼,把所有不確定因素的問題限縮到在最小的範圍內的時刻,需要有產出振奮士氣

planning

大會第一餐:胖老爹炸雞,填充過熱量後,Sprint#0 我們討論出主要是進行前期的研究工作,同時進行以下兩件事:

  • 嘗試API 的串接 主要是為了省後端的工,在還沒看過api document之前,我們希望以最快速簡單的方式就可以把api接起來,所以先決定直接用 jquery 來在前端進行串接(當然後來才發現無法偷吃步)
  • Prototype and UI implement 決定使用最簡單直接的 jquery + bootstrap 來進行實作。 UI 設計部份由W君主導,一開始他建以可以使用 Figma 這個ui建置tool 來產生prototype,但後來被大家說服了直接出 html source 就好,因為基本上 prototype 是針對 UX 的優化方便討論,但是我們要做的是MVP,求功能出來就好了,先省掉 UX tuning 的步驟。

Supplement

「欸Tenmax 的,外面有人要來探你們班」
funP 行銷長麥可竟然真的履行承諾要來送宵夜了,帶我們去附近的夜市又補了一頓,感動

Fire

宵夜喘息過後,開幹了,break down 後的分工如下:

  • S君 與 J君 - 先找方式製造頁面需要的假資料
  • W君 - 製作 UI 並出 html source code
  • N君 - 把UI 中的interaction 以 jquery 串起來
  • 我 - 試著串接api

API的串接過程中,應該跟其他大部份組別一樣先串接第一個 search 的API。

上面提到 S君做了一些事去除了我心中關於商業價值的疑慮。

「這個網站跟我們要做的事情幾乎一模一樣,但功能比我們想的更齊全了」S君嘆了一口氣,「可惡」

大家便圍過去他的螢幕前看是甚麼利害的網站,原來於大家正嘗試直接做下去的同時,
S君卻先進行了調查工作,一方面他在尋找可以爬取景點資料的網站,
另一方面也在確認同質性產品的差異。
這個網站是 TripAdvisor
主要是結合旅遊景點跟住宿資訊,提供訂房服務

但是旅遊資訊服務同質性的產品本來在網路上就是琳瑯滿目,
雖然TripAdvisor與我們的設計連UI上也有著類似的視覺Layout,
但我們服務所提供的是鐵路訂位服務,這就是一個極大的差異,
主打背包客客群,而正因為 TripAdvisor 這樣規模大的服務也提供了與我們類似的使用流程,
反而讓我們對自己設計的使用流程打上了一劑強心針,
也確認了這樣的服務是有商業價值的。

再望環顧一下其他人的狀況:

  • UI 實作組的 N君與W君,也已經快速用bootstrap 打造了一個有模有樣的首頁出來了。
  • 接著J君也從沐浴的舒爽中回歸戰場協助S君製作旅遊景點列表所需要景點假資料,
  • 我則是閱讀文件後知道 API 的 request authentication key 異常的複雜難產生,也發現因為要overwrite request header 中的 Date 而無法使用front-end 進行串接

時間跑著跑著,記得已經進行到凌晨兩點多了,大家有共識4點時先來standup sync 一下進度。

4:00am Mid Break - Stand up sync

其實這時有點累了,其他人sync的狀況我也不是記得很清楚,大概就是UI繼續進行,景點假資訊還在整理之類的?
而我則描述API串接遇到的困難,所以決定用 sprintboot 以Java來 porting API文件中 python 的串接範例。

反正大家遇到的所有問題都在這個時間點整理起來了,經過調整後,S君會跟我一起解決API的部份。

Issue of API integration

在大家抱怨完沒有人對python 比較熟的同時,S君靈機一動說,可以用JRudy 於JVM直接呼叫範例程式的.py檔。
如此只要研究一下JRudy的使用方法,便可以免去porting的工了。

後來再分析全部API也只有 search, booking, confirm, download 這四個,連車站列表的API也沒有,覺得還是先找John來了解一下是否有其他資訊。

其實這時候才發覺,我們太晚去詢問API的問題了,
因為以向來串接API的經歷,通常只要好好讀對方提供的API doc,基本上就可以順利串接起來
便沒想到大會提供的這個API卻這麼雷,而且導師們早就下班休息了
難怪中途接到John的恐嚇說:「你們落後了喔,可能是現在倒數第一二的」

就這樣,sprint#0 就這樣繼續如火如荼地進行著。

End of Sprint#0

然而,sprint#0進行到結束時,大概的狀況總結如下:

  • API 串接S君使用JRuby 有成功的打通了search 的範例,收到成功的response,但是其他的API都是 authentication error 的結果
  • John 像NPC一樣,問對了key word才會回應答案,但他提供新的token也是無法讓API通過authenthication,還是得等早上導師回來後才能解決
  • UI 進度神速,F君的回歸,建置好webpack設定,進一步加速了前端開發的進程
  • N君表示他已喝了第三罐紅牛,視紅牛如洛克人的E罐一樣用來回血,每喝一口好像就有回來一點精神,但我們得阻止他了,不然怕他要壞掉了 XD
  • 我睡了第一覺,然後請大家開始輪流休息。
  • 第一覺醒來後,發現大家竟然架起了不知哪來的投影機,正在review現有的頁面了
  • 從昨晚開始大會提供食物不斷: 胖老爹、永和豆漿、麥當勞早餐 ... 。

我們知道現在最大不確定的變數在於API,所以目標便是集中火力先把頁面都用假資料連結起來。

隨著第一次demo的逼近,Sprint#0的希望似乎也漸變明朗

最難熬的Sprint#0,似乎可以結束了。

待續...

 
about 1 year ago

9月29、30這兩天,參加了人生第一次的Hackathon比賽活動,雖然大會說這次活動也有別於一般的 hackathon,沒有天使投資人來參與評比與事後的創投,
但是這也絕對是我工程師生涯中重要的一次回憶了。

由於是AgileTour主辦的熱身活動,大會導師又有odd-e 的舟叔、柴叔等大師級人物
心中第一個念頭當然是找Tenmax這些有著默契的同事一同組一隊過去體驗這次活動

三五天就組召換了其他5人可以湊成一隊參賽了,
還曾經一度湯姆叔這個不會Coding的PO都要來跟我們熱血一番了,雖然最後他要陪他家,但還是先感謝他有支持的心
還要感謝我的團員這麼瞬速的響應

Prepare before start

Our crew

最後召集到含我6位勇士,分析一下大家的戰力成份
基本上有4人是前後端都沒問題,
4人中1人是全方位Developer的強者,開發速度神速,基本上有他在後端也無後顧之憂

另外2人則是front-end主打
1人專精前端,webpack工具運用自如,JS, CSS觀念掌握度極高
另1人具有很好的UI美感,能善用UI tools 快速做出頁面

在測試方面,大家也有前後端 unit test, integration test的經驗

工程開發上,算是蠻完整的一個組合。(對,最後就是輸在缺乏行銷能力 XD)

The Day before the game

忽悠的就到了28日,比賽前的一晚,我們在公司會議室召開了行前會,想說至少做好一些準備節省當天時間
馬上開了一個 Dropbox paper doc 來記錄發想和意見

第一件討論的事,卻是行前要帶甚麼東西過去會場,因為我們都有了要在現場過夜的決心了,個人生活用品少不了,
再者 「休息是為了走更遠的路」 ,地舖、枕頭甚麼的能讓大家好好休息,當然也是必備品

然後便是針對工程部份的討論了

  • Version control - 選擇了 GitLab ,因為有免費的private project的選擇,而沒有使用Github,馬上開好就把大家都加成member進去了
  • Framework選擇
    • Back-end - 因為在沒有熟悉 Python, nodejs 等快速的後端程式的條件下,好像也只能用我們較熟的java spring boot,而且或許還不需要用到back end,所以當下沒有定案,想說視情況而定
    • Front-end - 因為 React、 Angular 使用跟架構模組較為複雜,大家的結論是直接用 jQuery + Bootstrap 來快速暴力解決就好
  • Communicate - Slack已開好一個chat room
  • Planning - 平時我們跑 Agile 時少不了的實體工具: 白板筆、行動白板、便利貼

Product Brainstorming

從活動訊息中,只知道是利用「德鐵API」進行一些應用
找到了德鐵的官方的open api,馬上查看api有提供哪些接口和資料類型,還直接申請了一組帳號來try api

也看到了這個德鐵api也有辦過 Hackathon 的活動,當然也列出了相關獲獎的app應用

不過因為我們實在不知道這次比賽是否有明確主題或規則
所以也怕現在的討論題目會浪費,大概就是只能談談有哪些大方向而已,鐵路API,除了方便訂位,搶票和結合旅遊之外,我們也想不到更多有趣的方向了。

就這樣,期待著明天下班後直接直奔比賽場地。

30日,來到比賽現場,是一個位於德惠街上的工業風地下室。

記憶所及舟叔講解的注意事項大概長這樣吧:

  • 每隊最少5人,最多9人
  • 題目不限,最後成品就算沒有用到德鐵API也沒差,就是要夠吸引人就好(當然最後每組還是有乖乖地用上德鐵API,以下簡稱GT-api, GrailTrip-API)
  • 比賽評分標準,除了上台報告的表現之外:
    • 需要提交code base讓導師進行code review,也會重視是否有撰寫test case
    • 團隊的協作表現也會是考量因素之一
  • 隔天會有兩場demo,一場早上11:30進行,Final場則是下午5:30,活動大概晚上十點前結束
  • 現場有3個技術導師,每組可以挑選2個section來與不同導師提問討論,1個section半小時
  • 講解完後大家可以選擇是否要留下過夜

在舟叔講解完後,比賽也就隨即開始了

Kick off - Make Team & Project

10分鐘的自由組隊時間,當然我們就是直接把Study圍起來不讓他跑掉XD

接著就是隊名與比賽題目的決定,我們有半小時來決定,然後上台介紹。

因為神人Study,我們隊名就直接取為 Study group,以示好學之意XD
題目方面,紙跟筆交纏了半小時之後,看來我們還是選了一個比較大眾化的題目,旅行景點推介結合鐵路訂票
而且針對商業價值,我們得到了四點是我們的Project所提供應用上的核心價值的:

  • 德國景點推薦
  • 行程安排
  • 配合行程的鐵路訂票服務
  • 訂單管理

Setup environment

接著又有一個小時的時間,給我們挑選安身之所,然後進行賽前的安置準備
這次挑完地段後,我們對於挑地點有幾點心得:

  • 能用兩條串連的電源延長線就能接通的區域,且延長線是有剩餘長度可以平放在地上的,不是蹦直吊在空中阻礙行動
  • 避開冷氣出風口,漫漫長夜一直被冷氣吹著頭,在沒有足夠休息,抵抗力差的情況底下不感冒才有鬼
  • 能佔有一面牆,把行動白板貼上去,在牆上也可以貼memo貼,方便standup meeting的聚焦討論
  • 除了坐椅和討論佔用到的空間外,需要額外一個可以平躺的空間,安置地舖,讓累了的人可以即時躺平休息。比起趴睡,有被舖的平躺實在舒適多了,只要能直接睡著,30分鐘的補眠其實是非常有效的充電。

User storying mapping

針對之前討論出的4個核心價值: 德國景點推薦行程安排配合行程的鐵路訂票服務訂單管理

我們展開了更詳細的探討,務求要把商業價值對應到實際要提供的服務功能上,進行 Story mapping
雖然自己對User storying mapping 沒有較為札實的實踐經驗與研究
這時候我先提出一個建議,先把我們分成兩組人,兩組人各自針對我們這4個核心價值進行服務頁面的 prototype,然後再相互進行比較與分析
雖然我也不知道這樣分組方式是否能得到我們期望的結果,會這樣提議,
是因為覺得現在只有大方向,實際功能還沒有定案
還處在發想階段,希望以平行方式先發散思考,讓全部人都可以參與討論與發言,但又不置於有過多的提案難以取捨。

Business value - What problem we want to solve

原訂先進行20分鐘,然後互相說明比較,
但經過20分鐘,發現我所在的SNZ組 (成員S君,N君,Z君)3個人就已經無法達成共識了,
行程安排 這個功能上
我覺得網站一開始應該就是列出套裝,用家就只要選好這些套裝行程就好,不需針對個別景點安排行程組合
而S君則是覺得景點可以自由安排,由此發生分歧未能有共識討論下面其他的功能

於是我們便決定先跟另一組(FWJ組)來先sync一下大家對產品功能定義,
發現FWJ組的設計也是與S君的想法比較接近,但細看在 行程安排 與怎麼連結到 鐵路訂票 的方向上仍然是有一定程度的落差
大家不斷提出問題:

  • 為甚麼只能透過鐵路去這些景點?
  • 到底是以鐵路為主,找鐵路附近的景點?還是以景點為主,查出景點之間怎麼以鐵路通往?
  • 那如果選定的日期跟景點的距離根本是不合理的設定,例如要一天從意大利到法國再到德國這樣?系統要允許user做這樣的設定嗎?
  • 承上,如果允許這種設定的話,那系統應該自動幫他去掉其中一些景來配合時間吧? 要挑哪些景點去除?
  • 怎麼設定起站跟迄站?現在界面設計都是先選好一系列景點,但沒有設定從哪出發
  • 哪些資料該用假資料呈現? ... 大概還有一些問題我已經忘了

眼見時間一分一秒的縮緊,但我們的問題卻越來越膨脹。
雖然大家都是很理性很有邏輯地進行設計與分析,當中包含了使用者體驗、實作可行性及實用性的考量,
但確實也看到了假命題與over design的分歧,

為甚麼會說是假命題,因為我們真的只有20小時左右的時間,而現在的討論中許多的假設,
已經偏離了「我們如何利用這20hr來實作出符合這4個核心價值」的方向了

反正也沒有共識,我只好先打斷大家,停止深度與廣度的討論下去,
重新對齊團隊目標,「如何利用20hr來實現符合這4點核心價值的產品出來」

所以問題正式回歸到,如果要附合這4點價值,我們的內褲版本產品,至少需要呈現甚麼功能?

Define a MVP (Minimum Viable Product)

很高興大家馬上意識到我們當初所定立的價值是需要達成的,
然後,反而因為剛剛的諸多發想,讓我們更快速地從中萃取出來最不可缺少的部份:

  • 德國景點推薦
    • 單獨景點呈現,不必有套裝行程
    • 假資料呈現
  • 行程安排
    • 先支援只有兩個景點的行程
    • 先選的就是起點
    • 忽略日期合理性的判斷
  • 配合行程的鐵路訂票服務
    • 景點與車站先 hard code其地理距離,不用以程式計算
    • 只支援一位乘客訂票,簡化動態人數的表單複雜度
  • 訂單管理
    • 先用email 寄出/或是使用固定的票卷呈現在確認付款後的頁面上

就這樣,快速用這幾個明確的目標定義好我們明天早上11:30的第一場demo的MVP。
接下來便開始 Break down 工作了。

第一篇先在這裡打住,下一篇將是描寫我們怎麼在20小時裡經歷5個sprint的。

 
about 1 year ago

緣起

會有這次分享,最初的原因是因為真實在團隊成員開始著重寫 unit test 後,而test達到一定的量時,一些問題便慢慢浮上水面來。例如:

  1. 有人覺得功能開發很趕,來不及補test
  2. 有人不曉得自己的unit test 是否足夠
  3. 有人會直接使用 PowerMockito 來測 private function的正確性
  4. 大家的test function 越來越多,但命名卻沒有一定規則,難以閱讀
  5. 大家的測試邏輯也不太一致,有人會在同一個test裡測了五六種不同的input,即一個test測五六個情境,這樣的設計,如果又沒有加上適當的註解對每一段進行切割分類的話,基本上就只能從input跟做assert的程式碼來猜測這一段是為了測甚麼情境,但往往這是很累人的閱讀
  6. 到底哪些class或function是不能沒有unit test的?而哪些範圍又可以用覆蓋率較大的 integration test 取而代之?

以上遇到的問題,撇除第1跟2之外,其他的問題基本上就是會造成 test 日後難以維護的情況
進一步的,難以維護日後就會不想維護,想要拔掉,那code的穩定與品質性要靠誰來維護呀?
因此,我自己試圖整理一個talk,想要跟team裡面的大家一同溝通討論這些在寫test 中遇到的問題
一方面是整理自己在寫測試上的一些心得,二是想聽聽大家有沒有其他想法。

爾後,我便針對「如何寫有效的unit test」跟「Test的團隊共識」這兩件事分別在兩次code review的過程中跟大家分享,反應基本上不錯,而「Test的團隊共識」這件事更屬於應該是團隊一起決定的事情,大家都有很積極地發表一些意見。

由於分享後獲得的評價不錯,主管們便鼓勵可以致技術社團上分享,藉此與公司外的人促進交流。
於是便有了這次 AgileMeetup 活動的安排了。

第一次技術社團分享 - 感想是「既緊張又興奮」

對於這次活動會來參與的人有哪些其實我也不太清楚,不過應該都是多少有參與Agile社群裡的一些有志之士吧。
由於這次分享的內容主要以觀念為主,但又怕大家對於內容的深度有過度的期待,所以把題目定為「淺談」。
當天仍是十分緊張,Terry跟大家也在不斷地幫我打氣,「緊張就輸了」
John 卻說要留兩個位置給大人物的,害我更加緊張。
離開始時間7:30pm剩下不到十分鐘,發現2位身穿紫色T-shirt的熟悉面孔出現了
大牛 Daniel 跟 Vince都來了,真的是受寵若驚。
Daniel是啟蒙我當個成年人的可敬人物,大神來了,雖然緊張依舊,但其實心中確實有些亢奮

演講開始後,先告訴大家我不是台灣人,讓大家有做好聽奇怪口音的準備了。
slide我已經分享到 SlideShow 上了,過程就不多贅述了。

問題彙整:

演講分享,最開心的還是可以跟台下的大家互動、提問回答,分享意見與獲得回饋。
在分享的中途與結束後,都留了時間讓大家提問,出乎意料之外的多人提問。
以下把比較有印象的問題彙整一下:

  • 甚麼時候該針對 legacy code 寫unit test?
  • 怎麼針對無法寫 test 的 legacy code 進行 refactor ?
  • 你有講到不要按著product code來寫 unit test,在 extreme programming一書中提到可以把順序調過來,是可以先寫 test 嗎?
  • 針對restful api這樣的系統架構,如果controller就是純粹把service的output再往外丟,那還有需要針對controller寫unit test嗎?
  • 在一個function裡,有invoke很多外部component,如果要test這個function,需要進行大量的mock,那是否只用powermockito這類的library,嘗試去測其中重要的private function就好?但又怕之後有稍為rename private function的話, test又會壞掉

當中其實也有些蠻值得討論的議題,之後聊到落地實作時再聊聊

自己的程式自己測,「品質」絕對是自己堅持出來,而不是別靠人測出來的

Richard 在 FB上分享了這樣的感想:

今天很多社群朋友來公司聽聽我們TenMax
的工程分享,感覺注重 工程師自己寫測試/嘗試重構的案例愈來愈多了,問的問題也都比幾年前進階,所以也難怪這個主題的票仍然一個早上就售完!
很樂見這種工程文化在台灣也逐漸被重視,且有人戮力在實踐。

隨著敏捷文化在台灣開始被深耕,自己的程式品質自己要用測試來保證,這樣的概念似乎越來越被重視了,Developer跟QA的邊界也不再是清楚的楚河漢界了。

然而,大家的提問內容,針對legacy code的問題佔了大多數,
顯然,Legacy code真的是大家在開發新功能與維護舊功能上都會踫到的痛

Legacy code 到底該不該refactor?

其實我們團隊針對 legacy code 也是經歷過一番的掙扎與探,也有過一些嘗試與失敗的經驗。
但是處理 Legacy code, 基本的原則就是「不要為了無謂的程式潔僻而重構」

既然是legacy code,證明它已經存在著好一陣子了,系統運作上也應該是正確的
如果不是因為feature change要踫觸到這一塊legacy code的話,基本上就沒有必要去冒險與花費成本進行重構
因為legacy code又遇上沒有test的話,重構的成本是很大的,

  1. 要先重新理解這段code影響到的scope
  2. 確認SPEC
  3. 加入 test case
  4. 重構

但也因為是legacy code,在系統上造成影響的範圍一定不小,
當然我想大家應該也是遇到需求才會問這樣的問題,
也該 legacy code 會是討論測試實戰時的重點議題。

Team convention 不等於機械式的coding

對於test code的團隊共識是這次分享的其中一個重點概念,
但我想要重申一下,這樣的convention定義出來的目的,
並不是為了讓大家跟著誰寫出一樣的code,又也不考驗大家的英文水平

大家的邏輯都會有差異,coding風格差異更大
可讀性 是 test code裡最重要的,所以加快閱讀速度也是可讀性要達到的目的之一
因此,convention 最大的意義是團隊的共同認知,卻不侷限於我舉例的規則上。

感想

第一次進行技術分享,我覺得自己的收獲不比台下的聽眾少,因為在準備過程中我花更多的時間是去理清我還無法好好描述的觀念與問題
也因為被不斷的提問,讓我跟我的團隊回顧起更多還存在於我們程式碼裡的問題。
接下來還有好幾個主題想要跟大家討論分享。

  • TDD如何入門
  • Unit test實務中常用的驗證技巧
  • Legacy code的考量與重構

我會再花些時間整理,若有機會的話再來跟大家做個經驗之談。

對於大牛Daniel的驚喜參與還是很受寵若驚,
本日針對問題「請用一句話描述敏捷」的金句回答:

不要臉

P.S. 再次感謝過程中各位的幫助

主辦人 David
當天的大忙人 John,也幫我拍了很多照片的快梗王
主持人Terry,下午還參與主持我們team的retro
還有 TenMax 從鼓勵、給予議見、陪伴、到打氣的各位一同成長的伙伴們。
最後當然是感激有來參與的,讓台灣的軟體開發更上一層樓的在場各位。

 
over 1 year ago

The convention of writing test cases

Functions of test become more and more complicated to understand because of different kinds of coding style by developers. It is hard to maintein the test cases written by other developers as the test codes are difficult to read.

As a result, having a unique convention of how to write the test function is fundamental.

This document contains the following topics:

  • How to name a test function
  • What is the structure of a test function
  • How to make test content more understandable
  • Libraries for testing

How to name a test function

According to 7 popular unit test naming which gives different opinions of how to name unit test function.

As a combination of such suggestion, I prefer to use:

public void test_{functionName}_WHEN_special_situation_THEN_expected_behavior() {
    // test codes

} 

To begin with:

  • test is prefixed of all test functions, and it is often considered redundant, however, it helps to search all the test function in a test class
  • functionName is used in camel case and is the target function that aims to test
  • special_situation after WHEN is to describe the different input and given condition for the target function.
  • expected_behavior after THEN: to describe the expectation behavior after invoking the target function under the special_situtation

Example:
Assuming that a class, AccountService, containing a public function createAccount.

public class AccountService {
    public Account createAccount(AccountInfo accountInfo) {
        // implement codes

    }
}

Then the unit test of AccountService should look like following:

public class AccountServiceTest {
    
    @Test
    public void test_createAccount_WHEN_no_exist_accountId_THEN_create_succ() {
        // ... test codes

    }
    
    @Test
    public void test_createAccount_WHEN_existed_accountId_THEN_throw_AlreadyExistAccountException() {
        // ... test codes

    }
}

When to separate words with underscore _?

It depends on whether a words should be classified as a group that specified one thing or an item and mostly it should be composed by an adjective and a noun.

For examples:

  • _completedRequest_ represents for a completed http request
  • _throw_AlreadyExistAccountException means that will throw a specified exception class
  • _accountId_ is a certain property of a class

What is the structure of a test function

As mentioned in Clean Code #ch9, a test function is mostly composed by 3 parts: Prepare, Operation, Check; Then also are considered as another terms Given, When, Then for BDD.

Given

The preparation before the target function starts
Usually, the pre-test condition such as fake data in database or mock function should be defined prior to the preparation.

When

Invoke the target function (with parameters) you want to test.

Then

Finally, is a serial of validation action and it means checking what happens after calling the target function, for example, checking whether data set into the database or whether the core component is invoked.

Example

@Test
public void test_createAccount_WHEN_no_exist_accountId_THEN_create_succ() {
    // given

    String accountId = "nonExistAccount";
    AccountInfo accountInfo = new AccountInfo(accountId);
    accountInfo.setEmail("");
    when(accountRepository.findByAccountId(accountId)).thenReturn(null);
    // when

    Account account = accountService.createAccount(accountInfo);
    // then

    assertThat(account.getAccoundId()).isEqualTo(accountId);
    verify(accountRepository, times(1)).save(account);
    
}
  • Notably, sometimes Given is not necessary when we don't have any assumption or pre-test condition. Especially for some static util funciton.

How to make test content more understandable

The test code should be readable rather than following the code structure. If you even can't understand what a test is going on, then you no longer to be able to maintain this test.

There are 3 tips of making the test easier to read for other developers:

1. extract the behavior:

Most of time, we don't care much about the test details. So it'd better to extract the main behaviors into a function with enough narrativity naming. It is helpful to let others understand the purpose at the first moment they look into the test function:

@Test
public void test_createAccount_WHEN_no_exist_accountId_THEN_create_succ() {
    // GIVEN

    String accountId = "nonExistAccount";
    mockAccountNotExist(accountId);
    // WHEN

    Account account = accountService.createAccount(accountInfo);
    // THEN

    assertAccountIsCreated(accountId, account);
}

private void mockAccountNotExist(String accountId) {
    AccountInfo accountInfo = createAccountInfo(accountId);
    when(accountRepository.findByAccountId(accountId)).thenReturn(null);
}

private void assertAccountIsCreated(String accountId, Account account) {
    assertThat(account.getAccoundId()).isEqualTo(accountId);
    verify(accountRepository, times(1)).save(account);
}

The test structure is more clear when the details are hidden in the other more function.

2. One test function is for one test purpose

Don't mix up different purposes within one test function, because it betray the naming design rule. And it will lead to no recognization of what situation cause a fail test.

3. Separating the Give, When, Then with enough vertical distance.

It is a good way to insert the comment line separating these 3 parts, like our sample code. // give

Libraries for testing

  • For MOCK function purpose, the Mockito is the best choice to do function isolation.

    PowerMockito is NOT ADVICED TO USE although it is also another powerful test framework. Because of mock private functions does break the code design and result in useless verification when the private function is changed.

  • For do VERIFICATION, AssertJ is also the good for verifying behavior. It has completeness and fluent-design APIs, moreover, the usage is very intuitive. See the article for more information about the difference between several assertion libraries.

 
over 1 year ago

「Facilitator 引導者」這一個詞,

也是前年上了 odd-e Daniel 的課才開始接觸

而被Daniel 羞辱了後,對於「如何做引導」這件事情其實也是有著高度的憧憬

後來參加過「引水人」的活動後,對於 Facilitating 又有更深刻的體驗

Facilitative Agile Leadership 引導型敏捷領導力

公司這次提供了一個課程學習機會,一個不是全完對外開放的課程
由台灣 ICA 主辦,參與的公司分別有 我們FunP集團、鈦坦科技與趨勢科技
都是台灣科技界中較為投入於 Agile framework 的公司。

課程兩天,主要進行方式不是 Mentor一直講課
而是由不同的Mentor 們輪流帶領不同的環節,
在引入主題後,讓同學們透過分組互相討論,再分享,再與別組交流提問的方式進行。

一方面體驗被引導的方式
另一方面了解不同公司間對於 Agile中管理方式的不同問題。

我基本上把整個課程分為3個大部份:

  • 組織內狀況的了解深化
  • 組織外的Agile 文化衝突與交流
  • 個人 Mindset 的喚醒

先說課後收獲

課後其實讓我印象最刻的,是「覺察」這個動作一詞
這兩天的課中,Mentor一直提醒我們,不論在甚麼時刻

跟別人交流或是自我表述,都要處處覺察周圍

去發現甚麼時候自己感覺到慾言又止,
發現甚麼時候的話題或是氣氛讓自己感受到不安全

更甚者,是否有能力去感知自己正在製造一個讓與話者感受不安全的環境

在人與人溝通的過程中,針對議題探討的對話,
往往很容陷入傾向於發表己見、說服別人,或是透過質問的方式來否決對方的意見

這樣的傾向往往在組織、團隊裡造就不安全的氣氛,
資歷較淺或職位較低的成員便會不敢發表意見

「覺察」的能力很重要,
人常常在生活習慣中開始了「自動導航模式」,不知不覺地做出一些習慣性的動作行為
但這些習慣未必適合於所有情況下,

是否能在作出行動的前的環境中,覺察到環境條件的差異變數
再作出當下最適當的決定。

這樣講其實有點抽象空泛,我拿自己舉一個例子。

========================
我在推行team member使用 TDD 進行開發的日子中,試圖多次的去說服他們先開始
不要總是以「時程趕」來做為止步嘗試的理由,

但往往最後還是無法在討論中加深其他成員想要進行 TDD的意欲

某一次討論中,我有了一個覺察,
「大家其實無法從談話討論中被說服改變寫程式的流程習慣」
所以驅使我想要準備講義,程式碼素材以及講解的演練
嘗試用行動來向他們展示 TDD的好處

成效還沒知道,預計這周某天下班前會進行
但我知道一直口說是無法說服他們的
必需換一種行動。

=======================

覺察不是甚麼超能力或過人的技巧
但因為我們在交流過程中容易膠著於內容本身
往往就被忽略。

所以,我相信「覺察」需要常常於生活中練習,應該可以慢慢掌握。

寫到這邊,提及的內容好像跟敏捷沒有太大的關係
那我還是來補充一下課程上跟敏捷比較有關的事情吧
課中也有幾個較為印象深刻的觀念,補充的部份皆為我個人的理解:
(由於老師 Larry 是用英文發言,當中其實用了很多蠻有意思的比喻,
但我已記不起來原句了)

課程圍繞的3個最終關鍵原則:

1. Alignment and Mission Focus 團隊目標對齊與使命的聚焦

先找到共同前進的目標,避免意見分歧、各自發散發展而偏離團隊或商業目標

2. Autonomy & Self-organization 自主性&自我組織

對齊目標後,自發積極找到問題,再然找尋合適的解決方法
對於自我組織,則是由很多自主的個體,互相融合找到團隊的合作默契

3.「Fail fast, Learn fast」

Agile的精神,快速提早曝露問題,然後快速修正改善對應方案,但前提是組織環境能夠提供一個容許犯錯的環境,以及安全的發言空間,與上面提到的「覺察」息息相關

「團隊裡面每個人都有影響力,而且每個影響都會互相的。」

負面情緒較多的人很愛抱怨,影響其他成員的負面情緒增加;主管選擇質問式提問,成員久而久之處於高壓狀態。

「每一個動作,其實都是一種選擇。」

面對人際關係問題,選擇視而不見或是介入處理;面對負面能量爆表的下屬,屢勸不聽後選擇炒魷魚還是讓他轉換環境;

「有時候,不回應,也是一種選擇」

沈默也是一種選擇,有時候需要留給大家獨立思考的空間;對成熟的人來說,有時候觀望陪伴,便是最好的領導;

課程中還有些有趣的分析方式與主題探論方式,來 flash一下

  • 波浪分析法
  • 魚缸深度對談
  • 知者 Knower Vs. 學習者 Learner
  • 受害者 Victim Vs. 參與者 Player

之後再一一整理

 
almost 2 years ago

IMG_3050.JPG

Odd-e 每一次的課程總是對我造成一次又一次的衝擊
我不求學習很多,但只要每一次都有我從未接觸過的,讓我印象難忘的新知識
那麼這趟課程我就不沒有白白浪費了。

先來回顧一下這3天課程讓我最印象深刻的主題:

  • 實例化需求
  • Acceptance test solution - Cucumber
  • Mob programming
  • 極緻的 Code review
  • Code smell and Refactor
  • TDD (Test-driven developing)

之後再來一一回憶一下,
先來談談:

實例化需求

透過使用具體的資料來刻畫需求的輪廓,以便團隊針對具體的example來進行需求的確認與討論,因為實際例子更能體現實作的細節,團隊也就能更快地達成共識。

我需要一個「可以針對某一個月份來增加預算」的功能,
看似知道這個功能是要做甚麼,就是要可以選一個月份,然後輸入一個金額
這時候team裡面的engineer 可能就會很直接地開始想怎麼實作:
要用 year + month 來當 primary key?
ui 用哪個 date picker library?
有要紀錄更多的資訊嗎?例如留audit log, 哪個user 新增的?

顯然大家對需求確認有著不同的進行方式,
這時,課程老師 Joseph 請其中一組同學,
每人針對這個功能可否輸入「小數」金額給出答案
結果,這個6人的小組,有4個人的答案是可以輸入小數,2個人的答案是不能。

可以預見問題了嗎?

如果此時已經進入實作階段,
假設 a同學被assign開發backend的 API,而他認為是不能輸入小數的
另一位 b同學則負責前端ui開發,而他則是認為可以輸入小數
那麼這樣的串接過程,最後就會發現因為 b 傳呼叫 a 的 API,而增新金額是小數
最後 API 則會回傳unsupport format 的exception 回前端,
如此 a、b 同學又要針對這問題重新跟 PO/BA確認,再次修改實作方式

這個例子或許最後要重新修改並不難,但如果團隊中的認知落差體現於更大的問題上呢?

因為大家的經歷都不一樣,所以認知才會有落差,
這被稱為「知識的詛咒」(Curse of knowledge)- 當你知道的事情越多時,你的認知世界觀中就會發展出越多「個人認為的common sense」,就越容易會誤以為別人應該跟你一樣知道,
所以在溝通過程中,自以為是大家都孰知的事,故然不會特別拿出來討論或說明
誤會往往因此發生

有更好的方式來提早解決這溝通上的不足所引起的問題嗎?

這裡提出來的「實例化需求」,就是透過把需求透過用實際例子來說明,以「新增某一個月的預算」為例,舉列一個例子:

「透過界面,我可以輸入月份資料 "2016-09",並輸入金額 "1000.00"

仔細來看一下這個例子對於程式的實作上提供了甚麼有用訊息?
需要由 ui 介面操作;
月份資料的格式為 yyyy-mm
系統應該要支援小數金額的輸入, 並且數值只保留到小數點後2位
....

如此透過實際的例子來降低隊團成員的認知差異。
因此其實使用的例子也是需要有所巧思,盡量表達出意圖
例如 "2016-09" 會比 "2016-10" 更有含意一點,表達了月份的確切格式,
如果使用 "2010-10" 就不能確定個位數時的格式了。

再次強調,實例化的最終目的,是在於讓團隊對需求有更明確的共識,
所以實例需要經過思考設計,卻不必窮舉。

第一部份先寫到這邊,下一篇會來談談 acceptance test