l

2020年8月4日 星期二

3C採雷記

August 03 15:19~16:00

螢幕截圖 2017-08-03 15.52.07



Teddy的指導教授曾經說過:「要害一個人,就送他一台電腦」,這真是一句至理名言。

***

成功經驗

去年底買了新MacBook Pro用來替換使用多年的MacBook Air。新電腦跑起來很快(廢話),同時開Chrome(四、五十個tabs)、Safari、Parallels跑Windows 10加PowerPoint加Word加Visual Studio 2017社群版、Eclipse、IntelliJ都還「hold得住」。用了一陣子之後開始想,是不是應該升級外接螢幕,從24吋HD解析度升級到27吋4K。

因為新MacBook Pro只剩下USB-C接口,想找一台有支援USB-C輸入的顯示器。找了好久前一陣子才決定買了ASUS MX27UC,用到目前為止很滿意。

後來想多買一個外出電源轉接器,原廠那個「白豆腐」太大也太重,加上長達兩公尺的USB-C電源線也不好收納。找來找去找到Innergie PowerGear 45瓦USB-C筆電充電器,瓦數只有原廠87瓦的一半多一點點,還好實際使用之後發現可以正常充電而且電池也都維持在100%狀態,外出使用應該是沒問題。

***

採雷經驗

七月到台中上「Scrum敏捷方法實作班」,到了之後才發現場地的投影機只有HDMI介面,而Teddy只有Apple原廠的USB-C轉VGA轉接器,臨時拿Erica的筆電來用。還好上課資料都放在Dropbox裡面,無縫接軌的順利上完兩天課程。

課程結束後開始尋找合適的USB-C轉HDMI轉接器。當初是趁著Apple原廠打五折的時候買了USB-C轉VGA和USB-C轉USB-A轉接器,現在恢復原價之後。





9月16、17、23(六、日、六)
***

友藏內心獨白:。

2020年7月17日 星期五

領域驅動設計學習筆記(9):Query和Read Model

July 17 12:40~13:48

▲圖1:解釋所有事情的一張圖,取自《Introducing EventStorming


背景介紹

在Alberto Brandolini的《Introducing EventStorming》書中,有一張圖用來解釋他對於採用event storming塑模問題的想法,如圖1。


▲圖2:解釋所有事情的一張圖,取自《Introducing EventStorming


把圖1用event storming展開,出現如圖2所示的流程:

  1. 使用者執行Aggregate身上的Command。例如,在看板系統中,使用者新增看板(Create Board)、移動卡片(Move Card)。
  2. Aggregate執行完Command後發出Domain Event,用來代表系統狀態發生改變。例如看板已新增(BoardCreated)、卡片已移動(CardMoved),
  3. Domain Event也可能由External System所產生,例如,收到銀行傳來的付款確認(PaymentConfirmed)事件。
  4. 剛剛上述行為屬於Write Model,也就是執行Command改變系統狀態並產生領域事件。但使用者不只會改變系統狀態,也需要讀取系統資訊,以決定要執行哪一個Command。表達讀取資訊的模型稱為Read Model,它可以從改變狀態的領域事件而轉換出Read Model。
  5. 將這個Read Model傳給UI,可以做出最後使用者看到的系統畫面。
  6. 使用者看到系統畫面,或更抽象的表示,看到Read Model,從而做出決定,執行下一個Command。
  7. 圖2中的Policy表示發生領域事件之後需要後續處理的事情。例如,當使用者註冊成功,則寄發啟動帳戶的email。

***

Event Storming + Clean Architecture

▲圖3:cleanKanban範例,將Read Model簡化成Use Case的Input


Teddy在上〈領域驅動設計與簡潔架構入門實作班〉教導學員用Event Storming來建立Domain Model與Ubiquitous Language。在實作面,套用Clean Architecture,並採用TDD/SBE的方式來撰寫程式。因為Clean Architecture最核心之處在於Entity Layer與Use Case Layer,把UI和DB都當成技術細節,因此在塑模時先不考慮。

所以Teddy把原本Event Storming的綠色便利貼,由原本的Read Model,簡化為使用者看完Read Model之後,決定要執行哪一個Command所給予的參數。例如,顧客去麥當勞櫃台點餐,他看到Menu上面有1號餐、2號餐、N號餐等,這個Menu就是Read Model。最後使用者決定要點一份5號餐,外加一份大薯條,這些資料就是Input。

***

加上Query

如果只是實作後端,從Clean Architecture的角度來看,上面這些分別代表Command、Aggregate、Domain Event、Policy、Read Model(Input)以及UI 的便利貼,也就夠了。但實際開發完整的軟體需要接上前端,此時發現少了一種便利貼:Query

Command是會改變系統狀態不傳回值的操作,Query則相反,不會改變系統狀態但會回傳值。圖1與圖2中,Domain Event—>Read Model之間,應該還需要補上Query,這樣子參考Event Storming轉成程式碼的時候就可以有一對一的對應關係,如圖4所示。


▲圖4:ezKanban範例,由Query (Get Home Content) 產生Read Model (或稱為View Model),再將此Read Model顯示在UI上。


在圖4中,Query並不像Command需要傳給Aggregate,其實作方式可以透過撰寫Read Repository以及搭配Projection (將原本適合用來寫入的Write Model資料映射成適合讀取的Read Model資料)。

***

結論

加上Query之後,整個Event Storming的便利貼就更完整,也可以和UX/UI設計師討論人機互動的問題。

但是,加上Query與UI,整個模型也變得更加複雜。從軟體架構的角度來看,是否在軟體開發初期就需要增加這樣的複雜度,也是一個可以討論的議題。當然可以只針對Core Domain以及支援商業流程的主要Read Model優先設計畫面,其他次要部份採用迭代與增量的方式來實作,也是一種選擇。

***

友藏內心獨白:Model 不是越詳細越好,只要能表達problem domain我們所關心的問題就好。

2020年7月7日 星期二

領域驅動設計學習筆記(8):幫Event Handler取個好命字

July 07 13:32~14:50

▲幫Event Handler取個好名字


最終一致性(Eventual Consistency)

領域驅動設計(Domain-Driven Design;DDD)引入Aggregate,更新同一個Aggregate需要保證交易處裡的一致性達到ACID要求。跨Aggregate之間則是透過領域事件通知,達到最終一致性(eventual consistency)即可。


▲圖1:Board與Workflow兩個Aggregate


以cleanKanban系統為例,圖1表示兩個Aggregate—Board與Workflow的關係,一個Board擁有零到多個Workflow。因為兩者是獨立的Aggregate,當新增Workflow之後,Board需要收到WorkflowCreated領域事件通知,才能夠建立它與Workflow之間的關係,如圖2所示。


▲圖2:Aggregate之間透過領域事件更新狀態


***

取名字

圖2是Event Storming(事件風暴)產出圖表,Event Storming定義了Domain Event、Command、Aggregate、Read Model、Policy、External System等便利貼,但是沒有代表處裡事件的Event Handler。

基本上Event Handler是一種程式實作細節,是落實Policy的實作方式。為了落實DDD的ubiquitous language in code,Teddy希望Event Storming也可以用表達Event Handler的便利貼,以便於實作時可以看著Event Storming圖表來寫程式碼。


▲圖3:新增不同顏色便利貼並直接用EventHandler當名字


Teddy一開始嘗試增加一種新顏色的便利貼,並把它貼在要透過Domain Event達到最終一致性的兩個Aggregate之間。如圖3所示,WorkflowEventHandler負責聽取WorkflowCreated領域事件,然後呼叫Commit Workflow使用案例建立起Workflow與Board之間的關係。

現在試著讀一下這個模型的通用語言:


Teddy執行Create Workflow使用案例,執行完畢後產生Workflow Created領域事件。WorkflowEventHandler一收到Workflow Created,執行Commit Workflow建立剛剛新增的Workflow與它所屬Board的關聯。


2020年6月22日 星期一

UML Class Diagram小抄

June 22 10:12~10:38

▲小抄第一頁


明天要上第十梯次【敏捷開發懶人包:物件導向技能】課程。這門課主要是介紹物件導向觀念、SOLID原則、DBC,以及OOAD流程快速導覽。以往在課堂上Teddy並沒有講UML,當課程進行時如果有學員不清楚再補充說明。

前陣子參加一場碩士班口試,發生學生有一張基本的UML class diagram畫錯,這件事一直放在Teddy心中。UML 2.5.1版規格書一大本754頁,一般軟體工程師並不用去記住所有細節,但一些常用的基本符號大致上還是需要知道,至少做到團隊溝通時不要造成誤會。

這兩天花了點時間整了兩頁的UML class diagram常用符號,想說明天上課還是稍微補充說明一下,對學員應該還是有幫助。

▲小抄第二頁


兩頁的UML Class Diagram小抄可在此下載,有需要修正或加強之處歡迎提供建議。

***

友藏內心獨白:有點重要又不會太重要。

2020年6月20日 星期六

為什麼不反駁?

June 01 09:20~10:26

▲學生發問的問題,圖由學生所繪製


好問題

Teddy這學期在北科教軟體架構課程,設計一個專案給學生練習,題目是:「用DDD + Clean Architecture + TDD,開發看板系統的後端。」這禮拜四在北科上課,學生DD問:「Calculate cycle time這個Command要傳送給哪一個Aggregate?還是應該把這個Command實作成一個Application service?」

由於這整學期Teddy都在教學生如何把Event Storming的產出透過一致性、固定的步驟,在套用Clean Architecture的前提之下,採用TDD方式將設計轉成程式碼,以達到Ubiquitous Language in Code的目的。因此當學生認為他們找不到合適的Aggregate來接收Command,Teddy直覺反應就是:「因為這個Aggregate還沒有存在你們的domain model裡面,是你們還沒開始找,而不是沒有合適的Aggregate。

後來Teddy詢問每一組,得到的回答大都是「沒有合適的Aggregate,直接把這個Command做成Application service。」只有一組將這個Command送給Workflow Aggregate,但Teddy覺得送給Workflow並不合適,因為Workflow沒有Card移動的資料,無法計算cycle time。

***

公堂之上大膽假設

最後Teddy提議增加Cycle Time Calculator這個Class,由它負責計算cycle time,並寫了一段程式碼給學生參考。

Teddy:Cycle Time Calculator是一個沒有狀態的service類別,service有兩種:domain service與application service,它應該屬於domain service,放在clean architecture的entity層。

學生DD:可是老師你說接收Command的對象是Aggregate,而Aggregate是有ID與狀態的類別。但是Cycle Time Calculator是service,它並沒有狀態,這樣不是違反了之前design level event storming的規範?

討論到這裡Teddy不得不稱讚一下這位同學,因為這個問題Teddy之前也沒想過…

Teddy:將design level event storming轉成clean architecture的程式碼的方法是我們自己定義的,我們可以加上一個規則「Aggregate與Service都可以接受Command」。

這種說法感覺有點硬坳,但乍看之下也還說得過去。

***

忙到忘記

回家之後過了一會Teddy才想起來:「這個問題之前和ezKanban團隊開會時曾經討論過!」當時Teddy告訴團隊:「計算cycle time是在Reporting bounded context,它不是看板系統的core domain。因為它是產生報表的domain,是唯讀的,所以我們不一定要套用DDD或是OOAD的方式來建這個reporting domain,也許可以用transaction script就可以產生報表。

但後來Teddy沒有進一步與ezKanban團隊review他們實作reporting domain的程式碼,所以細節上他們到底如何實作Teddy也不知道。

***

討論無身分高低

在這禮拜四上課時Teddy曾詢問ezKanban的人如何實作Calculate cycle time?只得到「設計成service」的答案。後來Teddy發表一堆「公堂之上大膽假設」的言論,ezKanban的人也沒跳出來 打槍 提醒Teddy,這個問題之前曾經討論過。

可能學生預設認為上課只是來聽老師開講,把所謂的「正確答案」記下來就好,不要質疑老師,也儘量不要跟老師對上眼、說上話。

但Teddy的課程不一樣,第一個禮拜上課Teddy就告訴學生:「叫我Teddy就好,不用叫我老師。別的課我不知道,但在我的課堂上我們的關係是平等的,不是上下階級。我只是在課題上扮演老師的角色,你們扮演學生的角色,僅此而已。修這門課我會問很多問題,你要願意與我互動,再來修這門課,不然就請退選。

▲課堂上老師與學生的關係是A還是B?


雖然第一周上課Teddy就把話說得很清楚,但學生心裡還是千百個不願意,可能還是怕被老師擺一道,萬一多說話得罪「方丈」日子就不好過了。但專業討論不應有身分高低,如果學生心中有看法,但礙於身分不敢說,這其實是陷老師於不義,阻礙了課堂上探索知識的機會

***

反思

敏捷開發強調要透明,唯有透明,探索調適才可能發生作用。很顯然Teddy與學生之間的互信可能還不夠,導致學生有看法不好意思公開表達。

不過,學生當下沒提出來也不能排除另一個原因,就是學生自己也忘了,根本沒想那麼多。

***

友藏內心獨白:腦補得太厲害。

2020年5月13日 星期三

學習總在下課後

May 13 18:11~18:59

▲別人的水總是比較甜,江山易改,喵性難移。


行為是否改變

成立泰迪軟體這幾年,遇到企業內訓課程,有些HR問Teddy:「能不能幫忙在課堂上看看誰比較認真,或是出考卷作為訓練成果評量,這樣學生才比較會專心上課。」

這些事當然都可以配合,但我總是跟對方說:「我覺得最好的評量就是同仁上完課之後行為有沒有改變,考試、打上課成績,頂多就是因應公司規定滿足交差的形式要求。」

上完課之後行為有沒有改變,是一件需要後續追蹤的工作,也是一件耗費時間與金錢的工作,絕大多數的公司都覺得:「公司已經出錢辦教育訓練,上完課之後同仁應該就具備那種能力才對。」

除非課程內容難易度不高,否則要求學員上完課之後立刻變成高手是不太可能的事情。不可諱言,有些天賦異稟或是努力很久終於時機成熟的同仁可以在上課當下「開悟」,課程結束之後行為為隨之改變,但大部分的同仁可以藉由上課「獲取新知」就已經很不容易了,要求他們上完課後立刻可以排除萬難做出有意義且持久的改變,實屬不易。就好像看了場精采的電影,觀眾(同仁)在心中對劇情與演員的表現留下深刻印象。但要讓觀眾看完電影之後就變身為導演,可以開工拍戲,那還需要長時間的努力。

下課之後回到工作上,面對的又是現實問題,被一大堆代辦事項追著跑,如果沒有外力協助,光靠員工自己很難有辦法靜下來思考如何改善。與其花錢辦大量的訓練課程,還不如思考是否有可能把部分上課費用拿來找顧問、教練,在課程結束之後和團隊一起,協助團隊改變行為,並且將改變後的行為固定下來,變成新的工作方式

***

終身學習

奧修在《草木自己生長》提到:「知識是借來的,而學習是你自己的;知識是透過文字、語言、和觀念,而學習是透過經驗;知識總是一個結束,你知道了它,它就結束了;學習永遠沒有結束,它總是在途中;學習是一個過程…」

上課可以獲得知識(收集名詞),但學習必須靠自己,它是一個終身的過程。很多教育訓練成效不彰,因為來上課的人頂多只想獲得(收集)知識,而不想學習。教的人也只是講述知識,沒有鼓勵學習。

Teddy相信:「學習在下課之後才真正開始。」所以教學的主要目的,應該是讓學習者具備下課後持續學習的能力。為了達到這個能力,需要介紹基本的領域知識以及設計適合的體驗活動,讓學習者在一個比較輕鬆的情境下獲得這些知識與體驗。

***

友藏內心獨白:學習是軟體開發的瓶頸。

2020年5月12日 星期二

等一個人春天

May 12 14:25~15:50

▲浪浪也會自己生長。


緣起

Domain-Driven Design: Tacking Complexity in the Heart of Software》這本書出版於2004年,當時Teddy正在念博士班,忙著準備資格考與論文,根本不知道有這本書。後來好像曾經聽過DDD這個名詞,當時自己一直把它腦補成MDA(Model-Driven Architecture)。因為自己對MDA沒什麼好感,當然對DDD也就沒興趣 Orz。

***

一面之緣

2013年,在這本書出版9年之後,Teddy忘了在什麼機緣之下買了它。翻了翻書的內容,覺得:

  • Model-Driven Design和以前學過的OOAD(物件導向分析與設計)建domain model的內容大同小異。
  • Ubiquitous Language是一個新名詞,但是它目的和Alexander的Pattern Language很像—A common ground for communication,而且比Pattern Language還要簡單。

以上這兩個模式(Patterns)算是DDD的核心,先被Teddy給「鄙視」一番。繼續往下看,覺得比較「有用」的模式是:

  • Aggregate,將一群緊密相依的物件放在一起,這是一種人為的模組化單位,可以彌補一般程式語言在Package與Class之間的空白。
  • Context Map,表達bounded context之間的關係。

然後呢?就沒有然後了,書就被Teddy丟在一邊。

***

再續前緣

三年前指導教授想把他手邊的軟體架構這門課交給Teddy來教,Teddy參考了近10本軟體架構的書,最後選了當時剛出版的《Clean Architecture: A Craftsman's Guide to Software Structure and Design》。教軟體架構和DDD原本沒什麼直接的關係,因為實作Clean Architecture核心層(Entity Layer)需要建立domain model,而Teddy又不想只是使用原本OOAD的方法,想起DDD關於建立domain model的一些設計模式,於是又回頭探索DDD。

又過了一年,有一天Teddy在YouTube聽一個DDD演講,內容和講者是誰已經忘了,但是聽到一句ubiquitous language in code,好像被雷打到一樣,突然醒過來。這種感覺,就好像當年六祖慧能聽到金剛經的「應無所住而生其心」一樣,當下頓悟XD。

Alexander的pattern language使用對象是,人用它來設計住宅以及都市規劃。如果將pattern language應用在軟體開發上,則可以想像成套用了一群(數個)設計模式來解決一個大的設計問題,這也是原本Teddy對於ubiquitous language的看法。

但是,ubiquitous language不只是這樣。DDD的Model-Driven Design與Ubiquitous Language這兩個模式是一體兩面,如果只把它們應用在「概念層次」,只用來作為領域專家與開發團隊溝通的工具,那就只發揮了DDD一半的功力。還有另一半,而且是打通任督二脈的另一半,就是要將Ubiquitous Language表達在程式碼裡面。所以光是只談ubiquitous language還不夠,加上in code,才是畫龍點睛,才是幫佛像開光。

***

自然生長

Ubiquitous language in code,同樣一句話,當時的Teddy聽了有感覺,換成別人就不一定。就算是Teddy本人,如果早個幾年聽到這句話,也不一定有感覺。

奧修在《草木自己生長:禪的真隨》引用禪師齊內林的話:「靜靜地坐著,什麼事都不做,當春天來臨,草木就自己生長。」雖說「什麼事都不做」,實際上並不是「什麼事都不做」。而是以平常心,認真去做好每一件該做的事情

等到時機成熟,春天到來,草木自然生長。

***

友藏內心獨白:不能揠苗助長啊。

2020年5月11日 星期一

主要的事

May 11 21:34~22:49

▲愛是主要的,品種是次要的。


先因,後果

活到這把年紀,很多事情都看得比較開,執念也越來越少。但因為尚未悟道,還是有一些看不開的關卡,其中就是一個。

俗話說:「錢不是萬能,但沒錢萬萬不能」,沒人會嫌錢太多。Teddy自認對於賺錢的慾望相對而言已經保持在比較低的狀態,三不五時還會因為理念的關係推掉送上門的案子。但當生意比較不好的時候,雖然減少的收入完全不會造成生活困難,但心中還是不免會嘀咕一下,經濟成長率怎麼變負數勒。

這一陣子讀了奧修的《禪宗十牛圖》,書中提到(pp.168~170):

  • 非主要的事,你想要先確定它們,而你以為主要的事將會跟著來。要改變那種態度:先想主要的事,非主要的事就會跟著來。先想主要的事!什麼是主要的事?果並不是主要的,因才是主要的;別人並不是主要的,你才是主要的。
  • 比方說,人們認為如果他們能夠賺足夠的錢,他們就能夠快樂,但事實上事情並非如此。如果你很快樂,你就會很富有……一個快樂的人不可能不是如此。他或許沒有大的皇宮,但他仍是富有的。他或許是一個街上的乞丐,但他仍是富有的。但是你先試著去擁有很多財富,然後你認為你就會快樂,它從來不以那樣的方式發生,因為財富不可能是快樂的一個原因。快樂一直都是財富的一個原因
  • 試著深入去看你的本質,並且想想主要的事情。要很快樂!就在這個片刻你就可以快樂,沒有人在擋你的路。如果你無法在這個片刻就快樂,你將永遠無法快樂。快樂跟未來無關。快樂不知道有明天,因為快樂並不依靠其他任何東西,它只是一種態度,就以你這樣,你現在就可以快樂。
  • 你可以根本沒有理由地快樂,因為快樂是很多事情的理由,它是基本的因。你可以快樂,試試看。你一直都從另外一端來嘗試,現在從基本的因來嘗試。首先有那個因—成為快樂的—然後果將會隨之而來。永遠都要記住不要去找代罪羔羊,那樣做一定會錯過你的生命。

為什麼要賺錢?如果是為了快樂,錢的確可以帶來快樂,但也有很多快樂是錢無法買得到的。錢應該是果,而不是因。是某種主要目標的副產品,但它不是,也不應該是主要的事。

***

價值驅動的極致

關於「錢不是一切」的相關說法已經聽過很多,但奧修的闡述方式,讓Teddy豁然開朗。錢只是一個例子,書中的重點是:弄清楚什麼才是主要的事什麼是因

泰迪軟體成立的是什麼?公司當然要獲利、要生存、要賺錢,但賺錢絕對不是它的因。如果賺錢是主要的因,Teddy應該要專研拍馬屁、欺上瞞下,這樣賺錢還更輕鬆。

回到Teddy的初衷,希望能找到一個讓自己可持續追求The Timeless Way of Software Development的生存模式:不用看老闆、主管、同事的臉色,沒有辦公室政治,只要專心對付(服務)客戶即可。只要這個「因」做對了,錢應該也會隨之而來。

這個道理可以應用在各種場合。以軟體開發而言,什麼是主要的事?人與互動是主要的事,還是流程與工具(敏捷宣言第一條)?軟體架構與設計模式是主要的事,還是程式語言與框架?願景與里程碑(目標)是主要的事,還是User Story以及Tasks?通用語言與領域模型是主要的事,還是Aggregate、Entity、Value Object與Repository?

弄清楚主要的事,才不會瞎忙,心才會靜下來做出正確的決定。

***

靜心

今年因為疫情的關係,泰迪軟體的很多課程都因為招生不足而停開。如果是往年Teddy多多少少都還是有點焦慮。但此時此刻,雖然收入比去年少很多,但內心卻異常平靜。

因為Teddy知道,自己持續在做主要的事。而且,想要快樂就可以快樂,不需要等賺大錢。

***

友藏內心獨白:這是一種阿Q精神勝利法嗎XD。

2020年5月4日 星期一

變成一個點

May 04 09:52~11:19

▲學習的過程就是填滿圖形。


加法

老子說:「為學日益」。學習者,心中有一個學習的標的物(目標),例如設計模式、敏捷開發、軟體架構、人工智慧、大數據、領域驅動開發、測試驅動開發等。

這個目標,在學習者的心中形成某種形狀form),它可能長得像圓形、三角形、不規則圖形。這個形狀的邊界(boundary)界定了學習者的守備範圍,邊界以內屬於學習內容,邊界以外屬於脈絡、背景知識(context)。隨著學習進程,範圍可能會改變,但它總是一個有邊界的形狀,不管這個形狀長得像什麼圖形。

這個形狀一開始是空的,因為學習者還沒學會所需的知識。他藉由讀書、上課、討論、Google、練習、參加社群聚會、模仿、實作等方式,充實自己,填滿這個圖形。

***

智光忽明忽滅

▲從某個角度來看,形狀好像已經填滿了。

在某些片刻,學習者一度以為自己已經完全掌握學習內容,他可以正確回答許多(特定)問題,相當於考試獲得100分的喜悅。他自得意滿地認為,形狀好像已經填滿了。

***

▲換個角度才發現空白處還很多。

但換個角度、換個環境、換個題目、換個發問方式、換個時間、換個專案、換個公司,此時才發現原來形狀之中空白之處還很多,還需要精進學習。

***

▲總是還有填不滿的空隙。

有一天,這位學習者越來越博學,領域知識的名詞幾乎都已經收集得差不多了,如果參加全國性考試一定可以得高分。但是,形狀還沒填滿,還是有一些空隙。

***

變成厲害的人

敏捷宣言說:

藉著親自協助他人進行軟體開發,
我們正致力於發掘更優良的軟體開發方法。

(We are uncovering better ways of developing
software by doing it and helping others do it.)

學習者自己變得厲害只是過程中的一個階段,他還需要練習幫助別人,讓別人在他的幫助之下,有能力完成原本認為很困難無法做到的事情,成為Kent Beck所說的那種「厲害的人」。

▲到了這個時候,形狀已經填滿。

***

減法

▲Quality without a name,特質本身非常具體,變成一個點。它沒有面積,不再是形狀。

老子的道德經在「為學日益」之後還有幾句:「為道日損,損之又損,以至於無為,無為而無不為。」知識的累積,越來越多,就算此時自己覺得已經「收穫滿滿」,但這個收穫滿滿轉眼間又變成空。因為環境改變、領域改變、競爭者改變、專案改變、團隊改變、慾望改變,你滿別人比你更滿,不滿之心因而升起。

心永遠靜不下來。

Alexander在《Timeless Way of Building》書中提到學習模式(pattern)的過程也是如此,透過學習模式來重拾人們設計與建造建築的能力。但這不是終點,不是目的。透過這個過程,喚回人原有之本性、本能。之後,這些模式都要忘記。

金剛經云:「知我說法,如筏喻者,法尚應捨,何況非法。」聽佛說法(學習pattern),是為了開悟(追求quality)。有了quality之後,那些names、那些patterns,就可以捨棄了。

***

友藏內心獨白:試求未開悟前之心理陰影面積。

2020年4月27日 星期一

怎麼當好一個ScrumMaster?

April 27 12:46~14:15


演給你看不好嗎?

接觸過Scrum鄉民應該都會同意,Scrum的三個角色:Product Owner、Development Team與ScrumMaster,其中ScrumMaste是最抽象、虛無飄渺的存在,最不容易了解,也最難扮演好這個角色。

曾經有幾位客戶要求Teddy到他們家去充當短期的ScrumMaster。這是一個很合理的速成方法,如果請有經驗的人來當ScrumMaster,團隊的新手ScrumMaster就有一個「具體的範本」可以參考。日後只要依樣畫葫蘆照著做,應該八九不離十差不到哪裡去。

但就算是在缺少業績的情況下,Teddy從來沒有答應過客戶去當短期的ScrumMaster。Teddy可以當敏捷顧問、敏捷教練、碎碎念講師(看你喜歡哪個稱呼),陪著PO、團隊與ScrumMaster一起成長,但無法擔任團隊的短期ScrumMaster。

為什麼?因為Teddy始終是個外人。ScrumMaster與Product Owner和Development Team之間是一種很緊密的團隊合作關係,唯有長期承諾,讓整個團隊知道「你是在玩真的」,這種關係才會是完整的。外在環境、專案特性、團隊成員等不斷地變化,沒有固定的公式可以遵循,很能靠一個外人「演給你看」就可以了解箇中精隨。

ScrumMaster必須現時現地去體驗各種作用力、各種限制、各種壓力、各種機會,並且不斷地嘗試、調整。只是短時間加入團隊的「外派」ScrumMaster頂多在敏捷形式提供團隊參考,但這種參考非常片面,也很容易讓人誤解。

***

動輒得咎

書上說,ScrumMaster要協助團隊排除阻礙,因此有些ScrumMaster從這一點著手,最後變成團隊有任何問題都找ScrumMaster來處理,團隊變成了媽寶,而ScrumMaster變成了寶媽

書上又說,ScrumMaster採取僕人式領導(Servant-Leadership),從這一點出發,有些ScrumMaster最後成為團隊的僕人,負責幫團隊訂會議室、安排議程、寄發會議通知、撰寫會議記錄、更新Scrum Board,以及催大家準時參加Scrum會議。僕人易做,領導難行。

也有人覺得引導技能很重要,ScrumMaster要引導團隊發現自身的問題,而不是跳下去幫團隊解決問題。再加上Scrum團隊是自組織團隊,應該有能力能夠從失敗中學習,逐漸改善。因此,當團隊成員向ScrumMaster求助時,ScrumMaster總是說:「由團隊決定」,弄到最後讓團隊成員覺得ScrumMaster的存在本身變成了一種阻礙。

***

云何應住?

依據Teddy的理解,ScrumMaster之所以存在,他要解決的問題是:「如何讓Development Team、Product Owner與組織獲得Scrum的好處?」可以從這個角度切入,來思考要怎麼做好ScrumMaster。

金剛經裡面有一段話:

「菩薩於法,應無所住,行於布施,所謂不住色布施,不住聲香味觸法布施。須菩提!菩薩應如是布施,不住於相。何以故?若菩薩不住相布施,其福德不可思量。」

把「菩薩」換成ScrumMaster,就可以知道ScrumMaster要怎麼做。

ScrumMaster依據敏捷精神,無須拘泥一定的形式與方法,只求能夠幫助開發團隊、PO與組織。不需拘泥教練、僕人領導、流程專家、干擾屏蔽、阻礙排除、變革代理。ScrumMaster要專注在協助開發團隊、PO與組織獲得敏捷的好處,不拘泥於特定形式,如此便可產生有利的效果。

有些ScrumMaster很認真,為了做好自己的工作,上了很多課。但回到團隊之後,如果做得好,他變成了一個教練、一個僕人式領導者、一個流程專家、一個保護者、一個石頭搬運者、一個敏捷轉型策略大師。做不好,他成為沒打過棒球的棒球教練、任勞任怨的僕人、技術控、太極高手(推拖工作)、吵架王、嘴砲王。

他已經不是ScrumMaster,他被切割成好幾塊

***

無為而無不為

扯了這麼多,到底ScrumMaster要怎麼做?很簡單,在敏捷精神之下,該做什麼,就做什麼。做了之後有幫助,就持續下去。沒有幫助,思考如何改善,不斷精進。

這個過程很漫長、很痛苦,因為現實世界很危險,你要靜心,忍得住孤獨、寂寞、羞辱。你可能需要一位師父、前輩、長者,與你同在,支持你走完這個過程。

最後,你渡過河,到達敏捷的彼岸,你有能力幫助其他ScrumMaster繼續他們的旅程。

***

友藏內心獨白:是在找聖人逆!

2020年4月20日 星期一

毛書一刀未剪大公開

April 20 11:28~12:45


Teddy在2012與2014年所出版的兩本書《笑談軟體工程:敏捷開發法的逆襲》與《笑談軟體工程:例外處理設計的逆襲》已經絕版一陣子了。上個周末上【Scrum敏捷方法實作班】,有學員知道書已絕版,詢問Teddy是否能提供第一本書的電子檔?Teddy也忘了之前有沒有公開提供過,所以今天就寫一篇文章把這兩本書的電子檔公開。

因為書本最後出版的格式經過悅知出版社編輯過,這個「排版編輯」版權屬於出版社,所以Teddy只能公開當初提供給出版社的原稿。編輯前的原稿與最後出版的內容略有差異,且可能有一些尚未訂正的錯字,請讀者自行除錯。

電子檔下載:

***

友藏內心獨白:紙本的比較香。

2020年4月19日 星期日

塞翁失馬

April 19 20:37~21:28


也是疫情受害者

這兩天(4/18~19)是第32梯次【Scrum敏捷方法實作班】上課日,這梯次課程很早就確定開課,但因為前一陣子境外移入的新冠肺炎案例大增,陸續有學員取消報名,最後上課學員只剩下七位,剛好湊成一組。

原本課程最低開課人數是10人,因為目前處於疫情的特殊狀況,Teddy也沒有取消該梯次。疫情期間人少一點也好,雖然收入變少免不了有點小失望,但加減賺,至少可以付房租。

***

趁亂做實驗?

Scrum課程有一個練習活動,讓學員透過User Story Mapping(使用者故事地圖;USM)作為敏捷需求管理工具。上課前一天(禮拜五)Teddy想:「既然這次只有一組,練習活動是不是可以做一些調整,試看看改用Event Storming Workshop(事件風暴工作坊)來收集需求的效果?」。

想了一天,覺得自己沒有把握在短時間的練習活動中可以讓Event Storming Workshop達到原本USM的效果,於是決定還是先維持原本的練習活動。

昨天上了一天課,因為只有一組,Teddy反而有更多的時間與學員討論(WIP=1),講得話比往常都還要多。今天(禮拜日)早上起床,邊吃早餐邊打開電視聽新聞。突然間,不知怎麼的靈光乍現,有點想通了Event Storming Workshop與USM的差別,以及兩種方法個別合適的應用情境。

雖然在Event Storming發明人Alberto Brandolini的書中提過這個問題,但讀書的當下Teddy並沒有特別深刻的領悟。也許是緣分到了,經過一段時間的醞釀,突然有點感覺了。

***

上了台就不要想賺多少錢

Teddy在吳宗憲的綜藝節目中聽憲哥說過一句話:「上了台就不要想賺多少錢」。言下之意是說,不管此次的收入多少,身為一個藝人上台之後就是要拿出最好的表演。

***

如果不是疫情,最後報名人數只夠湊一組,人數不足是不會開課的。

如果Teddy抱持著:「只有七個人,那就不用特別準備,照以往的方式上課就好。」這兩天也就這麼過去了,也不可能有今天關於USM與Event Storming Workshop的小小突破。

所以說,認真把事情做好,其他事情就交給老天爺吧。

***

友藏內心獨白:活在當下。

2020年3月12日 星期四

英文不好

March 12 22:08~10:50


今天在北科大上軟體架構,有一位同學說他英文不好所以不知道怎麼表達作業中的一個名詞。後來我請這位同學上台畫給大家看,反正Quality Without A Name,名字雖然很重要可以幫助溝通,但名字背後所要表達的Quality更重要。

回家後想起幾年前有一位設計模式入門班的學員跟Teddy聊天時提到他有一個學習上的困擾:「我英文不好,有些patterns的英文名字記不起來,一些英文專有名詞也聽不太懂。」

在科技業走跳,英文程度好當然是大大加分的能力,甚至有不少人專案能力中等,但靠著流利的英文能力在公司(特別是外商公司)很吃得開。

但是,先不要想太遠,拉回現況,這位學員當下在學習設計模式,每一個patterns的英文名字一下子記不起來沒關係,先記中文就好。專有名詞聽不懂或看不懂,現在Google翻譯那麼方便,用軟體幫忙解決就好。真的都查不到,也可以問周邊的同事、朋友或臉書(凡事問臉書XD)。

***

英文能力目前不好,這是事實,但和學習設計模式絕對沒有必然的關係。與其不斷掛念著自己的短處而妨礙自己發展長處的機會,還不如先誠實承認自己的短處,放下它然後認真精進自己的長處。等待自己的長處發光發亮的一刻,建立信心之後,再回頭看看,也許此時原本認為的短處已經不再那麼重要。也有可能此時的自己已非吳下阿蒙,學習力已經增加,依據需要加強必備的英文能力即可。把學習英文當成產品釋出規劃,找到自己所需英文能力的MVP—最小可行性產品。

***

英文能力不能幫助你成長,只有你自己可以。

***

友藏內心獨白:先建立舒適圈再考慮跳出舒適圈。

2020年3月11日 星期三

可是誤一生

March 11 12:36~13:47

▲Ada:我有問題!


可是思維

成立泰迪軟體這些年,教過的學員也有數幾千人次。Teddy很歡迎學員發問,從問題中可以了解學員的困難以及學習狀況,也可以檢驗自己的知識是否足以回答問題,並刺激自己思考的角度。

但有一種學員的反應讓Teddy很無言,Teddy稱之為可是學員,他們總是在聽了你的建議之後,經常使用可是作為拒絕改變的藉口。

***

可是學員:我們軟體的bug很多,有沒有什麼做法可以改善這個問題?

Teddy:你們有寫單元測試嗎?

可是學員:沒有。

Teddy:是不是可以考慮先從寫單元測試開始,至少可以確定基本軟體元件的正確性。

可是學員:可是我們工程師都沒時間啊,程式就寫不完了不可能要求他們寫單元測試。而且他們也不知道怎麼寫,專案時程那麼趕也沒時間讓他們學。要讓他們寫單元測試這不可能啦。

Teddy:Code review呢?

可是學員:可是我們工程師程度都不好,沒有能力review別人的程式。

Teddy:難道都沒有資深工程師嗎?

可是學員:是有幾位資深工程師,可是他們覺得code review很浪費時間,沒人想做。

Teddy:是不是可以跟團隊成員溝通,透過code review可以協助資淺人員能力成長,改善產品品質,提升整個團隊的能力?

可是學員:可是公司也不想浪費資深人員的時間,畢竟他們的薪水比較高。公司希望他們專心開發核心程式,而不是花時間去幫其他人做code review。

Teddy內心獨白: (我的棍子放在哪裡!)

Teddy:有試過Pair Programming嗎?

可是學員:我在社群活動中有聽過Pair Programming介紹,可是公司一定不會同意。專案那麼趕怎麼可能讓兩個人一起寫程式,這不可能,打死都不可能。

Teddy:那……找QA或工讀生,用人工測試呢?

可是學員:可是公司根本沒有QA部門,也不可能撥預算找工讀生來測試。

Teddy:那還有一招,外包給客戶,請客戶幫你們測了

可是學員:我們現在就是這樣啊。

***

挑戰現況

凡事把可是兩字掛在嘴邊,很可能是一種不思改變只想找藉口拒絕改變的反射性動作。如果只是朋友之間互相訴苦,並不是真的想解決問題,那倒也無妨。但若是工作上遇到問題也抱持著這種心態,就無法突破現況並有所改善。

軟體工程,特別是敏捷實務做法,並不是什麼艱深理論,都是經過多年、多人、多團隊、多公司的實務經驗。也許這些經驗與你自己目前狀況不符,但也不要立刻否定,先把它當成一種假設,然後思考要做出何種改變、要如何努力,才有可能讓假設成真。

學員:我們軟體的bug很多,有沒有什麼做法可以改善這個問題?

Teddy:你們有寫單元測試嗎?

學員:沒有。

Teddy:是不是可以考慮先從寫單元測試開始,至少可以確定基本軟體元件的正確性。

學員:我們工程師都忙到沒時間,程式寫不完了要如何讓他們願意寫單元測試?

Teddy:你們應該是把寫production code和test code 看作是兩件事,而工作上只有要求完成production code即可,才會有這種「程式都寫不完了哪有時間寫測試」的想法。

學員:對啊,不都是這樣嗎?

Teddy:我認為單元測試是開發不可分割的一部分,所以做完的定義不是只有production code寫好就可以,應該也要包含足夠的單元測試。這在敏捷開發(Scrum)裡面叫做DoD—Definition of Done。藉由調整DoD(逐步增強),可以改善團隊的產品品質。

學員:聽起來滿有趣的,但我們團隊目前都沒有這樣的觀念,還是停留在犧牲品質以便趕上進度的狀況。短期間或許可以交差,但是對公司來說中長期發展會受到傷害。像最近客戶對於品質不良的抱怨聲音就很大,而且團隊成員工作也沒有成就感,流動率很高。

Teddy:解決方法不一定只有或只是單元測試,還有很多種解決方案,依據你們專案的情境(Context)可以選擇不同的方式。

學員:我回去跟我老闆討論一下,看看有沒有可能找一個新的小專案來試看看,做出一些改變。

***

想解決問題但卻不想做出任何改變,只想從別人口中聽到「你好辛苦」、「你好委屈」、「你好棒棒」、「公司好爛」、「同事好混」這類的話,那還是不要開口問Teddy問題好了。

***

友藏內心獨白:這樣不就不溫柔了XD。

2020年3月10日 星期二

相依不相依

March 10 15:18~16:31

▲圖1:Customer/Supplier(客戶與供應商)關係圖


上下游相依性

相依性,或稱為依賴耦合,無論是在做人做事,或是在軟體開發上,都是一種讓人又愛又恨的特性。

父母對妳的男朋友不滿意,嫌他太窮、薪水太低,因此反對妳的婚事。妳不敢違背父母,也不想分手,因此一直處在進退兩難之間,終生大事的時程(schedule)因此被延誤了。身為專案經理的妳,卻是一點辦法都沒有。

你的部門需要客服部門提供API讓你們查詢並分析客訴情況與進貨廠商之間的關係,但是客服部門覺得這不是他們的工作,而且他們太忙根本沒有時間可以幫你們開發這個API。這件工作一直卡住,從老闆的眼中看來,工作交派給你的部門但卻一直沒有完成,你的部門因此黑掉,黑到發亮。

以上例子如圖1所示,女兒和父母之間的關係,你的部門和客服部門之間的關係,稱為Customer/Supplier(客戶與供應商),父母、客服部門是供應商,是價值鏈的上游(upstream),女兒、你的部門是客戶,是價值鏈的游(downstream)

***

解決方案

當兩個個體或組織屬於Customer/Supplier關係,而Supplier佔有絕對主導權或是完全不想鳥你的時候,身處於下游的Customer做起事來就會很辛苦。為了獲得父母的支援,妳可能選擇遵從他們的想法(Conformist):「好吧,既然父母不喜歡這個男朋友,我就再找一個合他們意的對象」,不然就擺爛裝傻雙方僵在哪邊。

除了完全服從之外,你還可以選擇切斷對上游的依賴。反正結婚後不想拿家裡的好處,就走自己的路(Separate Way)吧。

但如果你父母是好野人,完全切斷來自他們的幫助有時並不是明智之舉,因為妳可能會損失少奮鬥10年的機會。但妳又不想委屈自己放棄目前交往的對象,此時可以考慮找一個中間人,吸收父母之間對於妳男朋友不滿的負能量,在婚後一方面應付父母,另一方面保持自己家庭和樂。這個防止毀壞層Anticorruption Layer)可以由妳自己當任,或是找父母信任的第三人,例如家族中的開明長輩或自己的哥哥、姊姊。

以上三種解法:Conformist、Separate Way、Anticorruption Layer,就是在《Domain-Driven Design》書中提到的三種不同的Bounded Context之間的關係。

除了上述這三種關係,還有第四種選擇可以避免下游被上游綁架,就是套用Dependency Inverse Principle相依反轉原則),如圖2所示。


▲圖2:套用相依反轉原則改變上下游的相依性


你不用無止境地等待客服部門提供API,反之,幫你所需要使用的服務定義一個介面,然後便可以依據此介面開始開發程式。等程式寫好,你便可以跟老闆回報進度。

你:報告老闆,您要的功能我們開發好了。

老闆:我看看……嗯,沒錯,這就是我要的功能。什麼時候可以上線使用?

你:我們的部分已經沒問題了,但是客服部門還沒有完成他們的開放資料API,實際上線時間要問客服部門。

老闆:客服部門的人在嗎?!

透過相依反轉原則,你成功把球丟給客服部門,進度就不是卡在你們這邊了。

***

友藏內心獨白:等來等去等成仇。

2020年2月26日 星期三

【還少一本書】Clean Agile

Feb. 26 15:00~16:54


Clean Agile

Clean Agile: Back to Basics》是Robert C. Martin(Uncle Bob)最新著作,這本書算是他老人家對於敏捷開發的歷史回顧,以及他對於敏捷開發應該長成什麼樣子的個人意見

***

第1章

第1章Introduction to Agile談到談到敏捷的歷史,從1880年代的Scientific Management(科學管理)演變到Waterfall,再到1980年代末期~1990年代早期的敏捷改革時期,Uncle Bob提到當時多個輕量級軟體開發方法的興起,到2001年17位輕量級流程愛好者在美國猶他州雪鳥滑雪聖地的聚會,誕生了敏捷方法與敏捷宣言

第1章最後提到Ron Jeffries所畫的The Circle of Life這張圖,它表達了XP的12個實務做法,《Clean Agile: Back to Basics》這本書的核心基本上是圍繞著The Circle of Life,由外而內分成三章解釋這張圖。

讀完《Clean Agile: Back to Basics》之後,Teddy覺得Uncle Bob所謂的Clean Agile底子裡其實就是XP,這很可能是因為Uncle Bob一開始接觸的敏捷方法就是XP,而且他是個TDD堅定信仰者的關係。

▲The Circle of Life,節錄自《Clean Agile: Back to Basics

***

第2章

第2章The Reason for Agile,對Uncle Bob來說,理由很簡單:「讓自己以及軟體開發這個行業變得更專業」。如果你夠專業,你就有勇氣可以拒絕長官不合理的要求,你敢說No。你軟體會變軟,你會持續改善與學習,且無懼改變。你的軟體品質會很好,QA應該找不到任何bug。客戶與開發人員各遵其職,相互合作。基本上算是一種軟體開發的大同世界XD。

***

第3~5章

接下來的三章分別介紹The Circle of Life的三個圈圈:

  • 第3章Business Practices:介紹Planning Game、Small Releases、Acceptance Tests、Whole Team這幾個實務做法。本章一開始簡短的介紹Story和Story Point,以及軟體估算的幾種方法。然後提到Velocity、小規模釋出、驗收測試以及敏捷團隊的組成。接觸過XP或Scrum的朋友讀起來應該沒什麼困難。
  • 第4章Team Practices:這一章提到Metaphor、Continuous Integration、Collective Ownership、Sustainable Pace,除了Metaphor以外其餘三個實務做法都很容易理解。Metaphor在XP剛提出的時候其實很抽象,不好解釋。但後來有了Domain-Driven  Design(領域驅動設計;DDD)之後,Metaphor就有了一個完美的解釋方式,就是DDD裡面的Ubiquitous Language(通用語言)。
  • 第5章Technical Practices:這一章提到Simple Design、Pairing、Test Driven Development、Refactoring,算是軟體開發人員比較熟悉的內容。

***

第6章

第6章Becoming Agile,這一章原本是最吸引Teddy的章節。如何變得敏捷?Uncle Bob又回頭偷Kent Beck的四個XP價值觀:

  • Courage
  • Communication
  • Feedback
  • Simplicity

這章還有三點Teddy覺得很有趣的部份

  • Transformation:敏捷轉型是這幾年很熱門的話題,作者認為˙(大型)組織的敏捷轉型很多都是失敗收場,因為「中間管理層」所存在的目的與敏捷精神相違背,因此他建議「產生新的組織來實施敏捷而非將現有組織轉型」。
  • Coaching:近幾年敏捷圈很流行的Coaching(敏捷教練),Uncle Bob的看法異於常人,他覺得敏捷團隊不需要,或是只有偶爾需要聘請教練。
  • Agile in the Large:Uncle Bob認為敏捷就是為了解決中小型軟體開發團隊所誕生出來的方法,所以根本沒有所謂「大規模敏捷」的問題。因為大規模團隊合作的問題在5000年前已經被解決了。

***

第7章

第7章Craftsmanship,本章不是由Uncle Bob執筆,而是「外包」給寫了《The Software Craftsman: Professionalism, Pragmatism, Pride》的作者Sandro Mancuso,寫得出乎Teddy意料之外的好。

Software Craftsmanship Manifesto(軟體工藝宣言)在2009年提出,Teddy之前一直覺得既然已經有敏捷宣言了,為什麼要畫蛇添足?是要另立山頭佔領地盤嗎?

廣義來看它可視為一種對於敏捷宣言的補充說明,身為一位軟體工程師,Software Craftsmanship Manifesto 的內容原本就是自己一直以來所重視與實踐的方向,落實敏捷不就是這樣嗎?!

還真的不是,敏捷經過這麼多年的演化,即使只將敏捷限定在軟體開發組織中,很多時候還是偏向A Name Without Quality,變成一種口號與行銷工具。所以這章重回敏捷軟體開發的初心,軟體工藝,也算是呼應了Uncle Bob在第二章所提到的專業

***

結論

這本書提到很多敏捷這個詞被提出前後的歷史故事,以及重新詮釋XP的12的實務做法與4個價值。雖然書中對於Clean Agile的看法可能與現今主流趨勢相差甚遠,但這應該是作者有意為之的結果。從正面來看,可以讚賞作者不忘初心,方得始終。從負面來可,可以批評他食古不化,沒有與時俱進。

看完《Clean Agile: Back to Basics》,Teddy立馬買了《The Software Craftsman: Professionalism, Pragmatism, Pride》,且興起把當年沒看懂的XP系列書籍拿出來再看一次的衝動。

▲年輕時購買的XP系列叢書,現在回頭讀應該比較看得懂吧XD。

***

友藏內心獨白:是初心不是粗心。

2020年2月20日 星期四

領域事件幫你切割使用案例

Feb. 20 13:45~14:36


售後服務

今天上午有一位剛上過【領域驅動設計與簡潔架構入門實作班】的學員B問Teddy一個關於如何切割使用案例(Use Case)的問題。為了不洩漏學員B的工作內容,以下的文章中Teddy將學員B的應用領域轉成開發看板系統,將他提出的問題改寫,再跟鄉民們介紹。

***

問題敘述

使用者想要列印看板系統中的卡片(Card),使用者可以選擇列印全部的卡片,或是只列印挑選過的若干卡片。開發團隊想到兩種可能的實作方式:

  • 方法一:實作一個PrintCardsUseCase使用案例,它接受兩個參數—boardId和filters。如果filters是空的,就列印該看板的全部的卡片;如果filters有資料,則先依據filters條件過濾不需要的卡片,再列印符合條件的卡片
  • 方法二:方法一需要在使用案例中加上一個if判斷,感覺不太好。因此衍生另一種想法,把使用案例拆成兩個—PrintAllCardsUseCase和PrintCardsByFilterUseCase,前者只需要boardId這個參數,後者則需要boardId與filters這兩個參數。

寶傑,你怎麼看?!

***

用領域事件思考

學員B遇到的問題很常見,Teddy年輕的時候學習物件導向分析與設計(OOAD)也遇過同樣的問題。學了領域驅動設計和Event Storming之後,這個問題的解決方式就變得很簡單。回到事件風暴(Event Storming)來思考:

  • 先寫出領域事件(Domain Event)


  • 幫每個領域事件加上Command


  • 幫Command寫上Input

分析到這裡就很清楚了(先不用管Aggregate與Policy),使用者的確需要兩個使用案例,但不是原本方法二的PrintAllCardsUseCase和PrintCardsByFilterUseCase這種切割方式,而是:

  • FilterCardUseCase
  • PrintCardUseCase

使用Event Storming,依據時間軸來思考領域事件,再寫出相對應的Command,系統的行為就會慢慢浮現出來。

***

友藏內心獨白:距離上市集資也就跨進一大步了。

2020年2月11日 星期二

領域專家X

Feb. 11 17:33~19:11

▲立志成為喵星人的領域專家


前言

無論是行為驅動開發(Behavior-Driven Development;BDD)實例化規格(Specification By Example;SBE)或是領域驅動設計(Domain-Driven Design;DDD),共同存在一個非常重要的假設:「正確的需求可以藉由領域專家與開發團隊密切的迭代溝通所產生」。

在這個假設之下,領域專家彷彿「神一般的存在」,他的腦袋中似乎對所有問題都有答案,對於團隊的提問,他不會說:「都可以,由團隊決定」。

可能是領域專家知道的太多,他無法將所有事情主動告訴開發團隊,需要藉由團隊成員與他的互動,將完整的需求慢慢誘導出來。

這其實並不是什麼新觀念,傳統的軟體開發方法也都持相同看法,只不過BDD/SBE與DDD,特別是BDD/SBE這一系列的方法,特別強調此觀點。

***

落實BDD/SBE的困難

讀過BDD/SBE書籍的鄉民一定會發現,許多書本都會以一個例子來示範如何學習這些方法,例如停車費計算、搭乘巴士或捷運的車資計算、包裹運費計算。相對於一般的商業軟體,這些例子除了功能較少以外(系統較小),還有一個共同特色,就是有著非常明確的商業邏輯

因為有著非常明確的商業邏輯,領域專家的角色就可以被簡化,也容易透過領域專家與開發人員之間的對話來釐清「規格」,進一步採取「舉例子」的方式來描述這些規格。作為學習目的,這樣的設計非常合理,並無不妥。

落實BDD/SBE的困難之一在於一個完整的系統除了「具備明確商業邏輯」的部分以外,也有許多功能的商業邏輯不是哪麼明確。又或者是這些邏輯不屬於核心商業邏輯(core business logic), 而是應用程式邏輯 (application logic)。換句話說,領域專家也許對於核心商業邏輯比較清楚,但不一定對於應用程式邏輯有特別的意見。這時候通常需要由開發團隊來主導,再與領域專家確認。這個部分的系統實作,在BDD/SBE的書籍討論的比較少,因為這原本就不是這系列方法所著重的焦點。

舉個例子,以看板系統(Kanban System)為例,它本身有一些相對明確的核心商業邏輯,例如看板核心三原則:

  • 視覺化
  • 限制WIP(work in progress/process)
  • 管理流

根據這三個原則可以舉出好幾的實例,這些都是領域專家比較熟悉的核心商業邏輯:

  • 工作流視覺化實例,包含垂直工作流、水平工作流(swim lane)。
  • 卡片(Card)視覺化:包含標準卡片、固定交期卡片、加急卡片、Bug修正卡片、技術工作卡片。
  • 工作流加上WIP限制之後,卡片數量符合與違反WIP限制的例子。
  • 阻礙(Blocker)的表達方式。
  • Lead Time、Cycle Time的定義與量測方法。

真正實作看板系統的時候,有一些不屬於核心商業邏輯的應用程式邏輯會跑出來,例如:

  • 一個使用者可以擁有多少個看板?
  • 不同的使用者是否可以共用看板?
  • 使用者要如何設計自己的看板?從頭開始設計,還是可以套用現成的模板(Template)?
  • 一個看板只能表達一種工作流程,還是可以同時表達多個工作流程,以便於讓多個團隊共用看板?
  • 已完成的卡片(當累積很多之後)要如何「收納」才不會阻礙使用者使用看板?
  • 如何表達看板的開始與結束,以便於計算lead time?

以上總總問題,雖然也屬於開發看板系統需要釐清的邏輯,但並不屬於核心商業邏輯,因為不同的看板系統,可以有不同的決定。例如,路人甲所開發的Simple Kanban系統決定一個看板只能有一個工作流程,而路人乙所開發的myKanban系統則是支援一個看板可以有多個工作流程。

***

落實BDD/SBE的困難

相較於BDD/SBE,DDD因為要探討領域模型(domain model)、通用語言(ubiquitous language)、bounded context、context map以及aggregate、entity、value object、repository、service、factory等DDD設計模式,因此需要一個相對比較完整的系統開發作為例子,例如《Implementing Domain-Driven Design》就以開發敏捷專案管理系統當作例子。

落實DDD的困難之一在於如何找到一個「合適且完整的系統當作例子?例子的問題領域很重要,因為學習者通常是軟體工程師,如果問題領域過於專業,例如健保系統、保險理賠系統、進銷存系統,軟體工程師很難在學習過程中弄清楚這些系統的核心商業邏輯與應用程式邏輯。如果例子太小,又失去套用DDD的意義。

為了解決缺少領域專家的問題,《Implementing Domain-Driven Design》作者選用了敏捷專案管理系統作為例子。一方面這個系統的大小適中,而問題領域又是開發人員比較容易理解的敏捷方法,因此開發人員可以自己腦補,同時扮演領域專家的角色。

***

真實世界的困難

剛剛從學習的角度來討論在學習BDD/SBE與DDD的時候,缺少真正領域專家所造成的問題。在真實世界中,這個問題是否就消失了?

雖然開發團隊應該會有專案經理、系統分析師、產品經理或Product Owner等角色來協助釐清系統需求,但實際上這些人很可能都不是真正的領域專家。就算團隊有領域專家的協助,但如前面所提到的,領域專家可以協助釐清核心商業邏輯,但對於應用程式邏輯的幫助相對較小。

此外,敏捷開發採用迭代與增量的方式,在開發過程需要持續與領域專家討論於釐清問題,但並不是所有領域專家都願意這樣子跟開發團隊配合。有些領域專家甚至認為:「這是開發團隊的工作,我為什麼要花自己的時間幫他們做事?」

所以,開發團隊不能無腦地一味將釐清商業邏輯的責任推給領域專家,而領域專家也應該多聽聽開發團隊的意見,不要把團隊提出的問題當成對自己專業知識的質疑,這是一種釐清問題的溝通過程。

***

友藏內心獨白:沒有的東西要去哪裡生?!

2020年1月1日 星期三

領域驅動設計學習筆記(7):Aggregate (下)

January 01 21:52~23:28

▲圖1:Clean Kanban領域模型(部分)


問題

領域驅動設計(Domain-Driven Design;DDD)的Aggregate物件之間透過ID(字串或GUID)參考,而不像傳統物件導向設計(OOAD)直接透過記憶體參考(memory reference)來存取依賴物件。對於「從小」熟練物件導向分析與設計(OOAD)的Teddy而言,剛開始覺得這樣做好像不太方便啊。只記錄Aggregate ID,還要透過Repository來取得該Aggregate物件,這樣不是有點麻煩嗎?

***

記憶體參考

圖1是Teddy所開發的看板系統的部分領域模型:

  • Board:代表一個看板。
  • Workflow:代表一個工作流程,一個看板可以有多個工作流程。
  • Stage:代表垂直的工作階段。
  • Swimlane:代表水平的工作階段。

如果領域模型直接透過記憶體參考,也不套用Aggregate,寫程式的時候就可以:

  • board.getWorkflows()傳回看板的全部工作流程物件,或用board.getworkflowsById()得到某個工作流程物件。
  • workflow.getBoard()得到這個看板所屬的board物件。

這樣一來透過物件的reference可以輕鬆自在存取整個領域模型,甚至可以:

stage.getworkflow().getBoard().getUser()……一直不斷的get下去。當然程式寫成這樣就產生壞味道,但是無限制的記憶體參考很容易「引誘犯罪」,讓開發人員寫出這種程式。

***

Aggregate形成邊界

圖2:套用Aggregate形成物件的邊界

如圖2所示,套用DDD的Aggregate設計模式,原本領域物件變成兩個Aggregate:Board與Workflow,得到如圖3所示的Board與Workflow類別。

圖3:Board與Workflow類別。

套用Aggregate有幾個好處:

  • Board與Workflow變成獨立的Aggregate,因此可以各自更新,不必放在同一個交易(transaction)裡面。如此一來可以提高並行處理的彈性。
  • 一個Aggregate對應一個Repository,物件儲存問題變得簡單很多。
  • Aggregate內部物件的存取必須透過Aggregate Root,因此可以讓Aggregate Root來確保對於Aggregate的操作不會違反invariant,也就是保持程式狀態的正確性。

當然有好處也有缺點:

  • 最大的缺點(也是優點)可能就是Aggregate之間透過領域事件(domain event)達成狀態同步,由原本同步的方式變成非同步方式,程式開發模式跟傳統不同,習慣需要改變一下,重新學習。
  • 無法像傳統一樣,只要透過物件參考就可以得到整個領域物件(或大部分領域物件)的資料。例如,如果使用者介面要顯示看板所有的工作流程,從Board物件無法直接得到Workflow物件,因為Board只記錄Workflow的ID,必須再透過WorkflowRepository才能得到Workflow物件。

***

View Model

▲Clean Architecture,圖片來源在此

將領域模型與使用者介面模型(View Model)切開,原本就是DDD的重點。但是領域模型最終還是要展示給使用者看,此時只要多設計一層View Model,將領域模型轉成使用者介面方便操作的View Model就可以了。從Clean Architecture的角度來看,讓Interface Adapter層(第三層)來負責做轉換。

▲設計BoardDto給UI使用。

***

結論

釐清邊界,單一責任,分層負責,系統的結構才會清楚明白,軟體也才能變軟。

***


友藏內心獨白:把一件事情做到最好就很厲害了。