從解決方案的角度上來說,我們如今在日常生活和工作中所使用的大部分網路應用程式,無論是基於 Android/iOS 系統的原生應用,還是基於微信/支付寶等平臺的小程式,亦或是基於 Web 瀏覽器開發的應用程式,它們所採用的都一種被稱之為客戶機/伺服器(即 Client/Server,簡稱 C/S)的分散式應用程式架構。在這種架構之下,開發者們可以選擇將應用程式中需要保障資料安全或者進行高速運算的那一部分部署在伺服器上,以便享用伺服器的高效能設定以及能就近維護的便利。然後根據客戶使用的裝置或 Web 瀏覽器來開發相應的客戶機軟體,並讓它來執行應用程式中需要與使用者互動的那一部分任務。這樣做既降低了應用程式部署與維護的成本,也在很大程度上減少了應用程式對使用者那一側的軟硬體依賴。在這篇文章中,我們將聚焦基於這一架構的程式設計議題,並以推薦書目的形式來為讀者規劃在這一課題上的學習路線圖,以供參考。
在學習基於C/S 架構的程式設計時,我們的首要任務就是要理清應用程式的客戶機部分與伺服器部分在該架構下各自所承擔的任務分工。雖然在手機、手錶上都搭載了多核處理器的今天,各型別計算裝置的效能事實上已經日漸趨同,客戶機與伺服器之間的界線有時候也並非是絕對的,但從專案開發與維護的角度來說,做某種程度上的分工安排還是非常有必要的。以我個人的經驗,C/S 架構之下的任務分工通常是這樣的:
客戶機部分在 C/S 架構下所承擔的工作主要是與客戶進行互動,其角色類似於銀行的前臺接待員,所以在術語上往往被稱之為應用程式的「使用者端」或「前端」。在通常情況下,應用程式的前端將負責渲染應用程式的使用者操作介面、處理使用者的操作、向伺服器傳送請求資料並接收來自伺服器的響應資料、維持應用程式的執行狀態,以求提供良好的使用者體驗。總而言之,這部分的開發與維護還將在很大程度上依賴於使用者所在的軟硬體環境。
伺服器部分在 C/S 架構下所承擔的工作主要是資料的處理和維護,其角色類似銀行金庫的管理人員,所以在術語上往往被稱之為應用程式的「伺服器端」或「後端」。在通常情況下,應用程式的後端將為使用者提供只有大型計算機才具備的運算能力以及安全可靠的資料庫服務,它會負責儲存並處理來自應用程式使用者端的請求資料,然後把響應資料返回給使用者端,一般用於處理較為複雜的業務邏輯,包括執行與天體物理相關的運算任務、儲存海量資料等。這部分的開發和維護通常可以不依賴於使用者所在的軟硬體環境。
當然,所有的事情都是一體兩面的,C/S 架構作為一種建構分散式應用程式的解決方案,除了享有上述優勢的同時也是存在著一些劣勢的。首先,由於伺服器端與使用者端是一對多的關係,這意味著伺服器端可能會需要同時處理來自成千上萬個使用者端的請求,這對伺服器的負載能力提出了較高的要求,因此維持伺服器端的穩定性將會成為專案維護階段的一大難題。其次,採用這種架構的應用程式在執行時也會嚴重依賴於使用者所在的網路環境,一旦網路中的某個節點出了問題,例如發生防火牆遮蔽或域名劫持,整個程式就會立即陷入無法執行的尷尬境地。所以,我們開發者在使用該架構來構建應用程式時必須要想好應對這些劣勢的預先安排,例如制定伺服器的負載策略、設定備用伺服器或備用域名等。
在瞭解了應用程式的使用者端與伺服器端在 C/S 架構中各自承擔的任務分工之後,我們就可以根據自己的工作需求來學習在該架構之下程式設計所需要學習的技能及其相關知識了。具體來說,如果想從事的是使用者端部分的開發工作,那麼我們需要學習的就是如何基於瀏覽器技術來開發使用者端應用、如何基於微信/支付寶/位元組跳動等平臺來開發小程式,以及如何使用 Android/iOS 系統框架來進行應用程式開發等方面的知識。而如果想從事的是伺服器端部分的開發工作,那麼我們需要學習的則是如何使用Python、JavaScript、Go 等程式語言及其伺服器端開發框架,並按照 REST 等伺服器端 API 實現規範來開發應用程式的相關知識。下面,讓我們基於上述建議來做一些具體的學習建議和書籍推薦,以供讀者參考。
如果讀者想開發的是基於瀏覽器引擎技術的應用程式使用者端(包括基於 Electron.js 框架構建的 PC/Mac 端桌面應用),那麼,HTML 和 CSS 這兩門標示語言的使用方法是我們首先要學習的基礎技能。其中:
在學習以上兩門標記性語言時,我個人會推薦讀者參考一下《HTML5 and CSS3》這本書。這本篇幅適中的教學將會幫助初學者們快速上手 HTML5 和 CSS3 的許多有用的新功能。例如在這本書中,我們將學會如何通過 HTML5 提供的新標記來為指定內容建立更好的檔案結構,為表單元素建立更好的介面,從而產生更乾淨、更容易閱讀的程式碼,使人和程式都能理解。我們還會學習到如何在不使用 Flash的情況下將音訊、視訊和向量圖嵌入到指定的頁面。你會看到網路通訊端、使用者端儲存、離線快取和跨檔案資訊傳遞是如何減輕現代網路開發的痛苦的。除此之外,我們也會看到,CSS3 是如何簡單地使你的頁面的各個部分具有風格。
接下來是程式語言的部分,由於 JavaScript 在設計之初就是一門專用於操作 HTML/XML 檔案物件的程式語言,這使得它在基於瀏覽器引擎技術的使用者端開發領域取得了絕對優勢的地位,因而自然也就成為了我們在這一領域的必修課。這門語言的主要職責是:
目前,我們通常會以 ECMAScript 5/6 標準(以下簡稱 ES5 和 ES6)為語言規範來使用 JavaScript,尤其其中的 ES6 標準,它為這門語言新增了許多過去需要引入 jQuery 這樣的第三方庫才能使用到的 API,這能幫助我們構建功能更為強大的應用程式使用者端。對於該程式語言的學習,我個人會推薦讀者花一點時間和耐心去閱讀一下《JavaScript 高階程式設計》這本書。
這本書的作者 Nicholas Zakas 是一位世界頂級的 Web 技術專家,現為雅虎公司介面呈現架構師,負責 My Yahoo! 和雅虎首頁等大存取量站點的設計,之前也曾參與過許多世界級大公司的 Web 解決方案開發。。他有足夠的經驗可以帶領讀者學習 JavaScript 這門語言的方方面面。當然了,這本書目前迭代到第三版,內容是基於 ES5 展開的。如果讀者想了解 ES6 部分的內容,也可以去參考該作者的另一本小書:《深入理解 ES6》。
在掌握了上述基本技能及其相關的基礎知識之後,讀者就可以根據自己要應對的具體工作場景來學習一些使用者端開發框架了,學習的目的是提高我們在生產、科研條件下的工作效率。例如:
在 C/S 架構之下,應用的伺服器端開發主要可分為動態頁面和 伺服器端 API 兩種解決方案,這兩種方案在開發應用程式的伺服器端業務時會體現出截然不同的設計思維。下面,就讓我們來分別介紹一下這兩種不同形式的伺服器端業務邏輯,以便讀者能瞭解它們各自擁有的優勢與劣勢,並根據自己的需要進行學習。
伺服器端動態頁面:在 Web 2.0 概念出現之前,我們使用 PHP、ASP 等構建的傳統 Web 應用程式通常使用的都是伺服器端動態頁面技術。這項技術最大的特點是,應用程式的伺服器端將會負責動態生成所有的 HTML 頁面。也就是說,當我們使用 PHP、ASP 這樣的程式語言編寫好帶有模板變數等預留位置的 HTML 模板之後,將由應用程式的伺服器端來負責獲取相關模板變數的值並將其填充到該模板中,以便將其動態渲染成實際可被Web瀏覽器解析的 HTML 頁面。而作為應用程式的使用者端,Web 瀏覽器實際上得到的只是一組靜態的 HTML+JavaScript+CSS 原始碼檔案。
相信讀者也應該或多或少地看出了動態頁面這種伺服器端開發形式存在著一些侷限性了。如果我們採用這種形式來開發基於 C/S 架構的應用程式,就意味著伺服器端不僅要負責資料的增、刪、改、查以及與之相關的大規模計算任務,還至少要負責一部分與人機互動相關的任務。這會給應用程式的專案開發與維護工作帶來以下三個不利的影響。
伺服器端 API:隨著 AJAX 等 Web 2.0 技術,以及手機、平板等行動端裝置的大量普及,業界針對上述問題提出了一種被稱之為「伺服器端 API」的全新解決方案。該方案主張將構建動態頁面的任務完全交付給應用程式的使用者端來執行,而伺服器端所要做的任務就是監聽並解析使用者端發來的請求,並根據解析的結果來進行資料的增、刪、改、查操作及其相關的大規模計算,然後將得到的結果以某種特定的資料格式返回給使用者端。到目前為止,業界流行的伺服器端 API 的實現方案主要有 SOAP、XML-RPC 和 REST 三種。總體而言,對基於伺服器端 API 來實現的應用程式來說,程式設計師們在開發和部署它們時通常會獲得一系列明顯的、相對於其他伺服器端解決方案的優勢。在這裡,我們可以簡單地將這些優勢歸納如下:
當然了,API 這種伺服器端解決方案在具體開發過程中呈現出來的究竟是優勢還是劣勢,最終還得取決於開發者們的具體實現能力。例如,如果我們開發的伺服器端 API 與使用者端之間要使用 HTTP 這種無狀態資料傳輸協定來進行通訊,就需要明白:這樣做雖然有助於減低伺服器的負擔,並讓伺服器端的業務邏輯實現更為獨立,但同時也意味著應用程式的伺服器端無法記錄其使用者端的執行狀態,使用者端必須自行利用相關機制(例如 Sessions 機制)來記錄應用程式的執行狀態,以便在必要時將執行狀態通報給伺服器端,以減少一些不必要的響應資料,這算是在使用伺服器端 API 方案來設計應用程式時需要會設法解決一個問題。
綜合上面的介紹,如果讀者想要學習的是動態頁面的伺服器端解決方案,個人會推薦從 PHP 這門經典的伺服器端指令碼語言開始。在這種學習需求下,《Head First PHP & MySQL》會是一本非常值得一讀的書。當然了,必須再次提醒的是,動態頁面如今已經不是實現應用程式伺服器端的最佳方法了。
而在 SOAP、XML-RPC 和 REST 這三種當下主流的伺服器端 API 方案中,基於 REST 規範的解決方案相較於另外兩種更為簡潔,因此如今越來越多應用程式的伺服器端 API 都採用了該規範來進行設計和實現,例如,亞馬遜就基於 REST 規範設計了其用於圖書查詢的 Web 服務,雅虎提供的 Web 服務也是基於 REST 規範來設計的。如果學習需求是基於 REST 規範的伺服器端解決方案,個人會推薦讀者參考一下《RESTful Web Services》這本書。
這裡需要特別說明的是,雖然上面這本書是使用 Rudy 為程式語言來講解如何實現 RESTful API 的,但 REST 規範本身只是一種伺服器端 API 的設計方案,它與我們具體使用的程式語言是無關的,即使是用 PHP 這類傳統的伺服器端指令碼語言也是可以構建符合 REST 規範的伺服器端 API 的,只不過需要改變一下設計思路,記住現在伺服器端要響應給使用者端的內容通常已經不再是由伺服器端程式碼在執行時動態構建的 HTML 頁面,而是 JSON、XML 等格式的資料資源了。
在文章的最後,讓我們來討論一下全棧開發的問題,並也請允許我為自己的拙作:《JavaScript 全棧開發》做個廣告。因為這本書的起心動念就來自於某年某月某日在 Facebook 上看到的一張名為「如何成為全棧工程師」的圖。該圖中堆疊著一摞足足半人多高的書籍,其中除了最基本的、與 HTML、CSS 相關的書籍之外,還有介紹使用者端程式設計的 JavaScript、Swift 等語言及其框架的書若干本,在伺服器端使用的語言(例如 Java、Go 等)及其框架的書又是若干本,最後再加上關於 MySQL、SQLite3 這類資料庫的以及關於 Apache 伺服器的書。這樣總體看下來,全棧開發的初學者要讀的各類書籍大概率會累計到十幾本以上,想一想都令人生畏。問題是,這真的是必要的嗎?
誠然,時下的全棧工程師確實是一個熱門且要求不低的求職方向。該方向要求程式設計師們必須瞭解一個網際網路應用從使用者端到伺服器端之間所涉及到的全部技術棧,因而被稱之為「全棧」,但需要提醒讀者的一件事是:這裡所要求的「全棧」並不等同於「全知全能」。即在大多數情況下,全棧工程師在職場中的優勢並不在於他一人能幹完所有的事,這在現代網際網路應用專案的開發中幾乎是不可能的,做幾倍的 996 工作量都不現實。畢竟,這類專案的開發通常是一個非常複雜的系統工程,需要團隊合作。而學習過軟體工程理論讀者一定都知道,專案的規模越大,溝通成本就越高,全棧工程師真正的優勢是他的技術視野。這其中的道理很簡單,大型開發團隊的溝通成本是非常巨大的,如果隸屬於不同技術棧的程式設計師彼此不能理解對方的技術問題,各說各話,那麼他們之間就一定會起衝突的。而如果團隊之中存在著幾位全棧工程師,這個問題就可以得到很好的解決,因為他們懂產品、懂設計、懂前端、懂後端,自然彼此都能聽得懂。而且,全面的技術視野也有助於做出更加全面客觀的技術架構和決策,從而對所在組織產生很大的正面影響。
所以,要想成為全棧工程師,最重要的任務是要擴充套件自己瞭解的技術棧,而不是去成為一個事必躬親的全能超人。至少在我個人看來,在 Node.js 執行平臺成功地將前端領域的王者 —— JavaScript 語言擴充套件到後端之後,那張圖中(或本文之前)所羅列的書中至少有一半與程式語言相關的問題完全是可以用一本全面介紹 JavaScript 的書來解決的。為了驗證這一設想,我嘗試著開始了之後長達十個月的創作。從 2019 年 9 月 16 日動筆,到 2020 年 7 月 22 日完成初稿,我自己也沒想到寫這樣一本小書竟然花了近一年的時間,以及需要花費我如此之多的體力,背傷如影隨形,汗水日日如雨,實現理想之路從來不會暢行無阻,今日回首,一切依然都是值得的。畢竟在我把自己關在家裡埋頭寫作的這段時間裡,外面的世界發生瞭如此巨大而劇烈的變化,暴虐的自然,醜陋的世界讓人感慨萬千。我應該慶幸自己選擇了「讀書寫作」這條通往桃花源的小徑,「問今是何世,乃不知有漢,無論魏晉」某種程度上真是何等的幸運,不然,請擡頭看看如今世上有那麼多莫名其妙的憤怒和亢奮。在那經歷了無數分岔的小徑盡頭,我們能聽到陶淵明、博爾赫斯那輕聲細語的傳世之言。