l

2019年12月31日 星期二

2019年終心得:突破

Dec. 31 08:45~10:02


停了三年沒寫年度心得報告,前幾年的心得分別是〈2012年終心得:堅持〉、〈2013年終心得:淡定〉、〈2014年終心得:專注〉與〈2015年終心得:學習〉,今年的心得可以用「突破」兩個字來概括。

2019年重大突破事件包括:

***

業績

今年泰迪軟體的營業額是成立以來最高的一年,說「高」也沒有到達真正「發大財」讓Teddy可以財務自由提早退休的地步,但的確是比往年都要來得好。

Teddy 猜想可能是敏捷在台灣近幾年比較流行的關係,市場變大,機會也變多了。泰迪軟體從2012年7月成立至今,始終沒有改變初衷,持續耕耘於敏捷開發的各個主題上,因此累積了許多老客戶。很多新的業務機會都是靠老客戶介紹,真的非常感謝。因為除了寫寫部落格,在Facebook上發發廢文以外,Teddy也沒什麼行銷能力去拉新客戶,只能被動地靠口碑行銷了。

***

同事

泰迪軟體只有兩位員工,Teddy與Erica。Teddy在〈2015年終心得:學習〉提過,Erica到泰迪軟體之後Teddy一直抱持著「訓練博士生」與「培養合作夥伴」的態度來與Erica互動。2019年Erica已經能夠獨立作業,在敏捷教練、引導、敏捷需求管理方面也有不錯的成績。

今年公司業績創新高有很大一部分也是因為Erica獨立接案的關係,畢竟Teddy一個人一年能夠賺的錢也就那麼多(少 Orz),公司有「兩顆CPU」當然是要「並行處理」才能夠擴大營收XD。

***

Teddy

精實開發有一句話:「沒有最好,只有更好」,今年Teddy也有一些長進。研究許久的Clean Architecture(簡潔架構)Domain-Driven Design(領域驅動設計),今年結合了這兩者,發現無論是在架構上、problem modeling以及coding,軟體開發與維護變得比較容易也更系統化。

Teddy一直相信敏捷開發是一種軟體從業人員追尋「The Timeless Way of Software Development」(軟體開發的永恆之道)的一種嘗試。永恆之道,沒有固定的形式,但任何認真於此道的人只要一看到就會知道:「啊,對了,就是這個樣子。」

這就是Quality Without A Name。

***

另外一個突破就是為了明年三月在台灣舉辦的AsianPLoP 2020暖身,Teddy在年底辦了一場【模式寫作工作坊】,幾位參加工作坊的朋友也開始嘗試撰寫模式(Pattern)。撰寫模式是將自己的專業知識淬鍊之後以精簡的語言與固定格式表達與分享的一種過程,這是一條辛苦的路,Teddy很高興有朋友願意一起嘗試,Teddy也很願意花時間幫忙這些朋友們修訂他們撰寫的模式。

2020年1月還有【模式寫作工作坊第二梯次】,有興趣的朋友可以參考。

***

最後還有一個突破就是Teddy今年收編了一隻浪浪,叫做Pascal。說是收編,其實是Teddy被收編

Pascal是Teddy餵養三年多的浪浪,他一開始跑到Teddy家的窗戶外偷吃Teddy準備給另一隻浪浪的飼料,一直持續三年多。有一天他突然消失一個禮拜,Teddy以為他出意外已經往生了,沒想到一個禮拜後他又突然出現,但此時他的左眼破裂,整隻貓也瘦到皮包骨。

看到餵了這麼久的浪浪受重傷實在於心不忍,於是Teddy買了捕貓籠,將他抓起來送醫治療。治好後恢復健康,但剩下一顆眼睛怕他無法適應街頭的生活,於是就將他收編了,取名Pascal。

▲Pascal本貓

Teddy家裡原本已經有Eiffel與Ada兩隻母貓,不過當初都是向「流浪動物花園協會」領養而來,約六3~6個月左右的幼貓,而且已經有人幫忙「整理過」了,比較親人。不像Pascal是成年公貓,而且又是浪浪,第一次收編還是有很多需要學習的地方,也算是有苦有樂。這就是人生啊。

▲Eiffel(虎斑)與Ada(橘白)

***

感恩

最後要感謝2019年直接或間接「金援」泰迪軟體的所有朋友們。沒有金錢的幫助,泰迪軟體無法經營下去,當然也就沒有現在的Teddy。

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

***

友藏內心獨白:最後重複使用了2015年的結語。

2019年12月27日 星期五

領域事件的發送與接收(下)

Dec. 27 06:40~09:02

▲圖1:兩個Aggregate透過領域事件同步狀態


前情提要

上一集談到Teddy開發的Clean Kanban系統範例其中的兩個Aggregate:Board與Workflow,如圖2所示。


▲圖2:Board與Workflow aggregates。

Workflow的addStage方法會發出StageCreated領域事件,先將領域事件儲存在身上,等待儲存Workflow之後再一起發送領域事件。

今天要介紹如何接收並且處理領域事件。

***

誰來接收領域事件

Board與Workflow被設計成兩個Aggregate,一個Board包含零到多個Workflow,Board依靠CommittedWorkflow Value Object來存儲它與Workflow關係。

如圖1所示,新增Workflow會產生Workflow Created領域事件,這個事件驅動Commit Workflow這個Command,通知Board將剛剛新增的的Workflow加入自己身上(透過新增一筆CommittedWorkflow的方式來紀錄)。

有兩種可能的方式來接收WorkflowCrated領域事件:

  • Board:既然Board對於WorkflowCrated領域事件感興趣,可以讓它直接接收這個領域事件。但是為了處理領域事件,Board可能需要透過Repository讀取其他物件,如此一來會讓Board與Repository產生相依性。依據Clean Architecture,Board屬於最內層的Entity Layer,而Repository屬於第二層Use Case Layer,因此Teddy不考慮讓Board直接去接收領域事件。
  • Event Handler:透過位於Use Case Layer的event handler來接收領域事件,接下來將採用此方式接收與處理領域事件。

***

程式範例

▲圖3:Workflow Event Handler程式範例

Event handler程式很容易撰寫,上一集提到Teddy使用EventBus元件來發送與接收領域事件,EventBus採用annotation的方式來標註event handler,如圖3所示,只要在處理領域事件的method身上貼上@Subscribe,然後再跟EventBus註冊即可。

註冊event handler的方式如圖4所示,呼叫EventBus的register方法即可。

▲圖4:註冊event handler

***

▲圖5:測試案例

圖5為測試案例,在setUp方法中記得先註冊event handler,然後驗證產生Workflow會在Board物件上將新增一筆CommittedWorkflow資料。測試案例通過代表event handler產生作用。

***

不是新東西

把Aggregate當成狀態機(State Machine),透過Command產生狀態改變(state transition)並發出事件,讓對於狀態改變有興趣的物件(也就是event handler)可以依據這些事件做出反應,並不是什麼新的技術,也不是領域驅動設計(DDD)或是Event Storming所獨創的開發方法。這種程式開發方式在「古早」時代就有了

從實作面來看,只要套StateObserver這兩個設計模式就可以做到。所以,不要被名詞給嚇到,要關注這些名詞背後所要解決的問題是什麼

DDD加上Event Storming在這裡的價值在於,前者提出Aggregate模式,讓開發者可以組織一個合適的物件群組邊界(a cluster of objects)。不同的Aggregate之間不再透過直接記憶體物件參考(object reference via memory address)而是透過事件(領域事件)來同步狀態。只有Aggregate內的狀態保存需要符合ACID(atomicity、consistency、isolation、durability),Aggregate之間的狀態放寬到最終一致性(eventual consistency)即可。

放寬了consistency model之後,除了可以提升程式的並行性,對於資料庫設計也簡化許多。不需要再像傳統系統一樣,使用一個大型關聯式資料庫來確保所有資料的一致性。系統可以切割成不同的模組、服務、微服務,或是用DDD的說法,Bounded Context,簡化了每個Bounded Context的設計、開發、佈署與維運等工作。

每一個Bounded Context之內的不同Aggregate透過Domain Event來同步狀態,不同的Bounded Context則是透過跨Bounded Context的Domain Event來同步狀態(也就是說Domain Event可以區分為Bounded Context之內與之外這兩種)。

既然系統演變成事件驅動的模式,傳統物件導向分析設計以名詞(先找概念)為主的塑模方式,就變得比較不那麼直覺。Event Storming,嚴格說起來,它的基本元素在傳統物件導向分析設計裡面幾乎都有,但是Teddy覺得Event Storming有幾點很不一樣的地方:

  • 採用以事件(領域事件)為主的塑模方式,不但在分析階段可以優先關注商業流程,在開發階段也可以自然配合事件驅動的系統架構。透過一個「無限大的牆面」,以迭代與增量的方式讓開發團隊與領域專家一起合作、學習、交換知識、產生共同語言。
  • 把傳統物件導向分析設計所需繪製的很多圖表,用一些很簡單的圖示來取代。請參考圖6,而這個圖中的元素不但可以用在分析商業流程(Big Picture Event Storming),還可以用在設計(Design Level Event Storming),簡單、好記、好用,又有足夠的表達力。


▲圖6:Alberto Brandolini 的「picture that explains everything」,節錄自《Event Storming》。

***

友藏內心獨白:不要被名詞嚇到。

2019年12月26日 星期四

領域事件的發送與接收(上)

Dec. 26 17:30~18:47

圖1:看板系統的部分領域模型


背景介紹

為了明年泰迪軟體新修訂課程【領域驅動設計與簡潔架構入門實作班】,Teddy最近三個禮拜都在修改課程專案的程式範例。簡單的說,Teddy想藉由開發一個看板系統,來達到學習領域驅動設計(Domain-Driven Design;DDD)、簡潔架構(Clean Architecture)以及實例化規格(Specification by Example;SBE)。

這一系列談用DDD實作系統時如何發出與處理領域事件(domain event),這一集先談Aggregate Root如何發送領域事件,下一集再談如何接收。

圖1是Teddy設計的CleanKanban系統的部分領域模型,包含了兩個Aggregate:

  • Board:代表一個看板,一個Board可以包含多個Workflow。這個aggregate由Board entity以及 CommittedWorkflow value object所組成,Board為Aggregate Root。
  • Workflow:代表工作流程,其中包含了Stage(垂直的工作步驟)以及Swimlane(水平的工作步驟),Workflow、Stage、Swimlane都是entity,Workflow為Aggregate Root。


圖2:新增Stage的時候Workflow會發出 Stage Created領域事件。

如圖2所示,如果使用者要新增一個Stage(垂直的工作階段),由於Stage屬於Workflow這個aggregate,所以Add Stage的要求會交由aggregate root,也就是Workflow來處理。

接下來看程式碼,如何送出領域事件。

***

Aggregate Root送出領域事件

有三種常見的方式可以送出領域事件:

  • 使用Publisher Subscriber設計模式,領域事件發生時立刻傳送出去。
  • 使用回傳值,呼叫產生領域事件的方法(method or function)之後傳回領域事件。
  • 將領域事件先存在Aggregate Root身上,等適當時機再發送。

Teddy試過第一種和第三種方式,覺得第三種方式比較好。接下來介紹第三種方式。

圖3:AggregateRoot抽象類別程式碼

步驟一:首先宣告一個AggregateRoot抽象類別,如圖3所示。在它上身有一個List<DomainEvent> domainEvents資料成員,用來儲存準備對外發送的領域事件。


圖4:Workflow類別的addStage方法


步驟二:接下來看Workflow的addStage方法,它負責產生一個新的Stage,並將該Stage加在它身上。完成之後Workflow產生一個StageCreated領域事件,並呼叫addDomainEvent方法把這個領域物件先存起來。


圖五:由使用案例層發出領域事件

步驟三:由於Teddy套用Clean Architecture,在實作Add Stage Command的時候直接把它變成一個Use Case類別,如圖五所示的CreateStageUseCase

CreateStageUseCase的execute方法,首先透過repository找出要在哪個Workflow新增Stage,然後呼叫該Workflow的addStage方法,接著把Workflow透過repository存起來。最後,呼叫eventBus的postAll方法將Workflow身上的領域事件全部送出。因為已經將Workflow狀態儲存起來,此時發出領域事件是很合適的時機。


圖六:DomainEventBus

至於傳送領域事件的方式,Teddy目前使採用Google開發的一個開源軟體元件叫做EventBus,然後稍微加工一下符合自己的需求, 請參考圖六。

這種寫法違反了Clean Architecture的相依性原則,需要自行定義一個介面,將對於EventBus的相依性反轉過來。這個就留給鄉民當作練習XD。

***

友藏內心獨白:領域事件先存起來稍後再發送比較好。

2019年12月16日 星期一

CRUD魔咒

Dec. 16 09:59~11:19


靜態的領域模型

最近在準備明年新修訂的課程【領域驅動設計與簡潔架構入門實作班】,花了一些時間重讀Alberto Brandolini的《Event Storming》。書中提到Event Storming的Domain Event(領域事件)應該以使用者操作為出發點去思考,而不僅是傳統的CRUD所產生的事件

讀到這段話Teddy突然想到:「自己在練習Event Storming也遇過同樣的疑問,怎麼許多領域事件都是代表CRUD的事件?」

***

領域驅動設計(Domain-Driven Design;DDD)有一個重點就是開發人員與領域專家一起討論領域模型,這個領域模型用來解釋與理解問題領域,成為開發團隊和領域專家在溝通時的通用語言。

使用領域模型(Domain Model)而不是資料模型(Data Model),這一點一直是物件導向分析與設計以及DDD的核心,但是以資料庫(或是使用者介面)為主的軟體設計思考方式已經深入許多開發人員的骨子裡。就算已經有了物件導向領域模型,在設計功能(use case或user story)時總是免不了寫出一堆CRUD(新增、讀取、修改、刪除)

***

動態的使用者操作

▲圖1:代表CRUD的領域事件

Teddy之前用Event Storming來塑模看板系統的工作項目(Work Item),當時直接反應就寫下圖1這三個領域事件。但這就是CRUD啊,系統的行為好像沒有被真實反應出來。


▲圖2:Kanbanize系統修改卡片的功能

上週Teddy花了點時間研究Kanbanize,這是一個做的很棒的商業看板系統,它的卡片(Card,在Teddy的領域模型中叫做WorkItem)提供很多使用者可以直接操作的功能,如圖2所示。例如:

  • Assignee:指派認領工作的人
  • Priority:設定優先順序為Low、Average、High、Critical
  • Deadline:設定卡片的截止日期
  • Done:把卡片移到完成階段

以上面四個操作為例,應該會產生類似以下的領域事件:

  • CardAssigned
  • PrioritySet
  • DeadlineSet
  • CardFinished

而不是只用一個CardUpdated來代表這些系統操作。

***

不只是粒度大小的差異

有些人可能會認為:「這只是系統功能粒度大小的差別而已啊。CardUpdated粒度比較大,包含了CardAssigned、PrioritySet、DeadlineSet、CardFinished這四個事件。」

某種程度來說,的確是功能的粒度大小不同,但除此之外還有更深層的含意。

系統行為有沒有被塑模出來?

換句話說,領域專家與開發人員針對系統的行為到底溝通到什麼程度?有沒有忽略了什麼重要的系統行為?

很顯然地,如果只是討論CRUD,使用者針對「卡片」本身有意義的操作都躲在「修改卡片」這個功能之下,因此很容易忽略的「修改卡片」這個功能在看板系統這個領域中,到底對於使用者的領域意義是什麼。如此一來,軟體功能並沒有反應出系統的領域知識,因而降低系統的易用性。

***

友藏內心獨白:系統行為的塑模和用戶體驗有關。

2019年12月11日 星期三

【模式寫作工作坊】第二梯次

Dec.11 16:40~17:22


第一梯次的【模式寫作工作坊】於上11/30圓滿結束,原本配合AsianPLoP 2020的截稿日期,這個工作坊只預計舉辦一次。

12月初與主辦單位討論,以推廣中文模式寫作為出發點,把中文模式與主辦單位正式徵稿的活動脫鉤。主辦單位將會在AsianPLoP 2020安排一個下午的session,讓(台灣的)與會者體驗中文的 Writer's Workshop,在活動中討論用中文撰寫的模式.

Teddy預計徵求3~5篇中文模式在該session中討論,目前有三位參加第一梯次【模式寫作工作坊】的朋友有興趣嘗試。一直到明年二月底之前,Teddy會免費協助有意願者修改他們的作品。

離明年三月會議舉辦還有一點時間,Teddy計畫舉辦第二梯次的【模式寫作工作坊】。

***

工作坊簡介

模式寫作工作坊議程如下:

  • 介紹模式起源與PLoP研討會Writer’s Workshop進行方式。
  • 模式六大格式介紹,並透過閱讀模式來驗證模式格式的作用。
  • 模式寫作,介紹Pattern Language、確定寫作主題以及現場寫作與修改練習。

***

報名

  • 課程費用: 8,000元。活動由「台灣軟體工程學會」開立收據(無提供發票)。
  • 日期:2020年1/7和1/14日(禮拜二),19:00~22:00,共6小時。
  • 地點:泰迪軟體,台北市延平南路12號四樓
  • 備註:
    報名本工作坊之「本人」將可免費參加2020 Asian PLoP (報名費價值約6,000元),https://pl.csie.ntut.edu.tw/asianplop2020/

    ***

    友藏內心獨白:真的是最後一梯次了。

    2019年12月10日 星期二

    領域邏輯與應用邏輯

    Dec. 10 13:50~14:49


    名詞解釋

    在物件導向分析與設計(Object-Oriented Analysis and Design;OOAD)、領域驅動設計(Domain-Driven Design)或是簡潔架構(Clean Architecture)中,經常會看到領域邏輯(Domain Logic)應用邏輯(Application Logic)這兩個名詞。在Clean Architecture中,前者稱為關鍵業務規則(Critical Business Rule),後者稱為特定應用業務規則(Application-Specific Business Rule)。

    一般針對這兩個名詞的解釋:

    • 領域邏輯:特定業務領域(business domain)都適用的邏輯。
    • 應用邏輯:在某個業務領域中,特定應用程式的邏輯。

    一般情況下,除非很大型的系統,否則開發人員遇到的情況很可能只有開發一個業務領域中的一個應用程式。也就是說,不太容易區分這兩者,特別是對初學者而言。

    ***

    例子

    最近跟北科大資工系ezKanban團隊討論看板系統的領域模型(domain model)。原本的需求只需支援圖1中的看板系統。

    ▲圖1:看板系統範例


    為了支援圖1的看板系統,ezKanban的domain model如圖2所示。

    ▲圖2:ezKanban的Domain Model


    圖2暗示了一個領域邏輯:一個Stage(圖1中的待辦事項、分析、實作等)有一個預設的MiniStage(圖1中待辦事項底下的想法與Top 5),一個MiniStage有一個預設的SwiLane(用來放置工作卡片的物件)。

    ***

    過了一陣子,Teddy覺得一個看板系統應該有一個預設的Stage用來存放剛剛新增的Work Item(工作卡片),還有另一個預設的Stage用來存放已完成的Work Item。如圖3所示。

    ▲圖3:新的看板系統需求,一個看板有兩個預設Stage:Backlog與封存(Archive)


    如此一來,增加了一個新的邏輯:一個Board物件至少有兩個Stage,如圖4所示。

    ▲圖4:Board與Stage的關係


    圖4中的關係,應該要算是領域邏輯還是應用程式邏輯?

    很顯然地這應該是一個應用程式邏輯,因為ezKanban這個應用程式的要求,才讓Board與Stage產生這樣的關係限制。如果是其他人使用相同的domain model來開發看板系統,則不一定會對Board與Stage的關係規範這種限制。

    所以要實作圖4的邏輯,應該是放在DDD所說的應用程式層(Application Layer),或是Clean Architecture裡面的使用案例層(Use Case Layer)。

    至於圖2中Stage與MiniStage以及SwimLange的關係,屬於domain model的核心邏輯,所以在DDD裡面的Domain Layer(又稱為Model Layer)或是Clean Architecture的Entity Layer實作。

    ***

    友藏內心獨白:分層負責才會乾淨。

    2019年12月9日 星期一

    變成專家之後的學習

    Dec. 09 14:10~15:10

    ▲畫片節錄自電影「鹿鼎記」


    念博士班的時候

    有一種說法,變成專家需要一萬小時的刻意練習(請參考〈一萬個小時的練習〉)。至於鄉民們對於這「一萬小時」的數據是否買單,信或不信,不是今天想要談的重點。Teddy想要說的是,每個人都有自己「學會一件事」(變成專家)所需要的時間。這個時間,依據每個人的能力可能會有所差異,但從「正常人類」的範圍來討論,大致上應該會落在一個相差不多的區間內。

    Teddy以前在念博士班的前三年,都屬於「練功階段」,修課、準備資格考、讀書、讀論文、練習寫作e-learning patters。因為還在蹲馬步階段,嘗試弄清楚「地形地物」,當時沒能力寫出什麼偉大的論文可以拿去投稿。

    後來基本功練得差不多,漸漸發現,接觸到一個軟工相關的新題目之後,可以在18個月(一年半)左右至少寫出一篇國際研討會的論文,算是對這個題目的學習成果給一個階段性的交代。

    後來這「18個月」就變成自己學習新題目的一個時程表,每當自己覺得「好棒棒」的時候,就會提醒:「你才接觸這個題目不到半年,一定還有很多問題你自己沒遇到,不要高興太早。多讀點書和論文,多動手寫程式才是真的。」

    18個月,以一天4小時計算,一年算200個工作天,18個月有300個工作天,一共是1200小時。這1200小時就是Teddy估算在自己成為軟工專家之後,學習軟工新題目到有所小成所需要的時間。

    ***

    成立泰迪軟體之後

    成立泰迪軟體之後,前幾年所開的課都是以前工作與唸書10幾年所累積的成果。即使是「單元測試這樣學就會了實作班」與「軟體重構入門實作班」這些原本已經很熟的技術,要變成一門課,也是要近百個小時的準備。

    2020年新開的「領域驅動設計與簡潔架構入門實作班」(原本的Clean Architecture實作班),則是前後花了約三年的時間才演化成現在的版本。以前念博士班的時候比較專心,WIP比較少,所以只要18個月就可以學會一個新的題目。現在年紀越來越大,理論上「知識越來越豐富」,但因為泰迪軟體個工作本質上context switch很大,一下子講Scrum,相隔沒幾天又要講Design Pattern,接著又切換成例外處理設計。這個多不同的主題平常都要花點時間去注意現況的發展,無法像以前念書時那麼專心學一件事,所以整個lead time拉長,從以前18個月,變成現在36個月。

    ***

    結論

    這幾年在北科大兼任授課,有些學生跟Teddy反映:「為什麼同一個問題Teddy可以翻來覆去用好幾種不同的角度不斷地拿出來討論?」因為學生覺得「這樣好浪費時間,希望Teddy教快一點,他們想多學一些。」

    Teddy總是跟學生說:「你們以為已經學會了,但其實只是學到表面薄薄一層的含意。這些表面的東西,根本不用來上課,去Google就可以找到答案。上課就是要讓你們學會自己思考,養成自我批判與學習的能力。老師不可能一直跟在你們身邊,遇到問題只要跑來問老師就有答案。要練習讓自己變成自己的老師。」

    但坦白說,並不是每個人都想要當自己的老師。想要搖一搖蘋果樹就有蘋果可以吃的人還是比較多。

    變成專家是一種獲得Quality Without A Name的過程,變成嘴砲王則是一種獲得A Name Without Quality的手段。沒有對錯,端看自己的取捨而定。

    ***

    友藏內心獨白:聽到「有一批便宜的牛肉」要提高警覺啊。

    2019年12月7日 星期六

    感受作用力

    Dec. 07 09:21~10:25

    ▲使用者故事對照(User Story Mapping;USM)活動


    不是可不可以的問題

    有一個問題每過一陣子Teddy就會被跑Scrum或Kanban的朋友被問一次:「可不可以用軟體加投影機取代實體Scrum Board或是Kanban Board?

    這種問題,問「可不可以」之前,應該先問「Scrum Board或Kanban Board要解決什麼問題?」,然後再問「改用電子化之後,原本要解決的問題依然持續被解決嗎?有沒有產生新的問題?」。

    ***

    低科技,高接觸

    敏捷圈有一種說法:「Low Tech, high touch. High tech, low touch」。有好幾位跑Scrum的朋友跟Teddy提過,他們從實體Scrum Board(Task Board)改用軟體加投影機之後,原本Daily Scrum每個人都投入的狀況,變成傳統會議那種大家看著投影機「假裝有在聽」別人說話,但卻少了很多之前的互動,原本Daily Scrum每天「重新計畫」的目的因而大打折扣。

    但也有朋友告訴Teddy,他們花重本買了大觸控電視用來取代實體Scrum Board,效果比起投影機要好很多,接近實體Scrum Board。

    感受案發現場的作用力(forces),看看解決方案有沒有平衡這些作用力,你就可以判斷目前的解決方案是否合適。

    通常會想用數位工具取代實體Scrum Board或Kanban Board,不外乎:

    1. 工作環境沒有牆面可以拿來建置實體Scrum Board或Kanban Board。
    2. 不是所有人都在同一工作地點,可以直接觀看實體Scrum Board或Kanban Board。
    3. 想要保存Scrum Board或Kanban Board的歷史紀錄。

    第1點,工作環境不允許應該是要「突破」的限制而不是反過來被它限制。工作場所沒有電腦怎麼辦?總不能上班的時候把程式寫在紙上,回家再輸入自己的電腦中吧!沒有電腦公司要去買啊(或是凹員工自己帶)

    至於其他兩點,Teddy建議以實體Scrum Board或Kanban Board為主,在讓團隊成員或指派特定人員每日更新電子看板即可。聽起來好像很麻煩,實體與電子各有一份,還要手動維持同步。但實際上,同步的工作一天頂多也就花個10分鐘,是值得的投資。

    ***

    感受作用力

    今年11月的【Scrum敏捷方法實作班】 ,不知道是不是因為學員組成比較多元,包含專案經理、產品經理、開發人員、主管,在各項練習活動中都特別投入,效果也很好。

    特別是在使用者故事對照(User Story Mapping;USM)活動中,所有人一起同步討論需求。有幾位學員跟Teddy反應,和他們以往的需求討論會議有很大的差別,不只是在形式上USM比較有趣,在實質面獲得的有用資訊量也大勝傳統方式。

    但這並不能完全歸功於USM,同樣的練習活動,Teddy也遇過產出空洞使用者地圖的團隊。所以說,好的團隊成員加上用對方法,身處現場便可感受到好的力場。

    這不是風水,更不是迷信。認真做事,活在當下,便可察覺到團隊的狀況。

    ***

    友藏內心獨白:工具與方法最後都是要遺忘的東西。

    2019年12月6日 星期五

    如何閱讀模型驅動設計建構區塊的模式語言

    Dec. 06 21:40~23:10

    ▲圖1:Model-Driven Design模式語言,節錄自藍皮書


    模式語言範例

    Domain-Driven Design: Tackling Complexity in the Heart of Software》(藍皮書)Part II,「The Building Blocks of a Model-Driven Design(模型驅設計的建構區塊) 」有一張圖( 如圖1所示),代表Model-Driven Design模式語言

    這個模式語言代表DDD單一bounded context內的核心模式,今天Teddy要談一下如何閱讀這個模式語言。

    ***

    模式語言

    模式語言由建築師Christopher Alexander所發明,透過一組有方向性的模式來解決一個大的設計問題。一個模式語言最頂端的模式,代表使用這個語言的人想要「製作出來的東西」。在圖1中,模式語言第一個模式是Model-Driven Design(模式驅動設計),它本身是一個DDD模式。這是一個比較大(或是說比較抽象、比較高層次)的模式,為了落實Model-Driven Design,需要依靠它下方第一層的其他四個模式,讓Model-Driven Design更完整:

    • Service
    • Entity
    • Value Object
    • Layered Architecture

    Service模式下方沒有其他模式,代表Service模式本身不特別需要其他模式來支持它就已經很完整。Entity模式則需要Aggregate、Repository與Factory這三個模式使其完整。Entity可透過Factory來產生實例。Aggregate包含Entity與Value Object,Entity也需要倚靠Aggregate來確保資料的完整性。

    在圖1中,標示著Entity透過Repository來存取,但Teddy認為其實這個關係可以不用畫在模式語言中,因為Aggregate才會有Repository,單獨的Entity是不能透過Repository來存取。客戶端只能透過Aggregate Root來讀取Aggregate內部的Entity。

    ***

    Value Object下方則有Aggregate與Factory,這個關係很清楚,就不解釋了。Aggregate下方則有Repository與Factory,分別用來儲存與讀取以及生成Aggregate。

    ***

    Model-Driven Design下方最後一個Layered Architecture模式,比起前述其他模式都要大得多。前面幾個模式算是「設計模式」,Layered Architecture已經是「架構模式」。嚴格說起來,Layered Architecture下方還是可以展開其他模式來支持它的實作。

    還有一點要注意,在藍皮書中,對於Layered Architecture模式的描述,屬於傳統階層式架構,階層之間的相依性是由上往下,上層依賴於下層。以現在的角度來看,這種解法應該改套用dependency inversion(相依反轉)原則,拿掉上層對於下層的直接依賴。

    如果是Teddy現在來畫這個模式語言,會用Clean Architecture模式來取代Layered Architecture。

    ▲中文版《領域驅動設計》第68頁描述Layered Architecture模式的解決方案。

    ***

    最後,圖1還有一個Smart UI模式,但是它與Model-Driven Design模式之間卻出現一個X符號。Teddy在Alexander原始的模式語言中並沒有看過這種表示方法,作者的用意只是提醒讀者,Smart UI與Model-Driven Design彼此互斥。

    ***

    重畫Model-Driven Design模式語言

    ▲圖2:Teddy重劃後的Model-Driven Design模式語言


    依據以上討論,圖2是Teddy重畫後的Model-Driven Design模式語言。Teddy習慣由上而下來畫製模式語言,而非像藍皮書中由左而右繪製。自己重新整理之後,感覺比藍皮書的版本還要清爽與容易記憶 XD。

    ***

    工商服務

    對於領域驅動設計(Domain-Driven Design;DDD)與簡潔架構(Clean Architecture)有興趣的鄉民,歡迎參加泰迪軟體的領域驅動設計與簡潔架構入門實作班】。

    對於設計模式有興趣的鄉民,歡迎參加泰迪軟體的Design Patterns這樣學就會了–入門實作班

    ***

    友藏內心獨白:用模式語言思考可以看到問題全貌。

    2019年12月4日 星期三

    把問題寫成一個問句

    Dec. 04 08:29~10:25


    選擇解決方案的困難

    使用設計模式(design pattern)超過20年,也教了好幾年的設計模式。Teddy發現一個常見的問題,就是遇到設計問題時,不知道要套用哪一個設計模式

    Teddy一直覺得,讀模式除了模式名字(Name)以外,最重要的就是要知道模式要解決什麼問題 (Problem),最好能夠把問題寫成一個問句,用一句話就能說出該模式存在的目的。

    如此一來,在套用模式的時候,針對解決相同問題的模式,只要考慮他們彼此之間forces的差異,就可以判斷哪一個解決方案比較合適。

    可惜很多模式的撰寫風格並沒有明確指出模式所要解決的問題,而是使用敘述性的文字把問題與forces甚至是解決方案混在一起談論。讀者只關注到模式的解決方案,導致誤用模式的情況。

    ***

    Value Object

    ▲翻拍自《Domain-Driven Design: Tackling Complexity in the Heart of Software》,p.98 。

    上圖為《Domain-Driven Design: Tackling Complexity in the Heart of Software》(藍皮書)書中描述Value Object模式的段落,黑體字的部分指出幾點問題,這個看起來好像是Value Object所要解決的問題(從Teddy的角度來看,黑體字的部分比較像是forces,也就是問題的限制或特徵)。但是,讀完之後還是不知道如何用一句話說明Value Object的Problem。

    黑體字之後突然冒出一句「An object that represents a descriptive aspect of the domain with no conceptual identity is called a VALUE OBJECT 」,這看起來像是在說明解決方案。一下子討論問題,突然又冒出解決方案(書中下一頁才是詳細的解決方案章節),更容易讓讀者抓不住模式所要解決的問題到底是什麼。

    ***

    改寫練習

    藍皮書第五章A Model Expressed in Software提到了四個模式:ENTITY、VALUE OBJECT、SERVICE、MODULE,Teddy認為它們都要解決一個共同的大問題。因為forces不同,所以衍生出四種不同的解決方案(四個不同的模式)。

    在此Teddy試著改寫前三個模式,它們擁有相同的Context以及Problem:

    Context:你正在使用物件導向方法定義領域模型。

    Problem:你如何表達物件(領域元素)?

    ***

    ENTITY

    Forces:

    • 物件不是由其屬性所定義。
    • 兩個屬性不同的物件可能被視為相同。
    • 即使兩個物件具有相同的屬性,它們可能被視為不同的物件。
    • 弄錯物件辨識碼可能導致資料損壞。

    Solution:將物件歸類為ENTITY如果它是透過辨識碼而不是自身的屬性來區分。使此辨識碼成為模型中其定義的主要依據。使類別定義保持簡單,並專注於生命週期的連續性和標識。定義一種區分每個物件的方法,無論其形式或歷史如何皆可依據該方找到想要找的物件。將需求中依據屬性匹配物件的要求改成依據辨識碼。定義一個保證為每個物件匹配產生唯一結果的操作,可能透過附加一個保證唯一的符號來實現。這種標識方式可能來自外部,也可能是系統為系統創建的任意標識符號,但必須與模型中的辨識碼相對應。模型必須規範物件相等的定義。

    ***

    VALUE OBJECT

    Forces:

    • 物件由它們的屬性定義。你只關心它們是什麼,而不關心它們是誰。
    • 紀錄物件的識別碼至關重要,但是將識別碼附加到每個物件身上可能會損害系統性能,增加分析工作並弄亂模型,使所有物件看起來都一樣。

    Solution:當你只關心物件的屬性時,將物件分類為VALUE OBJECT。使它表達其傳達屬性的含義並賦予它相關的功能。將VALUE OBJECT視為不可變。不要給它任何識別碼,並避免為了維護ENTITIES所需的設計複雜性。

    ***

    SERVICE

    Forces:

    • 領域操作(domain operations)本質上是活動或動作,而不是事物。
    • 領域操作無法被歸屬於某個ENTITY或VALUE OBJECT的自然職責時。

    Solution:在模型中增加一個操作,作為代表SERVICE的獨立介面。根據模型的語言定義介面,並確保操作名稱是UBIQUITOUS LANGUAGE的一部分。使SERVICE為無狀態。

    ***

    以上內容大多出自藍皮書,Teddy只是把格式重新調整,抓出Context與問題。以後看到ENTITY、VALUE OBJECT、SERVICE,鄉民們第一個想到的就是「設計領域物件嘿用得到」(這是它們的Context)。接著問題就是有哪幾種領域物件的種類?依據不同的forces,可以分成三種不同的領域物件。

    如果用這種方式去思考與記憶,Teddy覺得比較不會在藍皮書中所提到的一堆模式中迷路。

    ***

    動動腦

    同樣的內容,為什麼有些人可以用很有條理的方式讓別人聽懂,有些人卻講得非常冗長,讓人越聽越迷糊?!

    模式的六大格式是一種很好的收納知識方法,鄉民們可以自己練習一下,找幾個DDD書中其他模式,把它們的問題、解決方案,以及forces抓出來。

    練習過後會產生和吃「瀨尿牛丸」的效果,人都變聰明了!

    ***

    友藏內心獨白:練習把飯菜裝進六個格子的便當盒裡面。

    2019年12月3日 星期二

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

    Dec. 03 16:43~17:28

    ▲領域驅動設計與簡潔架構入門實作班課程照片 (原Clean Architecture實作班)


    時間過得好快轉眼就要跟2019說Bye Bye,又到了年底排課表的時間。2020年Teddy預計新開一門【行為驅動設計與實例化規格實作班】課程,開課時間大約在2020年8月之後。

    以下是泰迪軟體2020年上半年課表,原本的【Clean Architecture實作班】,因為課程內容包含許多領域驅動設計(Domain Driven Design;DDD),所以Teddy將課名調整成【領域驅動設計與簡潔架構入門實作班】。

    Scrum敏捷方法實作班

    • 假日班:2月22、23號(六、日)。
    • 假日班:5月9、10號(六、日)。

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

    • 假日班:3月21、22號(六、日)

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

    • 假日班:3月7、8、14號(六、日、六)。

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

      • 假日班:4月24、25、26號(五、六、日)。

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

      • 平日班:3月24(二)。

      領域驅動設計與簡潔架構入門實作班(舊課程名稱為:Clean Architecture實作班

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

      單元測試實作班

      • 假日班:4月11、12號(六、日)。

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

      • 假日班:6月13、14號(六、日)。

        軟體重構入門實作班

        • 平假日班:4月17、18、19號(五、六、日)


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

        螢幕截圖 2017-12-12 10.08.45

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

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

        螢幕截圖 2017-12-12 10.15.26螢幕截圖 2017-12-12 10.15.51螢幕截圖 2017-12-12 10.16.10

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

        螢幕截圖 2017-12-12 10.11.38

        ***

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

        2019年12月2日 星期一

        你也可以撰寫模式

        Dec. 02 09:53~10:55


        重複使用知識

        11月30日Teddy辦了第一次一整天的【模式寫作工作坊】,六個小時的工作坊內容包含了:

        • 介紹模式歷史與常見格式。
        • 閱讀模式
        • 寫作模式

        Teddy發現對於第一次寫作模式的人來講,第一個遇到的困難點就是如何挑選寫作題材。模式的定義,可以簡單用以下一句話來說明:

        模式就是在一個特定領域中,針對重複出現問題所提出證明可行的解決方案。

        也就是說,模式不是創新,而是將已知可行且可重複使用的解決方案與其所要解決的問題記錄下來。因此,模式寫作可視為一種整理知識的過程。要寫出好的模式,最簡單的方式就是從自己熟悉的身邊事物開始著手

        ***

        生活觀察家

        模式不限於軟體開發,而是可以很生活化,包含所有的領域。只要認真做事、認真過生活,便可觀察到許多有趣的模式。

        例如,對於一個專業宅宅而言,每天在家裡關注不同的網路紅人與YouTuber,久而久之很容易察覺這個領域的常見模式。像是:

        • 自己的定位:確定自己要當哪一種類型的網紅,例如知識性、網美、搞笑、旅遊等。
        • 鐵粉:找到自己的定位之後,想辦法吸引一群死忠支持自己的鄉民。
        • 人頭粉絲:有了基本盤之後,要擴大自己的網路人氣。此時可考慮廣納各方人士,增加自己的粉絲人數,壯大氣勢。
        • 互相拉抬:與其他知名的網紅合作,增加彼此的人氣與粉絲人數。
        • 系列故事:製作主題性的系列故事來吸引更多的關注者。
        • 業配:「風蕭蕭兮易水寒,網紅一樣要吃飯」。為了讓網紅這個職業可以長久持續下去,可以考慮接業配增加收入。
        • 安排好的偷拍照片:現在網紅這麼多,如何增加自己的曝光度?利用人們偷窺的好奇心,設計一些「偷拍自己的照片」,然後故意流出到各大社群網站,讓「小時不讀書,長大當記者」的朋友們幫你免費宣傳。
        • 小鈴鐺:你經常發布訊息、照片或影片更新,但你的粉絲卻無法即時收到。請粉絲們按下「小鈴鐺」,以便收到你最新的訊息。

        ***

        模式範例

        接下來Teddy寫一個網紅模式給鄉民們參考。

        安排好的偷拍照片

        ▲圖片來源在此

        Context:你將自己定位為網美型網紅。

        Problem:如何增加自己的粉絲數?

        Forces:

        • 你在知名社群軟體,例如IG與FB經營一段時間,定期發布自己的照片與短片。
        • 你有基本的粉絲。
        • 你不想花太多經費或時間。
        • 你父母不是知名藝人。

        Solution:拍攝自己的清涼偷拍照片,找人將其張貼在PTT、爆料公社等社群,吸引 無腦 媒體報導。

        Resulting Context:大部分的人喜歡看美女/俊男,更喜歡看被偷拍的美女/俊男。套用本模式可在短時間內衝高自己的人氣,進而增加自己的 豬哥 粉絲人數。實施本模式的成本很低,只要自己願意,可以簡易套用。

        但是,不可忽視鄉民的智慧。如果偷拍照片拍得太假,可能造成反效果,被鄉民貼上「假掰」、「做作」的標籤。

        ***

        友藏內心獨白:模式就是有六個空格的便當盒。