作者:張建飛
文章來源:微信公衆号"從碼農到工匠"
架構
什麼是架構?
關于架構這個概念很難給出一個明确的定義,也沒有一個标準的定義。
硬是要給一個概述,我認為架構就是對系統中的實體以及實體之間的關系所進行的抽象描述。
架構始于建築,是因為人類發展(原始人自給自足住在樹上,也就不需要架構),分工協作的需要,将目标系統按某個原則進行切分,切分的原則,是要便于不同的角色進行并行工作。
為什麼需要架構?
有系統的地方就需要架構,大到航空飛機,小到一個電商系統裡面的一個功能元件都需要設計和架構。
我很喜歡《系統架構:複雜系統的産品設計與開發》裡面的一句話:結構良好的創造活動要優于毫無結構的創造活動。
與之相對應的,現在很多靈活思想提倡no design,隻要work就好。期待好的架構可以在疊代中自然湧現。這個想法有點太理想化了,在現實中,隻要能work的代碼,工程師是很少有動力去重構和優化的。
架構師的職責
作為架構師,我們最重要的價值應該是“化繁為簡”。但凡讓事情變得更複雜,讓系統變得更晦澀難懂的架構都是值得商榷的。
架構師的工作就是要努力訓練自己的思維,用它去了解複雜的系統,通過合理的分解和抽象,使哪些系統不再那麼難懂。我們應該努力建構易懂的架構,使得在系統上工作的其他人員(例如設計者、實作者、操作員等)可以較為容易地了解這個系統。
軟體架構
軟體架構是一個系統的草圖。軟體架構描述的對象是直接構成系統的抽象元件。各個元件之間的連接配接則明确和相對細緻地描述元件之間的通信。在實作階段,這些抽象元件被細化為實際的元件,比如具體某個類或者對象。在面向對象領域中,元件之間的連接配接通常用接口來實作。
軟體架構為軟體系統提供了一個結構、行為和屬性的進階抽象,由構件的描述、構件的互相作用、指導構件內建的模式以及這些模式的限制組成。軟體架構不僅顯示了軟體需求和軟體結構之間的對應關系,而且指定了整個軟體系統的組織和拓撲結構,提供了一些設計決策的基本原理。
軟體架構的核心價值應該隻圍繞一個核心命題:控制複雜性。他并不意味着某個特定的分層結構,某個特定的方法論(貧血、DDD等)。
軟體架構分類
在介紹應用架構之前,我們先來看一下軟體架構的分類。
随着網際網路的發展,現在的系統要支撐數億人同時線上購物、通信、娛樂的需要,相應的軟體體系結構也變得越來越複雜。軟體架構的含義也變得更加寬泛,我們不能簡單地用一個軟體架構來指代所有的軟體架構工作。按照我個人了解,我将軟體架構劃分為:
業務架構:由業務架構師負責,也可以稱為業務領域專家、行業專家。業務架構屬于頂層設計,其對業務的定義和劃分會影響組織結構和技術架構。例如,阿裡巴巴在沒有中台部門之前,每個業務部門的技術架構都是煙囪式的,淘寶、天貓、飛豬、1688等各有一套體系結構。而後,成立了共享平台事業部,打通了賬号、商品、訂單等體系,讓商業基礎實施的複用成為可能。
應用架構:由應用架構師負責,他需要根據業務場景的需要,設計應用的層次結構,制定應用規範、定義接口和資料互動協定等。并盡量将應用的複雜度控制在一個可以接受的水準,進而在快速的支撐業務發展的同時,在保證系統的可用性和可維護性的同時,確定應用滿足非功能屬性要求(性能、安全、穩定性等)。
分布式系統架構:分布式系統基本是稍具規模業務的必選項。它需要解決伺服器負載,分布式服務的注冊和發現,消息系統,緩存系統,分布式資料庫等問題,同時架構師要在CAP(Consistency,Availability,Partition tolerance)之間進行權衡。
資料架構:對于規模大一些的公司,資料治理是一個很重要的課題。如何對資料收集、資料處理提供統一的服務和标準,是資料架構需要關注的問題。其目的就是統一資料定義規範,标準化資料表達,形成有效易維護的資料資産,搭建統一的大資料處理平台,形成資料使用閉環。
實體架構:實體架構關注軟體元件是如何放到硬體上的,包括機房搭建、網絡拓撲結構,網絡分流器、代理伺服器、Web伺服器、應用伺服器、報表伺服器、整合伺服器、存儲伺服器和主機等。
運維架構:負責運維系統的規劃、選型、部署上線,建立規範化的運維體系。
典型應用架構
分層架構
分層是一種常見的根據系統中的角色(職責拆分)群組織代碼單元的正常實踐。常見的分層結構如下圖所示:
CQRS
CQS(Command Query Separation,指令查詢分離)最早來自于Betrand Meyer(Eiffel語言之父,OCP提出者)提出的概念。其基本思想在于,任何一個對象的方法可以分為兩大類:
指令(Command):不傳回任何結果(void),但會改變對象的狀态。
查詢(Query):傳回結果,但是不會改變對象的狀态,對系統沒有副作用。
六邊形架構
六邊形架構是Alistair Cockburn在2005年提出,解決了傳統的分層架構所帶來的問題,實際上它也是一種分層架構,隻不過不是上下,而是變成了内部和外部(如下圖所示)。
六邊形架構又稱為端口-擴充卡架構,這個名字更容器了解。六邊形架構将系統分為内部(内部六邊形)和外部,内部代表了應用的業務邏輯,外部代表應用的驅動邏輯、基礎設施或其他應用。
擴充卡分為兩種類型(如下圖所示),左側代表 UI 的擴充卡被稱為主動擴充卡(Driving Adapters),因為是它們發起了對應用的一些操作。而右側表示和後端工具連結的擴充卡,被稱為被動擴充卡(Driven Adapters),因為它們隻會對主擴充卡的操作作出響應。
洋蔥圈架構
洋蔥架構與六邊形架構有着相同的思路,它們都通過編寫擴充卡代碼将應用核心從對基礎設施的關注中解放出來,避免基礎設施代碼滲透到應用核心之中。這樣應用使用的工具和傳達機制都可以輕松地替換,可以一定程度地避免技術、工具或者供應商鎖定。
不同的是洋蔥架構還告訴我們,企業應用中存在着不止兩個層次,它在業務邏輯中加入了一些在領域驅動設計的過程中被識别出來的層次(Application,Domain Service,Domain model,Infrastructure等)
另外,它還有着脫離真實基礎設施和傳達機制應用仍然可以運作的便利,這樣可以使用 mock 代替它們友善測試。
在洋蔥架構中,明确規定了依賴的方向:
- 外層依賴内層;
- 内層對外層無感覺。
COLA應用架構
COLA架構是我團隊自主研發的應用架構,目前已經開源(
https://github.com/alibaba/COLA)。在COLA的設計中,我們充分汲取了經典架構的優秀思想。除此之外,我們補充了規範設計和擴充設計,并且使用Archetype的方式,将架構固化下來,以便可以快速的在開發中使用。
分層設計
COLA的分層是一種改良了的三層架構。主要是将傳統的業務邏輯層拆分成應用層、領域層和基礎實施層。如下圖所示,左邊是傳統的分層架構,右邊是COLA的分層架構。
其每一層的作用範圍和含義如下:1)展現層(Presentation Layer):負責以Rest的格式接受Web請求,然後将請求路由給Application層執行,并傳回視圖模型(View Model),其載體通常是DTO(Data Transfer Object);
2)應用層(Application Layer):主要負責擷取輸入,組裝上下文,做輸入校驗,調用領域層做業務處理,如果需要的話,發送消息通知。當然,層次是開放的,若有需要,應用層也可以直接通路基礎實施層;
3)領域層(Domain Layer):主要是封裝了核心業務邏輯,并通過領域服務(Domain Service)和領域對象(Entities)的函數對外部提供業務邏輯的計算和處理;
4)基礎實施層(Infrastructure Layer)主要包含Tunnel(資料通道)、Config和Common。這裡我們使用Tunnel這個概念來對所有的資料來源進行抽象,這些資料來源可以是資料庫(MySQL,NoSql)、搜尋引擎、檔案系統、也可以是SOA服務等;Config負責應用的配置;Common是通用的工具類。
擴充設計
對于隻有一個業務的簡單場景,對擴充性的要求并不突出,這也是為什麼擴充設計常被忽略的原因,因為我們大部分的系統都是從單一業務開始的。但是随着業務場景越來越複雜,代碼裡面開始出現大量的if-else邏輯。此時除了正常的政策模式以外,我們可以考慮在架構層面提供統一的擴充解決方案。
在擴充設計中,我們提煉出兩個重要的概念,一個是業務身份,另一個是擴充點。
業務身份是指業務在系統唯一辨別一個業務或者一個場景的标志。在具體實作中,我們使用BizCode來表示業務身份,其中BizCode采用類似Java包名命名空間的方式。例如,我們可以用“ali.tmall”表示阿裡天貓業務,用“ali.tmall.car” 表示阿裡天貓的汽車業務,而用"ali.tmall.car.aftermarket"代表這是阿裡天貓的汽車業務的後市場場景。
每個業務或者場景都可以實作一個或多個擴充點(ExtensionPoint),也就是說一個業務身份加上一個擴充點,可以唯一地确定一個擴充實作(Extension)。而這個業務身份和擴充點的組合,我們将其稱之為擴充坐标(ExtensionCoordinate),如下圖所示。這樣,通過業務身份+擴充點,我們就可以從架構層面實作對不同租戶,不同業務,不同場景的擴充定制了。整個阿裡業務中台正是基于這個思想,實作的多業務支撐的。
規範設計
任何事物都是規則性和随機性的組合。規範的意義就在于我們可以将規則性的東西固化下來,盡量減少随心所欲帶來的複雜度,一緻性可以降低系統複雜度。從命名到架構皆是如此,而架構本身就是一種規範和限制,破壞這個限制,也就破壞了架構。
COLA制定了一些列的規範:包括元件(Module)結構、包(Package)結構、命名等。
比如對于元件,我們要求使用COLA的應用都應該遵循如下圖所示的元件劃分:
COLA架構總覽
在架構思想上,COLA主張像六邊形架構那樣,使用端口-擴充卡去解耦技術細節;主張像洋蔥圈架構那樣,以領域為核心,并通過依賴倒置反轉領域層的依賴方向。最終形成如下圖所示的元件關系。
換一個視角,從COLA應用處理響應一個請求的過程來看。COLA使用了CQRS來分離指令和查詢的職責,使用擴充點和中繼資料來提升應用的擴充性。整個處理流程如下圖所示:
應用架構的核心
縱觀上面介紹的所有應用架構,我們可以發現一個共同點,就是“核心業務邏輯和技術細節分離”。
是的,六邊形架構、洋蔥圈架構、以及COLA架構的核心職責就是要做核心業務邏輯和技術細節的分離和解耦。
試想一下,業務邏輯和技術細節糅雜在一起的情況:所有的代碼都寫在ServiceImpl裡面,前幾行代碼是做validation的事,接下來幾行是做convert的事,然後是幾行業務處理邏輯的代碼,穿插着,我們需要通過RPC或者DAO擷取更多的資料,拿到資料後,又是幾行convert的代碼,在接上一段業務邏輯代碼,然後還要落庫,發消息.....等等。
再簡單的業務,按照上面這種寫代碼的方式,都會變得複雜,難維護。
是以,我認為應用架構的核心使命就是要分離業務邏輯和技術細節。讓核心業務邏輯可以反映領域模型和領域應用,可以複用,可以很容易被看懂。讓技術細節在輔助實作業務功能的同時,可以被替換。
最後我們發現,應用架構的道就是:“讓上帝的歸上帝,凱撒的歸凱撒。”
更多技術文章,請微信掃碼關注我的公衆号: 從碼農到工匠
作者簡介:張建飛,阿裡巴巴進階技術專家,2007年雲南大學計算機應用工程碩士,12年軟體設計和應用架構經驗。熱衷于複雜業務分析和代碼複雜度治理,在外企工作6年,阿裡工作5年。