l

2020年12月2日 星期三

泰迪軟體2021年上半年開課時間表

Dec. 02 09:29~09:57

▲因應疫情Event Storming (事件風暴) 活動改用線上工具miro


2020年轉眼就要過去,又來到年底年底排課表的時間。今年因為新冠肺炎疫情的緣故,雖然泰迪軟體的生意沒有特別忙,但Teddy在下半年把主要空閒時間都供獻給ezKanban軟體的開發,持續增強【領域驅動設計與簡潔架構入門實作班】的課程深度與累積更多實作經驗。

以下是泰迪軟體2021年上半年課表:

Scrum敏捷方法實作班

  • 假日班:1月9、10日(六、日)。

領域驅動設計與簡潔架構入門實作班

  • 平假日班:1月15、16、17日(五、六、日)。

敏捷開發懶人包:物件導向技能

  • 平日班:2月23日(二)。

Design Patterns這樣學就會了--入門實作班

  • 假日班:3月13、14、20日(六、日、六)。

單元測試實作班

  • 假日班:3月27、28日(六、日)。

看板方法與精實開發實作班

  • 假日班:5月8、9日(五、六)

Design Patterns這樣學就會了--進階實作班

  • 假日班:5月28、29、30日(五、六、日)。

軟體重構入門實作班

  • 平假日班:5月14、15、16(五、六、日)。

例外處理設計與重構實作班

  • 假日班:6月22、23日(二、三) 。

***

以為下課程活動照片。


▼領域驅動設計與簡潔架構入門實作班


▼看板方法與精實開發實作班課程照片

螢幕截圖 2017-12-12 10.08.45


▼「單元測試實作班」課程照片。

螢幕截圖 2017-12-12 10.14.10螢幕截圖 2017-12-12 10.15.07


▼「敏捷開發懶人包:物件導向技能」課程照片。

***

友藏內心獨白:2021年還請鄉民們繼續支持。

2020年11月30日 星期一

DDD TW 2020 Conference一日遊

November 30 21:50~23:30

▲DDD是拿來踩在腳下實踐的,不是放在嘴邊打嘴砲


抵達會場

11/27~28日是第一屆台灣領域驅動設計年會舉辦的日子,數月前受到老友張國昭的邀請,在會中給個talk,11/27日八點半出門前往會議場所北投會館。

話說這個北投會館位置還真有點小偏僻,平常上班時間很少出門的Teddy,太高估台北的交通,開車走走停停到了會議場所已經錯過了9:00的第一場活動。

更慘的是,諾大個地下B1停車場,幾乎停滿車,而且也沒有燈號指示空位。沒方向感的Teddy繞了快10分鐘好不容易在角落的地方看到兩個空位,還沒停好車另一個空位立刻也被停走。

▲幾乎沒空位的北投會館停車場

***

離開停車場之後,到達會館入口,居然又花了快10分鐘才找到會議舉辦地點。先辦理報到,工作人員剛好是老朋友Max,算他倒楣,一早先被Teddy念了一頓。這活動場地也太不友善了啊。

***

參加活動

原本第一場想聽「返璞歸真:街口的"唯服務"之路」,等報到完畢都9:40了,只能作罷。本次活動同一時間一共有三場演講同時進行,分為產品軌、技術軌、流程軌。

不包含自己的演講,Teddy一共聽了四場演講如下:

  • DDD X Architecture by Clark:聽說早上技術軌的場地出了點狀況,所以剛進入技術軌會場有點兵荒馬亂。Teddy來的晚,只搶到最後一排的位置,加上會場的投影機解析度 非常 有點差,投影布幕也 很小 不夠大,所以嚴格講起來Teddy幾乎看不到講者的投影片內容 Orz。幸好Clark口條很清楚,說明當問題領域很大的時候,軟體架構應該如何應對以便管理這些眾多的bounded context。

整場演講Teddy印象最深刻的一點是Clark對於中台的解釋,這個詞彙據說是中國阿里巴巴集團所創。之前也有朋友跟Teddy討論過中台,但翻遍Teddy家中所有英文書,完全找不到中台的說明(廢話,因為這是阿里巴巴所提倡的,應該找簡體中文書),而Teddy平常也沒在追蹤中國的軟體技術發展,所以腦中只知道禪寺,卻不知中台為何?

以下是Teddy聽完Clark的解釋對中台所產生的理解—當你的問題領域非常巨大的時候,例如阿里巴巴集團這種規模,集團內各個子集團或部門所開發的系統,很可能會重複開發。例如,對岸很流行的發紅包服務,阿里巴巴集團內不同應用系統都有機會使用發紅包服務,如果不加以管理,很可能整個集團內不同單位重複開發相同的發紅包服務。因此,把這種不同單位都會使用到的服務(但又不是傳統所謂基礎建設平台的服務,例如email、SMS)抽離出來放到介於前台與後台之間,稱之為中台。


▲如果有帶望遠鏡出門就好了

***

  • 領域驅動設計參考過程模型 by 張逸:這場演講播放講者張逸事先錄好的影片,講者參考RUP的做法,介紹他自創的統一領域驅動設計參考模型,希望提供一個框架讓DDD的落實變得更具操作性。Teddy覺得這個做法滿有趣的,必須要整合很多不同的技術,才能把它們放到一個框架中又不會顯得過於突兀。

但是,用過RUP的人都知道,RUP最後失敗之處就在於它太過複雜。任何對於某種統一模型的嘗試,必須要小心不要步入RUP的後塵。

這場活動Teddy還是坐在原本場地最後一排的位置,所以講者的投影片也是看不清楚。只能等主辦單位公布活動錄影,再找時間了解細節。

***

  • 實踐 Clean Architecture(實作高可用性的軟件架構) by Gelis:下午原本要繼續留在技術軌聽好友Rex的演講,但因為Teddy自己在北科教Clean Architecture,同一時間流程軌的「實踐 Clean Architecture」更引起Teddy的注意,所以就「脫軌」跑到另一個場子。

這場演講,Teddy並沒有聽到什麼和Clean Architecture特別值得留意的內容,也沒聽到演講副標題「實作高可用性的軟件架構」在什麼地方。不知道是不是又是場地的問題抑或是什麼神奇的超自然現象,蒙蔽了Teddy的雙眼。

講者最後demo一個Visual Studio外掛程式,宣稱可自動產生符合Clean Architecture的程式碼。但Teddy不解的是,如果沒聽錯的話,講者使用該外掛的步驟,需要先匯入資料庫…….這和Teddy所理解的Clean Architecture好像不是同一個版本的Clean Architecture。

***

  • 金融業導入領域驅動設計之應用實例 by Otto:14:00~14:50這一場Teddy跑到B1的便利商店,買了杯咖啡在B1找個位置準備自己的演講。回到會場之後,聽了Otto介紹國泰金控導入DDD的過程。很可惜這場演講只有20分鐘,而中間又因前一場延遲而晚了幾分鐘開始,所以講者實際上只有10來分鐘的時間分享。整個故事滿有趣的,國內公司真正應用DDD開發系統應該也是極少數,值得參考。

***

Teddy的演講

Otto的演講結束後下一場終於輪到Teddy的演講:「DDD + Clean Architecture:從需求到實作」,介紹 Teddy 與北科大 ezKanban 團隊開發一個線上多人互動看板系統的過程,演講內容包含 Online Event Storming + DDD + Clean Architecture + TDD。

寫到這裡已經沒力了,Teddy的演講投影片在此,有興趣的朋友可自行觀看。演講活動有錄影,待主辦單位剪輯好公布之後再請鄉民自行服用。


***

辛苦了

謝謝DDDTW社群舉辦第一屆台灣領域驅動設計年會,雖然Teddy跟幾位義務當工作人員的老朋友碎念了一整天,大家真的辛苦。

***

友藏內心獨白:下次會更好。

2020年10月30日 星期五

能力 = 紀律 * 技能

Oct. 31 17:29~18:10


在北科資工所兼課這幾年,Teddy在每學期第一堂課都會與學生約法三章,要求學生上課:

  • 不能遲到
  • 不可以使用手機、筆電等3C產品
  • 要參與課堂互動

如果同意再修這門課。

***

曾經有一次在檢討考卷的時候學生拿手機拍照被Teddy發現,學生的理由是:「我看不到投影幕上面的字,所以拍照起來放大」。Teddy只能佩服這位學生的臨場反應能力真的有夠敏捷,但什麼理由都不是理由,違反規定一律請出教室。

還有一次在分組討論的時候有學生使用手機,他的理由很正當:「我在找討論內容的資料」。沒什麼好說的,還是請他離開教室。

最近一次是學生把手機放在桌上,用手指滑了幾下手機。這位學生的理由是:「我沒有玩手機,是手機螢幕上有灰塵,我把灰塵清走」。好吧,這位愛乾淨的同學,下次上課再見。

***

Teddy是台北工專電子科畢業的,在那個時代,念書除了學習技能(skill),也很講求紀律(discipline)。能力再好,做事態度隨隨便便,無法成為一位專業的工程師。

幾年前讀了《Management 3.0: Leading Agile Developers, Developing Agile Leaders》,書中提到:

discipline * skill = competence(紀律 * 技能 =  能力)

Teddy看了是相當認同。紀律,不是要無腦的聽老闆命令,或是拍老闆馬屁,而是要遵守團隊或專業領域中做事的共同規範。例如,你自認自己能力很強,沒把團隊的DoD(Definition of Done)當一回事;開會姍姍來遲;不遵守團隊的working agreement。這種人,除非真的是千年一遇的軟體奇才需要特別加以保護,否則不用也罷。

***

在學校上課,學習技能是基本的,但學習紀律的機會就比較少。Teddy兼任的課程剛好都是敏捷開發相關課程,敏捷開發講的就是軟體,在課程中加入一些「紀律」的要求,也是理所當然之事,絕對不是Teddy心理變態想要刁難學生。

***

友藏內心獨白:有時候不須講理由,只需承擔結果。

2020年9月10日 星期四

Clean Architecture之CQRS Pattern

September 10 14:20~15:20

▲跳出盒子思考,有時候跨層存取也是OK滴


緣起

前幾天Teddy在讀《Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#》,看到第3章有一個段落談Code Structure Within a Bounded Context。這是一個很有趣的議題但談得人並不多,既使是這本書也沒有講得很詳細,但其中有一張如圖1所示的圖引起我的注意。


▲圖1:每一個end-to-end功能橫切軟體架構的每一層,圖片節錄自《Domain Modeling Made Functional: Tackle Software Complexity with Domain-Driven Design and F#》,53頁。

***

Clean Architecture

看到圖1讓Teddy想起《Clean Architecture》第34章談到四種區分package的方法,回頭把這一章又讀了一次,看到圖2這段文字:


▲圖2:《Clean Architecture》 311頁。


當年Teddy在讀這段文字的時候並沒參透這個問題:為什麼在CQRS架構中就特意允許跨層參考?」雖然Teddy知道CQRS架構模式但自己沒有實際實作過,但這次讀懂了。

前陣子讀了一本奇書:《CQRS》。如圖3所示,書中明白建議:

  • 領域驅動設計(Domain-Driven Design;DDD)只需要應用在那些會改變系統狀態的Command。換句話說,只需要在Command套用DDD與Clean Architecture。
  • 針對不會改變系統狀態的Query不需要套用DDD,甚至根本也不要設計領域物件,直接讀取資料庫然後產生前端需要的View Model即可,這樣速度更快。


▲圖3:節錄自《CQRS


看完這本書之後Teddy就把ezKanban的use case改成Command與Query。昨天進一步和ezKanban團隊把帳號管理專案的package改用package by feature的方式來管理,如圖4所示。

▲圖4:ezKanban的帳戶管理專案採用package by feature


在重構成package by feature的過程中,GetUserUseCase這個Query與其它會改變系統狀態的use case分別放到不同的package。此時GetUserUseCase已經完全沒有對於User這個領域物件的依賴,如圖5所示它直接透過新的UserQueryRepository查詢資料庫並回傳UserDto給前端。換句話說,CQRS的Query端,故意省略domain model與資料庫之間的轉換,跳過domain model直接讀取資料庫。也就回答了圖2的問題。


▲圖5:直接操作資料庫並回傳DTO給前端


***

友藏內心獨白:繞了一大圈啊。

2020年9月8日 星期二

再談以前端為主的思考對於領域模型的影響

September 08 11:25~13:30

▲大部分的人都是「外貌協會」成員,UI當然非常重要,但不適合從UI來驅動領域模型的設計。

***

工商服務

想要看見別人看不到的設計盲點,想要知道怎麼套用設計模式才是恰如其分的設計,想要跟同事針對設計問題吵架時可以嘴砲勝利,歡迎參加第22梯次【Design Patterns這樣學就會了–入門實作班】,招生中。

***

背景介紹

前幾天Teddy談了〈為什麼不要把後端的領域物件直接傳給前端?〉,今天再舉一個同樣是在開發ezKanban所遇到的例子,討論以前端UI為主的思考方式,會如何影響到後端的領域模型,造成不必要的耦合。

約兩周前Teddy和ezKanban團隊開發Tag的功能,讓使用者可以幫看板中的卡片用Tag來分類,如圖1。


▲圖1:卡片上的多個Tags


ezKanban是一個支援多人同時使用的即時協作系統,如果很多人同時操作同一個看板,系統必須自動保持前端狀態同步。如圖3所示,ezKanban使用WebSocket做為後端主動通知的管道。當前端使用者執行某一個功能,會呼叫後端的Use Case。例如,呼叫CreateTagUseCase新增一個Tag。Use Case執行完畢後產生TagCreated Domain Event(領域事件),後端會將這個TagCreated Domain Event(轉成DTO)廣播給在同一個Board的使用者。當前端收到廣播的Domain Event之後,只要依據Domain Event的種類與內容,在前端直接更新本地UI狀態,便可達到狀態同步的目的。


▲圖3:ezKanban透過WebSocket廣播需要即時同步的領域事件

***

前端需要顯示Tag Name

當前端收到後端傳來的Domain Event,會把它顯示在畫面右上角,讓使用者知道系統狀態已經改變。參考圖4,Teddy把feature這個Tag指定給某張卡片,因此前端顯示如下訊息:「Teddy assigned a tag feature to card」。


▲圖4:前端將收到的領域事件顯示在畫面上


要顯示領域事件就顯示啊,有什麼好說的?」問題就出在這顯示的內容上面。ezKanban是採用領域驅動設計(Domain-Driven Design;DDD)+ Event Storming + Clean Architecture + TDD的方式開發,請參考圖5,原本的Event Storming關於Assign Tag的輸入,並沒有tag name,因為把一個Tag貼到Card上面並不需要tag name,只要有tag id即可。但是如果沒有tag name,要發TagAssigned Domain Event的時候會少了這個資料,導致前端無法顯示tag name。


▲圖5:前端將收到的領域事


因此當下ezKanban團隊的第一個反應就是:「把tag name加到AssignTagUseCase的輸入參數,再把它傳給Card,這樣子Card在發Domain Event的時候可以有tag name。

這就是因為前端顯示需求而影響後端use case layer與entity layer的例子。

***

啊不然勒?

「Separation of Concerns」,我們不應該只是因為前端顯示的需求而污染了use case layer與entity layer,特別是entity layer要好好保護它。既然都有了tag id,其實只要在將Domain Event傳給前端的時候,依據tag id 去找出tag name,然後把tag name塞到傳給前端的Domain Event DTO就可以了。最後實作的程式碼如圖6所示。


▲圖6:將領域事件傳給前端前在把tag name塞進去即可

***


不是不重要

這幾天討論前端與後端領域模型的這兩篇文章,以及之前一系列Clean Architecture/DDD談到資料庫是細節,不應該從資料庫來思考軟體設計,並不是說前端、UI、資料庫不重要。它們都很重要,軟體是一個整體,每一層都做好了,才能夠交付end-to-end價值。

但是,還是那句老話:Separation of Concerns。在討論複雜的業務邏輯的時候,就應該以問題領域的業務邏輯為主去思考,而不是從使用者介面或是資料庫表格的設計,來反推業務邏輯與領域物件應該怎麼設計。

把主要的事情確定了,其他次要的事自然會浮現。

***

友藏內心獨白:先後順序不要搞錯,要先脫衣服再洗澡,不要洗完澡才脫衣服。


2020年9月7日 星期一

PoEEA之Server Layer

September 07 22:36~23:20

▲PoEAA書中提到四種表達領域邏輯的模式


緣起

好一陣子沒幫部落格文章增加新分類,今天這一篇開啟【盡信書不如無書】這個分類,紀錄Teddy讀書時看到一些自己覺得怪怪的地方。

***

哪裡怪
前幾天Teddy在準備Asian PLoP 2020的演講題目:〈Pattern-Based Problem Solving: One Pattern at a Time〉,翻到《Patterns of Enterprise Application Architecture》第九章Domain Logic Patterns,看到Service Layer這個模式,如圖1所示。


▲Service Layer模式,節錄自《Patterns of Enterprise Application Architecture (PoEAA)》,133頁。


這本書2003年出版至今已有17年,當年Teddy讀到這個模式、看到這張圖,並沒有什麼感覺。但因為這幾年學了Clean Architecture,前幾天再次看到這張圖,當下就覺得不對勁:「Data Source Layer怎麼會畫在軟體架構的最核心?」。

***

資料庫是細節

Clean Architecture四層架構如圖2,資料庫屬於最外層,並非如PoEAA所畫的位於最核心。軟體架構的核心應該是Entity Layer,也就是Domain Model Layer。


▲圖2:《Clean Architecture》建議的四層架構,畫成同心圓(圖片來源在此


在階層式架構中,把資料庫畫成底層或是核心層,在N年前也算是常見的畫法。但以現在的角度來看,對照圖1與圖2,應該可以很清楚看出來,圖2的觀點比較正確。資料庫、使用者介面、框架、驅動程式等,都屬於細節,屬於階層式架構的外層,並非是核心部分。

其次,傳統階層式架構所說的Service Layer,就是Clean Architecture裡面的Use Case Layer。Teddy現在覺得Use Case Layer比較具體,因為Service這個字有很多種含意,因此用Service Layer來代表應用程式所提供功能或服務的邊界,好像有點那麼不是很直覺(就跟這句話一樣XD)。

***

讀書不是照單全收

PoEAA是一本很棒的書,書中所整理的模式很多到今日依然適用且日久彌新。但也有一些模式的內容,因為時代演進需要稍微修正,像今天介紹的Service Layer就是一個例子。

讀書不是照單全收,有時候同意,有時候疑惑,有時候反對。理論上,除非這本書有問題,否則同意的時候應該居多。疑惑時可能是自己離作者太遠,尚無法理解書中的微言大義,但也能不排除內容有誤的能性。

反對,代表自己有看法,這個看法與書中不同。自己的看法可能是錯的,也可能是對的。能夠說出不同,也算是一種讀書的層次。

***

友藏內心獨白:挑毛病也要講出個道理。

2020年9月6日 星期日

為什麼不要把後端的領域物件直接傳給前端?

September 06 20:50~22:22

▲ezKanban的tag功能


前幾天有一位朋友問Teddy:「Clean Architecture提到不要把Entity Layer的物件直接傳到UI端,但真的有需要跨層的時候把物件都轉成DTO再往外傳嗎?」

***

以ezKanban為例子

ezKanban是一個支援多人同時使用的看板系統,圖1為其簡化版的領域模型。Board代表一個看板,其中包含了若干個Workflow(工作流),每個Workflow可以有若干的Lane。Lane區分成兩種,垂直的Lane稱為Stage(階段),水平的Lane稱為Swimlane(泳道)。Card(卡片)可以被放到Lane上面,並在不同的Lane之間移動。


▲圖1:ezKanban簡化版領域模型


假設Board被直接傳到前端,前端設計出如圖2所示的畫面。

▲圖2:ezKanban畫面


到目前為止沒什麼問題,前端UI物件模型與後端的領域模型大致上是一致的。一直到有一天客戶有新的需求:

  • 希望增加Tag的功能來將Card分類
  • 每個Board都可以有自己的Tag,不會與其他Board共用Tag
  • 一張Card可以有多個Tag

如果從UI的角度來思考:「Board包含Tag,然後這些Tag才可以被指定到屬於這個Board的卡片裡面。」為了能夠在畫面上顯示Tag,前端的人很可能會要求後端將Tag加入Board物件成為它的屬性,變成如圖3所示的關係:


▲圖3:因為UI的需求,導致Board與Tag產生關係

***

問題出在哪裡?

直接把Entity Layer的物件傳給前端違反單一責任原則。Entity Layer的物件之所以會存在,是為了解決或是表達問題領域的重要概念與商業邏輯。如果把它們直接傳給UI,拿來當作顯示畫面之用,Entity Layer的物件就擔負了兩種責任:

  • 表達商業邏輯與概念
  • 表達顯示邏輯

如此一來Entity Layer的物件就可能因為兩種不同客戶端的需求改變而跟著改變,換句話說Entity Layer與UI產生耦合,導致程式難以理解、修改與維護。

***

如何解決?

回歸到Clean Architecture與領域驅動設計(Domain-Driven Design;DDD)的角度,先確定商業邏輯,至於使用者介面是屬於細節,等Entity Layer與Use Case Layer確定之後,再交給Presenter產生View Model來滿足前端顯示的需求即可

回到幫Card貼Tag的需求,把Tag歸類為Board的屬性並不合理,因為Tag並不是要貼在Board上面,使用者只需要知道這個Board裡面建了多少種類的Tag,再拿這些Tag貼在卡片上面。也就是說,Tag只需要知道它自己屬於哪一個Board的單向關係即可,Board根本不需要知道Tag,如圖4所示。


▲圖4:Board, Card與Tag的關係


至於前端所需的所有資料,如圖5所示另外設計一個BoardContentViewModel。這個View Model是由Presenter為了前端所需而動態產生,Entity Layer並沒有一個這樣的靜態Model。

▲圖5:ezKanban管理Tag畫面


最後的領域模型,Tag物件不屬於Board,使用者可以獨立新增與修改Tag,也很容易直接將Tag指定給Card,請參考圖6與圖7。


▲圖6:ezKanban管理Tag畫面


▲圖7:ezKanban顯示Card上面多個Tag

***

友藏內心獨白:UI歸UI,Domain Model要分明。