一個架構師的真正職責
一個架構師的真正職責
“你總提及的那個詞,它的含義與你想表達的意思並不一樣。”——Inigo Montoya,電影《公主新娘》中的人物
架構師的一個重要職責是,確保團隊有共同的技術願景,以幫助我們向客戶交付他們想要的系統。
在某些場景下,架構師只需要和一個團隊一起工作,這時他們等同於技術引領者。在其他情況下,他們要對整個專案的技術願景負責,通常需要協調多個團隊之間,甚至是整個組織內的工作。
不管處於哪個層次,架構師這個角色都很微妙。在一般的組織中,非常出色的開發人員才能成為架構師,但通常會比其他角色招致更多的批評。
相比其他角色而言,架構師對多個方面都有更加直接的影響,比如所構建系統的質量、同事的工作條件、組織應對變化的能力等。這個角色也很難做好,原因何在呢?
很多時候人們似乎忘了,我們的行業還很年輕。我們編寫的程式在計算機上執行,而計算機從出現到現在也只有 70 年左右而已,因此我們需要在現存的行業中不斷地尋找,幫助別人理解我們到底是做什麼的。
我們不是醫生或者醫學工程師,也不是水管工或者電工。我們處於這些行業的中間地帶,因此社會很難理解我們,我們也不清楚自己到底處於什麼位置。
所以我們嘗試借鑑其他的行業。我們把自己稱作軟體“工程師”或者“建築師”1,但其實我們不是,對吧?
建築師和工程師所具備的精確性和紀律性是遙不可及的,而且他們在社會中的重要性也很容易理解。
我的一個朋友在成為認證建築師的前一天說:“如果明天我在酒吧對於如何蓋房子給了你錯誤的建議,那麼我要為此負責。從法律的角度來說,因為我是一個認證建築師,所以做錯了很可能會被起訴。”
他們在社會中有非常重要的作用,因此需要經過專門認證才能工作。比如,在英國你至少需要學習七年才能成為一名建築師。這些職業在幾千年前就存在了,而我們呢?相差甚遠。
這也就是為什麼我覺得很多形式的 IT 證書都沒價值,因為我們對什麼是好的知之甚少。
有些人想要得到社會的認可,所以借鑑了這些已經被大眾認知的行業中的名詞,但這樣可能會造成兩個問題。
首先,這麼做的前提是我們要清楚自己應該幹什麼,而多數情況下事實並非如此。並不是說建築和橋樑就一定不會倒塌,而是它們倒塌的次數要比我們程式崩潰的次數少得多,所以跟工程師相類比是不公平的。
其次,經過一些粗略的觀察就會發現這種類比是站不住腳的。因為如果橋樑建築和程式設計類似的話,那麼建到一半的時候你可能會發現對岸比預想的要遠 50 米,而且其材質是花崗岩而不是泥土,更糟糕的是我們最終想要的是一座公路橋而不是步行橋。
軟體並沒有類似這種真正的工程師和建築師在物理規則方面的約束,事實上,我們要創造的東西從設計上來說就是要足夠靈活,有很好的適應性,並且能夠根據使用者的需求進行演化。
也許“建築師”這個術語是很有問題的。建築師的工作是做好詳細的計劃,然後讓別人去理解和執行。
進行這項工作需要對藝術性和工程性進行權衡,並且對整體進行監督,而其他所有的視角都要屈從於建築師的視角,當然有時候他們也會考慮結構工程師基於物理規則的一些建議。
在我們的行業中,這種建築師的視角會導致一些非常糟糕的實踐。人們試圖通過大量的圖表和文件創建出一個完美的方案,而忽略了很多基礎性的未知因素。
使用這種方式會導致人們很難真正理解實現起來的難度,甚至不知道這個設計到底能否奏效,想要對系統瞭解更多之後再對設計進行修改就更不可能了。
當我們把自己和工程師或者建築師做比較時,很有可能會做出錯誤的決定。不幸的是,架構師這個詞已經被大眾接受了,所以現在我們能夠做的事情就是在上下文中去重新定義這個詞的含義。
本文節選自《微服務設計》
架構師的演化視角
與建造建築物相比,在軟體中我們會面臨大量的需求變更,使用的工具和技術也具有多樣性。
我們創造的東西並不是在某個時間點之後就不再變化了,甚至在釋出到生產環境之後,軟體還能繼續演化。
對於我們創造的大多數產品來說,交付到客戶手裡之後,還是要響應客戶的變更需求,而不是簡單地交給客戶一個一成不變的軟體包。
因此架構師必須改變那種從一開始就要設計出完美產品的想法,相反我們應該設計出一個合理的框架,在這個框架下可以慢慢演化出正確的系統,並且一旦我們學到了更多知識,應該可以很容易地應用到系統中。
儘管截止到目前,本章都在警告你不要跟其他行業做過多的比較,但是我發現,有一個角色可以更好地跟 IT 架構師相類比。
這個想法是 Erik Doernenburg 告訴我的,他認為更好的類比是城市規劃師,而不是建築師。如果你玩過 SimCity,那麼你應該很熟悉城市規劃師這個角色。
城市規劃師的職責是優化城鎮佈局,使其更易於現有居民生活,同時也會考慮一些未來的因素。為了達到這個目的,他需要收集各種各樣的資訊。
規劃師影響城市演化的方法很有趣,他不會直接說“在那個地方蓋一棟這樣的樓”,相反他會對城市進行分割槽。
就像在 SimCity 中一樣,你可能會把城市的某一部分規劃成為工業區,另外一部分規劃成為居民區,然後其他人會自己決定具體要蓋什麼建築物。當然這個決定會受到一定的約束,比如工廠一定要蓋在工業區。
城市規劃師更多考慮的是人和公共設施如何從一個區域移到另一個區域,而不是具體在每個區域中發生的事情。
很多人把城市比作生物,因為城市會時不時地發生變化。當居民對城市的使用方式有所變化,或者受到外力的影響時,城市就會相應地演化。城市規劃師應該儘量去預期可能發生的變化,但是也需要明白一個事實:嘗試直接對各個方面進行控制往往不會奏效。
上面描述的城鎮和軟體的對應關係應該是很明顯的。當用戶對軟體提出變更需求時,我們需要對其進行響應並做出相應的改變。
未來的變化很難預見,所以與其對所有變化的可能性進行預測,不如做一個允許變化的計劃。為此,應該避免對所有事情做出過於詳盡的設計。城市這個系統應該讓生活在其中的住戶感到開心。
有一件經常被人們忽略的事情是:系統的使用者不僅僅是終端使用者,還有工作在其上的開發人員和運維人員,他們也對系統的需求變更負責。
借鑑 Frank Buschmann 的一個說法:架構師的職責之一就是保證該系統適合開發人員在其上工作。
城市規劃師就像建築師一樣,需要知道什麼時候他的計劃沒有得到執行。儘管他會引入較少的規範,並儘量少地對發展的方向進行糾正,但是如果有人決定要在住宅區建造一個汙水池,他應該能制止。
所以我們的架構師應該像城市規劃師那樣專注在大方向上,只在很有限的情況下參與到非常具體的細節實現中來。他們需要保證系統不但能夠滿足當前的需求,還能夠應對將來的變化。
而且他們還應該保證在這個系統上工作的開發人員要和使用這個系統的使用者一樣開心。聽起來這是很高的標準,那麼從哪裡開始呢?
分割槽
前面我們將架構師比作城市規劃師,那麼在這個比喻裡面,區域的概念對應的是什麼呢?它們應該是我們的服務邊界,或者是一些粗粒度的服務群組。
作為架構師,不應該過多關注每個區域內發生的事情,而應該多關注區域之間的事情。這意味著我們應該考慮不同的服務之間如何互動,或者說保證我們能夠對整個系統的健康狀態進行監控。
至於多大程度地介入區域內部事務,在不同的情況下則有所不同。很多組織採用微服務是為了使團隊的自治性最大化,第 10 章會對這個話題做更多討論。如果你就處在這樣的組織中,那麼你會更多地依靠團隊來做出正確的區域性決定。
但是在區域之間,或者說傳統架構圖中的框圖之間,我們需要非常小心,因為在這些地方犯的錯誤會很難糾正。
每一個服務內部可以允許團隊自己選擇不同的技術棧或者資料儲存技術,當然其他的問題也需要考慮。
但是事實上也不會無限制地允許團隊選擇任意技術棧,比如如果需要支援 10 種不同的技術棧的話,可能會在招聘上遇到困難,或者很難在不同團隊之間交換人員。
類似地,如果每個團隊自己選擇完全不同的儲存技術,可能你會發現自己對它們都不夠熟悉。
舉個例子,Netflix 在 Cassandra 這種儲存技術上有非常成熟的使用規範,並認為相比對特定的任務使用最合適的技術而言,圍繞 Cassandra 來構建相關的工具和培養專家更重要。
Netflix 是一個很極端的例子,他們認為可伸縮性是最重要的因素,但是通過這個例子你可以有自己的理解。
然而,服務之間的事情可能會變得很糟糕。如果一個服務決定通過 HTTP 暴露 REST 介面,另一個用的是 protocol buffers,第三個用的是 Java RMI,那麼作為一個服務的消費者就需要支援各種形式的互動,這對於消費者來說簡直就是噩夢。
這也就是為什麼我強調我們應該“擔心服務之間的互動,而不需要過於關注各個服務內部發生的事情”。
程式碼架構師如果想確保我們創造的系統對開發人員足夠友好,那麼架構師需要理解他們的決定對系統會造成怎樣的影響。最低的要求是:架構師需要花時間和團隊在一起工作,理想情況下他們應該一起進行編碼。對於實施結對程式設計的團隊來說,架構師很容易花一定的時間和團隊成員進行結對。理想情況下,你應該參與普通的工作,這樣才能真正理解普通的工作是什麼樣子。架構師和團隊真正坐在一起,這件事情再怎麼強調也不過分!相比通過電話進行溝通或者只看看團隊的程式碼,一起和團隊工作的這種方式會更加有效。至於和團隊在一起工作的頻率可以取決於團隊的大小,關鍵是它必須成為日常工作的一部分。如果你和四個團隊在一起工作,那麼每四周和每個團隊都工作半天,可以幫助你有效地和團隊進行溝通,並瞭解他們都在做什麼。
一個原則性的方法
“規則對於智者來說是指導,對於愚蠢者來說是遵從。”——一般認為出自 Douglas Bader
做系統設計方面的決定通常都是在做取捨,而在微服務架構中,你要做很多取捨!
當選擇一個數據儲存技術時,你會選擇不太熟悉但能夠帶來更好可伸縮性的技術嗎?在系統中存在兩種技術棧是否可接受?那三種呢?
做某些決策所需要的資訊很容易獲取,這些還算是容易的。但是有些決策所需要的資訊難以完全獲取,那又該怎麼辦呢?
基於要達到的目標去定義一些原則和實踐對做設計來說非常有好處。接下來讓我們對它們做一些討論。
1. 戰略目標
做一名架構師已經很困難了,但幸運的是,通常我們不需要定義戰略目標!戰略目標關心的是公司的走向以及如何才能讓自己的客戶滿意。
這些戰略目標的層次一般都很高,但通常不會涉及技術這個層面,一般只在公司或者部門層面制定。這些目標可以是“開拓東南亞的新市場”或者“讓使用者儘量使用自助服務”。因為這些都是你的組織前進的方向,所以需要確保技術層面的選擇能夠與之一致。
如果你是制定公司技術願景的人,那麼你可能需要花費更多的時間和組織內非技術的部分(通常他們被叫作業務部門)進行互動。那麼業務部門的願景是什麼?它又會如何發生改變呢?
2. 原則
為了和更大的目標保持一致,我們會制定一些具體的規則,並稱之為原則,它不是一成不變的。
舉個例子,如果組織的一個戰略目標是縮短新功能上線的週期,那麼一個可能的原則是,交付團隊應該對整個軟體生命週期有完全的控制權,這樣他們就可以及時交付任何就緒的功能,而不受其他團隊的限制。
如果組織的另一個目標是在其他國家快速增長業務,你需要使用的原則可能就是,整個系統必須能夠方便地部署到相應的國家,從而符合該國家對資料儲存地理位置方面的要求。
很有可能這些原則並不適合你的組織。一般來講,原則最好不要超過 10 個,或者能夠寫在一張海報上,不然大家會很難記住。而且原則越多,它們發生重疊和衝突的可能性就越大。
Heroku 的 12 Factors 就是一組能夠幫助你在 Heroku 平臺上建立應用的設計原則,當然它們在其他的上下文中可能也有用。其中,有些原則實際上是為了讓你的應用程式可以適應 Heroku 這個平臺而引入的約束。
約束是很難(或者說不可能)改變的,但原則也是我們自己決定的。你應該顯式地指出哪些是原則,哪些是約束,這樣使用者就會很清楚哪些是不能變的。從個人角度來講,我認為把原則和約束放在同一個列表中是有好處的,這樣我們就可以不時地回顧一下這些約束是否真的不可改變。
3. 實踐
我們通過相應的實踐來保證原則能夠得到實施,這些實踐能夠指導我們如何完成任務。
通常這些實踐是技術相關的,而且是比較底層的,所以任何一個開發人員都能夠理解。這些實踐包括程式碼規範、日誌資料集中捕獲或者 HTTP/REST 作為標準整合風格等。由於實踐比較偏技術層面,所以其改變的頻率會高於原則。
就像原則那樣,有時候實踐也會反映出組織內的一些限制。比如,如果你只支援 CentOS,那麼相應的實踐就應該考慮這個因素。
實踐應該鞏固原則。比如前面我們提過一個原則是開發團隊應該可以對軟體開發全流程有控制權,相應的實踐就是所有的服務都部署在不同的 AWS 賬戶中,從而可以提供資源的自助管理和與其他團隊的隔離。
4. 將原則和實踐相結合
有些東西對一些人來說是原則,對另一些人來說則可能是實踐。比如,你可能會把使用 HTTP/REST 作為原則,而不是實踐。
這也沒什麼問題,關鍵是要有一些重要的原則來指導系統的演化,同時也要有一些細節來指導如何實現這些原則。
對於一個足夠小的群組,比如單個團隊來說,將原則和實踐進行結合是沒問題的。但是在一個大型組織中,技術和工作實踐可能不一樣,在不同的地方需要的實踐可能也不同。
不過這也沒關係,只要它們都能夠對映到相同的原則即可。比如一個 .NET 團隊可能有一套實踐,一個 Java 團隊有另一套實踐,但背後的原則是相同的。
5. 真實世界的例子
我的同事 Evan Bottcher 幫一個客戶畫出瞭如圖 1 所示的圖表。該圖很清楚地顯示了目標、原則和實踐之間的相互影響。
幾年間,實踐改動得很頻繁,而原則基本上沒怎麼變。可以把這樣一個圖表打印出來並共享給相關人員,其中每個條目都很簡單,所以開發人員應該很容易記住它們。
儘管每條實踐背後還有很多細節,但僅僅能把它們總結表述出來也是非常有用的。
圖 1:原則和實踐的真例項子
上面提到的一些項可以使用文件來支撐,但大多數情況下我喜歡給出一些示例程式碼供人閱讀、研究和執行,從而傳遞上面涉及的那些資訊。更好的方式是,創造一些工具來保證我們所做事情的正確性。後面馬上就會對這個話題做深入的討論。
要求的標準
當你瀏覽這些實踐,並思考你需要做的取捨時,需要注意一個很重要的因素:系統允許多少可變性。
我們需要識別出各個服務需要遵守的通用規則,一種方法是,給出一個好服務的例子來闡釋好服務的特點。在系統中什麼是好服務“公民”呢?
它需要有什麼樣的能力才能保證整個系統是可控的,並且一個有問題的服務不會導致整個系統癱瘓?
這些問題很難回答,因為就像人一樣,在某種上下文中是一個好公民不代表在其他上下文中也是,但我們還是可以觀察到各個服務中一些通用的優秀實踐。一些關鍵領域有太多的變化方向,而這可能會導致很多問題。
就像 Netflix 的 Ben Christensen 說的那樣,當我們在考慮一個更大的全景圖時,“系統應該由很多小的但有自治生命週期的元件構成,而且這些元件之間有著緊密的關聯”。
所以在優化單個服務自治性的同時,也要兼顧全域性。一種能幫助我們實現平衡的方法就是,清楚地定義出一個好服務應有的屬性。
1. 監控
能夠清晰地描繪出跨服務系統的健康狀態非常關鍵。這必須在系統級別而非單個服務級別進行考慮。
往往在需要診斷一個跨服務的問題或者想要了解更大的趨勢時,你才需要知道每個服務的健康狀態。
簡單起見,我建議確保所有的服務使用同樣的方式報告健康狀態及其與監控相關的資料。
你可能會選擇使用推送機制,也就是說,每個服務主動把資料推送到某個集中的位置。(在作者所著的《微服務設計》第八章講到)
你可以使用 Graphite 來收集指標資料,使用 Nagios 來檢測健康狀態,或者使用輪詢系統來從各個節點收集資料。
但無論你的選擇是什麼,都應儘量保持標準化。每個服務內的技術應該對外不透明,並且不要為了服務的具體實現而改變監控系統。日誌功能和監控情況類似:也需要集中式管理。
2. 介面
選用少數幾種明確的介面技術有助於新消費者的整合。使用一種標準方式很好,兩種也不太壞,但是 20 種不同的整合技術就太糟糕了。這裡說的不僅僅是關於介面的技術和協議。
舉個例子,如果你選用了 HTTP/REST,在 URL 中你會使用動詞還是名詞?你會如何處理資源的分頁?你會如何處理不同版本的 API ?
3. 架構安全性
一個執行異常的服務可能會毀了整個系統,而這種後果是我們無法承擔的,所以,必須保證每個服務都可以應對下游服務的錯誤請求。沒有很好處理下游錯誤請求的服務越多,我們的系統就會越脆弱。
你可以至少讓每個下游服務使用它們自己的連線池,進一步讓每個服務使用一個斷路器。在第 11 章中討論規模化微服務時,會就這個話題做更深入的討論。
返回碼也應該遵守一定的規則。如果你的斷路器依賴於 HTTP 返回碼,並且一個服務決定使用 2XX 作為錯誤碼,或者把 4XX 和 5XX 混用,那麼這種安全措施就沒什麼意義了。
即使你使用的不是 HTTP,也應該注意類似的問題。對以下幾種請求做不同的處理可以幫助系統及時失敗,並且也很容易追溯問題:
(1)正常並且被正確處理的請求;
(2)錯誤請求,並且服務識別出了它是錯誤的,但什麼也沒做;
(3)被訪問的服務宕機了,所以無法判斷請求是否正常。如果我們的服務沒有很好地遵守這些規則,那麼整個系統就會更加脆弱。
4. 程式碼治理
聚在一起,就如何做事情達成共識是一個好主意。但是,花時間保證人們按照這個共識來做事情就沒那麼有趣了,因為在各個服務中使用這些標準做法會成為開發人員的負擔。
我堅信應該使用簡單的方式把事情做對。我見過的比較奏效的兩種方式是,提供範例和服務程式碼模板。
5. 範例
編寫文件是有用的。我很清楚這樣做的價值,這也正是我寫這本書的原因。但是開發人員更喜歡可以檢視和執行的程式碼。
如果你有一些很好的實踐希望別人採納,那麼給出一系列的程式碼範例會很有幫助。這樣做的一個初衷是:如果在系統中人們有比較好的程式碼範例可以模仿,那麼他們也就不會錯得很離譜。
理想情況下,你提供的優秀範例應該來自真實專案,而不是專門實現的一個完美的例子。因為如果你的範例來自真正執行的程式碼,那麼就可以保證其中所體現的那些原則都是合理的。
裁剪服務程式碼模板
如果能夠讓所有的開發人員很容易地遵守大部分的指導原則,那就太棒了。一種可能的方式是,當開發人員想要實現一個新服務時,所有實現核心屬性的那些程式碼都應該是現成的。
Dropwizard 和 Karyon 是兩個基於 JVM 的開源微容器。
它們的執行模式相似,會自動下載一系列第三方庫,這些庫可以提供一些特性,比如健康檢查、HTTP 服務、提供指標資料介面等。這樣你就有了一個可以從命令列啟動的嵌入式 servlet 容器。
這是一個很好的開始,但是你可以做得更多。在實際工作中,你可以使用 Dropwizard 和 Karyon 作為基礎,然後根據自己的上下文加入更多的定製化特性。
舉個例子,如果你想要斷路器的規範化使用,那麼就可以將 Hystrix 這個庫整合進來。
或者,你想要把所有的指標資料都發送到中心 Graphite 伺服器,那麼就可以使用像Dropwizard’s Metrics 這樣的開源庫,只需要在此基礎上做一些配置,響應時間和錯誤率等資訊就會自動被推送到某個已知的伺服器上。
針對自己的開發實踐裁剪出一個服務程式碼模板,不但可以提高開發速度,還可以保證服務的質量。
當然,如果你的組織使用多種不同的技術棧,那麼針對每種技術棧都需要這樣一個服務程式碼模板。你也可以把它當作一種在團隊中巧妙地限制語言選擇的方式。
如果只存在基於 Java 的服務程式碼模板,那麼選用其他技術棧就意味著開發人員需要自己做很多額外的工作。Netflix 非常在意服務的容錯性,因為它們不希望一個服務停止工作造成整個系統都無法正常工作。
Netflix 提供了一個基於 JVM 的庫來處理這些問題。任何一個新技術棧的引入都意味著要把這部分工作重新做一遍。相對於做這些事情的代價,Netflix 更關心的是,開發這些庫時可能會引入的錯誤。
如果某個新實現的服務的容錯處理機制出錯,其對系統帶來嚴重影響的風險也會增加。Netflix 使用挎鬥(sidebar)服務來降低這種風險。挎鬥服務會和 JVM 進行本地通訊,而為了完成這種通訊,該 JVM 需要使用某些特定的第三方庫。
有一點需要注意的是,建立服務程式碼模板不是某個中心化工具的職責,也不是指導(即使是通過程式碼)我們應怎樣工作的架構團隊的職責。應該通過合作的方式定義出這些實踐,所以你的團隊也需要負責更新這個模板(內部開源的方式能夠很好地完成這項工作)。
我也見過一個團隊的士氣和生產力是如何被強制使用的框架給毀掉的。基於程式碼重用的目的,越來越多的功能被加到一箇中心化的框架中,直至把這個框架變成一個不堪重負的怪獸。
如果你決定要使用一個裁剪的服務程式碼模板,一定要想清楚它的職責是什麼。理想情況下,應該可以選擇是否使用服務程式碼模板,但是如果你強制團隊使用它,一定要確保它能夠簡化開發人員的工作,而不是使其複雜化。
你還需要知道,重用程式碼可能引入的危險。在重用程式碼的驅動下,我們可能會引入服務之間的耦合。有一個我接觸過的組織非常擔心這個問題,所以他們會手動把服務程式碼模板複製到各個服務中。
這樣做的問題是,如果核心服務程式碼模板升級了,那麼需要花很長時間把這些升級應用到整個系統中。但相對於耦合的危險而言,這個問題倒沒那麼嚴重。
還有一些我接觸過的團隊,把服務程式碼模板簡單地做成了一個共享的庫依賴,這時他們就要非常小心地防止對 DRY(Don’t Repeat Yourself,避免重複程式碼)的追求導致系統過度耦合!這是一個很微妙的話題,所以第 4 章會做更深入的討論。
技術債務
有時候可能無法完全遵守技術願景,比如為了釋出一些緊急的特性,你可能會忽略一些約束。
其實這僅僅是另一個需要做的取捨而已。我們的技術願景有其本身的道理,所以偏離了這個願景短期可能會帶來利益,但是長期來看是要付出代價的。
可以使用技術債務的概念來幫助我們理解這個取捨,就像在真實世界中欠的債務需要償還一樣,累積的技術債務也是如此。
不光走捷徑會引入技術債務。有時候系統的目標會發生改變,並且與現有的實現不符,這種情況也會產生技術債務。
架構師的職責就是從更高的層次出發,理解如何做權衡。理解債務的層次及其對系統的影響非常重要。
對於某些組織來說,架構師應該能夠提供一些溫和的指導,然後讓團隊自行決定如何償還這些技術債務。而其他的組織就需要更加結構化的方式,比如維護一個債務列表,並且定期回顧。
例外管理
原則和實踐可以指導我們如何構建系統。那麼,如果系統偏離了這些指導又會發生什麼呢?有時候我們會決定針對某個規則破一次例,然後把它記錄下來。
如果這樣的例外出現了很多次,就可以通過修改原則和實踐的方式把我們的理解固化下來。
舉個例子,可能我們有一個實踐論述應該總是使用 MySQL 做資料儲存,但是後來有足夠的證明表明在海量儲存的場景下應使用 Cassandra,這時就可以對實踐進行修改:“在大多數場景下使用 MySQL 做儲存,如果是資料快速增長的場景,可以使用 Cassandra。”
在這裡我覺得有必要重申一下:每個組織都是不同的。我曾經合作過的某些公司有高度自治的團隊,他們也得到公司足夠的信任。對於這種情況,通常原則都是很輕量級的(例外管理可能會完全消失,或者大大減少)。
有些組織結構化較強,開發人員擁有較小的自由度。這種情況下,通過例外管理來保證規則的合理性就非常重要了。
現實中的情況是多種多樣的,但我個人非常支援使用擁有更好自治性的微服務團隊,他們有更大的自由度來解決問題。如果你所在的組織對開發人員有非常多的限制,那麼微服務可能並不適合你。
集中治理和領導
架構師的部分職責是治理。那麼治理又是什麼意思呢? COBIT(Control Objectives for Information and Related Technology,資訊和相關技術的控制目標)給出了一個很好的定義:
治理通過評估干係人的需求、當前情況及下一步的可能性來確保企業目標的達成,通過排優先順序和做決策來設定方向。對於已經達成一致的方向和目標進行監督。——COBIT 5
在 IT 的上下文中有很多事情需要治理,而架構師會承擔技術治理這部分的職責。
如果說,架構師的一個職責是確保有一個技術願景,那麼治理就是要確保我們構建的系統符合這個願景,而且在需要的時候還應對願景進行演化。
架構師會對很多事情負責。他們需要確保有一組可以指導開發的原則,並且這些原則要與組織的戰略相符。
他們還需要確保,以這些原則為指導衍生出來的實踐不會給開發人員帶來痛苦。他們需要了解新技術,需要知道在什麼時候做怎樣的取捨。
上述這些職責已經相當多了,但是他們還需要讓同事也理解這些決定和取捨,並執行下去。
對了,還有前面提到的:他們還需要花時間和團隊一起工作,甚至是編碼,從而瞭解所做的決定對團隊造成了怎樣的影響。
要求很高,是嗎?沒錯。但是我堅定地認為他們不應該獨自做這些事情,可以由一個治理小組來做這個工作,並確定願景。
一般來講,治理是一個小組活動。它可以是與一個足夠小的團隊進行非正式聊天,也可以是在比較大的範圍內,與一個有著正式成員的小組進行結構化例會。
在這些會議上,可以討論前面提到的那些原則,有必要的話也可以對其進行修改。這個小組應該由技術專家領導,並且要有一線人員的參與。這個小組也應該負責跟蹤和管理技術風險。
我很喜歡的一種模式是,由架構師領導這個小組,但是每個交付團隊都有人蔘加。架構師負責確保該組織的正常運作,整個小組都要對治理負責。
這樣職責就得到了分擔,並且保證有來自高層的支援。這也可以保證資訊從開發團隊順暢地流入這個小組,從而保證小組做出更合理的決定。
有時候架構師可能不認同小組做的決定,這時應該怎麼辦?我曾經面對過這樣的場景,我認為這是架構師需要面對的最富有挑戰性的場景之一。
事實上,大多數情況下我會認同小組的決定。我曾經嘗試說服大家,但事實證明這很難做到。一個小組通常會比單個人更加聰明,而且我也不止一次被證明是錯誤的!
如果你給一個小組權力去做決定,但在最後又忽略了這個決定,那這個小組就毫無意義可言了。有時候我也會對小組施加影響。那麼我為什麼這麼做,我會在什麼時候做,又會怎麼說呢?
類比一下教小孩兒騎自行車的過程。你沒法替代他們去騎車。你會看著他們搖搖晃晃地前行,但是,如果每次你看到他們要跌倒就上去扶一把,他們永遠都學不會。
而且無論如何,他們真正跌倒的次數會比你想象的要少!但是,如果他們馬上就要駛入車流繁忙的大馬路,或者附近的鴨子池塘,你就必須站出來了。類似地,作為一名架構師,你必須要在團隊駛向類似鴨子池塘這樣的地方時抓緊他們。
還有一點要注意的是,即使你很清楚什麼是對的,然後嘗試去控制團隊,也可能會破壞和團隊的關係,並且會使團隊感覺他們沒有話語權。
有時候按照一個你不同意的決定走下去反而是正確的,知道什麼時候可以這麼做,什麼時候不要這麼做是很困難的,但有時也很關鍵。
建設團隊
對於一個系統技術願景的主要負責人來說,執行願景不僅僅等同於做技術決定,和你一起工作的那些人自然會做這些決定。
對於技術領導人來說,更重要的事情是幫助你的隊友成長,幫助他們理解這個願景,並保證他們可以積極地參與到願景的實現和調整中來。
幫助別人成長的形式有很多種,其中大部分都超出了本書的範圍。微服務架構本身能夠提供一種很好的形式。
在單塊系統中,人們為某些事情負責的機會非常有限,而在微服務架構中存在多個自治的程式碼庫,每個程式碼庫都有著自己獨立的生命週期,這就給更多人提供了對單個服務負責的機會。
而當這些人在單個服務上面得到足夠鍛鍊之後,就可以給他們更多的責任,從而幫助他們逐步達成自己的職業目標,同時通過分擔職責也可以防止某一個人的負擔過重。
我堅定地相信,偉大的軟體來自於偉大的人。所以如果你只擔心技術問題,那麼恐怕你看到的問題遠遠不及一半。
小結
總結一下本章,下面是我認為的一個演進式架構師應該承擔的職責。
- 願景
- 確保在系統級有一個經過充分溝通的技術願景,這個願景應該可以幫助你滿足客戶和組織的需求。
- 同理心
- 理解你所做的決定對客戶和同事帶來的影響。
- 合作
- 和儘量多的同事進行溝通,從而更好地對願景進行定義、修訂及執行。
- 適應性
- 確保在你的客戶和組織需要的時候調整技術願景。
- 自治性
- 在標準化和團隊自治之間尋找一個正確的平衡點。
- 治理
- 確保系統按照技術願景的要求實現。
演進式架構師應該理解,成功要靠不斷地取捨來實現。總會存在一些原因需要你改變工作的方式,但是具體做哪些改變就只能依賴於自己的經驗了。而僵化地固守自己的想法無疑是最糟糕的做法。
雖然本章的大部分建議對任何一個系統架構師來說都適用,但是在微服務系統中,架構師需要做更多的決定,因此,能更好地平衡這些取捨是非常關鍵的。
作者簡介:
原創: Sam Newman。Sam Newman,ThoughtWorks 公司的技術專家、ThoughtWorks 內部系統架構師,同時還為全球的客戶提供諮詢服務。他在開發和 IT 運維方面與全球多個領域的公司有過合作。著有微服務領域著作《微服務設計》