首頁>資訊 >
從軟件歷史看架構的未來:編程不再是精英們的游戲 2021-11-12 12:22:15  來源:36氪

軟件歷史上有過兩次危機,有危機就有變革契機,第一次引出了“結(jié)構化編程”,第二次引出了“面向?qū)ο缶幊獭保⒅苯訉е萝浖こ痰恼Q生。今天我們且不用“第三次軟件危機”這樣的表述,但可以看到的是,從 2010 年左右開始興起的云計算是程序的運行環(huán)境繼“大型計算機”轉(zhuǎn)變到“客戶端 - 服務器”之后的又一場巨變。與前兩次軟件危機帶來的變革契機一樣,現(xiàn)有的許多軟件架構和開發(fā)方法,一定也會在以十年為計數(shù)單位的時間段內(nèi)逐漸被顛覆,而今天你我所談的云原生、微服務等話題,僅僅是這次變革浪潮的開端。那么,軟件開發(fā)的下一個核心矛盾將會是什么?下一個時代的軟件架構會具備何種特征?在今天由極客邦科技舉辦的 ArchSummit 全球架構師峰會 2021(深圳站)上,華為 SaaS 首席軟件教練、《深入理解 Java 虛擬機》系列書籍作者周志明發(fā)表了主題演講《從軟件的歷史看架構的未來》,以下為演講內(nèi)容整理。

1972 年,Edsger Dijkstra 在為圖靈獎頒授典禮所寫的感言文章中說到:“在沒有計算機的時候,也就沒有編程問題;當我們有了簡單的計算機,編程就變成了小問題;而現(xiàn)在我們有了算力規(guī)模龐大的計算機,那編程就成為一個同樣復雜的大問題了。”半個世紀前,Dijkstra 已經(jīng)敏銳洞見了機器算力的提升是編程方法發(fā)展的直接牽引,每當人類掌握了更強的算力,便按捺不住想去解決一些以前甚至都不敢去設想的新問題,由此引發(fā)軟件設計模式的重大變革。

歷史上的軟件危機和契機

計算機剛誕生的年代,硬件規(guī)模還很小,甚至程序員僅憑大腦就足夠記住數(shù)據(jù)在幾 KB 內(nèi)存中的布局情況,理解每條指令在電路中的運行邏輯。此時的計算機盡管運算速度比人類快,但其內(nèi)部卻沒有什么人所不知道的事情;此時的軟件開發(fā)并沒有獨立的“架構”可言,軟件架構與硬件架構是直接物理對齊的。

隨著計算機的快速發(fā)展,直接面向硬件進行的軟件開發(fā)很快觸碰到了瓶頸,人腦的生物局限顯然無法跟上機器算力前進的步伐,當機器強大到世界上最聰明的人都無法為它編寫出合適的程序了,那計算機科學還能繼續(xù)發(fā)展嗎?這便是歷史上第一次軟件危機的根源。

第一次軟件危機,同時也是結(jié)構化編程發(fā)展的契機,結(jié)構化編程扭轉(zhuǎn)了當時直接面向全局數(shù)據(jù)、滿屏 Goto 語句書寫面條式代碼(Spaghetti Code)的編程風氣,強調(diào)可獨立編寫、可重復利用的子過程 / 局部塊的重要性,讓軟件的每個局部都能夠設計專門的算法和數(shù)據(jù)結(jié)構,允許每一位程序員只關注自己所負責的部分,從而在整體上控制住了軟件開發(fā)的復雜度。此時,軟件的架構才開始獨立于硬件物理架構而存在,軟件業(yè)開始出現(xiàn)把控全局設計的架構師與聚焦局部實現(xiàn)的程序員的角色分工。

將軟件從整體劃分成若干個局部,人類能夠以群體配合來共同開發(fā)軟件,使得人與計算機又和諧共處了十余年。不過,機器的算力膨脹仍然在持續(xù),人類群體的溝通協(xié)作能力卻終究有極限。人畢竟不是可復制的程序,每個人都有自己的理解與認知,如何讓各個模塊能準確地協(xié)同工作成了一場災難,這就是第二次軟件危機的根源。

《人月神話》中有一個幾乎每位程序員都聽過的案例:IBM 公司開發(fā) OS/360 系統(tǒng)的投入成本達到了美國“曼哈頓”原子彈計劃的 25%,共有 4000 多個模塊,約 100 萬條指令,超過 5000 人年,耗資數(shù)億美元,即使如此,結(jié)果還是延期交付,在交付使用后的系統(tǒng)中仍發(fā)現(xiàn)大量的缺陷。

渡過第二次軟件危機的過程中,面向?qū)ο缶幊讨鸩饺〈嗣嫦蜻^程的結(jié)構化編程,成為主流的程序設計思想。這次思想轉(zhuǎn)變宣告“追求最符合人類思維的視角來抽象問題”取代了“追求最符合機器運行特征的算法與數(shù)據(jù)結(jié)構”成為軟件架構的最高優(yōu)先級,并一直持續(xù)沿用至今。這次危機還直接導致軟件工程的誕生,如何以系統(tǒng)性的、規(guī)范化的、可定量的方法去高質(zhì)量地開發(fā)和維護軟件成為一門獨立的科學。

云與分布式逐漸成為主流

如果說歷史上的第一、二次軟件危機分別是機器算力規(guī)模超過了人類個體的生理極限,超過了人類群體的溝通極限的話。那么在今天,在云計算的時代,數(shù)據(jù)中心所能提供的算力其實已經(jīng)逼近人類協(xié)作的工程極限。與此算力相符的程序規(guī)模,幾乎也到了無論采用何種工程措施去優(yōu)化過程、無論采用什么管理手段去提升質(zhì)量,都仍然不可避免會出現(xiàn)意外與異常的程度。

大家都相信只要軟件系統(tǒng)由大量人員共同研發(fā),并使其分布在云中大量節(jié)點協(xié)同運行,隨著項目規(guī)模的增大、時間變長,就肯定會有人疏忽犯錯,會有代碼攜帶缺陷,會有電腦宕機崩潰,會有網(wǎng)絡堵塞中斷,總之,必然會受到墨菲定律的無情打擊。

軟件架構要與硬件算力規(guī)模對齊,目前用來適配云計算與分布式的主流架構形式是微服務。微服務興起之時,曾涌現(xiàn)出各類文章去總結(jié)、贊美微服務帶來的種種好處,諸如簡化部署、邏輯拆分更清晰、便于技術異構、易于伸縮拓展應對更高的性能,等等。

這些當然都是重要優(yōu)點,可是,如果不拘泥于特定場景的某個問題,以宏觀的角度來看,前面所列這種種好處都只算是“錦上添花”、是屬于讓系統(tǒng)“更好”的動因,肯定比不上如何確保系統(tǒng)的“生存”來得關鍵。在我看來,從單體到微服務的最根本的推動力,是為了方便某個服務能夠順利地“消亡”與“重生”,局部個體的生死更迭,是關系到整個系統(tǒng)能否可靠續(xù)存的關鍵因素。

舉個例子,在很長的時間里面,企業(yè)應用中采用單體架構的 Java 系統(tǒng),其更新、升級都必須要有固定的停機計劃,必須在特定的時間窗口內(nèi)才能按時開始,必須按時結(jié)束。如果出現(xiàn)了非計劃的宕機,那便是生產(chǎn)事故。但是軟件的缺陷不可能遵循停機計劃來“安排時間出錯”,為了應對缺陷與變化,做到不停機地檢修,Java 曾經(jīng)搞出了 OSGi 和 JVMTI Instrumentation 等復雜的 HotSwap 方案,以實現(xiàn)給奔跑中的汽車更換輪胎這種匪夷所思卻又無可奈何的需求。而在微服務架構的視角下,所謂系統(tǒng)檢修,充其量只是一次服務滾動更新而已,灰度部署新的程序版本,然后導流、測試、發(fā)布即可。

流水不腐,有老朽,有消亡,有重生,有更迭才是生態(tài)運行的合理規(guī)律,如何采用不可靠的部件來構造出一個可靠的系統(tǒng),是軟件架構適配云與分布式算力發(fā)展的關鍵所在。如果系統(tǒng)中局部能擁有獨立的生命周期,在整體架構上有物理隔離的設計,那么即便采用了不可靠部件,在系統(tǒng)外觀察,整體上仍然有可能表現(xiàn)出穩(wěn)定健壯的服務能力。

從云計算到云不可知

我們繼續(xù)順著“軟件架構的演進由人與機器的矛盾所驅(qū)動,逐漸與算力規(guī)模對齊”這條線索,思考軟件開發(fā)的下一個核心矛盾將會是什么?窺探下一個時代的軟件架構會具備何種特征?

我認為,軟件發(fā)展的下一個關鍵矛盾將會是算力規(guī)模超過人應掌握合理知識的極限。經(jīng)過良好設計的分布式系統(tǒng),擁有局部的可再生性,確實能在整體上展現(xiàn)出可靠的服務能力。然而,“良好地設計”一個分布式系統(tǒng)很不容易。今天無限火熱的云原生、微服務、不可變基礎設施、彈性計算、服務網(wǎng)格、無服務器架構、高低零代碼等等,背后都能展開成一整套成體系的開發(fā)或者設計方法。這些新的技術在為人們解決了更復雜軟件問題的同時,也正在把編程這件事情本身的復雜度推向更高層次。

一名剛剛走出校園的大學生,要掌握計算機與程序執(zhí)行的基本原理,要消化完所用編程語言的核心細節(jié),要掌握領域中常用的類庫、框架和工具,要理解分布式系統(tǒng)的服務彈性、容錯、限流等設計技巧,要接觸容器、云原生、函數(shù)計算等運行架構層面的知識,耗費上十年時間都絲毫不奇怪。

在哲學里,有人曾經(jīng)嚴肅研討過“知識膨脹”的問題,說的是人類科學的前沿在不斷拓展,觸及前沿所需的基礎知識也不斷增加,是否會陷入后來者終其一生都無法攢下足夠基礎,導致人類知識陷入止步不前的危機之中。在計算機科學里就更加現(xiàn)實了,知識膨脹直接表現(xiàn)為從畢業(yè)到“35 歲退休”(梗)之前,很多程序員恐怕都很難具備設計分布式架構所需的全面知識。

云與分布式時代,軟件知識看來又到了該“打個結(jié)”的時刻,要設法把那些重要但普適的知識標準化并下沉。好比今天除去少數(shù)專門的領域,大多數(shù)程序員已經(jīng)不再需要關注寄存器、信號、中斷等與機器底層的細節(jié),也不會太關注操作系統(tǒng)內(nèi)存頁 / 段、執(zhí)行調(diào)度器、輸入輸出原理等操作系統(tǒng)底層的細節(jié)。等云數(shù)據(jù)中心徹底成熟,成為主流的程序部署運行環(huán)境后,云與分布式的復雜細節(jié)也同樣會被隱藏起來。

未來軟件如何使用云服務,現(xiàn)階段還很難有定論,但有跡象表明,軟件中的非功能屬性會率先被外置出去,而不會繼續(xù)像現(xiàn)在這樣,在開發(fā)階段鐫刻定型于程序代碼之中。

軟件是以單體還是以分布式運行,需要提供怎樣的 SLA,具體與哪些技術組件進行協(xié)作,通訊中是否要容錯限流等等,都不必在開發(fā)期就鎖定起來,也不必由業(yè)務開發(fā)人員去關注,他們只處理那些承載系統(tǒng)業(yè)務價值的功能屬性。

這種外掛式的軟件架構風格,如同你要上戰(zhàn)場便穿上軍裝,要游泳便穿上泳衣,去舞會便穿上禮服,不同的裝備讓人能適應不同的場景。而那些“可穿戴”的裝備,都是由專業(yè)廠商設計,有質(zhì)量保證,不需要每位編寫代碼的程序員都知道它們應該如何工作。

正在逐漸成熟的 Service Mesh 就展露出一些這方面的特征。Sidecar 以流量劫持的方式,能夠為程序間的網(wǎng)絡通訊額外附加上連接穩(wěn)定性(如重試、熔斷)、安全性(如鑒權、雙向通訊加密)、可管理性和可觀測性,既不依賴人專門去編碼,也不依賴某款語言或者框架的預置能力。

不過,Service Mesh 僅僅能滿足與服務通訊能力相關的治理,而軟件設計所需的能力并不止通訊這一項,開發(fā)者要依賴多種提供不同能力的運行時來搭建軟件,譬如高級語言虛擬機提供執(zhí)行能力、消息隊列提供 Pub/Sub 通知能力、容器編排系統(tǒng)提供生命周期管理能力等等。開發(fā)者使用這些能力時,也面臨與通訊一樣的治理需求。

ShardingSphere 的作者張亮曾經(jīng)在 InfoQ 撰文,提出過 Database Mesh 的設想,把數(shù)據(jù)庫發(fā)現(xiàn)、訪問路由、數(shù)據(jù)分片、讀寫分離、負載均衡等特性從程序代碼中拿出去,也交給 Sidecar 來實現(xiàn)。既然 Service 和 Database 可以 Mesh 化,那 Cache Mesh、MessageQueue Mesh、Storage Mesh 等自然都有了登場的理由。

更進一步,分布式中那些復雜卻有共性的處理技巧,如并行、并發(fā)、狀態(tài)、共識等等,是不是也可以從程序代碼中獨立出去,由 Sidecar 引導至合適的、不特定的部件中妥善處理?最后,一旦云計算服務提供商的技術貨架中大多數(shù)部件和能力被 Mesh 抹掉了差異化特性,剩下都是一致的標準操作,那 Serverless 一直倡導的“后端即服務”(BaaS)便立刻有了無比廣泛的基礎。此時,云數(shù)據(jù)中心就仿佛是一部擁有無限算力的機器與一套有標準接口的操作系統(tǒng),開發(fā)者無需關心程序在哪里執(zhí)行(FaaS),也不再關心程序有哪些依賴(BaaS)。

上面僅談概念恐怕有些抽象,筆者以“如何存儲一個 K/V 值對”為例,來看一下當前的編程與未來設想的編程方式會有什么差別。下面這段代碼是現(xiàn)在隨處可見的大路貨,它具有稍后列舉的幾點問題:

首先,這是一段操作 Redis 的代碼,意味著你需要了解 Redis 的知識,不說實現(xiàn)原理,起碼要知道它的 API 該如何使用,程序代碼也必須引入 Redis 的客戶端 SDK 作為依賴項。

其次,這是一段可運行的 Java 代碼,意味著你需要知道 Redis 的服務位置(如 Host 地址、端口等)、部署方式(如單點、集群、分片情況等)、鏈接信息(如鑒權方式、密碼等),這些其實應該是 SRE 而不是 SDE 的職責。

最后,這是一段在生產(chǎn)環(huán)境容易受到挑戰(zhàn)的代碼,生產(chǎn)可能還需要考慮額外的非功能屬性:要不要啟用連接池?并發(fā)策略是 first-write-wins 還是 last-write-wins ?是否需要支持事務?數(shù)據(jù)能保證什么級別的一致性?要批量操作該怎么辦?假若這些非功能屬性都反映到代碼上,結(jié)果肯定要比現(xiàn)在看到的復雜上不少,其中有一些需求甚至僅憑應用代碼是無法解決的。譬如要支持事務,用 Redis 可以,用 Memcached/Cassandra 就不行;要支持強一致性,用 Etcd/ZooKeeper 可以,用 Redis 就不行。

以上問題,在今天看來其實都算不上真正的問題,去寫程序就該懂得寫程序的知識,但是作為一名業(yè)務開發(fā)人員,目的僅僅是想保存或者讀取一個 K/V 值對而已,要用 Redis、Etcd、Memcached 或關系庫作為存儲、要用哪個云服務商提供的存儲服務、要滿足哪些非功能特性,這些本不該屬于操作意圖的一部分,都應該被隱藏起來。譬如下面這樣來完成 K/V 值對的存儲和訪問:

至于為什么會存在“http://localhost:3500”這樣的服務地址,后面連接的具體是什么存儲服務,這些是 Sidecar 而不是業(yè)務開發(fā)人員需要關心的事情。不同產(chǎn)品與不同云計算服務商之間的差異,被隱藏在相同的操作原語(Primitives)和代表服務標準含義的接口(如 HTTP URL)之下。這樣云計算就自然而然地打破了目前各廠商之間和產(chǎn)品之間的隔閡,順利步入到云不可知(Cloud Agnostic)的階段。這便是對云計算與分布式架構“打個結(jié)”的具體動作。

雖然迄今為止,上述設想距離現(xiàn)實還很遙遠,理論不夠成熟,能在生產(chǎn)環(huán)境中使用的多運行時框架仍處于十分早期階段。譬如上面用于演示的代碼是基于微軟的 DAPR 框架,它在上周才剛剛進入 CNCF 孵化。對這個演示 DAPR 目前也僅僅能處理 K/V 存儲,其它存儲類型(如更為常用的關系庫)目前都還完全沒有考慮。

但我愿意相信這是未來架構演進的一個主要方向,必須把復雜的問題盡量關進籠子,由專業(yè)人員去看護,才能讓普通程序員更好參與軟件開發(fā),甚至通過低 / 零代碼工具的支持,讓那些沒有太多編程知識、卻有豐富領域知識的業(yè)務專家,也能夠獨立制造出優(yōu)秀的軟件產(chǎn)品。

軟件、架構與人

第一次軟件危機在 1950 年代末期初現(xiàn)端倪,結(jié)構化編程思想在 1970 年才被正式提出;第二次軟件危機(連同“軟件危機”這個概念)是在 1970 年北約 NATO 會議上被定義的,要一直到 1990 年代面向?qū)ο蟮脑O計方法成為主流,以及 Scrum、XP 等軟件工程方法被提出后,這次危機才算是畫上句號。

從 2010 年左右開始興起的云計算是程序的運行環(huán)境繼“大型計算機”轉(zhuǎn)變到“客戶端 - 服務器”之后的又一場巨變。與前兩次軟件危機帶來的變革契機一樣,現(xiàn)有的許多軟件架構和開發(fā)方法,一定也會在以十年計數(shù)單位的時間段內(nèi)逐漸被顛覆,今天你我所談的云原生、微服務等話題,僅僅是這次變革浪潮的開端。

與技術變革相伴的,是它對行業(yè)以及對程序員這個群體的影響。

第一次軟件危機期間,世界上最聰明的科學家 / 工程學家在開發(fā)軟件;第二次軟件危機期間,社會中高智商高學歷的精英群體在開發(fā)軟件;云與分布式的時代,軟件開發(fā)者恐怕也不可避免會受到下一輪沖擊。未來的軟件架構對普通程序員應該會是更友善更簡單的,但是對普通程序員友善與簡單的背后,預示著未來的信息技術行業(yè)很可能會出現(xiàn)“階級分層”的現(xiàn)象。

由于更先進的軟件架構已經(jīng)允許更平庸的開發(fā)者也同樣能寫出可運行、可用于生產(chǎn)的軟件產(chǎn)品,同時又對精英開發(fā)者提出更多、更復雜的技術要求。長此以往,在開發(fā)者群體中會出現(xiàn)比現(xiàn)在還要更顯著的馬太效應,迫使開發(fā)者逐漸分層。從如今所有開發(fā)者都普遍被認為是“高智商群體”的狀態(tài),轉(zhuǎn)變?yōu)榇蟛糠止I(yè)化軟件生產(chǎn)工人加上小部分軟件設計專家的金字塔結(jié)構,就如同現(xiàn)在的建筑工人與建筑設計師的關系一般。今天我們經(jīng)常自嘲的 CRUD Boy,隨著軟件產(chǎn)業(yè)日趨成熟,恐怕還會真的會成為現(xiàn)實。

在本次分享中,我避免使用“第三次軟件危機”這樣有嘩眾取寵嫌疑的表述,危機總是與契機同時出現(xiàn),未來的軟件的一定是越來越貼近于普通平民百姓的軟件,但軟件的未來也一定有大量的挑戰(zhàn)與機會在等待著優(yōu)秀的程序員與架構師去承擔。

本文來自微信公眾號 “InfoQ”(ID:infoqchina),作者:周志明,編輯:羅燕珊,36氪經(jīng)授權發(fā)布。

關鍵詞: 架構 精英們 未來

相關閱讀:
熱點
圖片 圖片