為什么用Eclipse,VS Code不香嗎?
圖片來(lái)自 Pexels
它作為一個(gè)開源項(xiàng)目,也吸引了無(wú)數(shù)第三方開發(fā)者和終端用戶,成為頂尖開源項(xiàng)目之一。
它在功能上做到了夠用,體驗(yàn)上做到了好用,更在擁有海量插件的情況下做到了簡(jiǎn)潔流暢,實(shí)屬難能可貴。
我是 VS Code 用戶,同時(shí)也為它開發(fā)插件,插件市場(chǎng)里的眾多 Java 插件基本都是我們團(tuán)隊(duì)的作品,所以我在日常工作中觀察到不少 VS Code 在工程方面的亮點(diǎn),下面就來(lái)逐一探討。
簡(jiǎn)潔而聚焦的產(chǎn)品定位,貫穿始終
你知道 VS Code 的開發(fā)團(tuán)隊(duì)人數(shù)只有二十出頭嗎?
難以相信吧,大家都覺得 VS Code 無(wú)所不能,如此強(qiáng)大的工具那么幾個(gè)人怎么做得出來(lái)。
實(shí)際上功能豐富是個(gè)美好的錯(cuò)覺,因?yàn)榇蟛糠轴槍?duì)特定編程語(yǔ)言和技術(shù)的功能都是第三方插件提供的,VS Code 的核心始終非常精簡(jiǎn),這很考驗(yàn)產(chǎn)品團(tuán)隊(duì)的拿捏能力:做多了,臃腫,人手也不夠;做少了,太弱,沒(méi)人用。
他們團(tuán)隊(duì)選擇了專注于核心功能的開發(fā),為用戶提供簡(jiǎn)潔流暢的體驗(yàn),并將該思路貫穿在產(chǎn)品開發(fā)的每個(gè)環(huán)節(jié)。在我看來(lái),這就是第一個(gè)亮點(diǎn)。
第一個(gè)亮點(diǎn)同時(shí)也是一個(gè)難點(diǎn),因?yàn)?“簡(jiǎn)潔” 說(shuō)到底是產(chǎn)品的 “形態(tài)”,更關(guān)鍵的其實(shí)是前置問(wèn)題——產(chǎn)品的定位,它到底解決什么問(wèn)題。
該問(wèn)題如果從用戶的角度來(lái)看,可以轉(zhuǎn)換為以下幾個(gè)點(diǎn):
- 我們?yōu)槭裁葱枰粋€(gè)新的工具?
- 它到底是代碼編輯器 (Editor) 還是集成開發(fā)環(huán)境 (IDE)?
讓我們來(lái)看看項(xiàng)目負(fù)責(zé)人 Erich Gamma 的說(shuō)法:
這張截圖它闡述了 VS Code 的定位:編輯器+代碼理解+調(diào)試。這是一個(gè)非常節(jié)制而平衡的選擇,專注于開發(fā)者 “最常用” 的功能,同時(shí)在產(chǎn)品的形式上力求簡(jiǎn)潔高效。從結(jié)果來(lái)看,這個(gè)定位是相當(dāng)成功的。
在這個(gè)定位的指導(dǎo)下,這二十多位工程師搞出了 VS Code。相對(duì)較小的功能集,使得開發(fā)者們能在代碼質(zhì)量上精益求精,最終用戶們也得到了一個(gè)性能優(yōu)異的工具,這是 VS Code 從一眾編輯器中脫穎而出的重要原因。
正因?yàn)楫a(chǎn)品定位以及團(tuán)隊(duì)職責(zé)上的高度節(jié)制,團(tuán)隊(duì)成員才能把時(shí)間花在這類問(wèn)題上,寫出經(jīng)得起考驗(yàn)的代碼。
與此同時(shí),較小的團(tuán)隊(duì)也使得團(tuán)隊(duì)成員做到了行為層面的整齊劃一,這點(diǎn)在社區(qū)互動(dòng)上體現(xiàn)得尤為明顯。
大家可以去 GitHub 上看他們的 Issues,超出產(chǎn)品定位范疇的請(qǐng)求和反饋基本都被婉拒或者轉(zhuǎn)交到第三方插件項(xiàng)目,可以說(shuō)是很專注了。
看到這里,似乎一切都好,但問(wèn)題來(lái)了,碼農(nóng)千千萬(wàn),你用 Node 我用 Go,你搞前端我弄后臺(tái),VS Code 如何滿這些五花八門的需求呢?
機(jī)智的你已經(jīng)搶答了——海量插件。那么接下來(lái)我們來(lái)深究一下 VS Code 是如何經(jīng)營(yíng)一個(gè)龐大的插件生態(tài)的。
進(jìn)程隔離的插件模型
通過(guò)插件來(lái)擴(kuò)展功能的做法已經(jīng)是司空見慣了,但如何保證插件和原生功能一樣優(yōu)秀呢?歷史告訴我們:不能保證。
大家可以參考 Eclipse,插件模型可以說(shuō)是做得非常徹底了,功能層面也是無(wú)所不能,但存在幾個(gè)煩人的問(wèn)題:不穩(wěn)定、難用、慢,所以不少用戶轉(zhuǎn)投 IntelliJ 的懷抱。可謂成也插件,敗也插件。
問(wèn)題的本質(zhì)在于信息不對(duì)稱,它導(dǎo)致不同團(tuán)隊(duì)寫出來(lái)的代碼,無(wú)論是思路還是質(zhì)量,都不一致。最終,用戶得到了一個(gè)又亂又卡的產(chǎn)品。
所以要讓插件在穩(wěn)定性、速度和體驗(yàn)的層面都做到和原生功能統(tǒng)一,只能是一個(gè)美好的愿望。
來(lái)看看其他 IDE 是怎么做的,Visual Studio 自己搞定所有功能,并且做到優(yōu)秀,讓別人無(wú)事可做,這也成就了其“宇宙第一 IDE”的美名;IntelliJ 與之相仿,開箱即用,插件可有可無(wú)。
這么看起來(lái),自己搞定所有的事情是個(gè)好辦法,但大家是否知道,Visual Studio 背后有上千人的工程團(tuán)隊(duì),顯然,這不是 VS Code 這二十幾號(hào)人能搞定的。
他們選擇了讓大家來(lái)做插件,那怎么解決 Eclipse 所遇到的問(wèn)題呢?
這里分享一個(gè)小知識(shí)——Eclipse 核心部分的開發(fā)者就是早期的 VS Code 團(tuán)隊(duì)。
嗯,所以他們沒(méi)有兩次踏入同一條河流。與 Eclipse 不同,VS Code 選擇了把插件關(guān)進(jìn)盒子里。
這樣做首先解決的問(wèn)題就是穩(wěn)定性,這個(gè)問(wèn)題對(duì)于 VS Code 來(lái)說(shuō)尤為重要。都知道 VS Code 基于 Electron,實(shí)質(zhì)上是個(gè) Node.js 環(huán)境,單線程,任何代碼崩了都是災(zāi)難性后果。
所以 VS Code 干脆不信任任何人,把插件們放到單獨(dú)的進(jìn)程里,任你折騰,主程序妥妥的。
插件與主進(jìn)程隔離
VS Code 團(tuán)隊(duì)的這一決策不是沒(méi)有原因的,正如前面提到的,團(tuán)隊(duì)里很多人其實(shí)是 Eclipse 的舊部,自然對(duì) Eclipse 的插件模型有深入的思考。
Eclipse 的設(shè)計(jì)目標(biāo)之一就是把組件化推向極致,所以很多核心功能都是用插件的形式來(lái)實(shí)現(xiàn)的。
遺憾的是,Eclipse 的插件運(yùn)行在主進(jìn)程中,任何插件性能不佳或者不穩(wěn)定,都直接影響到 Eclipse,最終結(jié)果是大家抱怨 Eclipse 臃腫、慢、不穩(wěn)定。
VS Code 基于進(jìn)程做到了物理級(jí)別的隔離,成功解決了該問(wèn)題。實(shí)際上進(jìn)程級(jí)別的隔離也帶出了另一個(gè)話題,那就是界面與業(yè)務(wù)邏輯的隔離。
UI 渲染與業(yè)務(wù)邏輯隔離,一致的用戶體驗(yàn)
“不穩(wěn)定” 之后的問(wèn)題是 “難用”,具體來(lái)說(shuō)就是混亂的界面和流程,究其原因就是插件之間的界面語(yǔ)言的 “不一致”,它導(dǎo)致學(xué)習(xí)曲線異常陡峭,并且在面臨問(wèn)題時(shí)沒(méi)有統(tǒng)一的解決路徑。
VS Code 的做法是根本不給插件們 “發(fā)明” 新界面的機(jī)會(huì)。
如上圖,插件們被關(guān)在 Extension Host 進(jìn)程里,而 UI 則在主進(jìn)程里,所以插件們天然沒(méi)法直接在用戶界面上做手腳。
VS Code 統(tǒng)管所有用戶交互入口,制定交互的標(biāo)準(zhǔn),所有用戶的操作被轉(zhuǎn)化為各種請(qǐng)求發(fā)送給插件,插件能做的就是響應(yīng)這些請(qǐng)求,專注于業(yè)務(wù)邏輯。
但從始至終,插件都不能 “決定” 或者 “影響” 界面元素如何被渲染(顏色、字體等,一概不行),至于彈對(duì)話框什么的,就更是天方夜譚了。
VS Code 對(duì)于用戶界面的把控可以說(shuō)是謹(jǐn)慎到變態(tài),做過(guò)插件的人都懂的,感興趣的同學(xué)可以去深挖一下 TreeView 的歷史,會(huì)有更直觀的體會(huì)。
乍一看,第三方開發(fā)者被卡得死死的,這樣不是限制了大家的創(chuàng)造力嗎?我想說(shuō)這個(gè)做法跟這個(gè)團(tuán)隊(duì)的背景密切相關(guān),換一撥人很有可能會(huì)失敗。
他們之所以能成功,是因?yàn)樵搱F(tuán)隊(duì)在開發(fā)工具領(lǐng)域深耕多年,他們把經(jīng)驗(yàn)轉(zhuǎn)換為觀點(diǎn),最終落實(shí)到了 VS Code 的界面元素以及交互語(yǔ)言上,從結(jié)果來(lái)看,廣受歡迎。
界面和業(yè)務(wù)邏輯的徹底隔離,使得所有插件有了一致的行為,用戶就得到了整齊劃一的體驗(yàn)。
不僅如此,這種接口和行為層面的一致性,最終轉(zhuǎn)化成了另一個(gè) “偉大” 的功能——Remote Development,我們稍后討論。
接下來(lái)我們要聊的是 VS Code 另一個(gè)創(chuàng)舉——Language Server Protocol。
LSP:基于文本的協(xié)議
前文提到了 VS Code 定位中的兩個(gè)特色:代碼理解和調(diào)試,絕大部分都由第三方插件來(lái)實(shí)現(xiàn),中間的橋梁就是兩大協(xié)議——Language Server Protocol (LSP) 和 Debug Adapter Protocol (DAP)。
兩者從設(shè)計(jì)的角度來(lái)看高度相似,我們著重看一下最火的 LSP。首先,為什么需要 LSP?
全棧開發(fā)早已成為這個(gè)時(shí)代的主流,軟件從業(yè)者們也越來(lái)越不被某個(gè)特定的語(yǔ)言或者技術(shù)所局限,這也對(duì)我們手里的金剛鉆提出了新的挑戰(zhàn)。
舉個(gè)栗子,我用 TypeScript 和 Node.js 做前端,同時(shí)用 Java 寫后臺(tái),偶爾也用 Python 做一些數(shù)據(jù)分析,那么我很有可能需要若干工具的組合。
這樣做的問(wèn)題就在于需要在工具間頻繁切換,無(wú)論從系統(tǒng)資源消耗和用戶體驗(yàn)的角度來(lái)看,都是低效的。
那么有沒(méi)有一種工具能在同一個(gè)工作區(qū)里把三個(gè)語(yǔ)言都搞定呢?沒(méi)錯(cuò),就是 VS Code——支持多語(yǔ)言的開發(fā)環(huán)境,而多語(yǔ)言支持的基礎(chǔ)就是 Language Server Protocol (LSP)。
該協(xié)議在短短幾年內(nèi)取得了空前的成功,到目前為止,已經(jīng)有來(lái)自微軟等大廠以及社區(qū)的一百個(gè)實(shí)現(xiàn),基本覆蓋了所有主流編程語(yǔ)言。
同時(shí),它也被其他開發(fā)工具所采納,比如 Atom、Vim、Sublime、Emacs、Visual Studio 和 Eclipse,從另一個(gè)角度證明了它的優(yōu)秀。
更難能可貴的是,該協(xié)議還做到了輕量和快速,可以說(shuō)是 VS Code 的殺手級(jí)特性了,同時(shí)也是微軟最重要的 IP 之一。
哇塞,又強(qiáng)大又輕巧,怎么看都是個(gè)騙局啊,那我們就來(lái)看看它到底怎么做到的。
先劃重點(diǎn):
- 節(jié)制的設(shè)計(jì)
- 合理的抽象
- 周全的細(xì)節(jié)
先來(lái)說(shuō)說(shuō)設(shè)計(jì) (Design),大而全是很常見的問(wèn)題。如果讓我來(lái)設(shè)計(jì)這么一個(gè)用來(lái)支持所有編程語(yǔ)言的東西,第一反應(yīng)很可能是搞個(gè)涵蓋所有語(yǔ)言特性的超集。
微軟就有過(guò)這樣的嘗試,比如 Roslyn——一個(gè)語(yǔ)言中立的編譯器,C# 和 VB.NET 的編譯器都是基于它做的。
大家都知道 C# 在語(yǔ)言特性層面是非常豐富的,Roslyn 能撐起 C# 足以說(shuō)明它的強(qiáng)大。
那么問(wèn)題來(lái)了,為啥它沒(méi)有在社區(qū)得到廣泛應(yīng)用呢?我想根本原因是 “強(qiáng)大” 所帶來(lái)的副作用:復(fù)雜、主觀(Opinionated)。
光是語(yǔ)法樹就已經(jīng)很復(fù)雜了,其他各種特性以及他們之間的關(guān)系更是讓人望而卻步,這樣一個(gè)龐然大物,普通開發(fā)者是不會(huì)輕易去碰的。
相較之下,LSP 顯然把小巧作為設(shè)計(jì)目標(biāo)之一,它選擇做最小子集,貫徹了團(tuán)隊(duì)一貫節(jié)制的作風(fēng)。
它關(guān)心的是用戶在編輯代碼時(shí)最經(jīng)常處理的物理實(shí)體(比如文件、目錄)和狀態(tài)(光標(biāo)位置)。
它根本沒(méi)有試圖去理解語(yǔ)言的特性,編譯也不是它所關(guān)心的問(wèn)題,所以自然不會(huì)涉及語(yǔ)法樹一類的復(fù)雜概念。
它也不是一步到位的,而是隨著 VS Code 功能的迭代而逐步發(fā)展的。所以它自誕生至今依然保持著小巧的身材,易懂,實(shí)現(xiàn)門檻也很低,迅速在社區(qū)得到了廣泛的支持,各種語(yǔ)言的 Language Server(LS)遍地開花。
小歸小,功能可不能少,所以抽象就非常關(guān)鍵了。LSP 最重要的概念是動(dòng)作和位置,LSP 的大部分請(qǐng)求都是在表達(dá)“在指定位置執(zhí)行規(guī)定動(dòng)作”。
舉個(gè)栗子,用戶把鼠標(biāo)懸停在某個(gè)類名上方,查看相關(guān)的定義和文檔。這時(shí) VS Code 會(huì)發(fā)送一個(gè) 'textDocument/hover' 請(qǐng)求給 LS,這個(gè)請(qǐng)求里最關(guān)鍵的信息就是當(dāng)前的文檔和光標(biāo)的位置。
LS 收到請(qǐng)求之后,經(jīng)過(guò)一系列內(nèi)部計(jì)算(識(shí)別出光標(biāo)位置所對(duì)應(yīng)的符號(hào),并找出相關(guān)文檔),找出相關(guān)的信息,然后發(fā)回給 VS Code 顯示給用戶看。
這樣一來(lái)一回的交互,在 LSP 里被抽象成請(qǐng)求(Request)和回復(fù)(Response),LSP 同時(shí)也規(guī)定了它們的規(guī)格(Schema)。在開發(fā)者看來(lái),概念非常少,交互形式也很簡(jiǎn)單,實(shí)現(xiàn)起來(lái)非常輕松。
看到這里,大家應(yīng)該對(duì) LSP 有了更進(jìn)一步的理解,它本質(zhì)上是膠水,把 VS Code 和各種語(yǔ)言的 LS 粘在一起。但它不是普通的膠水,而是非常有品位的膠水,這品位就體現(xiàn)在細(xì)節(jié)上。
首先這是一個(gè)基于文本的協(xié)議,文本降低了理解和調(diào)試的難度。參考 HTTP 和 REST 的成功,很難想象如果這是一個(gè)二進(jìn)制協(xié)議會(huì)是什么局面,甚至同樣是文本協(xié)議的 SOAP 也早已作古,足以說(shuō)明 “簡(jiǎn)單” 在打造開發(fā)者生態(tài)里的重要性。
其次這是一個(gè)基于 JSON 的協(xié)議,JSON 可以說(shuō)是最易讀的結(jié)構(gòu)化數(shù)據(jù)格式了,大家看看各個(gè)代碼倉(cāng)庫(kù)里的配置文件都是啥格式就知道這是個(gè)多么正確的決定了,現(xiàn)在還有人在新項(xiàng)目里用 XML 嗎?又一次——“簡(jiǎn)單”。
再次,這是一個(gè)基于 JSONRPC 的協(xié)議,由于 JSON 的流行,各大語(yǔ)言都對(duì)它有極好的支持,所以開發(fā)者根本不需要處理序列化、反序列化一類的問(wèn)題,這是實(shí)現(xiàn)層面的 “簡(jiǎn)單”。
從這些細(xì)節(jié)可以看出,VS Code 團(tuán)隊(duì)對(duì)當(dāng)今技術(shù)趨勢(shì)的把握是相當(dāng)精準(zhǔn)的,他們決策充分考慮到了 “簡(jiǎn)單”,牢牢抓住了社區(qū)開發(fā)者的心。
所以重要的事情說(shuō)三遍:
- 在做設(shè)計(jì)的時(shí)候一定要傾向于簡(jiǎn)單
- 在做設(shè)計(jì)的時(shí)候一定要傾向于簡(jiǎn)單
- 在做設(shè)計(jì)的時(shí)候一定要傾向于簡(jiǎn)單
集大成的 Remote Development
去年五月,VS Code 發(fā)布了 Remote Development(VSCRD),有了它,我們可以在遠(yuǎn)程環(huán)境(比如虛機(jī)、容器)里開一個(gè) VS Code 工作區(qū),然后用本地的 VS Code 連上去工作。
下圖說(shuō)明了它的運(yùn)行模式:
VSCRD 從本質(zhì)上改善了遠(yuǎn)程開發(fā)的體驗(yàn),與常用的遠(yuǎn)程桌面共享相比,具體改進(jìn)如下:
- 響應(yīng)迅速:VSCRD 所有的交互都在本地 UI 內(nèi)完成,響應(yīng)迅速;遠(yuǎn)程桌面由于傳輸?shù)氖墙仄廉嬅?,?shù)據(jù)往返延遲很大,卡頓是常態(tài)。
- 沿用本地設(shè)置:VSCRD 的 UI 運(yùn)行在本地,遵從所有本地設(shè)置,所以你依然可以使用自己所習(xí)慣的快捷鍵、布局、字體,避免了工作效率層面的開銷。
- 數(shù)據(jù)傳輸開銷?。哼h(yuǎn)程桌面?zhèn)鬏數(shù)氖且曨l數(shù)據(jù),而 VS Code 傳輸是操作請(qǐng)求和響應(yīng),開銷與命令行相仿,卡頓的情況進(jìn)一步改善。
- 第三方插件可用:在遠(yuǎn)程工作區(qū)里,不僅 VS Code 的原生功能可用,所有第三方插件的功能依然可用;遠(yuǎn)程桌面的話,你得自己一個(gè)個(gè)裝好。
- 遠(yuǎn)程文件系統(tǒng)可用:遠(yuǎn)程文件系統(tǒng)被完整映射到本地,這個(gè)兩者差不多。
那么 VSCRD 做了什么神奇的操作能夠?qū)崿F(xiàn)以上效果呢?來(lái)看看它的架構(gòu)圖:
其實(shí)答案都在前文有所提及:
- 進(jìn)程級(jí)別隔離的插件模型:Extension Host(也就是圖中的 VS Code Server)與主程序做到了物理級(jí)別的分離,那么把 Extension Host 在遠(yuǎn)程或者本地跑沒(méi)有本質(zhì)的區(qū)別。
- UI 渲染與插件邏輯隔離,整齊劃一的插件行為:所有的插件的 UI 都由 VS Code 統(tǒng)一渲染,所以插件里面只有純業(yè)務(wù)邏輯,行為高度統(tǒng)一,跑在哪里都沒(méi)區(qū)別。
- 高效的協(xié)議 LSP:VS Code 的兩大協(xié)議 LSP、DAP 都非常精簡(jiǎn),天然適合網(wǎng)絡(luò)延遲高的情況,用在遠(yuǎn)程開發(fā)上再適合不過(guò)。
VS Code 團(tuán)隊(duì)在架構(gòu)上的決策無(wú)疑是非常有前瞻性的,與此同時(shí),他們對(duì)細(xì)節(jié)的把握也是無(wú)可挑剔。
正因?yàn)橛辛巳绱嗽鷮?shí)的工程基礎(chǔ),VSCRD 這樣的功能才得以誕生,所以我認(rèn)為這是集大成的作品。
還沒(méi)有嘗試過(guò) VSCRD 的同學(xué),這里再安利一下,它在以下場(chǎng)景中非常有用:
- 開發(fā)環(huán)境配置起來(lái)很繁瑣,比如物聯(lián)網(wǎng)開發(fā),需要自己安裝和配置各種工具和插件。
在 VSCRD 里,一個(gè)遠(yuǎn)程工作區(qū)的模板即可搞定,如需安裝額外的工具,也就是改改 Dockerfile 的事情,非常簡(jiǎn)單。在這里可以找到常用的編程語(yǔ)言和場(chǎng)景的模板。
- 本地機(jī)器太弱,某些開發(fā)搞不了,比如機(jī)器學(xué)習(xí),海量數(shù)據(jù)及和計(jì)算需求需要非常好的機(jī)器。
在 VSCRD 里,可以直接操作遠(yuǎn)程文件系統(tǒng),使用遠(yuǎn)程計(jì)算資源。
最后
VS Code 像一顆耀眼的星星,吸引著成千上萬(wàn)開發(fā)者為其添磚加瓦。從 VS Code 的成功中,我們看到了好的設(shè)計(jì)和工程實(shí)踐能創(chuàng)造多少奇跡。
放眼軟件產(chǎn)業(yè),各個(gè)層面的模式不斷被刷新,讓人激動(dòng)之余,也要求從業(yè)者不斷提高技能水平。
從個(gè)人學(xué)習(xí)的角度來(lái)看,了解這些模式誕生的前因后果,理解工程實(shí)踐中的決策過(guò)程是非常有利于提高工程能力的。
作者:李少俠
編輯:陶家龍
出處:zhuanlan.zhihu.com/p/35303567