l

2018年8月20日 星期一

薩提爾變革模型

August 20 21:29~22:28

螢幕截圖 2018-08-20 21.14.43

▲薩提爾變革模型,節錄自《溫伯格的軟體管理學:第四卷》 p.67


薩提爾變革模型

這兩年台灣談敏捷(Agile)的人與組織越來越多,嘴砲派、實務派、反對派、隕石派、佛系派等紛紛崛起。從狹義的軟體開發,到廣義的食、衣、住、行、育、樂,似乎萬事皆可敏捷。

談敏捷,就不能不談改變。敏捷談的是靈活性,如何在不斷改變的環境中獲得成功。無論是個人還是組織,要增強對改變的適應性,就不得不回應改變,也就是自己也要持續改變。

改變所帶來的成長總是伴隨著痛苦,因此變革失敗的例子不勝枚舉。在《溫伯格的軟體管理學:第四卷》中,介紹「薩提爾變革模型」,可以運用這個模型來分析變革應採取的行動。

「薩提爾變革模型」指出發生變革的四個階段:

  • 近期現狀階段(舊有現狀):個人或組織的現況,通常表示某種穩定與平衡的成功狀態,大家都熟悉現有的做法。

組織會一直停留在這個階段,一直到「有人」攪亂一池春水,才會打破現有的平衡。這個「有人」,通常是外來事件或外部人員,並不在系統控制者的控制範圍內。例如,外部顧問的加入、重要成員離職、競爭對手發布比我們更好的產品。

  • 混亂階段:既使組織想要推遲改變,但最終因為無法逃避的外部因素,導致只好承認現況無法應付未來的挑戰。之後系統進入混亂階段,原本熟悉的工作模式與方法不再適用,但新的做法卻還未被確定。在此階段人們嘗試各種可能性,甚至走回頭路尋找更早期的成功模式。
  • 整合與實踐階段:經過一段兵荒馬亂的時期,有些新的構想與方法存活下來,似乎可以應付新的挑戰。但組織還不確定,需要更多的實踐與改造,才能讓組織有效適應新的方法,提高組織的績效。
  • 新現狀階段:整合與實踐階段成功便進入新現狀階段,組織重新獲得平衡,不熟悉的工作模式變得熟悉。

***

有什麼用

這個模型告訴我們幾件有趣的事:

  • 牛頓運動定律說:「靜者恆靜,動者恆動」。組織停留在近期現狀階段的力量往往非常強大,由組織內部自發性所引發的變革往往十分困難。因為組織與個人會不斷地否定問題,迴避改變的必要性,這也就是薩提爾所說的熟悉總是比舒適更有力量。畢竟,待在舒適圈的力量真的太強,只要舒適圈依然存在,又何必做出改變呢。所以,要讓組織脫離舊有現狀,經常需要藉由外部力量來推動。
  • 當外部力量介入,組織正在嘗試找出新的工作模式時,此時的混亂階段不宜帶入更進一步的改變,否則組織將會因為無法接受過多的改變,因而放棄走回原本的老路子。例如,組織想要導入Scrum,在團隊剛開始接觸Scrum的前3~6個月內,已經被敏捷精神與Scrum框架搞得一個頭兩個大,此時若持續導入新的工程技術,例如TDD,可能使得團隊無法負擔,最後決定還是用原本的開發方式比較「有效率」。
  • 在整合與實踐後期導入新的變革會比在新現狀才導入要來得好,因為到了新現狀之後,不久新現狀就會變成組織的舊有現狀,此時引入變革的阻力又多了起來。

***

結論

鄉民們可以試著幫自己學習新事物或組織引入新方法的過程對應到薩提爾變革模型,看看目前處在什麼階段。如果一直處在舊有現況,是不是需要帶來一些外部衝擊,就算目前組織現況是「一攤死水」,好歹也可以引起一些漣漪。

有些人很喜歡到處上課,有活動就參加,不吝惜投資自己。但會不會讓自己一直處在混亂階段,而沒有時間去沉澱與實踐所學的技能?

這些都是值得思考的議題。

***

友藏內心獨白:變革需要時間,就跟自己開發瀏覽器一樣。

2018年8月15日 星期三

為了快,你損失了什麼?

August 15 14:33~16:14

螢幕截圖 2018-08-15 16.15.02


問題

三不五時會聽到來自不同公司的朋友提起他們sprint planning meeting的進行方式…

在會議進行的時候,我們分別請UX/UI設計師與程式設計師分組估算他們各自擅長的工作,以便減少會議的時間。反正雙方人馬都不懂對方的工作性質與內容,一起討論實在是很沒效率。

這樣子做,好嗎?

***

緬懷大師

2018年8月7日,也就是一個禮拜前,軟體工程界大師Gerald M. Weinberg(傑拉爾德‧溫伯格)以85歲高齡過世。溫伯格一生寫了很多書,以生活化、輕鬆且風趣的筆法說明艱澀無趣的軟體工程觀念與方法。他的過世,著實是軟體工程界的一大損失。

在溫伯格與Donald C. Gause合寫的《Exploring Requirements: Quality Before Design》(中文版《從需求到設計:如何設計出客戶想要的產品》)書中提到:

發現什麼不重要,重要的是發現(探索)的過程…探索需求的工作事實上就是建立一個團隊。

沒錯,探索需求的工作事實上就是建立一個團隊。只為了「快」就將Scrum團隊依據「專長」畫分成小組,讓小組各自討論得出估算值。這種做法只比讓專案經理或團隊主管一人制定時程要來得好一點,但卻失去了Scrum建議組成跨職能團隊(cross-functional team)的目的,變成「跨職能團隊中的元件小組(component group)」。

***

大師開示

在溫伯格的書中接著提到,若以下任一條件不符合,專案就很可能失敗:

  1. 了解需求要件
  2. (大多數都)貫徹始終參與專案
  3. 知道如何使團隊有效運作

Exploring Requirements: Quality Before Design》這本書是1989年出版,距今29年前,相信那時候Scrum應該還沒有正式誕生。有跑過Scrum經驗的朋友請回顧一下,這三點是否也都包含在Scrum之中呢?

***


友藏內心獨白:不需要做的事情,就不需要把它做好。

2018年8月10日 星期五

【敏捷開發懶人包:Clean Architecture嘴砲班】九月平日班首發團招生中

August 10 14:00~15:20

螢幕截圖 2018-08-10 15.19.07


2018年最新課程

俗話說「水清無魚、嘴賤無敵」,誰說嘴砲不能當一位好工程師?!對於身為技術主管或有志成為技術主管的你,沒時間寫code卻不能不跟上最新軟體架構潮流。

你的需求Teddy看到了,經由Teddy濃縮再濃縮、提煉再提煉的【Clean Architecture嘴砲班】,最適合沒時間深入瞭解的你。由Teddy為你展示Clean Architecture的日月精華,再一起透過最後的精選Clean Architecture專案設計與程式碼評論練習,帶你邁向說得一口好程式的主管行列XD。

***

課程大綱。

  • 軟體架構的定義與目的。
  • 從範例學整潔架構。
  • 整潔架構三原則:
    • 首部曲:分層原則。
    • 二部曲:相依性原則。
    • 三部曲:跨層原則。
  • 邁向Clean Architecture。
  • 嘴砲實戰練習:
    • 精選數個網路上實作Clean Architecture之範例專案,讓學員實際練習評論這些專案的架構設計。
    • 實作細節討論。
  • 回顧。

***

課程效益

  • 一日之內掌握《Clean Architecture》(中文版《整潔的軟體設計與架構》)這本書的重點,讓別人誤以為你已經看完了整本書  為日後深入學習奠定基礎。
  • 了解架構審視(architecture review)所需關注的焦點。
  • 應用分層原則、相依性原則、跨層原則於自己的軟體開發專案中。
  • 透過多個clean architecture 專案的architecture review與code review實際演練,強化嘴砲 架構分析能力,

***

課程費用

  • 原價NT$11,000元。
  • 首發團早鳥優惠: NT$8,900(2018年8月22日前報名並完成繳費)
  • 首發團2人團報,每人只需:NT$7,900。

地點:台北市(近台北車站)。上課日2018年9月4日(週二) 09:30-16:30,共六小時 。

image

***

友藏內心獨白:意圖使人家覺得自己好棒棒。

***

相關文章閱讀

2018年7月27日 星期五

阿嬤覺得你冷

July 27 10:09~11:11

螢幕截圖 2018-07-27 11.10.19

▲有一種趕,叫做司機覺得你趕


前言

有一種冷,叫做阿嬤覺得你冷。有一種敏捷,叫做長官腦中的敏捷。

***

故事一

去年年中有一位學員跟Teddy分享他們跑Scrum的經驗…

學員:我們跑Scrum已經一年了,我對團隊的表現很滿意。

Teddy:喔,怎麼說?

學員:因為我們團隊的產能很穩定,可預測性很高。

Teddy:你們是有經驗的Scrum團隊嗎?

學員:不是,我們一年前才剛開始接觸Scrum。

Teddy:所以你們新的Scrum團隊在這一年中的產能可預測性都很高?!

學員:對啊,這一年來,團隊的velocity都是50個story points,只有一個sprint稍微低一點42個story points。

Teddy:你們需求都沒改變嗎?

學員:有啊,這就是我覺得Scrum好的地方,我們團隊可以很敏捷的擁抱改變又維持固定的產出。

學員:有了穩定的產出我們做release plan就很簡單,照著計劃完成進度中的工作,沒什麼大意外,對老闆與客戶都很好交代。

Teddy:這樣啊,你說你們在跑什麼,waterfall嗎?

學員:不是啦,是Scrum!

友藏內心獨白:啊不就好棒棒。

***

後來經過側面了解,原來是他們公司大老闆在團隊跑Scrum之前曾經跟團隊精神喊話…

大老闆:我們團隊有五個人,一個sprint兩個禮拜,每個人每天做一點(1個story point)應該不過分吧?

從此之後大家的產出就變得很穩定了XD 。

***

故事二

幾年前有一位新創公司的老闆來上Teddy的Scrum課程,幾個月後在某個場合遇到他…

Teddy:上完課之後你們回去有開始試跑Scrum嗎?

老闆:有啊,而且成效很不錯。

Teddy:喔,怎麼說?

老闆:跑Scrum之後工程師都自願加班。

Teddy:啊,自願加班?!

老闆:對啊,以前專案時間是我估的,工程師抱怨說我估的時間太少,他們做不完,怪我逼他們加班。跑Scrum之後,時間都是團隊成員在sprint planning的時候估出來的。現在sprint結束之前user story做不完,團隊成員也沒話說,就會自願加班把沒做完的user story給做完。

Teddy:我上課沒這樣教吧?

老闆:是沒有,但是Scrum不是一種流程框架嗎,每個團隊可以依據不同狀況自行調整啊。我覺得我們現在這種調整很好。

友藏內心獨白:啊不就好棒棒。

***

結論

這1~2年「敏捷」在台灣突然有一種大爆發、大流行的趨勢,各種活動很多,有興趣的人也變多。

這種狀況,讓我想起電影達摩祖師傳中,達摩大師傳衣缽給慧可時對他說:「在我過世二百年後,衣缽傳至六祖,便不須再傳,因為在那個時候,禪宗法門已傳遍各地,不過,知道的人多而行道的人少,說理的人多而悟理的人少。」

不過達摩大師最後說:「你不可輕視執迷不悟的人,任何人在一念之差,都會棄惡從善。」這種毅力,應該只有得道高僧能做得到。

Teddy不是大師,只是工程師,離這個境界還差很遠。

***

友藏內心獨白:那個…那個誰,給我一根棍子先。

2018年7月6日 星期五

Clean Architecture(6):架構三原則三部曲—跨層原則

July 6 09:52~10:58

螢幕截圖 2018-07-06 10.58.15

▲直接跨層XD


前言

將軟體架構分層並且確認相依性嚴格遵守由外往內(由低層往高層)的這兩個原則之後,接下來會面臨到另一個問題:「物件跨層時該怎麼辦?」。

***

跨層範例

▼請參考下圖,AddHostController呼叫AddHost Use Case,它再呼叫Entity層的Host物件,並獲得一個Host物件。接著AddHost Use Case直接把Host物件往外傳給AddHostController。

螢幕截圖 2018-07-06 10.05.10


上面這個例子有兩件事情需要討論:

  • 內層物件可否跨層往外傳:舉例來說,位於Entity層的Host物件可以直接跨層(跨過Use Case層)傳給AddHostController嗎?依據相依性原則,上述情況還是有遵守「外層相依於內層」的規定,只不過AddHostController跨過Use Case這層相依於Entity層的Host物件。Teddy並未在《Clean Architecture》書中看到可否「跨層相依」的描述,而網路上國外鄉民所實作的範例,有些直接跨層相依,有些則是會將Host物件在AddHost Use Case轉過一次再傳給AddHostController(請參考稍後討論的Use Case雙向介面)。
  • 外層如何將資料傳給內層:假設AddHostController從瀏覽器收到使用者所填寫的「新增Host表單」,並將其內容轉成一個JSON物件。如果AddHostController直接將這個JSON物件傳給AddHost Use Case,將會破壞相依性原則,因為如此一來AddHost Use Case就相依於屬於應用程式框架的JSON物件。

▼直接把JSON從Controller往Use Case傳遞違反了相依性原則(假設JSON函式庫是由網頁應用程式框架所提供)

螢幕截圖 2018-07-06 10.29.56

***

定義雙向介面

▼如下圖所示,《Clean Architecture》書中建議Use Case需要定義「雙向介面」,簡單來說就是定義Use Case的Input與Output介面與參數的資料型態。

螢幕截圖 2018-07-06 10.32.55

Use Case本身提供Input介面與資料型別實作,外層的Controller要將參數傳給Use Case時,必須負責把參數型別轉成Use Case所定義的Input介面。

Use Case的Output介面則由Presenter所實作(Presenter是Model-View-Presenter設計模式裡面的那個Presenter),呼叫Use Case時Controller會傳入Presenter物件,Use Case則將透過Presenter物件輸出資料。


▼看一個程式範例片段,HostController的getHosts函數呼叫FetchHosts Use Case得到所有host的列表,它首先產生HostListPresenter物件與FetchHostsInput物件,並將它們傳給FetchHosts Use Case。FetchHosts Use Case從FetchHostsInput物件獲得搜尋物件的參數資料,並將找到的資料傳給HostListPresenter。

螢幕截圖 2018-07-06 10.40.21


▼FetchHostsUseCase介面定義

螢幕截圖 2018-07-06 10.45.04


▼FetchHostsInput類別。請注意,如果嚴格依據《Clean Architecture》書中的圖示,應該先將FetchHostsInput定義成一個介面,然後再讓FetchHostsUseCase提供這個介面的實作。在此Teddy偷懶簡化這個步驟,直接將FetchHostsInput設計成一個具體類別。

螢幕截圖 2018-07-06 10.45.49

▼FetchHostsOutput介面

螢幕截圖 2018-07-06 10.48.20


▼HostListPresenter

螢幕截圖 2018-07-06 10.49.15


▼FetchHostsUseCase實做

螢幕截圖 2018-07-06 10.52.54

***

結論

《Clean Architecture》整本書雖然有多達34章,如果可以掌握分層、相依性與跨層這三個重點,在實作Clean Architecture時應該就沒什麼困難之處。

***

友藏內心獨白:還有一個Missing Chapter沒討論…

2018年7月5日 星期四

Clean Architecture(5):架構三原則二部曲—相依性原則

July 5 16:17~17:23

螢幕截圖 2018-07-05 17.21.14


前言

軟體架構依據「距離I/O遠近」分層之後,接下來遇到一個問題:「如何管理各層之間的相依性?」。在《Clean Architecture》書中,把這個規則稱為相依性原則(Dependency Rule)。

***

低層相依於高層

《Clean Architecture》書中所定義的相依性原則只有如下的短短一句話:

Source code dependencies must point only inward, toward higher-level policies. (程式碼相依性必須只能往內,指向更高層級的策略。)


▼如下圖所示(圖片來源在此),內圈(較高層級)的元件不能知道(相依)任何外層的元件。也就是說,外層的函數、類別、變數或任何有名字的軟體實體,都不能出現在內層的元件之中。相依性只有一個方向,就是由外往內,由低層往高層。

CleanArchitecture

***

煩人的實作細節

相依性原則本身非常簡單,但實務上在系統中要完全落實此原則有許多細節要注意。

▼例如下圖中位於Entities層(最高層)的Host類別,依據相依性原則它不能相依於任何位於此層以外的「任何東西」。為了將Host物件儲存於資料庫中,Teddy使用了javax.persistence package裡面的annotation(@Entity、@Table、@EmbeddedId、@Column等)。

螢幕截圖 2018-07-05 16.34.14

雖然這些annotation是 Java Persistence API(JPA)標準的一部分,但它們的實作是由Hibernate所提供。嚴格來說,上面的程式違反了《Clean Architecture》的相依性原則。

如果不用annotation,也可以用XML檔案來註記,把對hibernate-jpa-2.1-api的相依性從原始碼中移除。但廣義的來講,雖然在原始碼中Host不直接相依於hibernate-jpa-2.1-api,但透過XML設定檔案還是間接的相依於hibernate-jpa-2.1-api,Teddy認為兩者效用實際上是差不多,只是把「顯性相依」轉成「隱性相依」,並沒有好到哪裡去,甚至更糟糕。

***

要完全把Host對hibernate-jpa-2.1-api的相依性拿掉,一個常見的作法是定義另一組針對持久化(Persistence )所需的物件,例如針對原本的Host物件的持久化需求另外定義一個HostEntity類別,如此一來原本Host類別中JPA annotation就可以移到HostEntity之中,然後再透過Hibernate把HostEntity直接存到資料庫。

但這種做法又衍生另其他問題,首先,必須另外撰寫物件負責把Host轉成HostEntity,以及把HostEntity轉成Host。這種物件稱之為Mapper

其次,HostEntity要擺在哪一層也是需要考慮一下,很顯然不會擺在Entities這一層。因為Repository通常被Use Case所使用,所以放在Use Cases層似乎很合理:當要儲存Host時,Use Case先產生或是獲得一個Host物件,然後呼叫Mapper把Host轉成HostEntity,在透過Repository將HostEntity存到資料庫。反之,要讀取Host時,Use Case透過Repository從資料庫讀取HostEntity,再把它轉成Host。

但是這麼做其實還是違反了相依性原則,因為Use Case相依於外部的hibernate-jpa-2.1-api。忙了大半天其實是白忙一場XD。

***

另一種作法是,不透過任何JPA annotation來簡化物件永久化的問題,只定義Repository介面,然後透過main元件注入Repository介面的實作。Repository介面的實作程式碼位於Interface Adapter層,也就是《Clean Architecture》架構圖裡面的Gateways。它再透過相依性注入的方式,獲得不同持久化框架的實作,如此一來便符合相依性原則。

但是,原本只要貼一貼annotation就可以把透過持久化框架(例如Hibernate)達到持久化的目的,現在為了嚴格遵守相依性原則,程式碼變得麻煩好多。這就是在實作上必須注意與取捨的地方。

***

結論

滿足相依性原則可以獲得兩大好處,首先,因為高層的物件不再相依於框架等低層的物件,所以測試碼可以單獨測試,大幅簡化測試的工作。

其次,系統的核心功能位於Entities與Use Cases這兩層(蛋黃區與蛋白區),要更換I/O或是應用程式框架「理論上」變得簡單很多。例如,如果要將Web-Based UI換成Android App,只需異動最外面兩層(Framework & Drivers與Interface Adapters),便可直接銜接原本的Use Cases與Entities。

***

友藏內心獨白:跟有潔癖的人住在一起家裡肯定很乾淨,但你可能會被對方煩死。

2018年7月4日 星期三

Clean Architecture(4):架構三原則首部曲—分層原則

July 3 14:38~15:58

螢幕截圖 2018-07-03 16.08.32


前言

《Clean Architecture》這本書一共有34章,全部讀完也是有點累。今天Teddy幫鄉民們整理一下重點,總地來講Teddy認為Clean Architecture有三個最重要的原則,將分三集逐一介紹這三個原則。今天先談「分層原則」。

***

階層式架構

軟體架構就是軟體的形狀(shape),而形狀是由多個元件及其互動所構成。這些元件通常會依據其功能加以分類,以便於管理、擴充與維護。


階層式架構就是一種很常見的分類方法,常見的階層式架構長成下面這樣 (詳細說明可參考https://goo.gl/Tjq75M):

螢幕截圖 2018-07-03 14.55.57


既然稱為階層式架構,一定有上、下層之分。請問上圖階層式架構中,誰是上層、誰是下層?

一般直覺的看法:Presentation Layer畫在架構的最上方,所以它是最上層,而Database Layer在最下方,所以它是最下層。這種解讀有一個問題,因為在階層式架構中,越上層的人(元件)通常擁有越核心的商業邏輯(business logic)。如果Presentation Layer是最上層,那豈不是代表它擁有最核心的商業邏輯?這也不對啊,因為大家都知道,儘量不要在Presentation Layer放置商業邏輯,因為那將使系統擴充、維護與測試變得更加困難。

***

定義高層與低層

《Clean Architecture》書中關於分層有一個非常明確的定義:「離I/O(輸入、輸出)越遠的元件層級越高,離I/O越近的層級越低」。這其實也很容易理解,在公司中,櫃台小姐離I/O(接電話、接待訪客)最近,通常層級比較低。董事長、總經理離I/O很遠,層級最高(通常看高階主管的辦公室位置離大門遠近就可猜出層級高低XD)。

▼Port and Adapter不把階層式架構畫成常見的垂直形狀,而是畫成圖1中的六角型。

螢幕截圖 2018-03-15 17.39.22


▼《Clean Architecture》書中則是畫成同心圓(圖片來源在此)。

CleanArchitecture


▲上圖中,蛋黃區(Entities)是架構中層級最高的一層,而最外圈屬於I/O層,是層級最低的。

《Clean Architecture》書中有四個預設的階層,分別是:

  • Entities:也就是傳統物件導向分析與設計所說的domain model object。
  • Use Cases:Entities這一層存放著核心商業邏輯,也就是在這個領域中,不同應用程式都用得到的物件。而Use Cases則代表應用程式邏輯,也就是應用程式的功能。Use Cases扮演著controller的角色,呼叫Entities或是Repository物件提供應用程式對外的服務。
  • Interface Adapters:將外部資料與呼叫介面透過此層轉呼叫Use Cases,如此一來Use Cases就可以與I/O或是應用程式框架無關。
  • Frameworks and Drivers:此層包含了應用程式框架,例如如果Java程式使用了Spring Framework,則Spring Framework就位於這一層。資料庫,或常見的MVC Framework也都位於這一層。通常大家在這一層所寫的程式都只是為了把應用程式框架與內部的Interface Adapters或Use Cases串起來的膠水程式,鮮少有複雜的商業邏輯會位於這一層。

***

結論

依據「元件距離I/O遠近」分好層級之後,高、低層之間的界線就非常的清楚。層級分明之後,接下來衍生出另一個問題:每一層之間的相依性要怎麼管理?如果層與層之間的相依性沒有好好管理,僅僅是分層你的架構還是很可能會一團亂。

下一集「相依性原則」將說明這個問題,下次見。

***

友藏內心獨白:真正的高層都是坐在離I/O很近的大門口XD。