潘愛民:計算機程序的演進——我的程序人生三十年(計算機程序發展史)
【CSDN 編者按】大神潘愛民,編程三十余年,從學生時代興趣出發進入計算機世界,經歷過北大教學科研、微軟亞研系統研究,盛大、阿里的工業研發,走上創業之路,創立指令集進行系統軟件的研發及落地場景應用。《新程序員004》,一起走進潘愛民的程序人生,從中可以一窺過去三十年計算機程序的演進,也可以通過他的視角,看透未來十年的發展。面向未來,潘愛民說,在中國寫代碼的人數將在兩到三年后達到高峰,更將誕生基于中文的編程語言。
作者 | 潘愛民 責編 | 唐小引
出品 | 《新程序員》編輯部
我在 1985 年第一次接觸到計算機程序,盡管那只是娃娃機上的一些作業型的 BASIC 程序,但我依然感受到了編程的樂趣,并且樂此不疲地編寫各種花樣程序。三十多年過去,計算機程序于我而言已經成為一種思考方式,無論是應用層的功能,還是系統層的能力,或者是背后的數據處理邏輯,都轉化成了機器的指令。
我有幸完整地經歷了從 PC 時代,到互聯網的興起與發展,再到移動互聯網,又到萬物互聯時代和產業數字化的發展歷程。這三十多年,既是軟件技術和產業的發展期,也是我個人的職業生涯和程序人生。本文介紹我認知中的計算機程序的演進,正好是程序人生三十年的一篇小結。
潘愛民(攝于 1999 年北大工作期間)
軟件棧 —— 從源代碼到機器指令
通常而言,計算機程序是指軟件中的代碼部分。軟件涵蓋的內容要多得多,比如還包括數據、文檔,甚至有硬件(比如加密狗),還可能有相應的服務等。計算機程序則是指一組指示計算機或其他具有信息處理能力的裝置執行各種動作的指令。計算機程序既可以是機器指令的形式(由二進制數 0 和 1 構成的序列,人難以解讀),也可以是人編寫的原始代碼的形式(通常由程序員來解讀和維護)。
過去三十多年軟件技術的發展,可以從程序編寫方式和運行方式來看待其中的變化。典型的有以下一些方式:
1. 代碼直譯執行
早期的程序編寫方式是,程序員按照機器執行指令的思路來控制一臺機器。最典型的是用 C 語言來編寫程序,幾乎每一行代碼都可以對應到一個指令序列,甚至可以在 C 語言源代碼中直接嵌入匯編指令(機器指令的字符描述方式)。
2. 代碼解釋執行
原始的代碼被解釋成一種中間抽象語言描述,再進一步轉換成機器語言被執行。以 Java 語言的哲學思想“一次編寫,到處運行(Write once, run anywhere.)”為基礎,用 Java 語言編寫的程序天然具有跨平臺特性。程序員面對的是一個抽象的計算環境,所編寫的 Java 代碼是如何被執行的,這中間有一個間接層。
3. 虛擬機和容器化
程序員編寫的代碼最終由機器上的 CPU 來執行,隨著計算機硬件能力越來越強,一臺機器可以被虛擬成多臺計算機。源代碼被編譯或者解釋出來的機器代碼,又進一步被映射成一個指令序列。云計算的發展和普及讓這種程序運行方式變成了主流。容器是虛擬機的一種輕量形式,其思想本質上是一致的。
4. 前后端分離
數據顯示用 Web 技術來完成,后端處理用合適的編程語言來完成,兩者之間通過符合 Web 標準的 API 進行通信。將可視化和用戶交互部分單獨劃出來,而不是跟業務邏輯耦合在一起,這是前后端分離的核心思想。
以上四種方式,前三種側重于計算機程序在同一臺機器上被引入了一個或者多個中間層,導致源代碼被多次解釋或映射才到達物理 CPU;第四種方式則是從橫向跨機器的角度將可視化和用戶交互部分與業務邏輯(特別是數據處理)解耦。這些變化與軟件產業的發展息息相關。下面幾點值得一提。
-
從源代碼到對應的機器指令,路徑越來越不清晰。在物理機器環境下,源代碼與 CPU 之間隔了一層或多層;在云計算環境下,程序員甚至完全不知道物理上代碼是如何被執行的。這種變化趨勢導致了程序調試和性能優化變得更加復雜和困難。
當程序運行時,業務功能的代碼路徑變長,甚至分布到不同的計算環境中。一個業務邏輯被觸發的地點,與它被處理的地點,之間可能跨了執行環境,甚至跨了網絡。這對于程序員的復合能力要求更高,單一技術棧的程序員將面臨很大的挑戰。
這些編程方式是融合的,有各自的適應場景。隨著互聯網絡的不斷發展,并深入到各個產業中,混合編程方式已經成為軟件行業的主流。對于軟件開發人員,我們需要在深度和廣度上并進:所謂深度,是指對源代碼往下一層遞進執行的理解;所謂廣度,是指對執行鏈從一個執行環境到另一個執行環境遷移過程的理解。
技術的進步是產業發展的內在動力,云計算得益于硬件的極大進步以及虛擬化技術的成熟。反過來,產業的發展又帶動了軟件從業人員的大規模擴大。中國的程序員有數百萬,甚至按有的統計途徑達到了上千萬。這些編程方式的發展與軟件產業的效率有極大的關系。新的軟件技術進步,有可能成倍地提高產業效率,進而又可能導致大量的從業人員需要進行技術變遷。
我始終認為,程序員寫代碼是一種創造活動,這是程序員職業的神圣之處。理想的情況是,程序員所寫的代碼都是創造性的,并且是高價值的,是機器人和人工智能所無法企及的。否則的話,這些工作遲早會被技術的革新取代。如果程序員編寫的代碼只是一些定式化的重復,或者可以用相對簡單的形式化來描述,那么按如今的技術演進,這些代碼可以不用人來編寫了。這是目前很多低代碼或零代碼開發平臺正在努力的目標,也導致了這樣一個趨勢:寫工具是非常有價值的,而不依賴于工具來寫大量邏輯的工作是價值有限的。
研究生期間在宿舍寫代碼
在我職業生涯的前半段,我一直信奉“用二進制的方式來理解程序或系統”,為每一個功能或任務都揣摩底層的指令序列。隨著程序或系統的復雜性增加、云計算及前后端分離模式的普及,我們越來越無法做到精細化地用二進制方式來理解它們了。在這種情況下,對軟件架構的把握變得越來越重要,機緣巧合之下我實現了從系統程序員到軟件架構師的升級。
網絡 —— 無處不在的連接
網絡的發展改變了我們的生活,這是過去將近三十年人類社會最大的變化之一。網絡也同樣改變了計算機程序的運行方式,甚至改變了編程的思想。我們首先看一下網絡本身的演變:
-
初期的網絡是在機房環境或者辦公環境中使用的,網絡的物理形態非常直觀,因為大多數情況下每臺機器都拖著一根線。常用的網絡功能都通過專門的應用程序來完成,比如電子郵件程序、瀏覽器、文件傳輸工具等。網絡功能的程序編寫屬于高級編程技術。
網絡開始普及,家庭和很多公共場所都有了網絡,連接的方式可以是一根線,也可以是 Wi-Fi 無線。在這樣的條件下,越來越多的程序加上了網絡的能力,網絡編程逐漸普及,但仍然屬于高級編程技術。不過,通過很多中間件,編程門檻已經降低。
移動數據網絡的普及。網絡的進步是全面的,包括硬件基礎設施和軟件棧。移動數據網絡相對不穩定,這對于軟件編程是一個挑戰,其復雜性來自于兩個方面:對網絡異常的處理,以及網絡連接涉及到兩方協同。然而,得益于移動操作系統原生提供的網絡基礎功能,網絡編程的門檻被大大降低。
其次,網絡的思想與操作系統密不可分,兩者的演進更是緊密關聯。網絡的核心哲學思想是協議分層,每一層的功能實現只依賴于下一層提供的語義,同時也為上一層提供標準或約定的語義。操作系統也有類似的分層結構,層次越往上,離硬件越遠;越往上,編程的門檻越低。網絡的軟件棧大部分位于操作系統中,相對應地,因網絡帶來的復雜性大部分由操作系統消化掉了,因此應用程序的編寫并不顯著地變得更加困難。譬如,移動數據網絡帶來的復雜性,絕大部分由移動操作系統處理了,它對上面提供的應用開發框架中并沒有暴露出移動數據網絡環境的復雜性。
然而,網絡本身對于應用程序的編寫還是有極大影響的,從軟件設計到代碼編寫都有深遠的影響,以下是一些顯著的變化點。
-
網絡編程最基礎的模式是異步編程,以及對異常的處理和恢復。TCP 和 UDP 不僅是兩個傳輸協議,更是兩種編程思想。它們指導我們如何設計和編寫服務器程序和客戶程序。
對于在網絡環境下運行的程序,我們編寫的可能只是半個程序。另外半個程序可能在完全不熟識的人手里進行開發,可能在地球的另一側,甚至不在地球上。我們需要遵守網絡雙方的約定、遵守對方的規范,或者要有足夠的靈活性來應對可能的意外。
網絡功能容易遭受性能和體驗的問題。網絡往往是一個共享資源,所以它的不穩定通常是可以預料的,編寫網絡功能的時候若處理得好,就有可能化解掉不穩定的因素;若處理不恰當,就會造成性能極差,乃至體驗極差,甚至進程死鎖或崩潰等。從這個角度而言,網絡編程總是有優化改進的空間。
網絡的不穩定帶來了不確定性,導致網絡程序的診斷變得困難。一方面,程序的網絡環境可能會有抖動,導致網絡行為可能無法重現,從而增加了診斷難度;另一方面,網絡程序可能運行在物理上不可達的環境(比如云主機)中,這要求程序員對網絡環境的理解要更加全面,否則難以從現象或錯誤代碼來分析問題的根源。
計算機網絡經歷了大量的技術擇優和淘汰,今天我們享受到的穩定網絡和良好的網絡應用程序是歷史沉淀的結果。硬件上,我們的網絡越來越穩定,無線網絡的基站(或訪問點)之間可以做到無縫切換;軟件上,操作系統解決了大量的網絡復雜性問題,留給應用程序的是相對容易實現的處理邏輯,比如方便處理的 HTTP 協議、無狀態的遠程請求、自動的離線緩存等等。在移動數據網絡的早期,很多應用程序一遇到網絡不穩定,就出現白屏、不響應,為了改善用戶體驗,應用開發人員需要編寫大量的代碼。隨著移動數據網絡的普及和穩定,以及移動操作系統的成熟,這一類應用代碼已經大大減少了。
隨著移動互聯網的發展,我們又邁進了萬物互聯時代,產業數字化如火如荼地進行。網絡上連接的已經不再限于計算機或者個人設備,越來越多各種各樣的設備都連接到互聯網上。網絡技術和操作系統都面臨一次升級,從概念到功能外延都在發生變化。我有幸在從業這么多年以后又趕上一次技術浪潮。在這一輪技術大升級中,面向設備連接的操作系統應運而生,因而我在 2018 年創立了指令集公司,專門從事物聯網操作系統的研發和商業化。
人工智能 —— 從模擬智能到超越人類智能
人工智能的發展代表了人類使用計算的一種追求。計算是一種能力,可以做很多事情,包括科學計算和事務型的任務等;其中人工智能的任務是指,讓機器通過計算,可以像人類一樣擁有智能。自從計算機誕生以來,人工智能的發展經歷了起起落落,但過去三十年間,人工智能學科總體上一直是在向前發展的,下面是人工智能領域的一些典型事件:
-
深藍計算機(IBM 制造),1997 年,深藍擊敗人類象棋冠軍卡斯帕羅夫。
仿生機器人“大狗”(波士頓動力學工程公司研制),2005 年,可以四條腿行走。
阿爾法圍棋(AlphaGo,Google 研發),2016 年,擊敗人類圍棋冠軍李世石。
人臉識別技術應用于移動 App,例如,2015 年馬云在 CeBIT(德國)展會上演示了刷臉支付。
AlphaFold/AlphaFold2(Google 研發),2020/2021 年,基本上攻克了困擾人類科學家已經很久的預測蛋白質折疊結構的問題。
此外,最近 10 年來,大多數汽車制造企業(無論是傳統車企,還是新勢力造車企業)以及一些互聯網科技公司都在研究自動駕駛汽車,并且陸續有一些自動駕駛汽車上市。從以上這些事件我們可以看出,人工智能應用有很多種探索路徑:
-
模擬智能
將人類的思考過程,利用計算能力進行模擬。比較典型的是象棋和圍棋這一類規則化的智力活動,人類的思考過程可以恰當地提煉出來。因此,只要有足夠的存儲和算力支撐,以及人類的經驗模型,就有機會做得比人類還好。
-
利用算法實現智能任務
在許多應用場景中,可利用人工智能算法(主要是深度學習算法)來完成一些明確定義的任務,比如人臉識別、車牌識別、語音識別等等。這一類人工智能應用需要具備兩個條件:足夠多的樣本和足夠強的算力。在過去十年中,移動互聯網的蓬勃發展使得很多業務場景匯聚了足夠多的樣本數據,再結合云計算的發展,因而這一類人工智能應用發展迅速。
-
綜合替代人類,達到人類智能
比較典型的是自動駕駛汽車,以及各種具有復雜決策能力的機器人。自動駕駛汽車可以將人從駕駛任務中解放出來,機器人可以代替人類進入到復雜場景中執行任務。這一類人工智能應用需要綜合各種軟硬件技術,近幾年在產業界是一個科創熱點。
-
超越人類智能
探索未知領域,造福人類。比較典型的是在一些科研領域,結合了人工智能的技術以后獲得了革命性的突破,例如上文提到的 AlphaFold2 使蛋白質折疊結構預測問題得到了突破,達到了原本人類通過實驗無法做到的結果。
人工智能的核心三要素是數據、算力和算法。算力是計算的物理基礎,數據是計算的原料,算法是計算的邏輯,其最終形式即軟件代碼。人工智能的發展催生了大量的數據工程師和算法工程師崗位。數據工程師負責采集數據,對它們進行各種處理,歸集起來以供算法使用;算法工程師負責實現各種算法,或者調用一些通用的算法來完成特定的任務。經過多年的發展,目前有很多算法庫已經沉淀下來,有不少以開源的方式供業界使用,例如 TensorFlow、PyTorch、Ray 和 SparkML 等。
算法的編程尤其要關注性能,以確保算法的性能足夠優,這不是一項簡單的任務,它需要扎實的底層系統知識,甚至要理解硬件架構。一方面,數據的傳遞和分布對于一個大計算量的算法是非常重要的;另一方面,在眾多計算節點中,要避免出現單點性能瓶頸。有很多的領域專家在使用人工智能算法時,并不洞悉底層計算平臺的配置要求,或者未能正確地使用計算庫,從而造成資源浪費或者計算時間過長,這在實踐中較為常見。
我有機會在之江實驗室建設一個大計算裝置,稱為智能計算數字反應堆,其旨在搭建一個大計算平臺。該數字反應堆可以聚合多種異構算力資源,并通過一些計算框架或者算法庫,為各種應用(包括科學發現、數字經濟、工業仿真等,稱為應用反應堆)提供統一的計算平臺??梢韵胂螅坏┯辛诉@樣的計算設施,將人工智能算法與各個領域模型結合起來,在局部領域超越人類智能將會成為一種發展模式。
可視化和用戶交互 —— 從 GUI 到數字孿生
在應用軟件開發工程中,可視化和用戶交互部分往往會占據相當大的比例。寫這部分程序邏輯的工程師往往比較受歡迎,因為他們可以快速搭建出一些看得見效果的程序。在當前如火如荼的產業數字化形勢下,除了數據工程師,可能最受歡迎的就是做可視化和用戶交互開發的工程師了。在過去三十年中,主流的用戶交互和可視化軟件技術有過幾次變遷:
-
原生的 GUI(來自于操作系統的支持)
在 1990 年代早期,編寫用戶界面往往要直接面對操作系統提供的 API。為了做出好看又整齊有美感的圖形界面,程序員不僅要熟悉操作系統的窗口管理和圖形 API,還要精通計算機圖形學,甚至還需要懂色彩美學。更要緊的是,程序的交互界面部分的代碼量極大,并且這些代碼對于硬件顯示器和操作系統版本的兼容性非常不友好。
-
應用編程框架中的 GUI
通過應用編程框架來實現圖形用戶界面,可以有效地解決直接在原生 GUI 基礎上編寫交互界面邏輯的不足,因此從 1990 年代中后期開始誕生了很多應用編程框架,最為經典的當屬微軟的 MFC 應用編程框架,以及跨平臺支持的 Qt。Java 環境提供了用戶交互和可視化支持,.NET 也提供了強大的圖形用戶界面開發功能。
-
圖形界面交互引擎
對于用戶界面動態性要求高的應用程序,譬如它們的數據是動態的,或者表單是動態可配置的,它們傾向于內置一個圖形界面交互引擎,從而將可視化界面的渲染效果和交互事件的處理流程控制在自己的程序內部。比較典型的渲染和交互引擎是 Apple 支持的 WebKit 引擎(其前身是 KHTML)、Adobe 的 Flash 引擎,以及 Google 的 Chromium 瀏覽器引擎(源自 WebKit 和 V8 引擎)。當 Adobe Flash 還在如日中天(2010 年)的時候,業界曾經引發過 Flash 和 HTML5 哪個是未來的爭論。
-
B/S 架構
經過多年的發展,可視化和用戶交互逐漸趨向于標準化——HTML CSS JavaScript,這正是前文提到的前后端分離的基礎。前提是每個前端環境都有 Web 瀏覽器(Browser),前端邏輯運行在瀏覽器中,它們通過 HTTP 或 HTTPS 協議與后端(Server)進行通信。這種架構與云計算的服務器虛擬化完美地切合起來。應用程序可以部署在云上,用戶只需通過一個瀏覽器,就可以在任何聯網的地方看到程序運行的結果,并且進行交互。
圖形用戶界面的技術演進經歷了“單機圖形顯示優化——圖形用戶界面標準化——圖形用戶界面前后端分離”這一過程,主流的可視化交互界面開發形式在往高效率方向發展,架構也趨向合理。然而,這些開發方式并非簡單的替代關系,每一種方式在今天的產業環境中,也仍然有它適用的軟硬件環境。
在 PC 互聯網時期,可視化和用戶交互技術側重于渲染性能和響應及時性的不斷提升;在移動互聯網時期,除了性能要求以外,動態性是一項更為側重的需求,很多應用程序中的頁面內容和交互邏輯需要方便地定制;而到了產業互聯網時期,可視化和用戶交互又有了新的需求和趨勢,以下兩方面的發展值得特別提一下:
1. 低代碼開發平臺
顧名思義,低代碼開發平臺是指只需少量的代碼,甚至無需編寫代碼,就可以完成應用程序的開發。這是在云計算虛擬化成熟以后,發生在應用層軟件開發的一種新模式。在產業數字化場景中存在大量動態的數據可視化需求,這就催生出了各種頁面定制工具,進一步擴展就形成了低代碼開發平臺。低代碼開發平臺的優勢在于:低門檻準入、生成頁面快捷,以及頁面測試流程短等。
2. 數字孿生
數字孿生首先在工業領域中被提出并發展起來,后來被應用于建筑和城市數字化,進而被各行各業所采用。數字孿生將物理世界與數字空間連接起來進行映射,并形成反饋。數字孿生涉及到的技術很廣泛,主要包括物聯網技術(用于物理世界數字化以及從數字空間反饋回物理世界)、數據建模(構建數字空間中的孿生體)、3D 可視化(將數字空間中的孿生體呈現出來)、GIS 和 BIM(在數字空間中建立起一致的坐標系)等。
過去三十年間,可視化和用戶交互技術,從初期要解決最基本的渲染效果、性能以及可用性等問題,到逐漸形成系統性的、高生產效率的解決方案和平臺工具,這使得軟件開發工程可以花越來越少的人力在可視化和用戶交互方面,而更多關注在軟件業務本身。得益于圖形界面交互引擎的不斷發展,以及人工智能技術的進步,未來越來越多的可視化和用戶交互工作將由機器來完成,最終做到零代碼開發。
在我近幾年的實踐中,我們團隊充分利用了可視化和用戶交互技術的進步,在指令集物聯網操作系統中內置了孿生模型和低代碼開發平臺。這樣做的一個直接好處是,對于每個用戶場景,只要設備接入進來,它就自然成為了孿生模型的一部分,參與到業務模型中,并且能夠在可視化界面中顯現出來。這種做法可以極大地提高物聯場景的數字化效率。
對程序技術進步的預測
前面回顧了過去三十年重要的程序技術進步,最后我們也展望一下未來。我按照接下來十年可能發生的事情來描述:
-
操作系統的發展路線將進入一個新的軌道——行業操作系統。
行業操作系統的本質是抓住行業的共性部分,形成一個軟件系統,可復制到該行業中具有顯著共性的硬件計算環境中。典型的例子是汽車操作系統和智慧建筑操作系統。只有可抽象出硬件計算環境和共性需求的行業場景,才能形成行業操作系統。
圖源:CSDN 下載自東方 IC
-
人工智能將會有重大突破,這些突破對人類的生產、生活的改變將是深遠的。
這一輪推動人工智能發展的契機是,各個基礎研究領域在使用計算能力上有了長足的進步。包括生物、醫藥、材料、天文、地理等領域中的研究人員,更加深刻地理解了可以用算力和算法來做什么。AlphaFold 是一個例子,該模式可以擴展到其他領域。
-
公共的數字孿生空間。
很多公共設施設備在數字孿生空間中是開放的,可以被公開網絡通過一個 URI 訪問到,它們構成了一個公共的數字孿生空間。在十年以后設備接入非常方便,若本地網絡的防火墻對一個設備不加限制的話,則該設備接入以后就成為公共數字孿生空間中的一個節點?;谶@一公共的數字孿生空間,也會誕生一些應用和服務。與公共的數字孿生空間相對應的是各個組織的私有數字孿生空間。
-
在中國,寫代碼的人數在 2-3 年后達到高峰,10 年后降低一個數量級。
這兩年產業數字化全面推進,并且都從應用需求做起,勢必造成大量的人員去做應用功能,包括各種數據工程和可視化等。隨著系統工具的完善以及數字化建設回歸理性,寫代碼人員的機會減少。好工具的誕生并普及,將會削減大量的工作崗位。當然,數字化的深入也會帶來新的代碼機會,這就看哪些人的再學習能力強了。
-
誕生基于中文的編程語言,用于應用層邏輯定義。
這個編程語言從某一個行業中誕生,也適用于更多行業。結合 NLP 和其他人工智能技術,我們國家的全民編程有望實現。
以上這些預測是一個程序員的思考,部分也承載著我個人的愿望,甚至是我當前已經在做的工作的延續,或期待要達成的目標。從這個角度來看,這些預測太現實,不夠離譜。
結語
最后,我提一下在計算機程序和編程技術發展背后的兩個基礎原則:
-
隨著計算機程序的使用場景和范圍越來越廣,適應這種廣度擴展的基本手段是分層,即增加層次;
在計算機系統的層次結構中,越是下面的層次,越是提供共性的能力,反之,越往上越個性化。
隨著產業數字化的廣泛推動,行業操作系統就是一個新的層次,而在行業操作系統下面還有一個更加抽象的技術操作系統。所謂計算機程序技術的進步,就是按照這樣的原則使得層次和分工趨向合理。
本文分別從軟件棧、網絡、人工智能以及可視化與用戶交互的角度回顧了過去三十年計算機程序的演進,正好對應了我的程序生涯三十年經歷中的一些感悟。期待未來十年計算機程序技術繼續進步,為人類開啟更加美好的生活和體驗。
作者簡介:潘愛民,指令集創始人兼董事長、之江實驗室智能計算數字反應堆首席架構師。長期從事軟件和系統技術的研究與開發工作,撰寫了大量軟件技術文章,著譯了多部經典計算機圖書,在國內外學術刊物上發表了 30 多篇論文。曾經任教于北京大學和清華大學(兼職),后進入工業界,先后任職于微軟亞洲研究院、盛大網絡和阿里巴巴。主要研究興趣包括移動操作系統、信息安全、大數據、移動互聯網、物聯網和智慧城市。
本文為《新程序員004》內容,二十年前,《程序員》創刊時,我們要全面關注軟件人的成長。今天,我們依然初心不變:在一行行代碼的背后,是一顆顆鮮活的開發者想要改變世界的雄心壯志。因此,《新程序員 004》從潘愛民到 MySQL 之父、MariaDB 創始人 Michael “Monty” Widenius,PostgreSQL 全球開發組聯合創始人 Bruce Momjian,阿里巴巴副總裁賈揚清,著名科技作者吳軍,Vue.js 作者尤雨溪……共談我們的程序人生,我們的技術時代?!缎鲁绦騿T004》即將上市,敬請期待。
速度是 macOS 的兩倍?首個支持 M1 Mac 的 Linux 發行版終于出現!
成就一億技術人