作者|Ionut Balosin 譯者|薛命燈
要 點設計軟體架構圖並非一件輕而易舉的事情,即使是很簡單的一個架構圖也可能會出錯。有意義且具備一致性的架構圖有助於為不同的利益相關者澄清事實,並達成共識。
在大多數情況下,問題的根源並不在於是否使用了一門有效的架構描述語言(比如 UML),而在於低估了架構圖的重要性,轉而依賴不恰當或不具備一致性的指導性原則,或者缺乏架構思維。
在創建架構圖的過程中,試著混合使用自動生成的圖元和手動創建的圖元,這樣可以減少工作量,並且可以表達出各方面的關注點,覆蓋到系統的各個層面。
系統不斷地發生演化,要維護更新架構圖需要花費額外的精力。我們需要知道如何有效地應對這種情況,同時能夠保持架構圖的一致性和健壯性。
現代的軟體架構帶來了更多的複雜性,這些都反映在了架構圖上。
手動分割線
曾幾何時,我們的每一個軟體項目都需要一個架構圖。不管我們是否遵循正式的架構模型(比如 Kruchten 4+1、Rozanski & Woods 等),都有必要通過圖表來對應用程序的某些部分進行文檔化。
在軟體架構里,這些圖表一般都是按照某些視圖進行設計的,這些視圖本身就是模型的一部分,不過在這篇文章里,我傾向於使用架構圖這個術語,因為它看起來不是那麼正式,至於其他方面的內容並不會在這篇文章里涉及到。
作為一個軟體架構師和技術培訓師,從我的經驗來看,不同項目之間以及同一個團隊的不同開發人員之間創建架構圖的方式也是很不一樣的。
我看到過很多問題,比如 一致性 問題、碎片化 問題、信息粒度大小 的問題,以及 圖表的外觀 問題。相比架構模型的正式和標準化,架構圖倒是不必要那麼正式或者遵循什麼標準。
不過,架構圖必須是 自描述 的,並且要具備 一致性 和足夠的 準確性,能夠 與代碼相呼應。這也就是為什麼架構師或軟體工程師在創建架構圖時需要依賴各種指導性原則,因為它們是 理解應用架構(比如結構、元素、關係、屬性、原則)的基石,同時也是具有不同技術背景和關注點的利益相關者的溝通基礎。
當前架構圖的不足之處在深入展開說明之前,我想引用一句英語諺語:「一張圖片勝過千言萬語」。Wiki 上解釋說,「這句諺語的意思是,一個複雜的想法可以通過一張靜態的圖片表達出來,或者圖片可以表達一個主題的意思,又或者圖片比文字描述來得更加直接有效」。
對於架構圖來說也是一樣的:如果它所導致的疑問比它能解釋的問題還要多,那麼它就不是一張好的架構圖。一張好的架構圖不需要多餘的文字解釋!
一張不是很好的架構圖
現在讓我們來過一下不好的架構圖都有哪些問題,這些問題會阻礙我們創建好的架構圖。
方框或其他形狀表示什麼意思?
隨意使用方框或其他形狀可能會引起誤解。這些形狀有可能表示數據、代碼或者流程。一個簡單的方框可能會引起多種猜想,所以很有必要顯式地給這些形狀添加有意義的說明。
形狀的邊線表示什麼意思?
在一個糟糕的架構圖裡,形狀的邊線(虛線、點線,等等)可能會引起誤解。邊線是否表示某種組件類型(比如虛線表示容器、微服務、層,等等),或者只是因為設計者想讓架構圖的觀感看起來更加豐富一些?所以,在使用多種邊線或非標準邊線時,要在圖例里提供準確的說明。
線條或箭頭表示什麼意思?
線條或箭頭可以被理解為 數據流(比如從系統 A 到系統 B 的數據流)或 元素間的關係(比如組件 A 依賴組件 B)。在大多數情況下,箭頭所表示的關係或數據流並不會總是匯聚到同一個方向上,所以很有必要在圖例里說明清楚。
線條或箭頭表示哪一種類型的交互或關聯?
儘管線條可以表示數據流或組件間的關係,但用於表示交互類型(對於數據流而言)或關聯類型(對於關係而言)的線條或箭頭仍然需要詳細說明。
例如,如果使用線條表示數據流,那麼交互類型可以是同步或非同步的,但如果線條表示的是關係,那麼關聯類型有可能是指依賴、繼承、實現,等等。這些細節必須在圖例里說明。
顏色代表什麼意思?
一個使用了多種顏色的架構圖卻沒有適當的文檔說明很容易引起誤解(比如為什麼有些方框是綠色的,而其他是紅色的?為什麼有些線條是黑色的,而有些是藍色的?)。
顏色在架構圖裡的作用不是非常大,添加太多的顏色並不會給架構圖帶來更多有價值的信息。一個僅僅使用了黑白兩色的架構圖也應該是不言自明的,除非非常有必要使用特定的顏色來強調圖中的某些部分。
在任何情況下都要保持顏色的簡單性,如果一定要用多種顏色,不要忘了添加說明。
單獨的元素或實體
如果架構圖中出現了單獨的元素或實體,說明架構圖有可能是不完整的。不管是從結構還是從行為角度來看,每一個元素或實體都應該依賴系統的其他部分,或者與它們之間存在某些聯繫。
費解的縮略語或含糊不清的名詞
在為架構圖中的元素添加標籤時,切忌使用費解的縮略語,這樣容易引起困惑。如果沒有恰當的說明,字母的堆疊(比如 TFH、RBPM,等等)就毫無意義,最好在圖例里進行說明(比如 TFH 表示 ticket feed handler,RBPM 表示 rates business process manager)。
在給元素命名時,另一個常見的問題是使用了含糊不清的名詞(比如業務邏輯、集成邏輯),這些名詞並不能做到 自解釋。代碼里可能也會存在這樣的問題,我們建議遵循清晰的代碼原則,使用自解釋的名字。
在架構圖中詳述技術、框架、編程語言、IDE 或開發方法論
架構圖並非以技術、框架、編程語言、IDE 或開發方法論為基礎,它們只是用來實現架構的工具,而不是中心關注點。它們不應該被包含在架構圖裡,不過可以在架構描述里簡述使用它們的理由。
在同一個架構圖裡混雜運行時元素和靜態元素
運行時元素(比如線程、進程、虛擬機、容器、服務、防火牆、數據倉庫,等等)不會出現在編譯階段,而且不應該與靜態元素(比如組件、包、類)同時出現在同一個架構圖裡。針對運行時元素有專門的類型圖(比如併發圖、部署圖),一定要注意區別這兩種元素,儘可能避免把它們混雜在一起。
「稍後詳述」或「稍後解釋」
不包含在架構圖裡的任何信息都有可能丟失,而架構圖裡並沒有額外的地方可以容納口頭說明。所有的口頭說明都會丟失,當其他利益相關者(比如開發人員、架構師)查看架構圖時,他們並不知道原來還有所謂的口頭說明。試著把所有必要的信息都包含在架構圖裡,而不是事後加以說明。
層級衝突或混合抽象
在同一個架構圖裡添加不同層級的抽象可能會導致衝突的出現,因為它們是從 不同的角度 描述問題的。例如,把組件添加到上下文架構圖裡,或者把類加到部署圖裡,這些都會偏離架構圖原先的目的。在創建架構圖時,試著保持相同的抽象層級。
使用混亂或含糊不清的架構圖表達過量的信息或無效的細節
愛因斯坦曾經說過,「凡事應該儘可能簡單,簡單到極致」。對於架構圖來說也是一樣的,我們需要謹慎地選擇信息的層級和粒度,這並不是一件容易的事情,它取決於所使用的架構模型、架構師的經驗和系統的複雜度。
在創建架構圖時可參考的指南除了上面列出的問題清單,還可以參考如下的一些指南來創建更好的架構圖。
選擇最優的架構圖數量
Philippe Kruchten 說過,「架構是一項複雜的工作,只使用單個圖表來表示架構很容易造成莫名其妙的語義混亂」。要對系統進行良好的文檔化,我們不能只使用一種圖表。
不過在創建架構圖的時候,我們也難以確定該使用哪些類型的架構圖以及應該創建多少個。在做出決定之前,我們需要考慮多方面的因素。例如,架構的屬性和複雜度、架構師的技能和經驗、可用的時間、維護成本,以及利益相關者的關注點。
網路工程師可能想看到包含了主機、通信埠和協議的網路模型,資料庫管理員更關心如何系統是如何操作、管理和分佈數據的。所以,我們要選擇最優的架構圖數量,不管這個數字是多少。
糟糕的架構圖(比如缺乏文檔)可能會缺失一些信息,反過來說,如果架構圖太多(比如過度文檔化),那麼用於保持架構圖一致性和更新架構圖的工作量也會相應增加。
保持架構圖的結構一致性和語義一致性
架構圖之間應該在方框、形狀、邊框、線條、顏色等方面保持一致。架構圖的結構外觀應該是一樣的,團隊不同成員創建的架構圖不應該給任何一個利益相關者造成理解上的障礙。理想情況下,可以在所有項目里使用相同的建模工具。
從語義角度來看,所有的架構圖與最新的代碼變更之間以及架構圖與架構圖之間都應該定期保持同步,因為一個架構圖的變更可能會影響到其他架構圖。
同步可以通過手動進行,也可以通過建模工具自動觸發。通過建模工具自動觸發會更好一些,不過這也取決於具體的項目。最終的目的是要保持架構圖和代碼之間的一致性,至於使用什麼樣的方法或工具可以自行決定。
Simon Brown 說,「如果架構圖與代碼失去了聯繫,那麼就無法用來改進架構」。他的話其實是在強調保持語義一致性的重要性。
避免架構圖碎片化
架構圖越多就越難以理解,而且維護起來也很費勁。最直接的後果就是有可能出現碎片化(比如,通過兩到三個架構圖來描述同樣的質量屬性——性能、伸縮性,等等——但每一個架構圖都無法完整地描述它們)。
在這種情況下,建議移除不能反映相關質量屬性的架構圖,或者把它們合併起來。
保持架構圖的可追蹤性
保留架構圖的變更記錄、比較不同版本架構圖之間的不同點,以及可以很容易地進行回退,這些都是很重要的。如果建模工具不支持這幾點,那麼對我們來說可能會是個問題。
最近業界傾向於使用簡單而直接的文本語言來生成架構圖,這樣似乎可以解決可追蹤性問題。這樣做的另一個好處是可以保持架構圖之間的結構一致性。
在架構圖旁邊加上圖例
如果你沒有使用標準的架構描述語言(比如 UML、ArchiMate),那麼就要在圖例里註明每個架構圖元素的用意(比如方框、形狀、邊框、線條、顏色、縮略語,等等)。
如果使用了標準的架構描述語言,只要在圖例里添加關鍵性的架構描述,不需要太多額外的信息,因為看圖的人都知道如何按照標準的描述語言規範來理解你的架構圖。
使用架構描述語言會有不一樣的效果嗎?關於如何在項目里使用正確的架構描述語言有很多不同的看法。有些人認為 UML 太過死板,用來做架構設計缺乏靈活性,在某種程度上我認同這個看法。
有時候,在不依賴 UML 的 profile 和 stereotype 特性的情況下也能很好地完成架構圖設計。至於說到其他的架構描述語言,我認為 ArchiMate 更加強大,相比 UML,它更適合用來為企業系統建模。
還有 BPMN,它更專註業務流程的建模。對這些工具進行深入比較已經超出這篇文章的範圍,所以不再累述。
在選擇架構描述語言時,綜合性和靈活性是首要考慮的因素。但據我所知,完全不使用架構文檔的情況也很常見。有些人覺得創建架構文檔是一件很無聊的事情,而且覺得它們沒有什麼意義。
這樣的項目應該不在少數。人們因為沒有使用合適的架構描述語言,所以創建不出很好的架構圖,相反,如果他們使用了更好的工具,結果可能會大不一樣。
但事實並非如此,實際上他們跟本不想去創建什麼架構文檔(包括架構圖),更糟糕的是,他們可能不知道該如何創建架構圖。這是我們首要解決的問題——了解文檔的重要性以及如何創建它們(給軟體工程師做培訓),然後選擇合適的工具。
在系統和架構發生變化時如何更新架構圖?更新架構圖有幾種方式,我將會介紹其中的三種。
第一種,也是最簡單的一種,就是直接從代碼生成架構圖。這樣可以保證架構圖與代碼是一致的。不過目前的工具還不能完全支持這種方式,在沒有人工介入的情況下,工具還無法基於代碼生成精確且有意義的架構圖。
Len Bass 說,「在最理想的開發環境里,只需要一個按鈕就能得到我們想要的文檔」。他指的就是自動生成架構圖,但我們還遠遠沒有達到那種程度。
第二種,先用建模工具創建架構圖,然後生成代碼骨架(比如組件或包、API),隨後開發人員可以在骨架上添加代碼。每次架構圖發生變更,需要從架構圖端重新生成代碼骨架。
第三種,在每次加入新特性時手動更新架構圖。為了保證代碼與架構圖的一致性,建議把更新架構圖作為開發流程的一部分。不過我們不推薦這種方式,因為這樣很容易造成架構圖過時或出現不一致(比如開發人員總是忘記或者不想更新架構圖)。
我的建議是 混合使用現有的工具,結合手動和自動的方式來創建架構圖。例如,嘗試自動生成架構圖,使用工具基於代碼渲染出符合基本要求的架構圖,不包含混亂無用的信息。
架構圖可以高度可變(比如可以適應頻繁的開發變更,這類架構圖一般具有較低層次的抽象),也可以是靜態的。這類圖表可以是上下文架構圖、參考架構圖、包圖、類圖、實體圖,等等。
不過有時候僅僅基於代碼無法生成滿足需求的架構圖,所以在這種情況下,自動創建架構圖不是理想的方式。這個時候需要手動建模作為補充,這類架構圖包括時序圖、狀態圖、併發圖、部署圖、運營圖,等等。
現代架構(如微服務)對架構圖有什麼影響?微服務或其他任何一個現代架構風格(如無伺服器、事件驅動)只會影響到系統的結構、組件間的交互方式(比如組件間的關係)和原則。在我看來,我不認為架構風格會改變架構圖原先的含義。
不過,相比傳統的系統(比如單體),我們所說的現代系統架構具有更高層次的複雜性,它們對架構描述和架構圖確實會有一些影響,這些是我們需要注意的。
我們需要考慮分散式組件(比如分散式微服務)、每種組件的類型、組件間的交互方式(比如邊界、API、消息)、他們的生命周期以及從屬關係。
總 結綜上所述,我們需要在架構圖中體現系統的分解、開發、部署和運維。假設有一個包含了大量微服務的系統,它就會有很多的架構圖,因為每個微服務都可能有自己的架構圖。
一致性(例如,改變一個服務的 API 會影響到其他服務,所有相關的架構圖都需要做出修改)、碎片化(例如,一個架構圖無法反映分散式服務的高可用性和性能)和橫斷面(例如,是誰在負責處理系統的監控或安全問題)問題會讓人手忙腳亂。我們首要面對的挑戰是如何進行良好的團隊協作,不僅僅是開發,也包括後續的維護。
總而言之,現代系統的複雜性會帶來額外的問題,它們會在架構圖層面造成一定程度的影響。
作者介紹Ionut Balosin 是 Luxoft 的軟體架構師,擁有十年以上的應用程序開發經驗,專註性能調優和軟體架構。他是開發大會的演講常客,也是一名技術培訓師。
英文原文傳送:
3 月到 7 月,在 DevOps 平台的成長中成長
最近 k8s 勢頭很火啊,無疑成為了時下最值得關注的技術之一,看來這場容器之戰就要見分曉了!CNUTCon2017 上海站特設「容器編排與管理」專場,邀請了來自 eBay、騰訊、京東的大咖現場分享他們在這方面的最新技術實踐,屆時可以面對面深入交流!目前距離大會開幕倒計時 10 天,點擊閱讀原文先睹為快!