l

2021年12月31日 星期五

2021年終心得:Coding & Learning

Dec. 31 20:34~22:08

截圖 2021-12-27 下午3.59.13

 

上次寫年終心得是〈2019年終心得:突破〉,這兩年疫情爆發,也發生了不少事,加上晚上有空,寫個2021年回顧好了。
今年的心得可以用Coding & Learning兩個字來概括。

2021年泰迪軟體的重大事件有:

***

業績

今年泰迪軟體的營業額是成立以來最高的一年,比2019年的高點還要多一點點。雖然因為疫情緣故很多傳統的課程像是Scrum、Design Patterns公開班今年都只開了一次,重構與測試的公開班課程則是完全停開,但受惠於【領域驅動設計與簡潔架構入門實作班】頗受鄉民歡迎,開了好幾梯次的公開班與企業內訓,反倒是增加不少收入。

但【領域驅動設計與簡潔架構入門實作班】之所以受歡迎,源自Teddy在2019年說過的一段話:「研究許久的Clean Architecture(簡潔架構)Domain-Driven Design(領域驅動設計),今年結合了這兩者,發現無論是在架構上、problem modeling以及coding,軟體開發與維護變得比較容易也更系統化。」

加上從2020年6月底開始,Teddy與北科大軟體系統實驗室的ezKanban團隊開始mobbing,至今花了超過1500小時的時間一起開發ezKanban。在這個過程中大量套用DDD、Event Storming、Clean Architecture、Event Sourcing、CQRS、TDD、Design by Contract(DBC)、Exception Handling、Specification by Example(SBE)、Living Documentation、Continuous Integration、Refactoring等方法,幾乎快把Teddy畢生所學都用在上面。

Teddy很喜歡Kent Beck說過的一句話:「If you stop coding, you stop learning」身為一位軟體開發從業人員,不管到了什麼階段,還是應該持續保持寫程式的習慣。寫程式的目的不一定是要拚production code的數量,而是要從中學習。這種學習的深度,會與所寫的程式數量成正比。寫得越多,領得越多。啊,不對,是寫得越多,學得越多。

今年七月ezKanban幾位研二學生畢業之後團隊只剩下3位學生,後來OIS團隊加入,增加了一搏、二碩、三大,一共六個人。感謝這幾位學生今年和Teddy一起mobbing,度過許多美好的coding時光。

***

畢業

2019年Teddy提到Erica已經能夠獨立作業,在敏捷教練、引導、敏捷需求管理方面也有不錯的成績。今年9月底Erica從泰迪軟體畢業,回到她的家鄉生活與工作。

泰迪軟體一開始就只有「Teddy」一個人,Erica加入之後,幫了很多忙,很多事情是Teddy能力範圍以外,剛好是Erica比較擅長,兩人互補。Erica剛到泰迪軟體的時候,Teddy告訴她:「我沒有把你當成員工,而是把你當成博士生來看待。我對你的責任就是希望能夠讓你有一技之長,別人不是因為你是泰迪軟體的Erica而付你錢,而是因為你是Erica而付你錢。這一天到來,就等於你博士班畢業。」

其實Erica的「點數」在2019年已經集滿,達到畢業的標準,算是在泰迪軟體多幫忙2年。當年Teddy博士班唸了N年,雖然捨不得但終究還是要離開實驗室。「畢業」,是另一個成長的開始,不是結束。


泰迪軟體又回到只有Teddy的公司,反映公司的名稱,可能是當初取名子就已經決定好的宿命XD。

***

感恩

2021-12-29 22.53.51

▲難得三喵同床

 

明年Teddy預計將ezKanban部署成微服務架構,在微服務架構上再多花點時間深入研究,同時準備這方面的新課程。另外,最近Teddy找到一個在DDD中簡單落實Living Documentation的方法,明年也會花點時間在這上面。

最後感謝2021年直接或間接金援泰迪軟體的所有鄉民與親朋好友。沒有金錢的幫助,泰迪軟體無法經營下去,當然也就沒有現在的Teddy。

對於一個不拉幫結派、不搞花俏行銷、不造神,相信把自己的專長持續做到最好就有一線生機的笨蛋,還可以在這片土地上生存下去,而且活得快樂、活的有尊嚴。除了感恩,還是感恩。

***

友藏內心獨白:想不到更好的,重複使用了2015、2019年的結語。

2021年12月23日 星期四

無痛將驗收測試文件寫在測試案例中

Dec. 23 20:18~21:45

截圖 2021-12-23 下午9.42.42

▲新買的電腦還沒寫code先來寫部落格

 

前情提要

2017年Teddy寫過一系列關於行為驅動開發(Behavior-Driven Development,BDD)的文章,請參考以下列表:

  1. BDD(1):詳盡的文件就是可用的軟體
  2. BDD(2):大家來吃小黃瓜之Cucumber運作原理
  3. BDD(3):在Eclipse執行Cucumber-JVM
  4. BDD(4):第一個Cucumber-JVM範例,上集
  5. BDD(5):第一個Cucumber-JVM範例,下集
  6. 在IntelliJ IDEA使用Cucumber(上)
  7. 在IntelliJ IDEA使用Cucumber(下)
  8. BDD(6):讓Step找到Step Definition
  9. BDD(7):使用Transform讓稅金同時支援5%和0.05表達方式
  10. BDD(8):實作第一個開發票Scenario
  11. 在IntelliJ IDEA使用Cucumber(上)
  12. 在IntelliJ IDEA使用Cucumber(下)

 

當時學了一陣子Cucumber但後來一直沒有真正使用它。主要原因在於Teddy覺得「Cucumber將需求寫在feature file裡面,然後再轉成step definition程式碼,然後開發人員在這些step definition立面撰寫真正的測試邏輯」的這種流程不太流暢。完整開發一個功能,從寫feature file到寫完produciton code的過程會一直撞牆(卡住),尤其是feature file有參數要傳給step definition,真的不太直覺。

但當時Teddy也沒多想,就把這個問題放著。

***

活文件

前幾天讀了《Living Documentation: Continuous Knowledge Sharing by Design》,書中有一個例子如下圖所示:

 

截圖 2021-12-23 下午8.59.19

▲圖1:Living Documentation書中範例

 

看到這個例子Teddy突然心中有感:「對了,就是這樣。應該要把Cucumber的feature file內容寫在程式碼中而不是與程式碼分離。」於是Teddy也試著修改ezKanban的測試案例看看效果如何,請參考下圖:

 

截圖 2021-12-23 下午9.26.24

▲圖2:修改後的ezKanban驗收測試案例

 

Teddy覺得直接在測試案例程式碼加上Given-When-Than說明文字讓測試案例清楚很多,也免去了原本Cucumber在feature file與step definition之間做binding的麻煩。

至於圖2中Scenario(), When(), WhenFailure()是怎麼來的?其實很簡單,原本Teddy以為書中用了什麼工具,但找了一下沒找到。後來想到,自己寫一個不就好了。程式很簡單,長成下面這樣:

截圖 2021-12-23 下午9.34.27

▲圖3:用來在測試案例中撰寫Given-When-Than說明文字的工具,算是一的超級簡單的DSL(domain specific language)

 

這種做法,與程式語言和工具都無關。絕大部分的高階語言要寫出圖3中的程式應該是幾分鐘就搞定的事。

 

***

 

友藏內心獨白:本篇在新買的第12代i9電腦上撰寫XD。

2021年10月5日 星期二

頭痛醫腳,腳痛醫頭

Oct. 05 17:24~18:55


幾年前有一陣子Teddy的左腳腳底板只要踩到地上就好痛,觀察了幾天都沒改善,查了網路資料,感覺很像足底筋膜炎。找了一天去看家裡附近的的復健科整所,把症狀告訴醫生之後,Teddy跟醫生說:「我覺得我好像是足底筋膜炎」。

醫生聽完之後面帶微笑,要Teddy擺出幾個姿勢,然後說:「你要拉腰。」

明明是腳底痛,為什麼要去拉腰?

醫生說:「你這是腰椎突出影響到腳,我看過很多類似的病人,他們也都以為是腳有問題。但這個現象一般來講只要拉腰就可以改善。」

Teddy半信半疑之下持續去復健拉腰,沒想到後來腳底板疼痛的問題就消失了。

***

最近有一位客戶打電話給Teddy…

Teddy:泰迪軟體您好,我是Teddy。

客戶:Teddy老師你好,我們是XX公司。

客戶:請問你們有單元測試的企業內訓課程嗎?

Teddy:有啊,泰迪軟體所有公開班課程都提供企業內訓。

客戶:是這樣,最近我們的系統出了點包,公司想要提升軟體品質,長期來講要做持續整合與持續佈署,短期想先從測試開始。

Teddy:這很合理,一般人想到提升品質、減少bug,直接就想到測試。

客戶:所以我們從自動化單元測試著手是OK的?

Teddy:從測試著手有兩個方向,第一個是人工測試,雖然看起來很笨,但只要有錢,這是最簡單又立即可以看到效果的方法,但長遠來講會不符成本,畢竟用人工方式做回歸測試不只成本高,速度也慢。

Teddy:如果從自動化單元測試著手,不是說員工學會測試技巧就可以快快樂樂寫出有效的單元測試。依據我的經驗,很多人不寫單元測試,或是說寫不出單元測試,不是因為測試太難,而是因為設計太爛

Teddy:因為設計太爛,所以耦合太高,系統很難獨立測試。這時候,可能需要先教同仁基本的物件導向設計觀念與SOLID等原則,更進階要學習Design Patterns與Clean Architecture。軟體設計品質提升,測試自然變得比較容易。

***

軟體品質不好,不一定直接從測試著手。有沒有可能是需求一開始就錯了?或是規格沒弄清楚?如果是這種狀況,也許要先學Event Storming、Specification By Example與Design By Contract。有沒有可能是設計過於複雜導致錯誤?如果是,應該先改善設計品質,讓設計簡單到不會出現明顯的錯誤。

設計與測試是一體兩面,設計能力好的人,通常測試也做得好,反之亦然。

***

友藏內心獨白:兩點之間最短距離通常不是直線。

2021年9月15日 星期三

成本與價值

September 15 18:36~19:02

▲ezKanban 團隊mobbing實況


學員:如何讓整個團隊,包含剛進來的新人,都可以學會用DDD(領域驅動設計)開發軟體?

Teddy:我有一個很簡單且有效的方法,但這個方法就算你知道了你們公司應該也不會採用。

學員:什麼方法?

Teddy:Mobbing,又稱為Mob Programming,整個團隊,包含測試、UI/UX與Product Owner,一起開發軟體。

學員:類似Pair Programming嗎?

Teddy:對,不過是Pair Programming的加強版,不只是兩個人一起開發,而是整個團隊。

學員:這樣的確是很難在公司推行,Pair Programming老闆都覺得成本太高

Teddy:那你們都怎麼帶新人?

學員:我們會指派一位導師帶著新人做一陣子。

Teddy:然後呢?是不是一、兩個禮拜之後就讓新人單飛,然後每天問他進度?

學員:(苦笑)沒有這麼慘啦,有問題還是會回答。

Teddy:軟體開發的成本,其實很難量化。老闆通常只看到「開發人員」的成本,因為這是最直接的成本。但除了直接寫code以外,其他的成本呢?

Teddy:你要不要Code Review?有bug要不要改?要改多久?做出來的東西客戶不要怎麼辦?舊員工離職新員工交接怎麼辦?軟體搞到變成硬體,改不動也沒人敢改怎麼辦?後端、前端、內人、外人互相等對方工作完成怎麼辦?需求不清楚開發人員亂寫怎麼辦?測試團隊自創需求,胡亂回報issues怎麼辦?

Teddy:從精實開發的角度來看,這些都是浪費。很多的等待(延遲)、重工、半成品、過度生產、交接、缺陷、工作切換、重複學習。我不敢說Mobbing可以完全消除這七種浪費,但以我的經驗,這種「看起來成本太高」的開發模式反而能夠消除浪費而降低成本並提高產品的品質與價值。

Teddy:老闆覺得開發成本太高,會不會是因為自身的產品在市場上的價值太低,或是想要犧牲品質來拉低成本,所以任何提高品質的活動都會被認為是增加成本。不管如何,這有可能是對於自己產品的定位不同,產生的價值觀落差。

***

沒有銀子彈,但是有高科技武器跟二戰時的武器之分。

***

友藏內心獨白:知道了也做不到。

2021年9月14日 星期二

有沒有發出聲音?

September 14 10:25~11:16

▲電影《達摩》畫面


幾年前讀了某本與禪學有關的書,書中提到一個公案:

「在深山中有一片茂密的森林,一棵大樹倒下,發出巨大聲響,但沒有任何人聽到。請問這棵樹有發出聲音嗎?」

***

梁武帝

梁武帝是一位篤信佛教的皇帝,在電影《達摩》中他與達摩會面,他問達摩:

梁武帝:「自朕登基以來,修佛寺,造佛像,抄寫經卷,供養僧侶無數。敢問大師,朕有何功德?

達摩:「無功無德。」

***

一棵大樹倒下,它不甘寂寞,怕沒有人知道它輝煌的一生,所以問了大師自己有何功德?

在電影中志公大師對梁武帝說:「皇上本有功德,但常掛口中,要人稱讚,便是刻意貪圖功德。善惡抵銷,也就沒有功德啦!」

***

政客

很多時候,政客為了自己的政治利益,大撒幣搞大內宣,明明沒有任何樹倒下硬是要誇稱自己做了什麼偉大的事。例如:台灣政府購買的疫苗數量已經夠了、廣告說明是劉德華演唱會,現場來的卻是蘆洲劉德華、演講題目是介紹DDD,但實際內容卻是資料庫驅動設計。

正所謂三人成虎,這種似是而非的大內宣,講久了還真的可能有人會相信。反正政客服務的對象原本就不是全體國民,只要能夠騙到「韭菜」就可以了。

梁武帝至少還做了點什麼,但政客型的人,光靠一張嘴騙選票,刻意貪圖功德的本領遠勝於梁武帝。

***

什麼是真的?

什麼是真理?這是一個很困難的哲學問題。樹的確倒下了,但世界上沒有人發現。從人的角度來看,並未觀察的樹倒下,不知道的事情等於不存在,這也是很合理的觀點。

對樹而言,我倒下了有必要到處宣傳讓人知道嗎?

你想要成為怎樣的樹?

***

友藏內心獨白:Quality Without A Name。

2021年9月13日 星期一

Clean Architecture是一種過度設計嗎?

September 13 11:24~11:46

▲恰如其分的設計,還是過度設計?


有一位學員問Teddy…

學員:Clean Architecture是一種過度設計嗎?

Teddy:怎麼會這樣想?

學員:我跟同事討論設計問題,同事覺得我們系統不大,如果套了Clean Architecture,這樣來看Clean Architecture算不算是一種過度設計(Over Design)?

Teddy:你知道Mac Pro嗎?

學員:知道。

Teddy:如果買到頂級的Mac Pro,一台要價超過一百六十萬台幣。這麼高的規格,請問你可以說Mac Pro是一種過度設計嗎?

學員:嗯……

Teddy:如果你買了一台頂規的Mac Pro,只是拿它來上上網,寫寫小程式,在這種情境之下你可以說這是一種「過度消費」,因為你買了你用不到的計算能力。但如果你是專業的影音剪輯人士,一台一百多萬的Mac Pro對你而言可能只是剛剛好而已,甚至還會覺得不足以應付你的工作。

***

Clean Architecture是一種過度設計嗎?

領域驅動設計是一種過度設計嗎?

Design Patterns是一種過度設計嗎?

微服務是一種過度設計嗎?

陶朱隱園是一種過度設計嗎?

高鐵是一種過度設計嗎?

以上皆非,它們都只是一種「設計」,至於這種設計是不是過度或是恰如其分,則是要看應用的情境(Context)而定。

一個事物的含意,必須放在特定的情境去解讀才有意義,才可以避免產生誤會。

***

友藏內心獨白:這就是DCI。

2021年9月10日 星期五

領域驅動設計學習筆記(22):貧血模型與充血模型(下)

September 10 03:38~04:58

▲ezKanban的Board Aggregate套用DCI之後,可以動態指派新的角色給它,以便獲得新的行為能力。


阿嬤的物件導向

DCI架構(Data, Context, Interaction)由Trygve Reenskaug和James O. Coplien所提出,這兩位都是軟體界的名人,前者是MVC(Model-View-Controller)架構發明人,後者是模式與敏捷領域的大師。Teddy今年6月曾介紹過DCI並應用它來重構DDD Aggregate:

***

傳統認為好的領域模型應該設計成充血模型(Rich Domain Model),物件身上封裝著資料與操作該資料的商業邏輯,程式比較容易閱讀與維護。貧血模型(Anemic Domain Model)則被認為是不好的物件導向設計,它將商業邏輯從物件身上抽離出來,物件行為被降級成單純的資料庫操作,因此導致商業邏輯不清、系統難以維護。

Coplien 在介紹DCI的演講中曾說過:「傳統物件導向將資料與行為封裝在一起的做法,是你阿公時代的物件導向技術。」他建議採用DCI架構,將系統區分為DataContextInteraction。DCI架構主張物件的行為,必須要放在特定的使用案例(Use Case)裡面來解讀,才能夠理解其意義。

舉個例子,「人」這個物件,具備「唱歌」的行為。但當一個人在唱歌的時候,到底代表什麼意義,必須從使用案例中去理解。你在KTV唱歌、在學校朝會唱歌、在當兵的時候唱歌、在求婚的時候唱歌、在失戀的時候唱歌、在遊覽車上唱歌、在無人的海邊唱歌、在選秀節目中唱歌、在監獄裡面唱歌,意義可能完全不同。在DCI架構中,將這些不同的使用案例稱為Context(情境、脈絡、上下文)

人這個物件,只需具備資料(Data)即可。至於人到底具備哪些行為,則是在某一個特定Context中,由Context將所需行為動態「注入」到人身上。一個Context經常需要協調多個物件一起工作,這個協調的動作在DCI架構中就稱為Interaction(互動)。

***

何處惹塵埃

上一集,Teddy將「Object is a poor man’s closure, and closure is a poor man’s object.」改寫成「貧血模型是富人的充血模型,充血模型是富人的貧血模型 。」不少鄉民不知道Teddy在瞎說什麼。

為什麼說貧血模型是富人的充血模型?從DCI(富人)的角度來看,貧血模型就是資料物件(Data Object),物件的真正行為延後到執行期間再由Context指派給它。所以,你希望物件有什麼行為,沒問題,爸爸(Context)都可以指派給你。這麼豐富的行為,領域物件還能不「充血」嗎!

為什麼說充血模型是富人的貧血模型?充血模型最佳代表,就是DDD的領域模型(Domain Model)。在DDD中,領域模型主要由一堆充滿行為的Entity、Domain Service、Value Object所構成。其中若干個Entity與Value Object依據商業規則被迫「群聚在一起」形成Aggregate(聚合),並從中找一個Entity出來當「大股頭」(Aggregate Root)號令這個「部落」(聚合)。

客戶端(漢人、老外)只可透過Aggregate Root存取內部的Entities或Value Objects,因此Aggregate Root身上會有很多行為,更是充血到爆。為什麼Teddy會說這些充滿行為的領域模型是「富人的貧血模型」?因為這些行為都是在編譯期間(Compile Time)就已經決定了,因此雖然從傳統物件導向的角度來看它們的血量都很足夠,但從DCI(富人)的角度來看,它們也只是另類的貧血模型罷了。

***

結論

世事無絕對,端看造化而定。

***

友藏內心獨白: 統領埔到底要租給誰,搞得我好亂啊 XD。