l

2019年3月29日 星期五

Scrum讓你家庭更幸福

March 29 07:06~08:08

▲畫面節錄自維基百科


家庭也是一個團隊

昨天到信義區對一群非資訊業的美女、帥哥主管介紹敏捷精神。談到Scrum團隊cross-functional team(跨職能團隊)的時候,Teddy開玩笑說…

Teddy:很多人家庭不幸福,因為他們的家庭採取專業分工的component team。小孩只負責做小孩該做的事,只要乖乖讀書就好,什麼家事都不用幫忙。爸爸只負責賺錢,回家一屁股坐下來,不是看電視等吃飯,就是打電動。媽媽最可憐,下班之後還要煮飯、做家事、顧小孩。

Teddy:這是一種「區域最佳化」的做法,每個人都扮演好自己的「專業」,感覺好像很有「生產力」,但卻沒有顧及整個家庭價值鏈的最佳化。

***

魔戒遠征隊

很多人對於導入Scrum從專業分工的component team轉換到交付價值的cross-functional team,一開始在觀念上無法接受。「我是一位UI/UX設計師,現在Scrum團隊中明明就沒有符合我專長的工作,那我要幹嘛?」

還記得電影魔戒中的魔戒遠征隊嗎?魔戒遠征隊有兩個特性和Scrum團隊很像:

  • 跨職能團隊:團隊中包含了完成任務所需要的各種人才,包含巫師、人類、矮人、精靈、哈比人,每個角色都有特定的專長。
  • 自組織:這個特性是到團隊組成中期之後才出現,一開始團隊沒有共同目標,有的人是想完成消滅魔戒的任務,有的人是陪鄰居出門郊遊、有的人是想要搶魔戒、有的人是老闆派來的、有的人是憂國憂民的先知。到後來大家確定共同目標就是要消滅魔戒,各自盡其所能來達成這個目標。

如果你是魔戒遠征隊的哈比人「山姆」,你原本的「專長」是負責煮飯。遇到強獸人來攻擊,你可以說:「我只負責煮飯,不負責打仗。你們慢慢打,我要繼續煮飯了」嗎?當然不會,此時煮更多的飯已經沒有意義,你會拿起短刀,在旁邊偷偷地刺啊、刺啊。就算不能對敵人造成致命攻擊,但總也是想盡辦法幫助團隊其他成員達成退敵的共同目標。

***

當作自己的事

Teddy覺得,敏捷講到底,也沒什麼大學問。就是好好過生活,認真做事,活在當下,去感受各種 forces(作用力、限制條件)。提升自我能力,靈活地面對這些 forces 做出反應,讓身處的環境回復到一個穩定的狀態,繼續面對新的 forces

很多人在公司跑敏捷,覺得痛苦、遇到阻礙,講到底也都是人的問題。從個人的角度來看,如果把手中的工作看成是「別人的事情」、「公司的事情」、「我只是領薪水的」,做事的動機、態度、積極性自然和「這是我自己的事」差很多。

但這也不能怪員工,因為很多時候公司的大環境、文化,迫使員工採取保守的做事心態,少做少錯,防弊重於興利。但無論如何,認真做事、認真過生活,不管公司待你如何,這種做人處事的態度,會跟著自己一輩子,別人是搶不走的。

反正跑不跑敏捷都要痛苦,還不如嘗試點新鮮的玩意,苦中作樂、苦中學習,也是一種不錯的選擇。

***

廣告

對於敏捷開發、Scrum有興趣的鄉民,可參考泰迪軟體的【Scrum敏捷方法實作班】課程,上課日期為4月27、28日(六、日)。

***

友藏內心獨白:小刀刺久了也是會有殺傷力的。

2019年3月26日 星期二

落實TDD的三個難題(下):技術能力的精進

March 26 07:37~08:53


難題三

落實TDD/ATTD/BDD/SBE最後的難題是技術能力的精進。TDD所需的技術能力,包含如何透過與領域專家緊密合作,找出代表規格的關鍵例子(key examples),再以軟體工具(Cucumber、SpecFlow、Robot Framework、xUnit等)逐一自動化這些例子(驗收測試)。

有了失敗的測試案例界定規格邊界(範圍),接下來便可撰寫production code實作這個規格。等待測試案例通過,代表某項規格已被實現,此時回頭思考程式碼是否可透過重構(refactoring)改善設計品質,讓軟體持續維持在軟的狀態。一個可閱讀、可維護、可測試、易修改、易部屬的軟體,才能給予團隊擁抱改變的力量。

遵循這個步驟,採取穩扎穩打、迭代與增量、價值驅動的方式,完成系統開發工作。

***

三個圈圈的交集

這系列三篇文章提到的三個主題:

三者看起來好像是各自獨立的議題,但實質上彼此緊密相關,互有增強效果。領域模型與軟體架構可促進團隊建立穩健的通用語言,讓後續開發工作變得更具體,更容易落實ubiquitous language in code。更強的技術能力,讓團隊與領域專家溝通時,能更精確找出代表需求的關鍵例子,以更準確、精練的語言,描述規格並將所獲的的知識以程式碼的形式紀錄下來。

舉個例子,當你準備採用最簡單的Rename重構程式中的變數、函數、類別、package名稱時,是否有著不知道如何命名的困擾?對於非英語系國家的人,可能直覺認為是自己的英文能力不夠好,所以不知道如何取名字。英文程度當然會影響取名字的能力,但有另一個更深層且不容易被察覺的問題,就是「團隊對於問題領域的重要概念或商業邏輯還沒有達成一定的共識,不知道用什麼名字來稱呼某件事情」,

另外一個常見的例子就是在沒有做任何分析的情況下,期望透過 TDD,在撰寫失敗的測試案例過程中就能夠直接找出類別必且定義它們的介面。這其實是一件困難的工作,「物件村」空無一人,你的失敗案例要呼叫誰來幫忙?如果可以做一點點事前設計,有了初始的領域模型,進一步甚至直接套用像是clean architecture這種通用軟體架構,可以讓後續實作自動化驗收測試的過程更加容易且比較不會長歪掉。

***

吃技術

Teddy的一位朋友在討論技術問題時很喜歡用「吃技術」這三個字:「TDD很吃技術、重構很吃技術、持續整合很吃技術、DDD很吃技術」。

軟體開發本身就是一件技術活,有什麼活動是「不吃技術」的嗎?只要基本功夫紮實,做起事來就跟喝開水一樣簡單,不會覺得做什麼都「吃技術」。

有不少人因為沒學過OOAD(物件導向分析與設計),或是學過OOAD但覺得OOAD好難,TDD好簡單,都不用作什麼分析、設計的工作,只要驗收測試寫出來,物件就自動冒出來,介面也設計好了。傑克,這真是太神奇了。

在此Teddy要告訴傑克:「這是不可能的」。能量不滅,原本OOAD所要做的工作,不會因為改用TDD就消失不見,只是以其他的形式呈現罷了。

想學好一件事,先弄清楚困難的地方在哪裡。知道地形地物、context之後,才不會人云亦云,才會有自己的看法,才能夠透過迭代與增量的方式累積層次而不至於長歪掉。

***

友藏內心獨白:做軟體的不吃技術難道要吃大便XD。

2019年3月22日 星期五

往外看一層

March 22 22:27~23:45


「這個我用不到」效應

幾年前有一次到某公司教【Design Patterns這樣學就會了–入門實作班】,課程結束後邀請我去的主管覺得還滿有幫助的,但他發現部門內一位小組長上課時興趣缺缺,於是主管主動詢問小組長對於課程的看法。

小組長告訴主管:「我工作上所需要的東西Microsoft .Net Framework都有了,不需要自己設計新東西,Design Patterns對我工作上沒什麼幫助。」

這位小組長說的也有他的道理,如果目前工作上用不到,學習的動機也就減低。顧好目前工作最重要,以後的事以後再說。他會出席這個課程,是因為主管要求,並不是因為他自己覺得有需要。

***

Teddy的VB經驗

N年前Teddy五專畢業後,在當兵前有三個月空檔,經過朋友介紹接了一個用VB 3.0寫Windows應用程式的案子。當時Teddy沒學過VB,擔心無法勝任。但朋友一再保證,VB非常、非常、非常簡單,一定沒問題。基於打工賺點小錢外加人情因素,於是就大膽接下這個案子。

做專案之後才發現朋友沒有欺騙Teddy,VB真的非常、非常、非常簡單。突然覺得自己好棒棒,英明神武,一下子就學會視窗程式開發,可以用VB打天下。

寫了一陣子之後,遇到第一個瓶頸:「為什麼別人的系統畫面(UI)那麼好看?我的卻那麼普通?」

原來VB有很多OCX元件,可以用拖拉方式讓自己的系統畫面變得非常「有質感」。從專案預算中花了一點小錢,買了幾個OCX元件。突破畫面關卡之後,再次覺得自己好棒棒,可以做出這麼有質感的視窗應用程式。

又過了一陣子,發現第二個瓶頸:「為什麼別人的視窗程式可以做出半透明與最小化之後縮到工具列的效果,而我卻只能作出標準的視窗?」

到處找書、看雜誌,終於發現原來這些效果要呼叫Windows API才作得到。知道這點之後好像發現新大陸一樣,透過Windows API可以做的事情太多了,功力大增。再次覺得自己好棒棒,可以做出這麼酷炫的視窗應用程式。VB + Windows API萬歲!

後來案子完成沒多久Teddy就去當兵了。

***

因緣際會之下,在當兵的兩年期間,第二年一整年都在部隊中寫VB程式。這時候沒遇到什麼技術上的問題,累積了更多VB開發經驗。

退伍之後上班,原本Teddy應徵這份工作是要用Java開發e-learning(網路教學)系統,但因為神秘的原因公司接了一個連鎖洗衣店門市系統的案子,結果又變成Teddy用VB練功的機會。

從VB 3.0用到VB 6.0,寫得程式越多,心情越不美麗。因為VB不是真正的物件導向語言(object-oriented language),只能算是object-based language。VB有Class,但卻不支援實作繼承。此時遭遇第三個瓶頸:「為什麼別人用C++/Java都可以開發真正的物件導向系統,而我只能用VB這種不物件導向的語言來寫程式?整個氣勢都弱掉了,一點都不酷啊。」

有一天讀到GoF的《Design Patterns》,被書中這兩句話震撼到:

  • Programming to an interface, not an implementation
  • Favor object composition over class inheritance

啊!原來實作繼承要少用,那麼VB沒有實作繼承這件事,好像就沒有那麼嚴重了。寫了好幾年的VB程式,居然此時才發現,VB其實是有「介面繼承(與Java的Interface類似)」的功能。透過介面繼承,你可以「programming to an interface」,也可以做多型(polymorphism)。

知道這點再度發現新大陸,後來用VB開發的新系統,物件導向程度到了前所未有的境界,自詡為VB OO之神…精病XD。

又過了一陣子,寫程式寫到手好痠。不是因為打字太多、太快,而是因為手動測試真的太累人。此時遇到第四個瓶頸:「有沒有什麼方法可以取代人工方式驗證程式的正確性,讓我的手不要那麼累啊?」

剛好這時候JUnit問市,原來這世界上還有一種東西叫做「自動化單元測試」。當時沒有免費的VB Unit可以使用,上網花了一點小錢買了一個付費版本。Teddy的第一個工作上實際使用的自動化單元測試,就貢獻給VB了。

從此之後,又發現另一個新大陸,哇,原來自動化單元測試可以節省這麼多手動測試以及debug的時間啊。傑克,真的是太神奇了。

***

往外看風景更美

學習與能力增強,是一種累積層次的過程。學會一樣工具或技術,自然很高興、有成就感。但如果就此自滿而停滯,你所能解決問題的範圍(context或scope)就會受限於這個工具或技術所設定的邊界。一直到有一天,你發現這項工具已經不能解決你的問題,這時候才想要找新的方法,很可能會緩不濟急,或拉長解決問題的時間。

Teddy的VB學習過程就到自動化單元測試為止嗎?當然不是,隨著公司人員增加,管理團隊、溝通的問題逐漸浮現。如何讓一群人一起有效合作開發軟體?這已經跳脫程式語言的層次,要往 外太空 更外層探詢答案。於是來到軟體開發流程、專案管理、需求探索、軟體架構這個世界繼續拓荒。

還有沒有更外層,當然有,繼續往外拓展,遇到公司經營、客戶滿意、產品獲利等問題。

很多時候,問題的答案不在你以為的「這一層」。往外看,視野更好,答案也呼之欲出。

***

友藏內心獨白:就連地獄都有18層了。

2019年3月18日 星期一

落實TDD的三個難題(中):通用語言的建立

March 18 17:02~18:11

▲廣義的說,TDD、ATDD、BDD、SBE都是同義字。


難題二

落實TDD/ATTD/BDD/SBE的第二個難題就是通用語言的建立。傳統TDD(先寫失敗的單元測試)好像只是開發人員自己的事情,它被降級為一種開發方式的選擇(Test First VS. Code First),一種技術議題,與商業無直接關係。

但後來的TDD,也就是冠上ATTD/BDD/SBE之後的TDD,強調透過開發團隊與領域專家的合作,以「舉例」的方式一起釐清需求與商業價值

這裡說的領域專家,可能是Scrum團隊的Product Owner,或是任何具備問題領域知識的stakeholders。這是一種頻繁、高互動性且非常燒腦的活動,而不是單方面由Product Owner寫好user story然後在sprint planning meeting「宣達聖旨」給團隊的那種溝通模式,更不是瀑布式開發那種「文件丟過牆」的溝通模式。

***

通用語言

通用語言(Ubiquitous Language)是領域驅動設計(Domain-Driven Design;DDD)所提出的觀念,意指「在一個特定領域中,所有人所固定使用的術語」。例如,在貓奴這個特定領域(bounded context),大家對於乾乾、濕濕、罐罐、浪浪、小橘、賓士、虎斑、三花、玳瑁、麒麟尾、鏟屎官、聖上、皇后、離胺酸、貓砂、逗貓棒、結紮、貓毛、掃地機器人等名詞有著高度共識。一群貓奴聚在一起,用他們的「通用語言」可以非常有效率溝通而且比較不會造成誤會

這個概念,應用在軟體開發上面,當團隊建立了良好的的通用語言,問題領域的知識可以直接出現在解決方案領域,商業人士可以直接和技術人員用相同的語言溝通,表達商業邏輯。更進一步,在實作軟體系統時,這個通用語言將直接反應在程式碼裡面,也就是ubiquitous language in code。如此一來,程式將變得更加容易理解與維護,也更容易擴充。這是一種讓軟體變軟,擁抱改變的做法

***

通用語言和TDD有什麼關係?

在〈落實TDD的三個難題(上):領域模型與軟體架構〉中Teddy提到建立領域模型對於TDD的重要性,而建立通用語言的過程,同時間幫助團隊建立領域模型,兩者相輔相成。

只要Teddy聽到有朋友「宣稱」採用TDD開發軟體,Teddy一定會問對方:「你們的需求如何產生(如何撰寫失敗的驗收測試)?」如果答案是「Product Owner寫好給我們照做」,那麼落實TDD的程度就還有不少改善的空間。

如果答案是「透過頻繁地與Product Owner溝通,討論列出需求中的重要例子(key examples)」,那就比單向的接受user story要好很多。如果答案是「透過與Product Owner以及stakeholder的討論,以舉例的方式,建立共同討論的語言,並以此為基礎來撰寫程式」,那就可以獲得一張「好棒棒」貼紙。

***

結論

TDD是透過先撰寫測試案例來釐清需求或規格,之後再考慮如何開發程式的一種設計方法。套用建築師Alexander的模式框架,這是一種「先決定Context,再決定Form」的設計方法。

為什麼網路上的TDD範例與TDD Kata你都做得嚇嚇叫,公司的專案做起來卻讓人很想睡覺?很簡單,因為前者具有定義清楚的Context,而後者的Context非常模糊。

一般來講,Product Owner與stakeholders擁有比較多的領域知識,換句話說他們比較了解Context。缺少這些角色的幫忙,開發人員很難獨自透過TDD的方式自行決定Context,這也是許多人在真實專案中落實TDD所遭遇到的困難。

在許多公司,Product Owner與stakeholders覺得「撰寫失敗的測試案例是開發人員的事」,人家不願意理你啊。

難怪你的TDD又變成XD了。

***

友藏內心獨白:不能放任開發人員自由發揮,結果會很恐怖。

2019年3月15日 星期五

落實TDD的三個難題(上):領域模型與軟體架構

March 15 07:11~09:11


緣起

幾年前有一位泰迪軟體忠實學員問Teddy:「我上過TDD的課,但回公司後卻不知道該怎麼落實,為什麼?」當時Teddy無法回答這個問題,因為:(1)他上的TDD課程不是Teddy教的,不知道他學了什麼;(2)Teddy以前工作上開發的軟體,只有不到10%是採用TDD,其他大部分都是用傳統OOAD,code first(先寫production code再寫test code)的方式,所以沒在工作上遇到全面落實TDD的問題。

雖然工作上TDD用的不多,但Teddy寫了很多測試案例,也做了持續整合,算一算也有16年的時間。這幾年因為教學需要,投資大量時間在TDD/BDD/SBE以及DDD/Clean Architecture上面,直到最近才慢慢有種可以清楚回答N年前這個問題的感覺。

***

例子太小

不少人都是透過網路上的例子或是TDD Kata來學習TDD,這些例子大多具備以下特點:

  • 所需物件很少:只有單一或少量物件、例如著名的Bowling Game Kata,只需要一個Game物件就搞定。
  • 商業邏輯明確:上述提到的Bowling Game Kata,或是計算不同方式的郵寄費用(平信、掛號、國內快捷、國際郵件)、商品費用(一般客戶、VIP、大量採購、特價商品)等例子,它們要解決的問題「商業邏輯」都非常明確,很容易透過TDD,採用逐次完成每一個例子的方式來實作完整商業邏輯。
  • 不須考慮架構:因為例子小,邏輯清楚,所以也不需要考慮軟體架構的問題。

以上特性,對於一個「以學習TDD為目的」的例子來說,原本都不是問題,反而是優點。因為例子很專注在特定的小問題上面,所以學習者可以在短時間內把握TDD的精神:

  • 寫一個失敗的測試案例
  • 用「最笨」的方式撰寫程式碼讓測試案例通過
  • 重構程式

***

問題在哪裡?

當使用者學了TDD要實際應用在工作上的專案,此時卻發現,實際要解決的問題放大了N倍。不只物件變多、商業邏輯複雜,連帶著軟體架構也需要一起考慮。這些都是在學習TDD階段沒有冒出來的因素(forces)。

奇怪,為什麼看別人TDD,只要透過撰寫測試案例,物件與介面好像信手拈來就有。換成我來TDD,就D不出來,最後只能XD。


▼如下圖所示,這個問題隨著驗收測試開發(ATTD)、行為驅動開發(BDD)、實例化規格(SBE)等方法,將原本傳統TDD「先撰寫失敗單元測試」提升為「先撰寫失敗驗收測試」之後稍有緩解。驗收測試提供TDD一個更大的Context (背景、脈絡),讓開發人員擁有更多的資訊來「隔空抓藥」,透過測試案例描述物件以及物件之間的互動關係。


▼Specification By Example範例


但就算有了驗收測試,整個系統的全貌還是無法清楚呈現,透過每次撰寫失敗測試案例來完成系統依舊屬於由下而上的開發方式。

由下而上的開發方式最大的問題就是:「最後兜出來的系統很容易長歪掉。」看到這裡鄉民們可能會想:「敏捷開發是一種迭代與增量的方法,這不也是一種由下而上的方式?難道敏捷開發也很容易長歪掉嗎?

沒錯,完全正確。這也是為什麼現在敏捷開發流行採用「影響力對照(impact mapping)」與「用戶故事對照(user story mapping)」協助團隊關照系統全貌。撰寫程式之前,不管這個程式是test code還是production code,如果對於所開發的系統缺少一種「整體的感覺」,最後的系統設計就很容易長歪掉。

***

怎麼辦?

其實答案很簡單,就是準備「剛剛好的事前設計」(just enough up-front design)。問題是怎麼拿捏這個「剛剛好」?

▼如下圖所示,對照OOAD與TDD/BDD/SBE的做法,後者少了強調「建立領域模型」(domain model)這個步驟,讓鄉民以為domain model裡面的物件,不需要特別分析與設計就會自然而然隨著撰寫失敗的測試案例而冒出來。就算是剛開始找到的物件不洽當,反正最後總是可以透過重構來改善設計品質。


能力強者如Kent Beck或Uncle Bob等級的人物,在腦海中已有某種 皇輿全覽圖「軟體全貌地圖」,因此可以信手拈來得到合適的領域物件。就算設計不小心歪掉,後續採用重構來改善系統設計品質對他們而言也不是難題。大師們只需極小化的事前設計便可順利透過TDD完成系統,但一般大眾畢竟敏捷性沒有那麼高,所以適量的事前設計有助於TDD。

扯了這麼久還是沒講到具體解法。以下是Teddy建議的方向:

  • OOAD:如果鄉民們學過OOAD,可以參考80-20原則。找出系統中20%最優先的use case或user story,花一點點時間地建立domain model。有了這個domain model,對於後續將「失敗測試案例」轉成test code會很有幫助。


▼cleanKanban系統的領域模型


  • DDD:參考領域驅動設計方法(Domain-Driven Design;DDD),建立domain model與通用語言(Ubiquitous Language)。有這兩項「致命武器」,後續不管你想「怎麼D」都可以得心應手。


▼透過事件風暴(event storming)找出領域事件與建立領域模型


  • Clean Architecture:軟體架構百百種,屬於「插件式架構」的Clean Architecture,因為具備高度擴充性與可測試性,很適合作為各種軟體的「預設架構」。搭配Clean Architecture,撰寫TDD的失敗驗收測試直接對應到呼叫Use Case,而Clean Architecture的Use Case有著固定的結構,需要定義清楚的Input與Output介面。也就是說,Clean Architecture限縮了開發者的「選擇性」,而讓TDD的開發的工作變得更簡單。

▼搭配Clean Architecture採用TDD開發所撰寫的失敗驗收測試。

***

結論

敏捷開發與TDD都不鼓勵大量事前設計(Big Up-Front Design;BUFD),但並不是說不需要任何事前設計直接「帶著鋼盔往前衝」就可以攻克敵軍山頭。合適的事前設計,可以幫助開發人員釐清目標,支撐後續迭代與增量式開發活動,讓整體設計慢慢湧現。

***

友藏內心獨白:緣分到了,問題就想通了。


廣告

對於Clean Architecture搭配TDD與Event Storming(事件風暴)有興趣的鄉民,可參考泰迪軟體的【Clean Architecture這樣學就會了實作班】,2019年4月份課程已確定開課。

2019年3月14日 星期四

無用之用

March 14 16:37~18:06


The Timeless Way of Building》這本書從2003年5月30日入手起算到現在已將近16年。剛到手時幾乎每天都在傻傻地讀,因為看不懂作者想要表達的真正意思,只能硬著頭皮念下去。這本書的英文用字與文法不算太難,而且有中文版可以對照著看,所以讀不懂的主要原因倒不是因為語言隔閡,而是無法理解作者背後的整體思想。作者的腦袋裡不知道裝什麼,真是太奇葩了XD。

有人可能會問:「念資工的幹嘛去讀建築的書?當然看不懂啊。」當初因為博士論文想研究設計模式,指導教授說:「要研究pattern,不能只看GoF 的《Design Patterns》這本書,要從源頭去研究pattern發明人Alexander的作品。

就因為這句話,Teddy立刻上Amazon買了《The Timeless Way of Building》、《A Pattern Language》以及《Notes on the Synthesis of Form》各兩本。一本自己讀,另一本給指導教授,「暗示」指導教授也要一起讀。總不能只有Teddy一人受苦啊 XD。

***

印象中,過了一段瞎子摸象的日子,後來慢慢地有點感覺,可以將書中的一些講法「硬套」在軟體開發上面,有種重見光明的感覺。

數年後,一直到博士班畢業,Teddy都還沒把這本書整本看懂。又過了幾年,泰迪軟體成立後因為要賺錢生存下來,在設計【Design Patterns這樣學就會了–入門實作班】教材時,Teddy特別在第一天的課程介紹Alexander的方法。幾年下來,「Design Patterns這樣學就會了–入門實作班」教了20幾次,不斷地修改教材內容,對這本書的體會又更深了一些。

***

五年多前Teddy開始讀《Domain-Driven Design》(DDD),一開始也搞不清楚DDD到底在搞什麼。表面上看起來,就是另一種物件導向分析設計(OOAD)的方法啊,但仔細一看,和傳統的OOAD味道又不一樣。那是個有點陌生但又熟悉的味道,耶,原來DDD是一種pattern language!作者Eric Evans很顯然也受到Alexander的影響。有了這層認識,再回頭看DDD的眼光就不一樣。不但看得更深入,也可以重複使用以前讀Alexander書本的那些知識。

這就是Teddy之前說的:「有九陽神功護體,學什麼功夫都快。

***

兩個多禮拜前Teddy因為要設計【Clean Architecture實作班】課程教材,用TDD/Specification By Example(SBE)加Clean Architecture加DDD的Event Storming、Ubiquitous Language與Aggregate等技術,幾乎「無痛地」很快就把範例做好。之前對於TDD/SEB有一些沒想清楚的地方,在無形之中居然豁然開朗。這並不是因為這兩個禮拜Teddy吃了天山雪蓮突然功力大增,而是之前下的功夫點點滴滴累積,剛好在這個時間點「因緣成熟」而豐收

如果沒讀過Alexander的書,也許這一切「好事」都不會發生。

感恩seafood、讚嘆seafood。

***

友藏內心獨白:還好在台灣這本書沒什麼人讀,少了很多競爭對手。

2019年3月12日 星期二

關於時間的測試

March 12 07:51~09:07


時光一逝永不回

程式中如果有使用到「時間」,對測試來說是一個很傷腦筋的問題。例如,在看板系統中,想測試一個工作項目(work item)的lead time(從開工到交貨的時間)或cycle time(在某個或某些工作階段停留的時間),如果採用手動測試,測試人員需要不斷修改電腦時間,以便模擬出工作項目停留在不同工作階段的狀況

在〈對付時好時壞的測試案例(5):Time〉Teddy曾經談過這個問題,今天要從程式碼的角度再談一次。

***

程式範例

為了製作「Clean Architecture實作班」課程範例,Teddy最近忙著開發一個看板系統軟體稱為cleanKanban。Teddy參考領域驅動設計(Domain-Driven Design;DDD)的作法,套用Aggregate設計模式。一個aggregate將一小群物件包裝在一起,最上層的物件稱為aggregate root,負責維持不變量(invariant)與交易一致性。

不同Aggregate之間的狀態透過領域事件(domain event)保持同步,下圖AbstractDomainEvent類別代表領域事件的抽象類別,其中occurredOn屬性紀錄事件發生的日期與時間。

上圖中AbstractDomainEvent類別直接透過 new Date()獲得日期物件,這種寫法要撰寫自動測試就很傷腦筋。

學過測試替身Test Double(1):什麼是測試替身?〉的鄉民應該會想到以下兩種解法:

  • 相依性注入技巧,AbstractDomainEvent不要自己產生Date物件,而是讓呼叫它的物件傳入。這種做法有兩個潛在問題:
    • 需要改程式,破壞了既有程式的介面。如果AbstractDomainEvent已經有很多子類別實作,異動到的程式就比較多。
    • 客戶端比較難用。很多領域物件(domain object)都會產生領域事件,代表事件產生時間的occurredOn屬性如果只是因為測試的原因需要外部注入,平添客戶端的麻煩。
  • 採用mock object,透過mock object在測試時直接攔截 new Date()呼叫,注入特定日期。這種做法不需要改程式,在測試案例上動手腳即可。詳細討論可參考stackoverflow的這篇文章

***

透過第三者

除了上述兩種解法,還有一種方式就是透過第三者得到時間物件。撰寫DateProvider類別,透過它間接獲得日期物件。DateProvider 允許使用者注入一個日期物件,在測試模式下可注入特定日期達到模擬不同日期的自動化測試目的。

▼修改AbstractDominEvent的建構函數,透過DateProvide.new() 傳回日期。


▼在測試案例中,將特定日期傳給DateProvider,可以模擬領域事件發生在特定日期的情況。

***

結論

今天談到關於日期測試的三種方法,各有優缺點,視不同情況可能都會派上用場。DateProvider的缺點是,萬一有人要搞破壞在production code裡面呼叫到DateProvider.setDate(),注入一個特定日期,系統狀態可能就整個錯掉。這個問題可以透過把DateProvider寫得更「精緻」一點,只允許在測試環境被注入日期來改善。

關於更多測試技巧,歡迎參考泰迪軟體的【單元測試這樣學就會了實作班】。

***


友藏內心獨白:有月光寶盒才可以穿梭時空。

2019年3月6日 星期三

最新課程:【Clean Architecture實作班】

March 06 14:00~16:20


今年泰迪軟體新規畫一門兩天課程:【Clean Architecture實作班】(簡潔架構實作班),這是去年「Clean Architecture嘴砲班」的進化版。今年的新課程,打嘴砲練練嘴上功夫還是必要的,此外增加了一個完整的實作練習,讓大家動動腦與練練手上功夫。

關於這個練習題目Teddy規劃了超過一整年,去年設計好的題目經過實驗發現整體來說有點太難。於是今年Teddy從新設計一個練習範例,除了學習Clean Architecture以外,還同時兼顧TDD/BDD/SBE,並借用DDD(領域驅動設計)的Ubiquitous Language(通用語言)Event Storming(事件風暴)AggregateEntity來幫助學員分析domain model(領域模型)的物件邊界。

今天簡短介紹一下課程範例。

***

看板系統需求

課程範例要開發一個看板系統(Kanban System),稱為cleanKanban。看板範例如下所示,由不同工作階段所組成,以下圖為例,有待辦事項、分析、實作、測試、可佈署等五個工作階段。

▲看板範例


每個工作階段還可以分為子工作階段,以上圖為例,待辦事項細分成「想法」與「Top 6」,分析階段細分成「進行中」與「完成」。

使用者將工作項目移入不同的工作階段,以視覺化方式追蹤工作進度。每個工作階段可以設定WIP上限(Work In Progress Limit),當工作項目已達WIP上限時,就不可以再拉入工作到該工作階段。

最後,系統要計算工作項目在每個工作階段所停留的時間,稱為Cycle Time,以及Lead Time

結論就是,cleanKanban系統要支援看板系統三原則:

  • 視覺化(工作流程)
  • 限制WIP
  • 管理工作流

***

測試驅動開發/行為驅動開發

Clean Architecture的重點之一就是將系統分層,如下圖所示,由內而外分別是:Entity(Domain Model)Use CaseInterface AdapterFramework and Driver

▲Clean Architecture,圖片來源在此


課程採取測試驅動開發(TDD/BDD/SBE)方式,首先寫出規則(Specification)例子(Example)


看到這裡鄉民們可能會想:「要用BDD或Specification by Example方法,需要使用Cucumber或SpecFlow工具嗎?

答案是:可以使用但先不要用工具之前,先練習用腦,以免在學習過程中被工具綁住。本練習只需要最簡單的xUnit單元測試工具即可 。


▲用JUnit撰寫第一個失敗的驗收測試


▲因為要套用Clean Architecture,最後的驗收測試長成這樣,直接呼叫use case。

***

事件風暴(Event Storming)

Clean Architecture非常重視領域模型的建立,如果有學過物件導向分析與設計(OOAD)的朋友,可以沿用原本OOAD的技巧來建立領域模型。在這門課中,Teddy將介紹在領域驅動設計很流行的事件風暴,來協助建立領域模型與通用語言。

***

專案結構

最後開發出來的專案結構,反應Clean Architecture的三大原則:

  • 分層原則
  • 相依性原則
  • 跨層原則

***

課程費用

  • 原價$22,000元。
  • 早鳥優惠: NT$18,900/人(2019年3月19日前報名並完成繳費。)
  • 2人團報:$17,900 元/人。
  • 嘴砲班舊生優惠:$9,900 元/人(僅限五名)。

課程網址:http://teddysoft.tw/courses/clean-architecture/

上課地點:台北市(近台北車站)。2019年4月19、20日(五、六),09:30-16:30,共12小時

image

***

友藏內心獨白:一個課程三種享受—Clean Architecture、TDD與DDD。