許式偉:架構設計的巨集觀視角
本文內容選自 《許式偉的架構課》
在資訊科技高度發展的今天,我們每個人隨時隨地都可以接觸到由程式驅動的智慧電子裝置,包括手機(如 iPhone、oppo 拍照手機)、平板電腦(如 iPad)、手錶(如 iWatch、小天才智慧手錶)、音箱(如天貓精靈)、汽車(如特斯拉)等等。
這些東西背後是怎麼工作的?單就其中的軟體系統而言,這些小小的裝置上往往執行著成千上萬個軟體模組,這些模組是如何如此精密地一起協作的?
對此,我過去接觸過很多的軟體開發工程師,或者架構師,很多人對這些原理也是一知半解,雖然“知其然”,但卻“不知其所以然”。甚至有些朋友可能覺得,學這些有什麼用處呢,在我看來,這部分內容恰恰是我們 成為架構師很重要的一門基礎課 。
為什麼需要建立巨集觀視角?
如同造房子有建築工人(負責搬磚)和建築師(負責架構設計)一樣,軟體系統的開發過程同樣需要有程式設計師(負責搬“磚”)和架構師(負責架構設計)。作為架構師,我們需要的第一個能力是巨集觀的全域性掌控能力。
如果把應用程式比作一座大廈,那麼我們作為大廈的架構師,需要把大廈的結構搭建好,讓程式設計師可以把磚填充進去,我們都知道,一個大廈的結構建得是否穩固,與地基密不可分。
所以,我們首先就需要從大廈的地基開始,熟悉這座大廈。畢竟,你對所依賴的基礎架構瞭解得越全面,做業務架構設計就會越發從容。
介紹基礎架構的知識點並不是讓你真的去實現它們。但你仍然需要懂得它們的核心思想是什麼,知道有哪些資訊是你必須深刻理解的,以便可以更好地駕馭它們。
我們的 整個專欄內容 也會 從基礎架構開始講起,最後逐步過渡到業務架構,到最終完成一個完整應用程式的設計過程。
那麼,在今天的開篇第一篇,我們需要站在巨集觀視角,從基礎架構開始,逐漸來解剖一個應用程式的整體構成,我希望,通過今天的文章,可以讓你對於一個程式的全貌,形成完整的認識。
應用程式的基礎架構
我們想學習一個程式的基礎架構,其實就是弄清楚電腦的工作原理,以及程式的執行原理。
無論是什麼樣的智慧電子裝置,手機也好,汽車也罷,它們都可以稱為“電腦”。所有的電腦都可以統一看作由 中央處理器 + 儲存 + 一系列的輸入輸出裝置 構成。
中央處理器,也就是我們平常說的 CPU,負責按指令執行命令;儲存負責儲存資料,包括我們要執行的命令,也是以資料形式儲存在儲存中的。
每次在開啟電腦的電源後,中央處理器都會從儲存的某個固定位置處開始讀入資料(也就是指令),並且按指令執行命令,執行完一條指令就會繼續執行下一條指令。電腦就這樣開始工作了。
你可能會說,就這麼簡單?是的,就是這麼簡單。
那這麼簡單的話, 為何電腦能夠完成這麼多複雜而多樣化的工作?
這整個過程,在我看來主要依賴兩點。
第一是可程式設計性 。 大體來說,中央處理器(CPU)的指令分為如下這幾類。
-
計算類,也就是支援我們大家都熟知的各類數學運算,如加減乘除、sin/cos 等等。
-
I/O 類,(從儲存讀寫資料)從輸入輸出裝置讀資料、寫資料。
-
指令跳轉類,在滿足特定條件下跳轉到新的當前程式執行位置。
雖然, CPU 指令是一個很有限的指令集,但是 CPU 執行的指令序列(或者叫“程式”)並不是固定的,而是依賴儲存在儲存中的資料—— 由軟體工程師(或者叫“程式設計師”)編寫的軟體來決定。指令序列的可能性是無窮的,這也就意味著電腦能夠做的事情的可能性也是無窮的。
第二是開放設計的外部裝置支援。雖然我們電腦可以連線非常非常多種類的外部裝置,比如鍵盤、印表機、螢幕、汽車馬達等等,但 CPU 並不理解這些裝置具體有什麼樣的能力,它只和這些裝置交換資料。它能夠做的是從某個編號的裝置(通常這個裝置編號被稱為“埠”)讀入一段資料,或者向裝置的埠寫入一段資料。
例如,當你在鍵盤上按下了 A 的時候,CPU 可以從鍵盤連線的埠讀到一段資料,通過這段資料來表達你按了“A”,可能 CPU 會向印表機連線的埠傳送一段資料,來驅動印表機列印特定的文字;還有可能 CPU 會向汽車馬達所在的埠傳送資料,來驅動馬達轉動,從而讓汽車按照預期來行駛。
值得注意的是,CPU 知道的是如何和這些裝置交換資料,但是並不理解資料代表什麼含義。這些外部裝置的廠商在提供裝置硬體的同時,往往也需要提供和硬體匹配的軟體,來完成和 CPU 的協作,讓軟體工程師可以輕鬆使用這些裝置。
從上面可以看出, 電腦的 CPU 是一個非常簡潔的模型,它只讀入和寫出資料,對資料進行計算 。這也是為什麼我們往往把電腦也叫作“計算機”,這是因為 CPU 這個計算機的大腦的確只會做“計算”。
這個基礎的設計體系,我們很多人都知道,這就是馮·諾依曼計算機體系。1945 年 6 月,馮·諾依曼以“關於 EDVAC 的報告草案”為題起草的長達 101 頁的總結報告,定義了“馮·諾依曼體系結構”,他現在也被稱為計算機之父。我想看到這裡,你應該不難理解他的偉大之處了吧?
有了這個基礎的計算機體系之後,我們就可以編寫軟體了。
當然我們遇到的第一個問題是 直接用機器指令編寫軟體太累,而且這些機器指令像天書一樣沒人看得懂 ,沒法維護。
所以, 程式語言 + 編譯器 就出現了。編譯器負責把我們人類容易理解的語言,轉換為機器可以理解的機器指令,這樣一來就大大解放了編寫軟體的門檻。
在編寫軟體不是問題時, 我們遇到的第二個問題,就是多個軟體在同一個電腦上怎麼共處。多個軟體大家往同一個儲存地址寫資料衝突怎麼辦?一起往印表機去傳送列印指令怎麼辦?有的軟體可能偷偷搞破壞怎麼辦?
於是, 作業系統 就出現了。
它 首先要解決的是軟體治理的問題 。它要建立安全保護機制,確保你的電腦免受惡意軟體侵害。同時,它也要建立軟體之間的協作秩序,讓大家按照期望的方式進行協作。比如儲存你寫到這裡,那麼我就要寫到別處;使用印表機要排隊,你打完了,我才能接著去列印。
作業系統其次解決的是基礎程式設計介面問題。這些程式設計介面一方面簡化了軟體開發,另一方面提供了多軟體共存(多工)的環境,實現了軟體治理。
例如,對於螢幕裝置,作業系統需要提供多工視窗系統,以避免螢幕被多個軟體畫得亂七八糟;對於鍵盤輸入裝置,作業系統引入焦點視窗,以確定鍵盤輸入的事件被正確傳送到正確的軟體程式。
你會發現,今天的我們開發軟體的時候,已經處於一些基礎的架構設計之中。像馮·諾依曼計算機體系,像作業系統和程式語言,這些都是我們開發一個應用程式所依賴的基礎架構。
基礎架構解決的是與業務無關的一些通用性的問題,這些問題往往無論你具體要做什麼樣的應用都需要面對。而且,基礎架構通常以獨立的軟體存在,所以也稱為基礎軟體。
例如,我們熟知的 Linux、Nginx、MySQL、PHP 等這些軟體都屬於基礎軟體,這些基礎軟體極大地降低了應用開發的難度。在今天軟體服務化的大趨勢下,很多基礎軟體最終以網際網路服務的方式提供,這就是所謂的“雲端計算”。
完整的程式架構是怎樣的?
講完了程式的地基,讓我們來總覽一下程式的完整架構。
在越強大的基礎架構支撐下,應用程式開發需要關注的問題就越收斂,我們的開發效率就越高。 在我們只需要關注應用程式本身的業務問題如何構建時,我們說自己是在設計應用程式的業務架構(或者叫“應用架構”)。
業務架構雖然會因為應用的領域不同而有很大的差異,但不同業務架構之間,仍然會有許多共通的東西。它們不只遵循相同的架構原則,還可以遵循相同的設計正規化。
一些設計正規化被人們以應用程式框架的方式固化下來。例如,在使用者互動領域有著名的 MVC 框架(如 JavaScript 語言的 Angular,PHP 語言的 Zend,Python 語言的 Django),在遊戲開發領域有各種遊戲引擎(如 JavaScript 語言的 Phaser,C# 語言的 Unity3D),等等。
對於一個服務端應用程式來說,其完整的架構體系大體如下 :
對於客戶端應用程式來說,和服務端的情況會有非常大的差別。客戶端首先面臨的是多樣性的挑戰。
單就作業系統來說,PC 就有 Windows、Mac、Linux 等數十種,手機也有 Android、iOS,Windows Mobile 等等。而裝置種類而言就更多了,不只有筆記本、平板電腦,還有手機、手錶、汽車,未來只會更加多樣化。
第一個想消除客戶端的多樣性,並且跨平臺提供統一程式設計介面的,是瀏覽器。
可能在很多人看來,瀏覽器主要改變的是軟體分發的方式,讓軟體可以即取即用,無需安裝。但從技術角度來說,底層作業系統對軟體的支援同樣可以做到即取即用。
這方面蘋果在 iOS 上已經在嘗試,大家可能已經留意到,如果你一個軟體很久沒有用,iPhone 就會把這個軟體從本地清理出去,而在你下一次使用它時又自動安裝回來。假如軟體包足夠小,那麼這種行為和 Web 應用就毫無區別。不同之處只在於 Web 應用基於的指令不是機器碼,而是更高階的 JavaScript 指令碼。
JavaScript 因為指令更高階,所以程式的尺寸比機器碼會有優勢。但另一方面來說 JavaScript 是文字指令,表達效率又要比機器碼低。但這一點也在發生變化,近年來 WebAssembly 技術開始蓬勃發展,JavaScript 作為瀏覽器的機器碼的地位會被逐步改變,我們前端開發會面臨更多的可能性。
瀏覽器的地位非常特殊,我們可以看作作業系統之上的作業系統。一旦某種瀏覽器流行起來,開發人員都在瀏覽器上做應用,那麼必然會導致底層作業系統管道化,這是作業系統廠商所不願意看到的。
而如果瀏覽器使用者量比較少,那麼通過它能夠觸達的使用者量就太少,消除不同底層作業系統差異的價值就不存在,開發人員也就不樂意在上面開發應用。
我們知道,PC 的瀏覽器之戰打到今天,基本上就剩下 Chrome、Internet Explorer、Safari、Firefox 等。有趣的是,移動瀏覽器的戰場似乎是從中國開始打起的,這就是微信引發的小程式之戰,它本質上是一場瀏覽器的戰爭。
瀏覽器是一個基礎軟體,它能夠解決多大的問題,依賴於它的市場佔有率。但是基於同樣的瀏覽器技術核心也可以構建出跨平臺的應用框架。我們看到 React Native 就是沿著這個思路走的。當然這不是唯一的一條路,還有人會基於類似 QT 這樣的傳統跨平臺方案。
整體來說,對於一個客戶端應用程式來說,其完整的架構體系大體如下:
對於架構師來說,不僅僅只是想清楚業務應該怎麼去做好分解,整個應用從底到最頂層的上層建築,每一層都需要進行各種決策。先做 iOS 版本,還是先做小程式?是選擇 Java 還是 Go 語言?這些都是架構的一部分。
結語
今天,我們從“計算機是如何工作”開始,一起登高鳥瞰,總覽了程式完整的架構體系。
可能有人看到今天的內容心裡會有些擔心:“原來架構師要學這麼多東西,看來我離成為架構師好遠。”
好訊息是:我們就是來打消這個擔心的。如果我們把寫程式碼的能力比作武功招式,那麼 架構能力 就好比內功。內功修煉好了,武功招式的運用才能得心應手。而架構能力的提升,本質上是對你的知識脈絡(全身經絡)的反覆梳理與融會貫通的過程。具備架構思維並不難,而且極有必要。不管今天的你是不是團隊裡的一位架構師,對任何一位程式設計師來說,具備架構思維將會成為讓你脫穎而出的關鍵。
這就像你沒有從事雲端計算行業,但是你仍然需要理解雲端計算的本質,需要駕馭雲端計算。你也不必去做出一個瀏覽器,但是你需要理解它們的思考方式,因為你在深度依賴於它們。
作者介紹:
許式偉,七牛雲 CEO,ECUG 社群發起人。曾就職於金山、盛大,在搜尋和分散式儲存相關技術領域有十幾年的研發經驗。在金山,他以首席架構師的身份主導了 WPS Office 2005 的架構設計和開發。在創立金山實驗室後,作為技術總監主導了分散式儲存開發,後加入盛大創新院,併成功推出“盛大網盤”和“盛大雲”。
這些年,他扛過國產軟體研發的大旗,忍受過在 Office 和盜版夾擊下的艱難求生,經歷過公司轉型和個人轉型交織的洗禮。2011 年,他成為一名創業者,建立了七牛,專注企業級儲存服務。
這個專欄 , 是他第一次完整、系統地分享自己的架構經驗和思考 ,老許將毫無保留地分享自己近 20 年的經驗總結, 讓你一定能夠學有所得 。