1. 程式人生 > >如何向小白講述軟體架構發展歷程?

如何向小白講述軟體架構發展歷程?

點選上方“CSDN”,選擇“置頂公眾號”

關鍵時刻,第一時間送達!

作者簡介:kimmking,關注於網際網路電商,金融,支付等系統領域,10多年研發管理和架構經驗,前阿里架構師、某商業銀行北京研發中心負責人,某電商公司高階技術總監。本文來自作者 kimmking 在 GitChat 上分享 「軟體架構發展歷程分享」。

什麼是架構

電腦科學和程式設計的飛速發展,使得軟體設計應用到從航空航天到日常生活的方方面面。單個人開發一段小程式的做法早就過時,大範圍協作的工程化時代隨即到來。

隨著大範圍協作的效率問題和軟體複雜度的爆炸式增長,管理和技術方面的各種不確定性也爆發性增加,導致軟體開發的質量無法得到有效保證,週期和成本無法得到有效控制。

人們一直在尋求找到這些問題的解決辦法。然而 Fred Brooks 在 1975 年出版的軟體工程聖經《人月神話》中說,沒有(能解決所有問題的)銀彈(There is no silver bullet)。

自此,人們發展了專案研發過程管理來控制管理活動的不確定性,同時也發展了軟體架構設計方法來控制技術方面的不確定性。

進而在實踐中不斷的總結和改進,用於有效指導和最大程度的保障軟體開發的質量、週期和成本。

架構的定義

架構(Architecture)一詞源於建築領域,其本身就是建築的意思,也是體系結構的意思。維基百科英文版裡對 Architecture 的解釋是:規劃、設計和建造建築物的過程及產物。

鑑於軟體工程與建築工程一樣是一項系統的工程性工作,引入到計算機領域後,軟體架構就成為了描述軟體規劃設計技術的專有名詞。

特別地,軟體架構師一詞在英文裡,和建築師也是同一個詞(Architect)。

維基百科裡對軟體架構的定義:

軟體架構是有關軟體整體結構與元件的抽象描述,用於指導大型軟體系統各個方面的設計。

軟體架構師定義和設計軟體的模組化,模組之間的互動,使用者介面風格,對外介面方法,創新的設計特性,以及高層事物的物件操作、邏輯和流程。軟體架構是一個系統的草圖。

軟體架構描述的物件是直接構成系統的抽象元件。各個元件之間的連線則明確和相對細緻地描述元件之間的通訊。

在實現階段,這些抽象元件被細化為實際的元件,比如具體某個類或者物件。在面向物件領域中,元件之間的連線通常用介面來實現。

比較公認的軟體架構定義是在 2000 年的 ANSI/IEEE 1471 標準中定義的:

  1. 架構過程:在系統整個生命週期中構思、定義、表達、記錄、交流,驗證合適實現,維護和改進架構的過程,也就是設計過程。

  2. 架構:一個系統體現在其環境中的元素、關係的基本概念或屬性,以及其設計和進化原則。

  3. 架構描述:表達一個架構的工作產出物(通常指的是各種架構圖和設計文件)。

  4. 架構檢視:通過系統的某些關注點的視角,表達一個系統的工作產出物(例如部署檢視、開發檢視等)。

  5. 系統:包含了一個或多個程序、硬體、軟體、工具與可以滿足需求的人的集合。

  6. 環境:決定了開發、操作、策略和其他影響系統的設定和條件。

在 UML 中,架構則被認為是系統的組織結構和相關行為。架構可被分解為通過介面互聯部分的關係,以及相互作用。

通過介面相互作用的部分包括類、元件和子系統。這樣就可以通過 UML 的各種架構圖來描述這些物件和關係,從而表達清楚一個系統的架構。

總結 

軟體架構是一個用於指導系統實現的草圖,這個草圖越詳細對於系統實現的指導意義越重大,貫穿於軟體的整個生命週期。

在建築領域,大樓尚未建造前,就已經存在於建築師的腦海裡;同樣地,系統開始編寫第一行程式碼之前,就已經存在於軟體架構師的心裡。

幾個相關概念

模式(Pattern)

UML 中給出的解釋更通俗易懂:模式是對於普遍問題的普遍解決方案。

我們可以把一類問題的共性抽象出來,這樣就可以用同樣的處理辦法去解決這些問題,從而形成模式,所以模式是一些經驗的總結。

類庫(Library)

類庫是一組可複用的功能或工具的集合,應用系統通過呼叫它們從而達到複用功能的目的。

例如,Windows 應用開發裡的各種靜態或動態連結庫 DLL 檔案,Java 開發中專案裡依賴的或者 Maven 中央庫裡的各種 jar 包,都是 Library,比如 Apache Commons IO、HttpClient,Log4j 等。

框架(Framework)

框架是基於一組類庫或工具,在特定領域裡根據一定的規則組合成的、開放性的應用骨架。

比如 SSM/SSH 框架,更大範圍來說 Dotnet Framework、JDK 都算是一種框架。

關於框架與架構的關係,Vasyl Boroviak 曾在 Stack Overflow 網站上通過兩張圖做了形象的對比,如下所示。

  • 框架:

  • 架構:

模組(Module)

模組是業務或系統的安裝特定維度的一種切分,同時也可以看做是各種功能按照某種分類聚合的一種形式。

例如我們的一個電商系統,可以從業務上劃分為使用者模組、商品模組、訂單模組、支付模組、物流模組、售後模組等。

另一方面,我們也可以說使用者模組聚合了使用者註冊、使用者驗證等業務功能。

元件(Component)

元件是一組可以複用的業務功能的集合,包含一些物件及其行為。

元件可以直接被用做業務系統的組成部分,粒度一般小於模組,也是一種功能的聚合形式。比如日誌元件、許可權元件等。

服務(Service)

服務是一組對外提供業務處理能力的功能,服務需要使用明確的介面方式(比如 WebService 或 Rest 等)。

服務描述裡應該包括約束和策略(比如引數、返回值,使用什麼通訊協議和資料格式等)。

平臺(Platform)

平臺一般來說,是一個領域或方向上的生態系統,是很多解決方案的集大成者,提供了很多的服務、介面、規範、標準、功能、工具等。

例如 J2EE 平臺,包含了企業級應用開發裡的各種基於 Java 語言和 JVM 虛擬機器執行時的技術能力。

知乎社群程式設計領域優秀問題回答者 ze ran 說:

庫是工具箱。

框架是一套通用的解決方案。

架構是高度抽象的需求,是系統中的不變數。

平臺是所有可能做的事的集合。

從軟體的生命週期看架構設計

設計期

在設計期,軟體作為一個成品還不存在,所以我們可以稱之為概念形態。

此時架構師、產品經理或需求分析師等人員利用自己的經驗能力,對系統的業務需求進行分析、拆解、抽象,形成業務文件和技術文件,以及技術驗證程式碼等。

這個階段,架構設計工作是重中之重,其中包括:

  • 系統分拆:如何把系統拆解為不同的子系統、模組、業務單元;

  • 技術選型:使用什麼樣的基礎技術框架或腳手架;

  • 技術驗證:確定核心技術難點如何解決,檢驗能否滿足期望指標;

  • 介面規範:系統的內部不同部分以何種形式確定介面契約和資料通訊;

  • 整合方式:系統與外部其他業務系統如何進行整合;

  • 技術規範:如何規範開發、測試、部署和運維的技術標準性;

  • 部署方案:系統如何進行物理部署,需要多少機器、什麼配置,對網路有什麼要求;

  • 運維方案:系統如何進行技術性運維,如何日常監控、預警報警;

  • ……

這個階段總結一下就是:業務為要,架構先行(包括業務架構和技術架構)。

實現期

這個階段主要是編碼與測試,準備部署上線,是軟體從程式碼到最終的生產系統的過程,我們可以稱之為程式碼形態。此階段需要考慮的技術類工作包括:

  • 確保各項技術規範和技術指標的執行落地,保障高質量的程式碼;

  • 指導研發人員和解決各類技術問題,提升研發團隊效率;

  • 制定測試的技術性方案和基準,自動化、效能、安全等;

  • 配合準備部署環境,運維實施方案落地等。

執行期

這個階段系統上線、驗收通過,已經初步穩定,然後進入維護階段,成為了設計期架構設計草圖的一個可用例項,我們可以稱之為例項形態。此時需要考慮:

  • 釋出上線相關基礎性工作,包括是否使用持續整合(CI)、自動化釋出等技術;

  • 運維基礎性工作,自動化運維,監控等相關技術。

架構的形式與特點

設計文件和程式碼

我們一般說的架構既包括架構的設計過程,也包括設計的產出物,一般可以包括各類設計文件、設計圖,也可以包括一些技術驗證程式碼、Demo 或者其他相關程式。

文件的目的在於準確記錄我們的思維產物,在軟體尚未實現時,作為指導藍圖,儘量精確的描述清楚軟體。

在軟體的實現過程中,可能隨時隨著我們的深入研究,根據具體情況對文件做出區域性的一些調整和修改。

文件作為結項或交接的一部分,也是整個軟體專案的產出物的一部分,成為公司 IT 資產的有機組成部分。

架構服務於業務

正如 19 世紀的偉大建築師路易斯•沙利文(Louis Sullivan)倡導的建築設計著名格言:“功能決定形式(Form follows function)”。

軟體架構首先是要服務於業務功能的。

架構影響研發團隊的組織形式

業務拆分的方法和技術框架的選擇必然會影響到研發團隊的組織形式。

業務拆分的越細緻,越有利於我們更好的對專案的各項指標量化計算,更精確的估計工時和成本,從而指導我們每個小組應該分配多少資源,使用什麼樣的協同和任務確認形式。

並且隨著專案的推進,計劃與實際情況之間的匹配程度也隨時可以進一步精確調整,進而影響到我們應該對每一塊任務的投入資源進行動態調整。

架構存在於每一個系統

每一個已經實現並執行的系統,都是特定架構設計的載體。

有些系統對應的架構,有詳細的設計文件來描述;有些系統的設計文件,殘缺不全,甚至還因為在系統的發展變化的同時,文件沒有更新,導致設計文件與實際系統不符。

有些系統乾脆就沒有設計文件。

但是這些系統,都是基於一定的架構來建立的。

每種架構都有特定的架構風格

每種架構方式,每個具體系統內所體現的架構設計,都是可以被工程師們理解,進而提煉出來一些架構思想和設計原則,這些思想和原則就是這種架構方式的風格。依據這些風格,我們可以將各種架構方式,進行分門別類,從而進一步討論每種架構風格的特點。

架構需要不斷的發展演進

隨著計算機軟硬體的不斷髮展,軟體架構思想也在不斷的發展變化。

另一方面,軟體為其提供業務處理和服務能力的每個具體行業領域也在不斷髮展變化,業務處理流程、參與角色、業務形式不斷的推陳出新。

這就要求我們在系統架構設計時,保持終身學習的精神,持續吸收新思想新知識,保持貼近一線業務群體,隨時因地制宜,調整架構設計,採取最適合當下場景的解決方案。

架構的目標與方法

明確軟體系統架構的一些通用目標,可以使我們更明確如何考慮架構的方向;而瞭解架構的方法和方法論,則讓我們可以知道從哪些角度可以比較全面的描述清楚一個系統的架構設計。

可控性與拆分

對於複雜問題的簡化處理,一個簡單辦法就是分而治之。

按一定的粒度把目標問題進行分解,可以非常有效的提升目標的可控性,使得目標變得更加可以量化、進而優化。

系統按照合適的粒度拆分成不同模組的過程,我們一般稱為模組化。模組化也是軟體工程化的基礎。

在這個基礎上才能夠實現分工合作。

複用性與抽象

複用性一直是軟體設計領域的一個很重要的指標。

複用的一個關鍵是我們對於現有具體問題的抽象,找到各種不同問題中存在的不變性,進而作為一種通用結構來統一處理。

拆成是把整體變成很多區域性,再對區域性分開對待和研究其性質。

反過來,我們按照高內聚的指導思想把一些緊密聯絡的功能聚合後,打包成一個可以整體複用的部分,這就是元件,這個過程就是元件化。

通過元件化,我們可以得到抽象再組合出來很多業務元件。這樣,在更大粒度上實現了功能的複用。

非功能性需求九維目標

(1)高效能

系統必須滿足預期的效能目標,在併發使用者數(Concurrent Users)、併發事務數(Transactions per Second,TPS)、吞吐量(Throughout)等指標方面達到預估值,支撐使用人群的正常使用操作。

(2)可靠性

業務系統直接影響到使用者的經營和管理,因此必須是可靠的。

(3) 穩定性

軟體系統必須是能夠在使用者的使用週期內長期穩定執行的。這要求系統具有一定的容錯能力。

(4)可用性

可用性是指系統在指定時間內的提供服務能力的概率值。我們一般採取叢集、分散式等手段提升系統的可用性。

高可用性是目前系統架構設計方面的一個熱點。

(5)安全性

使用者的業務資料是具有非常高的商業價值,如果被洩露或篡改將會帶來重大損失。

安全性是軟體系統的一個重要的指標,也是架構設計的一個重要目標。

(6)靈活性

軟體系統應該具備滿足不同特點的使用者群和目標市場的能力,更靈活。

(7)易用性

軟體系統必須擁有較好的使用者體驗,便於使用者使用。

(8)可擴充套件性

業務和技術都在不斷的發展變化,軟體系統需要隨時根據變化擴充套件改造的能力。

(9)可維護性

軟體系統的維護包括修復現有的錯誤,以及將新的需求和改進新增到已有系統。

因此一個易於維護的系統對於使用者提出的問題或改進,可以及時的實現高效的反饋和響應支援,同時有效降低維護成本。

基於這些目標,經常有人說:“架構是系統非功能性需求的解決辦法的集合”。

架構的不同風格

典型的企業級應用系統或者網際網路應用系統一般都是通過 Web 提供一組業務服務能力。

這類系統包括提供給使用者操作的、運行於瀏覽器中、具有 UI 的業務邏輯展示和輸入部分,運行於伺服器端、用後端程式語言構建的業務邏輯處理部分,以及用於儲存業務資料的關係資料庫或其他型別的儲存軟體。

根據軟體系統在執行期的表現風格和部署結構,我們可以粗略地將其劃分為兩大類。

(1)整個系統的所有功能單元,整體部署到同一個程序(所有程式碼可以打包成 1 個或多個檔案),我們可以稱之為 “單體架構”(Monolithic Architecture);

(2)整個系統的功能單元分散到不同的程序,然後由多個程序共同提供不同的業務能力,我們稱之為 “分散式架構”(Distributed Architecture)。

再結合軟體系統在整個生命週期的特點,我們可以進一步區分不同的架構風格。

對於單體架構,我們根據設計期和開發實現期的不同模式和劃分結構,可以分為:

  • 簡單單體模式:程式碼層面沒有拆分,所有的業務邏輯都在一個專案(Project)裡打包成一個二進位制的編譯後文件,通過這個檔案進行部署,並提供業務能力;

  • MVC 模式:系統內每個模組的功能元件按照不同的職責劃分為模型(Model)、檢視(View)、控制器(Controller)等角色,並以此來組織研發實現工作;

  • 前後端分離模式:將前後端程式碼耦合的設計改為前端邏輯和後端邏輯獨立編寫實現的處理模式;

  • 元件模式:系統的每一個模組拆分為一個子專案(SubProject),每個模組獨立編譯打包成一個元件,然後所有需要的元件一起再部署到同一個容器裡;

  • 類庫模式:A 系統需要複用 B 系統的某些功能,這時可以直接把 B 系統的某些元件作為依賴庫,打包到 A 系統來使用。

對於分散式架構,我們根據設計期的架構思想和執行期的不同結構,可以分為:

  • 面向服務架構(Service Oriented Architecture):以業務服務的角度和服務匯流排的方式(一般是 WebService 與 ESB)考慮系統架構和企業 IT 治理;

  • 分散式服務架構(Distributed Service Architecture):基於去中心化的分散式服務框架與技術,考慮系統架構和服務治理;

  • 微服務架構(MicroServices Architecture):微服務架構可以看做是面向服務架構和分散式服務架構的拓展,使用更細粒度的服務(所以叫微服務)和一組設計準則來考慮大規模的複雜系統架構設計。

也有人把如上的各個架構風格總結為四個大的架構發展階段:

  • 單體架構階段

  • 垂直架構階段

  • SOA 架構階段

  • 微服務架構階段

這種分類跟前述的方式並沒有多大區別。我們接下來詳細介紹其中的一些重要架構風格。

單體架構:簡單單體模式

簡單單體模式是最簡單的架構風格,所有的程式碼全都在一個專案中。這樣研發團隊的任何一個人都可以隨時修改任意的一段程式碼,或者增加一些新的程式碼。

開發人員也可以只在自己的電腦上就可以隨時開發、除錯、測試整個系統的功能。

也不需要額外的一些依賴條件和準備步驟,我們就可以直接編譯打包整個系統程式碼,建立一個可以釋出的二進位制版本。

這種方式對於一個新團隊的創立初期,需要迅速開始從 0 到 1,抓住時機實現產品最短時間推向市場,可以省去各種額外的設計,直接上手幹活,爭取了時間,因而是非常有意義的。

但是這種方式對於一個系統的長期穩定發展確實有很多壞處的。

首先,簡單單體模式的系統存在程式碼嚴重耦合的問題。所有的程式碼都在一起,就算是按照 package 來切分了不同的模組,各不同模組的程式碼還是可以直接相互引用。

這就導致了系統內的物件間依賴關係混亂,修改一處程式碼,可能會影響一大片的功能無法正常使用。

第二,簡單單體模式的系統變更對部署影響大,並且這個問題是所有的單體架構系統都存在的問題。

系統作為一個單體部署,每次釋出的部署單元就是一個新版本的整個系統,系統內的任何業務邏輯調整都會導致整個系統的重新打包,部署、停機、再重啟,進而導致了系統的停機發布時間較長。

每次釋出上線都是生產系統的重大變更,這種部署模式大大提升了系統風險,降低了系統的可用性。

第三,簡單單體模式的系統影響開發效率。

如果一個使用 Java 的簡單單體專案程式碼超過 100 萬行,那麼在一臺膝上型電腦上修改了程式碼後執行自動編譯,可能需要等待十分鐘以上,並且記憶體可能不夠編譯過程使用,這是非常難以忍受的。

第四,簡單單體模式打包後的部署結構可能過於龐大,導致業務系統啟動很慢,進而也會影響系統的可用性。

這一條也是所有單體架構的系統都有的問題。

第五,擴充套件性受限,也是所有單體架構的一個問題。

如果任何一個業務存在效能問題,那麼都需要考慮多部署幾個完整的例項的叢集,或者再加上負載均衡裝置,才能保證整個系統的效能可以支撐使用者的使用。

所以,簡單單體模式比較適用於規模較小的系統,特別是需要快速推出原型實現,以質量換速度的場景。

單體架構:MVC 模式

MVC 也是一個非常常見的 3 層(3-Tier)結構架構模式,它把每個模組劃分為模型層(Model Layer)、檢視層(View Layer)、控制器層(Controller Layer)等部分。

  • 模型層:代表業務資料實體部分;

  • 檢視層:代表前端的展示部分;

  • 控制器層:代表請求分發,處理排程部分。

更一般地,我們可以新增資料操作層(Data Access Layer)等,形成一個 N 層(N-Tier)結構模型。

整個系統由多個模組組成,每個模組又由這種不同的部分組成。這樣一來,我們就把整個系統拆解成了很多粒度較小的零件。這種方式之所以流行開來,主要是因為:

  • 簡單,直觀,可以非常有效的上手,作為 Web 系統設計的一般方法,這一點是 MVC 模式被普及的基礎條件;

  • 經過上面過程的橫割豎切,我們已經把系統拆解為一個個的小單元,非常有利於分配開發工作,投入大量的工程師進行大規模的工程化開發,這一點非常重要,在軟體行業高速發展的今天,適合工程化的方式才是最具有生產力的辦法;

  • 不同的模組和分層結構,本身就可以作為一個開發層面的子專案拆分結構,這樣我們就可以把系統拆分成多個不同的子專案;

  • 基於 MVC 模式,又陸續發展了 ORM 等簡化資料操作層的技術與框架,以及相應的程式碼生成工具等,極大的提供了軟體開發效率。

當然,MVC 模式也存在定義不夠明確,對於簡單的業務場景拆解過細導致複雜度增加等問題,需要在實踐中不斷摸索和總結應用經驗。

基於單體架構下的 MVC 模式依然解決不了單體架構本身存在的問題,特別是對於可用性和擴充套件性的影響。

單體架構:前後端分離模式

傳統的 Web 系統都是 BS 結構的。

一般的 JSP 或頁面標籤 Tag 技術、後端 FreeMaker 或 Velocity 等模板技術導致 HTML/CSS/JavaScript 等前端技術與後端的處理邏輯和資料耦合到一起,這種方式明顯不符合現代工程化的專業領域細分原則。

特別是隨著富網路應用程式(Rich Internet Application,RIA)概念的興起,Ajax 和 JQuery 框架,前端 UI 元件技術的大行其道,程式設計師們在瀏覽器端寫了很多邏輯處理和介面處理的 JavaScript 程式碼。

後來越來越多的業務邏輯需要在瀏覽器端實現,前端技術逐漸發展到了一個百花齊放的階段,特別是近年來基於 NodeJS 前端技術棧的成功應用,最終使前端技術成為了一個與後端技術領域並駕齊驅的領域。

其實早在 2006 年,ExtJS 作為當時的前端解決方案集大成者,已經實現了前端程式碼邏輯和介面全部都由 JavaScript 完成,後端只提供基於 URL 的 JSON 資料介面。

這樣 Web 系統就由原來的 BS 系統,變成了提供 UI 和互動的前端 B 系統,提供資料介面的後端 S 系統,從而達到了前後端分離的目標。

自從,越來越多的系統採用前後端分離的模式,並且進一步影響了研發團隊的組成:前端團隊負責前端系統開發,後端團隊負責後端系統開發,兩個團隊一起制定前後端系統的資料介面。

只要資料介面保持穩定不變,那麼前後端系統可以各自獨立發展和維護。這一條準則不僅僅是單體架構獨有的,所有的 Web 系統都可以按照這種方式進行設計。

前後端分離模式一直影響到現在的系統架構方法,成為了當下的一種最佳實踐。目前最主流的三種前端開發框架(React、AngularJS、Vue),都遵循著這種設計理念。

分散式架構:面向服務架構(SOA)

  • 服務與 SOA

面向服務架構(SOA)是一種建設企業 IT 生態系統的架構指導思想。SOA 的關注點是服務。服務最基本的業務功能單元,由平臺中立性的介面契約來定義。

通過將業務系統服務化,可以將不同模組解耦,各種異構系統間可以輕鬆實現服務呼叫、訊息交換和資源共享。

(1)從巨集觀的視角來看,不同於以往的孤立業務系統,SOA 強調整個企業 IT 生態環境是一個大的整體。整個 IT 生態中的所有業務服務構成了企業的核心 IT 資源。

各系統的業務拆解為不同粒度和層次的模組和服務,服務可以組裝到更大的粒度,不同來源的服務可以編排到同一個處理流程,實現非常複雜的整合場景和更加豐富的業務功能。

(2)從研發的視角來看,系統的複用可以從以前程式碼級的粒度,擴充套件到業務服務的粒度;能夠快速應對業務需求和整合需求的變更。

(3)從管理的角度來看,SOA 從更高的層次對整個企業 IT 生態進行統一的設計與管理,對訊息處理與服務呼叫進行監控,優化資源配置,降低系統複雜度和綜合成本,為業務流程梳理和優化提供技術支撐。

  • SOA 落地方式

SOA 的落地方式與水平,跟企業 IT 特點、服務能力和發展階段直接相關。目前常見的落地方式主要有分散式服務化和集中式管理兩種。

(1)分散式服務化

網際網路型別的企業,業務與技術發展快,資料基數與增量都大,併發訪問量高,系統間依賴關係複雜、呼叫頻繁,分散式服務化與服務治理迫在眉睫。