1. 程式人生 > >Cloud Native-產品級敏捷 2.0: 打造服務化的架構, 使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力

Cloud Native-產品級敏捷 2.0: 打造服務化的架構, 使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力

2017.10.28, Ken Fang, 深圳

I. 前言:
產品級敏捷 2.0 是我在 2016 年所建立的。

建立產品級敏捷 2.0 最主要的目的是:
在產品級敏捷與 Design Sprint 的基礎之上, 結合敏捷開發與軟體工程, 而使團隊成員可高效的協作; 系統化、精益化、嚴謹的進行產品服務化的設計◦ 使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力。

II. 本文:
在談論產品級敏捷 2.0 前, 我們先回顧下, 產品級敏捷與 Design Sprint。

產品級敏捷共有五大核心工程實踐:
 Slice Board (切片板) : 使得每一輪版本的釋出, 都能以最少的產出, 卻能對客戶產生最大的影響。
 Architecture Map (架構地圖): 輕量級的設計每一輪版本的架構設計, 並識別每一輪版本在架構上的風險。
 Story Wall (故事牆): 使得開發人員與測試人員, 認同 User Story 的價值, 並從產品外部的視角, 清楚的明白: User Story 完成的定義或標準為何?
 Scenario Tree (場景樹): 輕量級且視覺化的 Story 的設計與定義完成。
 Feature API (特性API): 從外部的視角, 使得特性對外所提供的 API, 均能代表ㄧ有價值的 “業務概念”。

這裡寫圖片描述
[圖一: 產品級敏捷]

Design Sprint 共分為五個過程:
 Understand (瞭解): 探索產品上的問題、使用者的問題、使用者平常都在做些什麼?
 Diverge (分歧): 產生各種的想法。
 Converge (聚合): 決定最佳的想法。
 Prototype (原型): 建立有使用者體驗的原型。
 Test (試驗): 經由觀察使用者使用原型的情況, 驗證所提出的想法。

這裡寫圖片描述
[圖二: Design Sprint]

所以, 在整個產品開發的生命週期中:
 Design Sprint 能協助我們在產品的規劃上具備前瞻性; 協助我們能做對的事情。
 產品級敏捷能協助我們快速的響應使用者的變化與交付符合使用者期望的產品; 協助我們快速的將事情給做對。

這裡寫圖片描述
[圖三: Design Sprint vs. Product Backlog vs. 產品級敏捷]

產品級敏捷 2.0 則期望能藉由 Cloud Native 的架構, 使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力。

產品級敏捷 2.0 共有三大核心工程實踐:
 Boundary (分界線): 使得微服務能從特性業務場景的緯度、分散式呼叫技術的緯度、團隊成員能力成熟度的緯度, 進行設計上的隔離; 劃分出適當的微服務的粒度。
 Service API (服務API): 使得微服務對外部不同型別的產品、系統, 均能提供一標準、完整且易於使用的 Rest 介面與版本演進的機制。
 Service Event (服務事件): 使得微服務間能藉由事件驅動的方式, 以達到事務的一致性, 而使得微服務可更有彈性的擴充套件、可更自主的運作著。

所以, 產品級敏捷 2.0 是藉由 Boundary (分界線)、Service API (服務API)、Service Event (服務事件), 而使得產品的架構能擁有更佳的 ”關注點隔離 (Separation of Concern)”; 當我們的產品能擁有更佳的關注點隔離時, 我們的產品便自然而然的能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力。

這裡寫圖片描述
[圖四: 產品級敏捷 2.0: 打造服務化的架構; 使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力 ]

產品級敏捷 2.0 的三大核心工程實踐詳述如下:

1) Boundary (分界線):

微服務到底應該如何的識別? 微服務的粒度為何? 微服務該如何的分析與設計?
這些問題的答案, 取決於: 為何需要微服務?

為何需要微服務?
目的只有一個: 使得我們的產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力。

所以, 微服務的分析與設計, 決不是單純的只考量技術上的解決方案。
微服務的分析與設計, 必需要掌握兩個核心的原則:
 從外部的業務場景, 驅動微服務的分析與設計。
 經由微服務分析與設計出的 Cloud Native架構, 必需是能演進與能擴充套件的架構。

讓我們開始探索微服務的分析與設計:

任何的產品; 不論是會與使用者直接發生互動的應用系統, 或是提供給眾多產品使用的平臺; 都應該要先有一個完整的產品特性樹。
產品特性樹將使得我們可以很清楚的知道, 從外部使用者或外部產品的視角, 產品的 Cloud Native 架構, 最終應提供哪些有價值的服務?
而團隊中針對產品特性樹中的每一個特性, 都應該要有一個主要的特性負責人; 每一個特性都會有一個主要的特性負責人負責, 每一個特性負責人, 都將負責多個特性。

在微服務分析與設計中, 特性負責人主要的責任便是:
經由與團隊中各不同領域的成員; 架構師, 開發骨幹人員, 測試經理, 資深測試人員; 共同具體分析出每個特性的業務場景與微服務的 Boundary (分界線)。

特性負責人與團隊成員協作, 分析每個特性業務場景的主要步驟如下:
1. 特性負責人, 分析特性是由哪些業務活動所構成的?
2. 特性負責人, 針對特性中的某個業務活動, 分析出此業務活動的基本流。
3. 團隊成員, 以特性負責人所分析出的基本流為基礎, 分析出相關的擴充套件流與異常流。
4. 特性負責人, 決定團隊成員所分析出的擴充套件流與異常流, 哪些是需在這個版本中, 置入到微服務的架構中, 來進行開發的。
5. 特性負責人, 再選取特性中的其他業務活動, 並重復步驟二至步驟五。直到特性中的所有業務活動均已分析完畢為止。
當特性負責人, 將特性的所有業務活動均分析出, 其各自的基本流, 擴充套件流與異常流之後, 特性負責人便可經由組合基本流, 擴充套件流與異常流, 而分析出從外部使用者或外部產品的視角, 有價值的端到端的業務場景切片。

特性負責人經由與團隊成員的協作:
 團隊成員, 分析出擴充套件流與異常流; 團隊成員作加法。
 特性負責人, 從團隊成員所分析出擴充套件流與異常流中, 刪除不需要置入微服務的架構中, 去進行開發的擴充套件流與異常流; 特性負責人作減法。

團隊成員作加法, 特性負責人作減法; 此種團隊協作的方式, 不僅使團隊成員間能對需開發的微服務場景 (需求), 迅速的達成一致的共識, 並且能使得每個微服務, 都能以最少的場景 (需求), 卻能對外部使用者或外部產品, 產生最大的正面影響。

這裡寫圖片描述
[圖五: 特性負責人與架構師, 開發骨幹人員, 測試經理, 資深測試人員協作; 共同分析出特性中的基本流、擴充套件流與異常流]

這裡寫圖片描述
[圖六: 特性負責人組合基本流, 擴充套件流與異常流, 而分析出從外部使用者或外部產品的視角, 有價值的端到端的業務場景切片; 處理國內訂單、處理國外訂單、稽核客戶的信用額度]

當特性負責人, 將特性的所有業務活動均分析出, 其各自的基本流, 擴充套件流與異常流之後, 特性負責人便可經由組合基本流, 擴充套件流與異常流, 而分析出從外部使用者或外部產品的視角, 有價值的端到端的業務場景切片後, 特性負責人便可將各業務場景切片中, 共同的場景提取出, 成為所謂的 infrastructure services。

也就是說:
 對外部的使用者或外部的產品而言, 有價值的端到端的業務場景切片, 便構成了所謂的 functional services; 可供外部使用者或外部產品經由 api layer 來呼叫。
 各 functional services 中所存在的共同場景, 便構成了所謂的 infrastructure services; 只供 functional services 呼叫, 外部使用者或外部產品是無法經由 api layer 來呼叫的。

這裡寫圖片描述
[圖七: api layer: 構建在微服務與外部的使用者介面、系統或裝置之間]

這裡寫圖片描述
[圖八: Order Microservice: functional services; 提供服務給外部的使用者或外部的產品處理國內外訂單。Customer Microservices: functional services; 提供服務給外部的使用者或外部的產品稽核客戶的信用額度。Product Microservice: infrastructure services; 提供服務給 Order Microservice 獲取產品的資訊]

現在的問題是:
經由基本流, 擴充套件流與異常流的組合, 所構成的業務場景切片, 是否就能形成 functional services 這類微服務的最佳 Boundary (分界線)?

要能回答這個問題, 需先思考下面的六個問題:
1. functional services 的 Boundary (分界線) 內的業務場景切片是否過於龐大與複雜? 而使開發人員或測試人員不易於理解?
2. functional services 的 Boundary (分界線)內的業務場景切片是否過於龐大與複雜? 使得在版本開發中, 會產生過多的變更或缺陷, 而使得版本升級的速度與質量因此而下降?
3. functional services 的 Boundary (分界線)內的業務場景切片是否過於龐大與複雜? 而使得在版本開發中, 此 functional services 已無法由單一的團隊所完成?
4. functional services 的 Boundary (分界線)內的業務場景切片, 實際是否僅是能完成某業務活動中的某個功能點? 因而, 使得此 functional services 需要遠端呼叫其他多個的 functional services, 才能完成某業務活動中的某個業務切片; 別忘了, functional services 之間的遠端呼叫, 往往可能會引入效能、可靠性、甚至是安全性等的問題。
5. functional services 的 Boundary (分界線) 內所包含的資料庫是否需要與其他的 functional services 發生資料一致性的問題。別忘了, 在分散式微服務的架構下, 微服務間的資料是一定會延遲的, 所以, 假如, 某個 functional services 的 Boundary (分界線) 內所包含的資料庫, 是需要與其他的 functional services 維持數 據的一致性時, 則將會因過長的資料延遲, 而使得使用者的體驗不佳。當然, 要維持眾多 functional services 間的資料一致性, 在開發上也不是件容易的事。
6. 是否會因過多的 functional services , 而使得在自動化配置、測試與自動化部署的難度與風險增加?

所以, 當特性負責人, 經由基本流, 擴充套件流與異常流的組合, 所構成的業務場景切片, 而形成 functional services 這類微服務的 Boundary (分界線) 後, 便需與團隊中各不同領域的成員; 架構師, 開發骨幹人員, 測試經理, 資深測試人員; 再共同的協作, 針對每個 functional services, 反覆的推敲、分析、回答上述的六個問題, 直到獲得大家都認可的 Boundary (分界線) 為止。

這裡寫圖片描述
[圖九: Order Microservice, Customer Microservices 的 Boundary (分界線) 是否過大? 是否過小?]

2) Service API (服務API):

特性負責人與架構師, 開發骨幹人員, 測試經理, 資深測試人員, 經由協作, 完成了: 微服務的 Boundary (分界線) 的界定後, 接下來特性負責人便可:
 將微服務內部的業務場景切片, 依場景或功能點, 拆分成一個或多個 User Stories。
 將微服務會與其他微服務產生互動的場景, 拆分成一個或多個 User Stories。

這裡寫圖片描述
[圖十: Order Microservice 的 Microservices Team Backlog: Story: 稽核客戶訂單, 負責 Order Microservice 與 Customer Microservice 間的互動]

特性負責人, 並且需針對每一個 User Stories, 提供以下的資訊給開發人員與測試人員:
 會與 User Story 直接產生互動的外部使用者、系統、裝置或事件。
 外部使用者、系統、裝置或事件, 和 User Story 直接產生互動的目的。
 外部使用者、系統、裝置或事件, 和 User Story 直接產生互動的主要場景。
 User Story 完成標準 (驗收條件)。

特性負責人, 說服開發與測試人員, 能認同微服務中的 User Story 的價值, 並使開發與測試人員能從產品外部的視角, 清楚的明白: 外部使用者、系統、裝置或事件所期望的微服務中的 User Story 完成的定義或標準為何後…

開發人員與測試人員便必需協作, 藉由 “Story 場景樹”, 針對微服務中的每個 User Stories, 共同的完成:
 從產品外部的視角, 分析出 User Story 最佳的易用性業務流活動步驟。
 分析出 User Story 每個業務流的活動步驟, 對外依賴的介面, 資料庫或埠。
 分析出 User Story 每個業務流活動步驟完成後, 其所產出的實體。
 設計出關鍵的緯度, 經由這些關鍵的緯度, 便能校驗出 User Story 每個業務流活動步驟完成後, 其所產出的實體是正確、不正確、合法或不合法。

這裡寫圖片描述
[圖十一: Order Microservice 的 Story 場景樹的分析]

每個微服務依照場景或功能點, 分解成一到多個的 User Stories。每個 User Story 經過開發人員與測試人員協作, 藉由 “Story 場景樹”, 分析出微服務中包含哪些 “Entity (實體)” ?
每一個微服務中的實體應能只明確代表微服務中的某個單一的業務概念; 同樣的, 微服務中的某個業務概念應也只能由微服務中某個單一的實體所代表。
所以, 在微服務中的 Story 場景樹中, 假如, 識別出有一個以上的實體; 名稱不同, 但這些實體所代表的業務概念, 卻是同一個的業務概念; 則開發與測試人員, 便應該將這些代表相同業務概念的實體, 合併為單一的實體。最後, 開發與測試人員便從所分析出的實體中, 決定那個或那些的實體是微服務的 Root(s)。開發與測試人員便可從 Root(s) 著手, 設計出微服務對外的 Rest API; Service API (服務API) 。

這裡寫圖片描述
[圖十二: Orders 與 Order Status 代表同一個的業務概念, 所以, 合併為單一個實體; Orders。Order Microservice 中共有 Items, Cart, Orders 三個實體]

這裡寫圖片描述
[圖十三: 實體 Orders, 實體 Cart 都是 Order Microservice 的 Roots]

如圖十三所示, 實體 Orders, 實體 Cart 都是 Order Microservice 的 Roots。
而由實體 Order 設計出 Order Microservice 對外的 Rest API; Service API (服務API); 便如下表所示:
這裡寫圖片描述

這裡有兩點要強調的是:
 一個微服務會有一個或多個的 Root(s) 。
 當某個微服務有一個以上的 Root(s) 時, 團隊成員便需要再共同的討論; 確認先前所設計的微服務 Boundary (分界線) 是否適當? 微服務的粒度是否過大?

設計出了微服務的 Service API (服務API) Endpoints, 便可接著設計 Content-type; 如: application/json; 與 HTTP Status Code。

HTTP Status Code 超過 70 個; 沒有人可以完全記得住。

產品級敏捷 2.0 建議:
 團隊應統一會用到那些 HTTP Status Code。
 團隊會用到的 HTTP Status Code 不要超過 8 個。

這裡寫圖片描述
[圖十四: 建議用到的 HTTP Status Code 不要超過 8 個]

產品級敏捷 2.0 建議 Service API (服務API) 版本演進的策略如下:
 同時支援兩個版本在線上運作; 以使使用 Service API (服務API) 的開發人員, 能有足夠的時間進行升級到新版的 Service API (服務API) 。
 在線上只有主要 (Major) 版本, 主要 (Major) 版本只在 URL 中體現;
如: GET https://api.a9.com/v1/orders。以避免因為過多的版本, 而使使
用 Service API (服務API) 的開發人員, 產生不必要的困擾與麻煩。
 Service API (服務API) 的每個主要 (Major) 版本都有以下的三個屬性; 控制著某個主要 (Major) 版本, 有那些使用 Service API (服務API) 的開發人員可以/ 不可以使用?
1. Available: 使用前一版本的開發人員也能使用。
2. Deprecate: 只有曾使用過前一版本的開發人員才能使用。
3. Retire: 任何的開發人員都將無法再使用。
舉個例子:
這裡寫圖片描述
[圖十五: 同時支援兩個版本在線上運作]

 Q1/2017, Service API (服務API) 的 Version-1 上線; Version-1 版本屬性在 Q1/2017 : Available。
 張三, 在 Q1/2017 使用了Service API (服務API) 的 Version-1。
 Q2/2017, Service API (服務API) 的 Version-2 上線。Version-2 版本屬性在 Q2/2017 : Available。而 Version-1版本屬性在 Q2/2017 變為: Deprecate。
 David, 在 Q2/2017 使用了Service API (服務API) 的 Version-2。
 因為, 張三在 Q1/2017 曾使用了 Service API (服務API) 的 Version-1, 所以, 張三在 Q2/2017 仍能使用了 Service API (服務API) 的 Version-1。當然, 張三也能使用 Service API (服務API) 的 Version-2。
 因為, Version-1 的屬性在 Q2/2017 已變為: Deprecate。而且, David 沒在 Q1/2017 使用Service API (服務API) 的 Version-1, 所以, David 將不能使用 Version-1。
 Q3/2017, Service API (服務API) 的 Version-3 上線。Version-3 版本屬性在 Q2/2017 : Available。
 Q3/2017, Version-2 的屬性變為: Deprecate。
 Q3/2017, Version-1 的屬性變為: Retire; 任何的開發人員都將不能再使用 Version-1。

3) Service Event (服務事件):

微服務間能藉由事件驅動的方式, 以達到事務的一致性, 將能使得微服務可更有彈性的擴充套件、可更自主的運作著。
微服務間事件模型的設計, 產品級敏捷 2.0 是採用 Event Storming; Vaughn Vernon。

Event Storming; 1-2 天的 workshop; 特性負責人與業務領域專家, 架構師, 開發骨幹人員, 測試經理, 資深測試人員協作, 活動的內容如下:

 按照事件發生的先後順序, 依時間的順序, 分析出微服務之間會發生的事件。

這裡寫圖片描述
[圖十六: 事件: 以橘色的自貼上紙代表]

 針對每個事件, 分析出觸發事件的命令 (Command) 。
當然, 單一的命令會觸發一個或多個的事件。
觸發事件的方式不外乎兩種:
• 同時並行觸發多個事件。
• 按時間的順序, 循序觸發多個事件。

這裡寫圖片描述
[圖十七: 命令: 以藍色的自貼上紙代表]

 分析出會處理命令, 產生事件的 Aggregate。

這裡寫圖片描述
[圖十八: Aggregate: 以黃色的自貼上紙代表]

 將需在同一事務完成的實體, 聚合在同一個 Bounded Context 中。

這裡寫圖片描述
[圖十九: Order Bounded Context vs. Payment Bounded Context]

 設計 Bounded Context 的 Policy; Aggregate 該如何響應事件? 該生成什麼命令, 告訴其他的 Aggregate 該作什麼?

這裡寫圖片描述
[圖二十: Policy: 以綠色的自貼上紙代表]

III. 結論:
 Design Sprint:
協助我們能做對的事。
 產品級敏捷:
協助我們快速的將事情給做對。
 產品級敏捷 2.0:
使得產品能隨著時間、版本的演進, 而能不斷的提升其價值與對使用者正面的影響力。

這些年來, 我最幸運的一件事便是: 永遠和一群比我聰明的夥伴們, 共同探索著敏捷開發與軟體工程。
非常感謝這些年來, 和我一起努力走過, 這一段挺辛苦又挺孤獨道路的夥伴們。

我們將持續的探索著, 期待著下一段的旅程將會更精彩、更有趣。
我們將探索著將人工智慧應用在產品的開發上。

我們堅信: 我們將能打造更開心、更健康、更有價值的產品開發生態系統。

期待著你也來加入!
謝謝。