l
顯示具有 Patterns 標籤的文章。 顯示所有文章
顯示具有 Patterns 標籤的文章。 顯示所有文章

2022年3月21日 星期一

物件聚合與類別繼承的取捨

March 21 15:16~16:14



不是說好要少用繼承嗎?

昨天上「Design Patterns這樣學就會了–入門實作班」,講完Template Method設計模式之後Teddy問學員:「GoF不是說Favor object composition over class inheritance,但Template Method卻使用class inheritance,為什麼?你們能不能用object composition 達到Template Method的效果?

 

圖1是Teddy上課時設計的Template Method範例,鄉民們一起想想看,如何用object composition來取代Template Method。



▲圖1:Template Method類別圖

***

不使用繼承的設計

圖2是使用object composition取代class inheritance的設計,原本Template Method所呼叫的primitive operations或是hook operations改呼叫實作Operation的具體類別,請參考圖3程式碼。

 

▲圖2:用object composition取代class inheritance (套用Command設計模式取代Template Method)

 

▲圖3:圖2中的ConfigParser程式示意範例

 

***

哪種設計比較好?

如果只從Favor object composition over class inheritance的觀點來思考,圖2套用Command設計模式的設計比較好。但是,請數一下這兩個設計所需要的類別/介面數量:

  • Template Method:如圖1所示需要3個類別:
  • Command:參考圖3,ConfigParser與Operation這兩個是固定的,要分別支援從檔案與資料庫讀取設定資料,所以需要兩種DataSource實作,因此最少需要 1 + 1 + 2 + 4 = 8個類別/介面。

 

從Kent Beck的建單設計(Simple Design)原則來看:

  1. Passes the Tests
  2. Reveals Intention
  3. No Duplication
  4. Fewest Elements

第4條:最少元素,達到相同的功能,在這個例子裏面Template Method(class inheritance)用了3個「元素」,而Command(object composition)則用了至少8個「元素」,因此在這裡用Template Method的設計應該是比較簡單的設計。

***

友藏內心獨白:繼承不是不能用。

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就是一個例子。

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

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

***

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

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月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月2日 星期一

    你也可以撰寫模式

    Dec. 02 09:53~10:55


    重複使用知識

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

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

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

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

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

    ***

    生活觀察家

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

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

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

    ***

    模式範例

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

    安排好的偷拍照片

    ▲圖片來源在此

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

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

    Forces:

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

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

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

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

    ***

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

    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年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年5月7日 星期二

    尋找第一個Pattern

    May 07 14:11~15:07


    很久以前有一次Teddy在某場合介紹Alexander的pattern languages,談到這個方法是一種「由上而下」的設計過程,透過一次套用一個pattern(one pattern at a time)的方式逐次展開,採用pattern為基礎的方式解決一個大問題。就好像人類使用「語言」解決問題一樣,Alexander把這種方法稱為pattern language。

    聽完演講之後有一個聽眾問我:「要如何選擇最上層的第一個pattern?」當下Teddy心裡覺得:「啊不就是你書讀得少,pattern認識沒幾個,所以才不知道要如何選擇第一個pattern。」

    事實上Teddy的想法並不完全正確,對方也許真的不熟pattern,但這個問題首要的重點不在於對方懂多少個pattern,而是「最上層的第一個pattern,就是你要解決的那個大問題,也就是你想要達到的目標 (goal)」。


    ***

    設計模式的例子

     

    ▲Mediator範例


    上周末在上【Design Patterns這樣學就會了:進階實作班】,討論到Mediator模式的時候有學員問…

    學員:如果Mediator的coordinating logic太複雜,我是不是可以把 Mediator + Strategy或是Mediator + Command混和一起使用?

    Teddy:你先不要把問題複雜化,想著把A模式加B模式結合起來的可能性。「理論上」很多模式可以被「一起使用」,但如果只從解決方案來看設計模式,你會有太多排列組合都可以達到「相同功能」。這樣子學習者會無所適從,不知道怎麼套用pattern解決設計問題才合適,很容易變成為了套pattern而套pattern,變成過度設計(over design)。

    Teddy:你要先問自己「目前你首要想解決的設計問題是什麼?」以Mediator的例子來看,因為你想拿掉Colleague與Colleague之間多對多的相依性,所以找一個中間人來負責協調與溝通。此時此刻,根本還沒有「Mediator的coordinating logic太複雜」的問題,所以不需要討論Mediator + Strategy或是Mediator + Command的可能性。

    Teddy:當你套了第一個Mediator pattern,過了一段時間後,你發現coordinating logic太複雜。這個複雜性已經強大到讓你修改coordinating logic變得很困難,你的軟體慢慢變成了硬體。此時,你再來考慮要採取什麼方式來對付這個force。

    一次一個pattern,第一個pattern解決你目前首要凸顯出來的問題。套完第一個pattern之後,如果沒有其他未被處理問題,那就沒事了。如果還有(例如Mediator的coordinating logic變得太複雜),你再進一步思考要如何解決。

    ***

    道理很簡單但你不一定能活用

    幾年前有一次到客戶端幫忙看Scrum團隊運作情況,客戶覺得他們跑的卡卡的,劈哩啪啦跟Teddy描述一大堆「可疑現象」。經過Teddy實地觀察之後,發現問題的確並不單純。

    要從何開始著手?如果用pattern解題的方式來思考,要先套用哪一個pattern?

    Teddy發現客戶的Scrum團隊最大的問題就是他們並不是真正的跨職能團隊(cross-functional team),團隊成員主要都是程式設計師,沒有測試專長的人,也沒有UI/UX的人。上游(UI/UX)的步調搭不上下游開發團隊的步調。經常發生UI/UX自己覺得效率很好,但他們完成的工作,開發團隊可能好幾個sprint之後才會用到,甚至也有完全沒用到的時候,最後直接丟到「垃圾桶」。

    伴隨著這個根本原因,團隊產生了很多病症,必且試圖用各種有創意的方式來延緩這些病症,但都無法長期維持下去。

    其實這個問題很簡單,先讓自己笨一點,既然是跑Scrum,為什麼不直接聽Scrum的話,組織一個真正的cross-functional team,先傻傻套用這個pattern「試看看」。套用之後,跑一陣子,如果有其他的問題浮現,再思考要如何解決。例如,之後可能發現需求管理很困難,團隊對於產品願景與sprint目標不明確,此時再討論嘗試套用impact mapping與user story mapping的可能性,才顯得有其意義。

    ***

    友藏內心獨白:這麼簡單的道理居然這麼久才想通啊。

    2019年2月1日 星期五

    繞過去,好嗎?

    Jan. 31 23:07~23:58

    ▲逢山開路,遇水搭橋


    問題

    從去年開始Teddy和指導教授一起帶幾個實驗室學生做研究,目前遵循clean architecture的方法正在開發看板軟體。一個多禮拜前學生問Teddy關於Repository的介面設計,經過討論後Teddy請他們做點研究,下次開會再談。

    今天回學校和學生開sprint review會議,順便請學生說明他們研究Repository的結果。學生告訴Teddy他們發現有兩種Repository的設計方法,第一種是接受由外部給定的specification當作查詢條件,可以比較有彈性的支援多種查詢條件。第二種是在Repository介面上設計常見的方法,例如findAll、findById、findChildrenById等。

    學生採用第二種設計方法,聽了請他們選擇的理由後,Teddy還是覺得不滿意(forces沒有被平衡XD)。於是請學生把domain model叫出來,一起讀過一次,發現他們所採用的Repository介面設計無法支援domain model的所有物件。

    ***

    程式可以動啊

    學生寫的程式可以動,這個sprint所完成的user story還算做得不錯。但是,如果細看軟體設計,其實還有不少可精進之處。

    Teddy告訴他們:

    Repository的問題還沒徹底解決,雖然程式可以動,但是如果不管這個設計問題,繞過去,以後你們還是有很大的機會會再遇到它。你們是研究生,專案中遇到問題應該利用機會把問題搞懂,徹底解決。日後遇到同樣的問題,既使context不同,別人花三天,你們只要花一小時就可以解決。層次與專業就是這樣累積出來的。

    這個問題,最好的解決方式就是你們搞懂後做出設計的決定,然後說服我(教我)。次一等的解決方式,就是我弄懂後教你們。最糟的方式就是不管它,反正程式可以動就好。

    ***

    Repository Pattern

    因為Google太方便,所以學生遇到問題尋找資料,大多下個查詢條件,然後看最前面的幾個連結之後就做出結論,草草結束。Teddy在〈增進學習力的三個練習〉提到,首先要知道名詞的定義。學生只知道可以套用Repository pattern,但很可能對於該pattern的定義只是一知半解。

    在《Patterns of Enterprise Application Architecture》的第322頁就介紹Repository pattern。在《Domain-Driven Design: Tacking Complexity in the Heart of Software》以及《Implementing Domain-Driven Design》也都有提到,後者並且包含範例程式碼與實作細節。

    ***

    龜毛

    大家都說日本人做事很龜毛。同樣的商品,例如Toyota汽車,MIT和MIJ,相信大部分的人還是比較喜歡日本原裝進口。為什麼?因為組裝的人不一樣啊…Orz

    軟體開發是一種專業,就好像醫生也是一種專業。你總不希望醫生開刀的時候遇到問題「繞過去」吧?!反正 程式可以動 人還有呼吸就好XD。 

    ***

    友藏內心獨白:書還是要讀,不能只看網路文章。

    2018年1月5日 星期五

    【敏捷小酒館】第八夜:如何學好設計模式?

    December 05 17:00~

    image

    ▲練習看看上面這段程式中有那些forces沒有被平衡?


    Erica找Teddy一月份到台中【敏捷小酒館】分享,原本想把「達摩祖師」拿出來重複使用,介紹導致軟體社群開始使用Patterns的歷史緣由,以及Patterns的起源—《The Timeless Way of Building》這本武功祕笈的最高心法。

    但Erica覺得Teddy第一次來【敏捷小酒館】就下這麼猛的藥,怕鄉民們一下子承受不住,所以準備另一個比較通俗且具體的題目:【敏捷小酒館】第八夜:如何學好設計模式?


    ▼達摩祖師此次無緣上場XD(畫面節錄自電影達摩祖師傳)

    image

    ***

    GoF的《Design Patterns》設計模式這本書已經出版22年,多年來設計模式廣泛地應用在軟體開發的所有活動,從需求、分析、設計、實作、測試到流程,都有模式可遵循。

    對許多開發人員而言,學習模式就好像背英文單字一樣,並不是一件輕鬆且容易駕馭的活動。就算好不容易學會某些模式,也經常發生誤用模式過度設計的問題。

    實務上使用模式還有另一個問題,就是團隊中只有你自己會沒有用,要其他團隊成員也要懂、願意使用才能發揮模式的效果。Teddy聽過好幾個類似的情況:公司同事出差,某人把該同事原本寫的程式改成套用設計模式,結果同事回來之後就森七七了。「我的程式可以正常執行你沒事幹嘛亂改?你改成這樣這麼複雜反而看不懂,我以後要怎麼維護。」

    最後,同事還是把程式碼改回原本的寫法,徹底落實小瑛總統所說的「維持現狀」

    ***

    Teddy在本次敏捷小酒館將分享學習設計模式的經驗,希望可以減少鄉民們學習設計模式的門檻,並且可以知道何時該用,何時不該用設計模式。

    迷之音:桌上的核武按鈕不可以隨便按。

    ***

    友藏內心獨白:下次再恭請達摩祖師上場。

    2017年9月8日 星期五

    《設計模式的逆襲》第N度復活:Composite

    September 08 19:05~19:15

    螢幕截圖 2017-09-08 18.18.07

    Composite(組合)設計模式表達部分-整體的樹狀階層式結構,讓客戶端對於單一元素與聚合元素一視同仁,例如檔案-目錄、員工-組織。

    寫Composite花了五天,實際工作天兩天,檔案在此請服用。

    一併提供之前完成的十個模式:

    ***

    友藏內心獨白:Lead Time騙不了人。

    2017年8月31日 星期四

    《設計模式的逆襲》第N度復活:State

    August 31 22:10~22:25

    螢幕截圖 2017-08-31 14.16.30


    明後天要上「Scrum敏捷方法實作班」沒辦法寫書,今天加個班寫完State(狀態)設計模式。

    「當物件內部狀態改變的時候允許它改變行為,使得該物件好像變成另一個類別。」如果你的物件有狀態有如此巨大的改變,就是套用State模式的好時機。例如自動販賣機會因為投幣金額與販賣產品的數量,導致面板上的按鈕有著不同的行為。

    套用State模式讓狀態轉換變得很清楚,搭配狀態圖可以讓測試變得很簡單。這次趕工從早到晚花了1整天完成,檔案在此請服用。

    一併提供之前完成的九個模式:

    ***

    友藏內心獨白:程式碼多,慎入。

    2017年8月30日 星期三

    《設計模式的逆襲》第N度復活:Strategy

    August 30 15:30~15:51

    螢幕截圖 2017-08-30 09.54.12


    Strategy(策略)設計模式讓同一種行為擁有多種不同的實作方法,透過抽象耦合的方式來使用這些實作方法。例如,一個壓縮檔案物件,可以採用zip、arj、rar、tar、7z等不同的演算法來執行壓縮工作。

    這個模式是繼承的替代方案,讓類別不透過繼承也可以達到動態改變行為的目的。Strategy簡單易懂,花了1天就寫完了,檔案在此請服用。

    一併提供之前完成的八個模式:

    ***

    友藏內心獨白:詭計多端。

    2017年8月29日 星期二

    《設計模式的逆襲》第N度復活:Template Method

    August 29 14:25~14:33

    螢幕截圖 2017-08-29 17.51.03


    Template Method(模板方法、範本方法)設計模式定義一個固定的演算法,讓子類別覆寫演算法中的步驟以提供擴充性。

    這個模式使用物件導向技術最基本的繼承,但是一種有紀律的使用繼承,符合窄繼承介面原則。花了2天寫完,檔案在此請服用。

    一併提供之前完成的七個模式:

    ***

    友藏內心獨白:天氣這麼熱賣冰應該比賣pattern要好賺。

    2017年8月25日 星期五

    《設計模式的逆襲》第N度復活:Facade

    August 25 16:12~16:29

    螢幕截圖 2017-08-24 13.46.37


    Facade(外觀、門面)設計模式提供一個統一且容易使用的介面來操作子系統,並減少客戶端和子系統的耦合度。例如,電視機控制面板或遙控器、多功能事務機、編譯器,都提供一個統一介面讓使用者容易操作子系統。

    這個模式比較簡單,在概念上很容易理解,花了1天就寫好了。檔案在此請服用。

    一併提供之前完成的六個模式:

    ***

    友藏內心獨白:寫作還是要心無旁鶩。

    2017年8月24日 星期四

    《設計模式的逆襲》第N度復活:Abstract Factory

    August 24 11:10~11:34

    螢幕截圖 2017-08-21 15.38.50


    Abstract Factory(抽象工廠)是Factory Method(工廠方法)的拓展,當你需要產生同一系列(家族)的不同種類產品的時候,它就可以派上用場。

    例如,你需要產生圖形介面元件,像是視窗、按鈕、文字框等,而這些產品類別有Windows、macOS與Linux平台不同實作。你可以把createWindow、createButton、createTextField等工廠方法集中在一個抽象類別(AbstractFactory)身上,讓它的子類別決定如何產生具體產品物件。如果上次的Factory Method有學會,就會覺得Abstract Factory很簡單。

    這幾天雜事纏身,花了4天才「煮好」Abstract Factory,檔案在此請享用。

    一併提供之前完成的五個模式:

    ***

    友藏內心獨白:找東西好累,找了老半天又找不到,更累…Orz。

    2017年8月18日 星期五

    《設計模式的逆襲》第N度復活:Factory Method

    August 18 13:48~14:00

    螢幕截圖 2017-08-18 13.49.51


    打個廣告先,第十七梯次「Design Patterns這樣學就會了:入門實作班」招生中,上課日為9月16、17、23(六、日、六)。課程提供Java與C#程式範例。

    ***

    Factory Method(工廠方法)是一個很常用也很簡單的設計模式,不過因為它有幾種變形,每個人對於這些變形的稱呼又不一定相同,所以還是經常會造成溝通上的誤會。

    Teddy參考《Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing》書中的分類,把Factory Method分成三種:

    • Simple Factory Method:一個封裝產生具體類別過程的函數,又稱為Simple Factory。
    • Polymorphic Factory Method:GOF書中的Factory Method模式屬於這種類型,在父類別中定義產生物件的介面,讓子類別覆寫此介面以決定產生哪種具體類別。
    • Class Factory Method:又稱為Static Factory,類別靜態函數,用來產生自己或其他型別的實例。

    但實際上有許多人將Simple Factory Method和Class Factory Method視為同一類,都稱為Simple Factory,也有人乾脆不分,直接統稱Factory模式。鄉民們在閱讀其他資料的時候請注意用詞不同的差異。

    這次花了2.5天生產出Factory Method模式,檔案在此請安心服用。

    一併提供之前完成的四個模式:

    ***

    友藏內心獨白:看似簡單還是有一點小門道。

    2017年8月10日 星期四

    《設計模式的逆襲》第N度復活:Observer

    August 10 12:00~12:59

    螢幕截圖 2017-08-09 10.37.34


    前幾天家裡有點事情在忙,有幾天都沒動 手寫書。後來不知道哪根筋不對勁,花了2天時間整理家裡。整理完畢之後突然覺得書房好亂,一堆書堆在地上,於是上網找看看有沒有類似圖書館的還書車,可以把常用的書放在上面。

    ▼很幸運地找到一台大小適中價格也可以接受的公事車,解決了困擾Teddy多年的問題。

    螢幕截圖 2017-08-08 13.09.22


    ▼解決了書堆在地上的問題之後又覺得工作桌面太小,於是順便買了一台折疊式小餐車(照片左方)。電腦螢幕支援虛擬桌面,真實世界則需要實體桌面XD。

    螢幕截圖 2017-08-10 12.35.49


    ▼兩台車擺在一起,有輪子真的很重要。

    螢幕截圖 2017-08-10 12.40.01

    ***

    工作環境升級之後回頭繼續寫書,選一個之前整理過的Observer(觀察者)模式,這次比較快只花了兩整天就寫好了,檔案在此歡迎批評指教。

    一併提供之前完成的三個模式:

    ***

    ▼偷渡兩張小朋友睡覺的照片。

    螢幕截圖 2017-08-10 12.53.20

    螢幕截圖 2017-08-10 12.50.49

    ***

    友藏內心獨白:還有什麼東西可以買的XD。

    2017年8月3日 星期四

    《設計模式的逆襲》第N度復活:Command

    August 03 12:37~13:06

    螢幕截圖 2017-08-02 08.15.08


    打個廣告,第十七梯次「Design Patterns這樣學就會了:入門實作班」招生中,上課日為9月16、17、23(六、日、六)。課程提供Java與C#程式範例。

    ***

    Kay常說Teddy做事情「開機很慢」,可是一旦開機之後做事情動作就很快。其實也不是Teddy喜歡拖,只是想把事情做好有很多事前工作需要準備。尤其是寫書、製作教材這種事,不認真做變成「誤人子弟」這個罪名可是擔當不起。

    有些事情可以很敏捷、很靈活,小步 亂跑 快跑,收集回饋。有些事情則需要好好規劃,收集資料,醞釀、等待時機。

    希望這次「開機」可以維持久一點,以四天完成一個pattern的進度估算,23 * 4 = 92,加上「一例一休」,順利寫完GoF 23個設計模式大約需要4個月的時間,也就是年底。

    今天完成第三個模式:Command,檔案在此歡迎批評指教。

    一併提供之前已完成的兩個模式:

    ***

    友藏內心獨白:三個分類先各寫一個。