l

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

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

        ***

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

        2019年11月26日 星期二

        透過協作產生敏捷需求

        Nov. 26 17:48~18:35


        不是需求

        許多跑敏捷的團隊會使用user story(用戶故事、使用者故事)來表達「需求」,大家一般認為寫user story是Product Owner的責任,團隊只要照著user story所描述的內容就可以做出PO所希望的功能。

        但實際上功能做好之後卻經常被PO要求改東改西,導致開發團隊抱怨:「Product Owner寫的user story太簡略,害他們不能『按圖施工,保證成功』,要不斷地重工」。PO則是不滿開發團隊都不動腦筋,遇到問題也不及時跟他溝通與釐清。

        其實user story不算是傳統軟體開發所說的需求或規格,user story只是引發團隊討論需求的一句話真正的需求,透過開發團隊、Product Owner與利害關係人的對話、討論、探索而產生。討論之後所產生的需求,可以透過specification by example(實例化規格)的方式記錄下來。

        另外,撰寫user story的責任也不能全部推給PO。User story的「為了…(目的)」所描述的是使用者所遭遇的問題,這是PO需要負責搞清楚的部分。而「我想要…(做什麼)這句話已經包含某種解決方案,則是需要PO與開發團隊一起討論,尋求各種可能的做法

        ***

        心態改變

        上週Teddy在上【Scrum敏捷方法實作班】介紹user story的時候跟學員提到上述觀念,下課時有一位學員說…

        以前團隊在product backlog refinement workshop的時候,我們都習慣要求PO要把user story寫清楚,如果有不清楚的地方,我們會責怪PO,覺得他沒有準備好就找我們來開會。但上完課之後,我才發現原來撰寫user story的責任不能完全推給PO一個人。下次再開refinement workshop,我會改變作法,多提供意見。

        ***

        協作遊戲

        敏捷開發是一種協同合作的活動,不是傳統瀑布式開發那種「透過文件溝通」的模式,更不是找個issue tracking system(議題追蹤系統)來「開票、領票」(分派、追蹤工作)。

        只是做做敏捷的樣子,心態沒變,還是白搭。

        ***

        友藏內心獨白:讓團隊每個人都動腦真的不容易。

        2019年11月19日 星期二

        Pattern寫作工作坊

        Nov. 19 16:54~17:57


        一起做功德

        PLoP(Pattern Languages of Programs)是模式(Pattern)社群一年一度的聚會,在全球各洲都有類似的活動,在亞洲舉辦的PLoP稱為AsianPLoP。

        AsianPLoP 2020 明年3月4-6日將於台北舉辦,這個活動往年都在日本東京舉辦,明年是第二次移師到台北來。因為Teddy的指導教授是活動主辦人之一,而Teddy也是模式的愛好者,利用此次機會跟AsianPLoP 2020的主辦單位「台灣軟體工程學會」合作,於今年11/30日在泰迪軟體舉辦一天的【Pattern寫作工作坊】,藉此活動讓更多鄉民有機會接觸的模式社群,從了解模式、閱讀別人的模式,進而能夠利用模式來整理自己的知識(寫作模式)。

        本工作坊費用8,000元,由「台灣軟體工程學會」開立收據。所繳交費用可全額抵免明年的AsianPLoP 2020研討會費用。也就是說,報名此工作坊的學員本人明年可以免費參加在北科大舉辦的AsianPLoP 2020 (無論是否投稿,都可參加)。

        工作坊已確定開課,對模式有興趣的朋友,歡迎一起來聽聽模式的歷史、閱讀模式、寫作模式。

        ***

        Teddy的模式之旅

        Teddy從1997年開始接觸到設計模式,當時讀了GoF的《Design Patterns》,實際應用之後覺得設計模式對於軟體開發很有用,但對於書中提到的23個模式也是一知半解。

        幾年後回北科大念博士班,因為之前工作從事e-learning系統與數位教材製作工具的開發,對design patterns也熟,因此指導教授建議Teddy可以研究e-learning領域的patterns。因此,讀了pattern發明人建築師Christopher Alexander一系列的幾本書,同時也開始寫作e-learning patterns。在2004年時,第一次到美國參加PLoP,那時有種劉姥姥逛大觀園的震撼---原來這就是傳說中的PLoP啊。

        這幾年Teddy建議不少人讀Alexander的書,但似乎效果不適很好。Alexander的書有點哲學的味道,剛開始不是那麼容易讀懂。但他的思想的確影響了很多軟體社群的人,Design Patterns、Architecture Patterns、Testing Patterns這些大家都耳熟能詳就不說了,最近1~2年在台灣流行的領域驅動設計(Domain Driven-Design;DDD),發明人Eric Evans所寫作的「藍皮書」,其實就是一本DDD Pattern Languages,書中介紹了數個DDD patterns。


        ▲「藍皮書」本身就是一堆patterns


        ***

        有什麼用

        PLoP研討會已經舉辦了20幾年,學習pattern不是什麼趕流行,而且坦白說有點門檻。對Teddy而言,pattern(特別是pattern language)的訓練有三個主要的好處:

        • 讓人具備一種關照全面看到事情本質的能力。學習pattern很重要的一環就是觀察Forces,體驗Forces。漸漸地,你更能關注事物核心的Quality,而不是表面的Name(因為Quality Without A Name)。
        • 吸納新的知識:很多領域專家,會將他們多年累積的知識寫成pattern。對於真正了解pattern的人,就比較容易吸收這些以pattern所表達的知識。以DDD為例,Teddy很晚(2013)年才開始接觸,但因為Teddy的腦中已經內建 九陽神功 pattern解譯器,對於DDD的學習就比一般鄉民要來得容易與深入一些。
        • 系統性的整理自己的知識與經驗。你覺得自己很厲害,好,然後呢?FB貼廢文、寫blog、參加社群聚會當講者,這些都很好。但,如果要更進一步挑戰自己,將自己的經驗整理成pattern是一個很好的方式。

        ***

        報名

        報名表單在此,錯過這次,下一次就要等……不知道有沒有下一次了。

        ***

        友藏內心獨白:我以為畢業後就不用再寫pattern了XD。

        2019年10月18日 星期五

        學習DDD有感

        Oct. 18 14:46~16:18


        客戶的發問

        昨天下午到客戶家介紹領域驅動設計(Domain-Driven Design;DDD),以及如何運用事件風暴(Event Storming)、Clean Architecture、TDD的工具落實DDD。

        活動結束時有同仁問Teddy:「你演講中提到DDD的好處我們都可以理解,具體上有沒有什麼實際的經驗可以分享?」

        ***

        第一次接觸

        Teddy首先想起幾年前剛接觸DDD,讀到《Domain-Driven Design: Tackling Complexity in the Heart of Software》這本書的情景。由於多年來Teddy已經習慣物件導向分析與設計(Object-Oriented Analysis and Design;OOAD)方法,當時覺得DDD強調建立領域模型(domain model)這件事,和OOAD並沒有什麼不同。另外書中提到的ubiquitous language、bounded context等觀念,其實就是pattern發明人Christopher Alexander在《Notes on the Synthesis of Form 》與《The Timeless Way of Building》等書中所提到的設計方法。至於DDD的Tactical Design(戰術設計)所包含的entity、value object、aggregate、factory、service、layered architecture這些patterns,也不過就是物件導向設計中常見的作法。

        結論就是,這本書稍微翻一下就沒再理它了XD。

        ***

        第二次接觸

        過了一陣子,可能是因為微服務(Microservice)流行的緣故,DDD也跟著流行起來,Teddy同溫層的「臉友」談論DDD的人漸漸多了起來。這也引起Teddy的好奇,想說光看《Domain-Driven Design: Tackling Complexity in the Heart of Software》可能不夠,又買了幾本DDD的書,花了不少時間用力讀了一下。此時對於DDD所提出的這堆patterns的內涵有比較完整的認識,但總覺得,要開發軟體我就用熟知的OOAD就可以了,找不到一個施力點來使用DDD。

        ***

        第三次接觸

        兩年前在指導教授的建議之下,Teddy停掉在北科大資工所兼任的「軟體生命週期管理」課程,改教「軟體架構」。當時剛好Robert C. Martin 的新書《Clean Architecture: A Craftsman's Guide to Software Structure and Design》 出版,Teddy就用這本書當教科書。兩年來為了學習與教學的目的,Teddy設計兩個不同的專案,用了好幾種方式來詮釋Clean Architecture的實作。後來發現搭配DDD的domain model、ubiquitous language、bounded context、event storming、entity、aggregate、repository、service、domain event等pattern,以及Clean Architecture,加上採用TDD/BDD/SBE的方式實作系統,可以很漂亮的串起這些軟體開發方法。

        此時,Teddy才慢慢感受到DDD的威力,特別是ubiquitous language in code的實踐,對於軟體的開發與維護所帶來的好處。另外,aggregate與domain event的使用,讓系統模組自然支援現今主流的分散式架構,這是傳統OOAD方法需要特別而外去關注才做得到的地方。

        ***

        第四次接觸

        約一年前Teddy帶幾位研究生開發一個看板系統,當初一開始設定的目標是要採用Clean Architecture作為此系統的架構。隨著開發活動進行,慢慢發現使用到DDD patterns越來越多,像是原本Clean Architecture就很強調的domain model,以及DDD的ubiquitous language in code、aggregate、repository、service、domain event等。

        多年來Teddy也帶過好多組學生開發軟體,每次都立下宏願,希望用畢生所學,讓學生可以開發出「高品質」軟體。坦白說,多年來這個宏願一直無法實現。一方面研究生時間不多,要修課、寫作業、過日子,而且每年都有學生畢業,真正有時間投入專案開發頂多就是一個寒暑假而已。

        另一方面學生的軟體開發能力與經驗也不足,還在學習當中,不容易要求在短時間內就可以做出設計良好的系統。

        但是,這次開發看板系統Teddy感受到一絲曙光。初期Teddy花了很多時間與學生code review,先確認他們的Clean Architecture沒有走偏(目前還是有點偏,但至少沒有歪的太厲害)。後來隨著一個個user story實作的機會,幫助學生認識如何落實domain model與ubiquitous language in code。Teddy覺得光是這兩點做到,再搭配Clean Architecture,整個軟體系統的可讀性提升好幾個檔次。

        Teddy希望有朝一日能做到「即是是學生所開發的軟體,也能夠達到專業的水準」。

        ***

        老外幫我們做實驗

        Teddy後來告訴發問的同仁:「DDD外國外已經提出10幾年了,有很多老外已經幫我們做過實驗。落實DDD的難度相對而言是比較高的,但是一旦公司與團隊能夠掌握這項方法,以我切身的經驗,我相信可以讓軟體開發更接近『讓軟體變軟』這個目標。」

        落實DDD除了技術上的門檻以外,還有一點非常重要,就是團隊中有沒有領域專家,以及這位(或這一票XD)領域專家是否願意與開發團隊緊密合作,採用迭代與增量的模式,共同建立軟體系統的domain model與ubiquitous language。

        DDD的技術門檻,可以來上泰迪軟體的〈Clean Architecture這樣學就會了實作班〉補足。至於有沒有領域專家願意與團隊緊密合作,就只能靠緣分了XD。

        ***

        放下偶包

        整個學習DDD的過程讓Teddy有一個很深刻的感觸:「很多時候以往的成功經驗可能會阻礙自己學習新的事物。」OOAD太熟導致一開始忽視DDD、Waterfall太熟導致覺得敏捷無用、壓專案時程太方便導致沒有給團隊自主決定的機會、成功的大公司導致無法冒險也沒有容忍失敗的空間。

        所以武俠小說裡面的橋段:「欲練神功,揮劍自宮」都是真的。

        ***

        友藏內心獨白:該不會下一頁是不用自宮,也能成功吧!

        2019年7月2日 星期二

        領域驅動設計學習筆記(6):Aggregate (中)

        July 02 21:45~22:48


        在上一集〈領域驅動設計學習筆記(5):Aggregate (上)〉提到為了避免破壞aggregate invariant(聚合不變量或聚合規則),aggregate root在回傳資料的時候,需要考慮:

        1. 完全禁止回傳Aggregate內部的Entity。
        2. 可以回傳Entity,但只回傳immutable Entity或是Entity的deep copy。
        3. 設計immutable interface,讓Entity實作immutable interface並透過immutable interface回傳給客戶端。

        今天討論這幾種做法的優缺點,並展示一個透過自動產生immutable proxy的工具來解決這問題的範例。

        ***

        禁止回傳Aggregate內部的Entity

        • 優點:這個方法因為禁止aggregate root回傳內部entity,所以客戶端不可能透過aggregate內部entity來破壞aggregate invariant。
        • 缺點:為了提供資料給客戶端,aggregate root可能需要將內部entity轉成DTO(data transfer object)再往外傳。這種做法有點類似clean architecture中,use case層定義雙向介面將entity往外傳遞。從架構的角度來看可以切得很乾淨,但是需要花費額外的功夫包一層DTO。

        ***

        回傳immutable entity或是entity的deep copy

        • 優點:用相同的domain model(直接回傳aggregate內部的entity)來處理程式邏輯,而且因為回傳的entity是不可修改的物件,或是原本物件的複製版本,所以也不可能透過這個entity破壞aggregate invariant。
        • 缺點:無論是實作immutable entity或是deep copy(GoF的Prototype設計模式),都需要花費額外的設計、實作與測試的功夫。特別是deep copy,不小心沒有實作好變成shallow copy就GG了。

        ***

        設計immutable interface

        Immutable interface是一種設計模式,請參考c2。簡單講,immutable interface是一個只有getter沒有setter的介面。設計好immutable interface之後,讓你的entity實作此介面。如果aggregate root要回傳entity,只能傳回entity所實作的immutable interface,如此一來客戶端就不可能修改到aggregate的資料。

        Immutable interface的缺點和回傳DTO類似,domain model裡面除了原本的entity,又多了另一種代表「不可修改」的immutable interface。

        ***

        折衷作法

        如果程式語言可以支援自動回傳immutable object,這個問題就不是問題。Teddy不知道有沒有哪個程式語言有這種功能,目前只能從上述三種做法中挑一種來實做。

        Teddy想用方法二。方法二有兩種實作,考慮到回傳entity的deep copy比較不好實作,所以決定優先選擇回傳immutable entity的方式。

        要實作immutable entity,可以套用Proxy設計模式,概念如下:

        Ministage是一個mutable介面,MinistageImpl是這個介面的實作,而ImmutableMinistage則是將MinistageImpl包裝一層,只要客戶端呼叫到setter的函數,就丟出例外。

        這種方法的優點是,從客戶端的角度,他看到的就是Ministage這個domain model的概念。至於它是mutable還是immutable,則只是實作細節。

        這種做法當然也有缺點,首先設計上當然比沒套用Proxy設計模式要來的複雜。其次,因為在編譯期間(compile time)客戶端不知道拿到的Ministage是mutable還是immutable,如果不小心拿到immutable但卻呼叫到它的setter函數,則會出現runtime exception。

        程式設計師都有偷懶的天性,Teddy想回傳immutable entity但又懶得手動實作proxy,於是google了一下,找到一個Java語言的reflection-util工具,可以自動產生immutable proxy。


        ▼使用方法很簡單,以maven建構工具為例,首先加入reflection-util的參考。



        ▼接著在程式中透過ImmutableProxy.create()方法,可以直接產生immutable entity,非常容易使用。

        ***

        從Clean Architecture的角度來看…

        使用reflection-util這種工具,可以幾乎無痛產生immutable entity。但是從clean architecture的角度來看,在最核心的entity層引用外部工具,違反了相依性原則,你的架構就變得不再那麼乾淨了。

        Teddy覺得這個「小違規」目前是可以接受的折衷方案。因為你可以透過將reflection-util再包一層,讓aggregate root透過間接的方式呼叫reflection-util來獲得immutable entity。有朝一日如果真的不想使用reflection-util,也可以在影響最小的情況下,以其他實作方式將它取而代之。

        所以,雖不完美,但還可接受。

        ***

        友藏內心獨白:設計就是取捨後的結果。

        2019年6月17日 星期一

        領域驅動設計學習筆記(5):Aggregate (上)

        June 17 15:36~16:42


        問題

        在物件導向的domain model裡面,物件和物件之間經常有著複雜的關聯(associations)。如下圖所示,一個看板系統的domain model,Board擁有若干的Stage,一個Stage擁有若干個MiniStage,一個MiniStage擁有若干個SwimLane,一個SwimLane擁有若干個WorkItem。


        當修改這些物件狀態時,如果不小心很可能會違反系統的不變量(invariant)或固定規則而導致系統狀態不正確(產生bug)。例如,看板系統的一個不變量是:「SwimLane的WorkItem數量不可以超過WipLimit數值。」

        試想在一個多人使用的狀況下,為了滿足上述不變量,當修改SwimLane的狀態時,你可能要鎖住SwimLane,甚至是鎖住整個系統,導致系統無法使用或效率很差。

        ***

        Aggregate Pattern

        Aggregate是領域驅動設計(Domain-Driven Design;DDD)裡面很重要的pattern。依據《Domain-Driven Design: Tackling Complexity in the Heart of Software》書中的定義,Aggregate想要解決的問題與解決方案分別為:

        Problem

        It is difficult to guarantee the consistency of changes to objects in a model with complex associations. Invariants need to be maintained that apply to closely related groups of objects, not just discrete objects. Yet cautious locking schemes cause multiple users to interfere pointlessly with each other and make a system unusable.

        很難保證具有複雜關聯的模型中物件更改的一致性。 需要維護不變量,這些不變量適用於密切相關的物件組,而不僅僅是離散的物件。 然而,謹慎的鎖定方案會導致多個用戶無意義地相互干擾並使系統無法使用。(中文修改自google翻譯)


        Solution

        Cluster the ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each. Choose one ENTITY to be the root of each AGGREGATE, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to the root only. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the AGGREGATE and for the AGGREGATE as a whole in any state change.

        將ENTITIES和VALUE OBJECTS聚集在一起形成AGGREGATES並定義AGGREGATES的邊界。 選擇一個ENTITY作為每個AGGREGATE的根,並透過根控制對邊界內物件的所有存取。 允許外部物件僅保留對根的引用。可以傳遞對內部成員的瞬時引用,以便僅在單個操作中使用。 因為根控制存取權限,所以內部的更改不能繞過它。 這種安排可以確保任何針對AGGREGATE裡面的物件以及AGGREGATE本身的狀態修改都不會違反不變量。(中文修改自google翻譯)

        ***

        實作細節

        以上述看板系統為例子,Stage、MiniStage與SwimLane形成一個Aggregate,Stage是Aggregate Root。依據DDD的定義,為了確保不變量:

        1. 所有對於Aggregate內部物件的操作都要透過Aggregate Root。也就是存取MiniStage與SwimLane都要透過Stage。
        2. 外部物件只可以擁有Stage物件的reference(因為它是Aggregate Root),不可以擁有MiniStage與SwimLane的reference。
        3. 但是,Stage可以將MiniStage與SwimLane往外傳,只不過客戶端程式只能在單一method中操作這些entity,不可以把它們的reference保存起來(例如,不能存在data member裡面)。

        前兩點很容易理解與實作,但第三點就需要進一步討論。因為如果把MiniStage與SwimLane往外傳,既使在單一method裡面使用,也可能繞過Stage直接呼叫MiniStage與SwimLane,因此改變Stage這個Aggregat的狀態而破壞不變量。

        所以,在實作Aggregate的時候,就有幾種可能的選擇:

        • 完全禁止回傳Aggregate內部的Entity。
        • 可以回傳Entity,但只回傳immutable Entity或是Entity的deep copy。
        • 設計immutable interface,讓Entity實作immutable interface並透過immutable interface回傳給客戶端。

        無論採取哪種方式,在實作時都需要特別留意,以免Aggregate的不變量一不小心就被違反了。

        ***

        廣告

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

        ***


        友藏內心獨白:還是要看定義。

        2019年5月31日 星期五

        如何用看板管理卡住的工作項目?

        May 31 10:30~11:53


        狀況分析

        使用看板的團隊經常會遇到工作做到一半卡住的問題,卡住的原因不外乎:

        • 遇到技術困難不知道該怎麼做下去。
        • 遇到相依性問題,需要等待其他資源(工作、人、設備、材料)完成才可以繼續。

        依據卡住的時間長短,卡住的狀況又可分為:

        • 短期:團隊投入資源想辦法排除卡住的原因,每日站立會議追蹤卡住工作的進度,儘量讓工作可以順利往下游移動。
        • 遙遙無期:預期工作會卡住很久,或是在特定時間才有辦法處理該工作。不需要在每日站立會議追蹤卡住工作的進度,一周、兩周甚至一個月更新一次進度即可。

        ***

        用看板管理卡住的工作項目

        ▼針對短期卡住的工作,在該工作卡片上面貼上一張粉紅色便利貼,提醒團隊該工作項目發生阻礙,需要特別關注排除阻礙讓工作順利流動。


        ▼每日站立會議時追蹤阻礙項目的狀況,如果尚未排除則在該阻礙項目上用筆點一點,類似progress bar的概念。如果阻礙卡片上的progress bar越長,表示該阻礙停留時間越久。

        ***

        針對被卡住「遙遙無期」的工作項目,短時間團隊並不會也沒辦法去處理它。如果直接把它放在看板上不管,會佔據一個WIP,這樣也不好。

        ▼一種常見的作法是在看板上建立一個獨立的Ice Box(冰箱)工作階段,把卡住遙遙無期的工作項目移入Ice Box。如此一來原本的工作階段便空出一個WIP,而團隊只需要定期檢視Ice Box裡面的工作卡片有沒有「臭酸」或「超出保存期限」即可。

        當Ice Box中的工作項目其卡住的原因排除之後,只要原本的工作階段未達WIP上限,便可移回原本的工作階段繼續施工。

        ***

        如果怕整個看板只有一個Ice Box不容易分類不同工作階段卡住的工作項目,可以參考《Agile Project Management with Kanban》書中的做法,直接在工作階段增加一個追蹤(Track)欄位。

        ▼如下圖所示,追蹤欄位和Ice Box類似,(通常)沒有WIP限制,放在其中的工作項目數量不會佔據實作工作階段(WIP Limit  = 5)的WIP。

        ***

        結論

        看板透過小批量生產消除變異性讓工作流動得更順暢,縮短產品交期。卡住的工作代表產生阻礙,也就是工作流程產生變異,需要特別關注,才不會發生「人進不來,貨出不去,公司發不了財」的問題。

        ***

        友藏內心獨白:貨暢其流。

        2019年5月29日 星期三

        設定看板的WIP

        May 29 11:52~13:41


        前言

        很多剛開始跑看板的鄉民都有一個疑問:「要如何設定每個工作階段的WIP?」今天介紹《Agile Project Management with Kanban》書中提到的方法。

        ***

        準備工作

        要決定如何設定WIP,以下資料需要先準備好:

        • 視覺化工作流程,例如分析、開發、測試。
        • 知道每個工作項目(work item)完成的平均時間,例如分析工作一周完成六個,開發工作一周完成兩個,測試工作一周完成三個。
        • 每個工作階段有多少人負責,特別是瓶頸工作階段的人數(詳見下面說明)。

        ***

        開始計算

        有了以上資訊,就可以計算初始看板的WIP。參考下表,計算步驟如下:

        分析

        實作

        測試

        平均每人完成工作速度

        6/week

        2/week

        3/week

        工作階段人數


        3


        產能


        6/week


        WIP


        3 * 1.5 = 5


        • 找出瓶頸,也就是速度最慢的工作階段,在這個例子中實作速度最慢。
        • 算出瓶頸的產能:平均每人完成工作速度 * 工作階段人數,2 * 3 = 6,代表實作階段每周可完成6個工作項目。
        • 將實作的WIP訂為:工作階段人數 * 1.5 (四捨五入),實作階段的開發人員有3人,3 * 1.5 = 5。乘上1.5的目的是讓每個人手邊有1.5件工作可以做,以免WIP太小任何一件工作卡住就必須等待。但也不會因為WIP太高導致context switch的浪費。這個技巧在《Kanban in Action》書中也有介紹。
        • 其他工作階段配合瓶頸速度:由於屬於瓶頸的實作階段每周只可完成6件工作,因此分析只需要1人即可搭配實作階段的消耗工作速度。同理,而測試階段只需要兩人。

        分析

        實作

        測試

        平均每人完成工作速度

        6/week

        2/week

        3/week

        工作階段人數

        1

        3

        2

        產能

        6/week


        6/week

        6/week

        WIP


        3 * 1.5 = 5


        • 計算其他工作階段WIP:分析工作階段WIP = 1 * 1.5 = 2。測試階段WIP = 2 * 1.5 = 3。

        分析

        實作

        測試

        平均每人完成工作速度

        6/week

        2/week

        3/week

        工作階段人數

        1

        3

        2

        產能

        6/week


        6/week

        6/week

        WIP

        2

        3 * 1.5 = 5

        3

        ***

        人太多怎麼辦

        剛剛的例子是由瓶頸階段的人數與平均每人完成工作的速度,回推其他工作階段需要多少人。但很多情況是團隊人數已經確定,例如分析、實作、測試各2人,請參考下表:

        分析

        實作

        測試

        平均每人完成工作速度

        6/week

        2/week

        3/week

        工作階段人數

        2

        2

        2

        產能


        12/week


        4/week

        6/week

        WIP

        3

        3

        3


        在這種情況下,因為一周完成12件分析工作但卻只能消化4件,因此分析階段的工作會累積在實作之前。而測試會沒有工作可做,導致人員閒置。

        但是,幸好有WIP限制,分析工作不可能無限增加。如下圖所示,假設分析與實作階段已達WIP上限,此時分析人員便不可再從待辦事項中拉取工作來分析,只能停下來看看如何幫助工作流動得更順暢。

        同理,測試階段可能沒有多餘的工作可以做,一樣需要思考如何幫助工作流動得更順暢。最直接的方式就是所謂的swarming,分析與測試階段的人到實作階段幫忙,提高實作階段,也就是瓶頸階段,的產能。

        如果能夠從每個工作階段的產出可以互相匹配的角度來安排人力與設定WIP,會讓工作流動比較順暢。

        當然,實務上平均每人完成工作速度變異性可能很高,受到品質、施工人員的技能與身心靈狀態、工作項目大小、需求不確定性等因素影響,導致需要控制的因素很多,因而需要時時檢討人力、WIP的設置是否恰當,以及透過流程改善來讓工作流動更加順暢,降低交期(lead time)。

        ***

        友藏內心獨白:小批量生產與消除變異性。

        2019年5月28日 星期二

        不要只聽半套

        May 28 23:11~23:54

        ▲這句怎麼都沒人聽進去XDD


        故事一

        有一個公司派了整個團隊來泰迪軟體上Scrum敏捷方法實作班,回公司之後團隊跑了一陣子Scrum。有一天因為產品出了包,非常緊急,Product Owner希望團隊加班趕緊把這個問題解決。沒想到,團隊中有成員居然回答PO:「我們去上Teddy的課,Teddy說跑Scrum不能加班。」

        公司老闆得知後非常氣憤,有一次遇到Teddy,用開玩笑的語氣說:「我員工去上你的課,回來之後都不加班了」。

        這,員工不想加班就大聲說「我不想加班」,幹嘛扯到Teddy頭上哩?!Teddy上課時是說:

        敏捷開發講求「穩定的開發步驟」(sustainable pace),早期XP對於穩定開發步驟有一個簡單的說法,就是每週工作四十小時。我自己還在與Scrum團隊的時候,也是儘量利用上班專心把工作完成,以不加班為原則。

        假設公司因為產品出問題都火燒屁股了,作為員工此時還在「我跑敏捷我不加班」,如果Teddy是老闆,也會發火啊。古語有云:「善戰者無赫赫之功」,這也是好的敏捷團隊期望達到的狀態。但是,天有不測風雲,總是會遇到需要「江湖救急」的時候。此時願不願意跳下來解決問題,就不是敏不敏捷的問題,而是心態的問題了。

        ***

        故事二

        某PO質問Teddy:「為什麼你跟團隊成員說retrospective沒用?」聽到這樣的質問,Teddy也是滿頭黑人問號???

        細問之下,原來是Teddy和團隊成員聊天時提到:

        如果retrospective會議沒有訂定具體的改善執行計畫(action plan),或是改善計畫都沒有落實,相同的問題便會一再出現,導致每次retrospective都討論一樣的議題。有迭代沒有增量,久了之後團隊就會覺得retrospective沒有用。

        不知道這位團隊成員是不是buffer不夠,只擷取到「retrospective沒有用」這幾個字。也未免斷章取義的太厲害了一點吧。

        ***

        問題是自己狀況的投射

        相信很多人都有這樣的經驗,聽了一場演講,或是經過一次對話,腦袋中留下來最深刻的只有「與自己現況不滿相關的記憶」。因為這些不滿的力量非常強大,強大到足以「扭曲力場」,把別人的意思曲解成自己的內心獨白,然後採用「借刀殺人」的手段,將自己一直想說卻不敢說出口的話,假借「別人的名義」說出來。

        這種斷章取義、扭曲本意、沒有脈絡(context)的引用,並非全無意義。它往往透露出講話者內心真正的感受,只不過平常不敢說出來罷了。

        為什麼敏捷開發的始祖XP要提「勇敢」?因為太多人不敢面對自己,不敢正視問題。真、善、美,只有真誠的表達自己的感受,改善才有可能發生。只有改善發生,才有可能逐步趨近完美。

        ***

        友藏內心獨白:Teddy有說多讀書你怎麼都沒聽進去?!

        2019年5月24日 星期五

        一個Scrum各自表述

        May 24 00:40~01:27

        ▲每個component team都在跑Scrum,啊不就好棒棒…Orz


        沒事不要找Teddy聊天XD

        去年在某個演講場合,演講結束後某位鄉民找Teddy聊天….

        鄉民:Teddy你好,我是你部落格的忠實讀者。

        Teddy:你好、你好,謝謝捧場。

        Teddy:你看我的部落格,是因為你們有跑Scrum嗎?

        鄉民:對,我在用戶研究團隊跑Scrum。

        Teddy:喔……用戶研究團隊跑Scrum…..這麼神奇。這是什麼意思?

        鄉民:就是我們團隊會在專案開始前期用迭代、增量的方式,跑幾個sprint產出用戶研究報告。

        Teddy:然後把產出的報告交給開發團隊去實作?

        鄉民:對。

        Teddy:怎麼我聽起來好像是瀑布式開發?

        鄉民:不是、不是,我們是跑Scrum。

        Teddy:你們做出用戶研究報告交給開發團隊之後,需求都不會改變嗎?

        鄉民:會啊。

        Teddy:那之前花時間所做的用戶研究報告需要重做嗎?

        鄉民:這……….

        Teddy:你們就是waterfall啊。

        鄉民:我們是Scrum啦……至少在公司內我們要說我們在跑Scrum。

        Teddy:那你們當初為什麼想「跑Scrum」?

        鄉民:因為總經理下令說要跑Scrum。

        Teddy:喔,對、對。幾個月前我有看過你們公司發的新聞稿,說你們Scrum跑得很成功。


        ▲有功大家練,有敏大家捷。

        ***

        高興就好

        ▲圖片來源在此


        陳近南:反清復明 敏捷只不過是個口號,跟阿彌陀佛其實是一樣的。Waterfall一直欺壓我們公司,浪費我們的銀兩,所以我們要反Waterfall!

        韋小寶:要反Waterfall搶回我們的錢,是不是?說來說去敏不敏捷根本就是脫褲子放屁!關人鳥事呀?行了,大家聰明人,了解!繼續!

        陳近南:嗯。總之,如果成功的話,就有無數的銀兩,你願不願意去呀?

        韋小寶:願意~!只不過你剛剛那句九死一生太嚇人了。

        ***

        友藏內心獨白:敏捷就是專案出得去,錢進得來,公司發大財XD。


        2019年5月20日 星期一

        2019 iMac 27吋開箱

        May 20 20:58~22:31


        Teddy手邊2016年購買的MBP 15”用了兩年半,已略顯老態。平常上網、文書處理是沒什麼問題,但只要同時開啟Parallels與IntelliJ,加上數十個分頁的Chrome,整台電腦跑起來就會有點卡卡的。

        今年決定不要再買筆電,改買桌機。本來考慮iMac或是Mac Pro,但Mac Pro遲遲未上市,最近寫程式的頻率比較高,等不及Mac Pro決定先買2019年iMac。


        ▼美國今年三月就上市,台灣等到五月七日才開放訂購。這次狠下心來攻頂,購買最高階i9版本。


        ▼記憶體選擇最基本的8GB,自己另外購買4條OWC 32GB RAM,擴充為128GB。


        上禮拜六(5/18)11點多iMac送到家裡,但我人卻在台南。隔天下午回台北後,趕緊開箱。


        ▼打開後包裝很簡潔。


        ▼把螢幕撲倒準備加裝記憶體,後來發現其實螢幕立著也可以裝記憶體,不用撲倒。


        ▼連接電源線的位置有一個按鈕,用十字起子用尖尖的東西刺一下,記憶體被蓋就會彈出。


        ▼兩條內建的4GB記憶體。


        ▼鍵盤、滑鼠、觸控板。原本考慮是否要買附數字鍵的鍵盤,但顧及桌面空間,以及之前已經用了六年多的無數字鍵的鍵盤也還算習慣,最後還是選擇無數字鍵鍵盤。這一代的鍵盤、滑鼠、觸控板都內建鋰電池,可以直接充電,方便很多。


        ▼開機後開始設定。


        ▼2019 iMac 27” 可以安裝128GB記憶體,Apple Store最多只可客制到64GB,而且價格比自己到外面購買要貴一倍。如果需要擴充記憶體,還是自己動手比較省錢。


        ▼因為經常需要使用Windows,此次特別買了專業版的Parallels,可以設定比較大的記憶體給VM使用。

        ***

        剛拿到iMac兩天,目前只有一個問題,就是iMac不能調高低,Teddy覺得iMac螢幕高度太高,和以前使用的螢幕高度比較來脖子要稍微抬高,有點不舒服。

        桌機的速度還是比筆電快很多,價格也比較便宜。像Teddy這種使用習慣,應該老早買桌機才對。只要搭配一台輕巧、長效的Windows筆電外出使用即可。

        ***

        友藏內心獨白:爽度破表XDD。

        2019年5月14日 星期二

        三小故事之這不是多型,什麼才是多型

        April 14 09:55~10:33

        ▲貓也是多型的生物


        多型的定義

        一個訊息的含義,是由訊息接收者所決定,不是由訊息發出者所決定。

        ***

        故事一

        幾年前有一個外商網通公司的HR找Teddy去他們公司擔任半年的Scrum Master。當時因為有顧問案在身,只能婉拒。

        HR退而求其次,希望Teddy幫他們介紹合適的人選。Teddy請對方提供徵人資格條件,看了之後Teddy委婉的說:「你們要求的標準很高啊!」。沒想到對方居然說:「對啊,我覺得好像在找聖人一樣。」

        這個故事Teddy講過好幾次,主要是要強調「好的ScrumMaster難尋」。沒想到有一次跟客戶講到這個故事,對方好幾個人居然異口同聲的說:「Teddy你是說你是聖人嗎!」

        冤枉啊,包大人。小的從來都沒這麼想。也許客戶是跟Teddy開玩笑,不過還真沒想到這個故事可以被這樣解讀啊。

        ***

        故事二

        好幾年前在一個介紹Scrum的演講中,休息時間有聽眾問Teddy…

        聽眾:在跑Scrum的時候怎麼設計軟體架構?

        Teddy:這個問題很多人都有疑惑,我以前去上Bas的CSM課程也問過她同樣的問題。我問他,跑RUP會建議在elaboration階段產生architecture baseline,跑Scrum要怎麼設計軟體架構?

        聽眾:他怎麼說?

        Teddy:他反問我…什麼是architecture baseline?

        聽眾:你是說Bas不懂軟體架構?

        Teddy:不是啦,我是說,Scrum根本不管這些,跑敏捷的人會告訴你,軟體架構是長出來的,不是事先設計出來的。該怎麼長就怎麼長,你自己慢慢長吧你XD。

        怎麼會解讀成Bas不懂軟體架構哩…

        ***

        故事三

        有一次在 C C Agile介紹TDD/BDD/SBE,Teddy提到…

        很多TDD的例子,都有兩個特色。第一,domain model很簡單,只有1~2個類別。其次,都有非常清楚的商業邏輯, 這樣子學習者才可以在很短的時間內體驗TDD。例如,保齡球計分、網球記分、電子商務系統結帳計價、郵寄系統。

        但是,回家之後發現,自己手邊的案子,domain model都很複雜,商業邏輯不太清楚,所以都D不太出來。

        結果回家後,有鄉民又私下問Teddy…

        鄉民:Teddy你剛剛是在暗指XXX的TDD例子都太簡單對不對?

        Teddy:XXX?你說Uncle Bob嗎?我又沒上過他的課怎麼會知道他的例子長什麼樣子。

        Teddy:我只是想指出,快速學習TDD所用的例子,和實際工作上會遇到的專案,有一些距離。而這些距離需要被克服才可以落實TDD,你想到那裏去了。

        鄉民:!#!@$%

        ***

        結論

        年輕的時候,很怕被「誤會」。只要覺得別人誤解自己,就好像受到天大的冤屈,恨不得找包大人來主持公道。從某種角度看,這是一種沒有自信、缺少歸屬感的表現。

        幾年前讀了幾本哲學、禪的書,越發體會Quality Without A Name 的道理。反正不管是真話、假話都無法驗證,那就不用管那麼多,全心專注在 Quality 上面。用自己的生命去展現這個 Quality,然後只要加強被討厭的勇氣就好了 XD。

        ***

        友藏內心獨白:你今天被討厭了嗎XD。