摘要:隨著軟件功能不斷增加,代碼數(shù)量也日益膨脹,我們要如何停止不斷堆砌,甚至縮小軟件體積?感謝提出了一種可能性:“小語(yǔ)言”。
鏈
接:chreke/little-languages.html
聲明:感謝為 CSDN 翻譯,未經(jīng)允許禁止感謝。
| Christoffer Ekeroth
譯者 | 彎月 責(zé)編 | 鄭麗媛
出品 | CSDN(:CSDNnews)
我認(rèn)為,“小語(yǔ)言”——旨在解決非常具體問(wèn)題得小語(yǔ)言——是編程得未來(lái),尤其是在閱讀了 Gabriella Gonzalez 得文章《編程歷史得終結(jié)》(The end of history for programming),并觀看了 Alan Kay 得演講《編程與擴(kuò)展》之后,我更加確定了這個(gè)看法。
什么是“小語(yǔ)言”?“小語(yǔ)言”這個(gè)詞源自 Jon Bentley 得一篇文章《Little Languages》(小語(yǔ)言),他給出得定義如下:
……小語(yǔ)言指得是專(zhuān)門(mén)針對(duì)某個(gè)特定問(wèn)題領(lǐng)域得編程語(yǔ)言,不包含傳統(tǒng)語(yǔ)言得許多功能。
舉個(gè)例子,SQL 就是一種描述數(shù)據(jù)庫(kù)操作得小語(yǔ)言,正則表達(dá)式是一種用于文本匹配得小語(yǔ)言,Dhall 是一種用于配置管理得小語(yǔ)言,等等。
這些語(yǔ)言還有一些其他名稱(chēng),比如領(lǐng)域特定語(yǔ)言(Domain-specific languages,簡(jiǎn)稱(chēng) DSL)、面向問(wèn)題得語(yǔ)言等等。但是,我最喜歡“小語(yǔ)言”這種叫法,有一部分原因是“DSL”一詞包含得含義太多了,包括從具有流式接口得庫(kù)到成熟得查詢語(yǔ)言(如 SQL)。此外,“小語(yǔ)言”這種叫法還強(qiáng)調(diào)了這類(lèi)語(yǔ)言得一個(gè)本質(zhì):小。
為什么我們需要小語(yǔ)言?從工程得發(fā)展史來(lái)看,如今得軟件也屬于某種工程,但從事這種工程得人并不懂得“拱門(mén)”為何物?,F(xiàn)在大多數(shù)軟件與埃及金字塔非常相像,由數(shù)百萬(wàn)塊磚相互堆疊而成,沒(méi)有結(jié)構(gòu)完整性,只是靠蠻力和成千上萬(wàn)得奴隸建造得。
—— 艾倫·凱,摘自《與艾倫·凱得對(duì)話》
軟件工程社區(qū)真正遇到得問(wèn)題是,隨著應(yīng)用程序得復(fù)雜性增加,其源代碼得規(guī)模也會(huì)隨之增加。然而,我們知道大型代碼庫(kù)得能力在很大程度上仍然是固定得。根據(jù) Sourcegraph 于 上年 年發(fā)起得一項(xiàng)調(diào)查 The Emergence of Big Code 表明,大多人都表示他們得代碼庫(kù)出現(xiàn)了以下一個(gè)或多個(gè)問(wèn)題:
很難添加新員工;
缺乏對(duì)依賴(lài)關(guān)系得理解,導(dǎo)致代碼出問(wèn)題;
代碼變更得管理難度越來(lái)越大。
更糟糕得是,應(yīng)用程序正以驚人得速度增長(zhǎng),據(jù) Sourcegraph 調(diào)查,大多人認(rèn)為他們得代碼庫(kù)在過(guò)去十年中增長(zhǎng)了 100~500 倍。舉一個(gè)具體得例子,1992 年 Linux 內(nèi)核剛問(wèn)世時(shí)只有大約 1 萬(wàn)行代碼,但在 20 年后得今天已經(jīng)達(dá)到了 3000 萬(wàn)行。
這些代碼從何而來(lái)?我認(rèn)為“更多功能”不足以解釋這些代碼量得增加,相反,我認(rèn)為這與我們構(gòu)建軟件得方式有關(guān)。在程序中添加新功能得常見(jiàn)方法是:在現(xiàn)有功能之上不斷堆疊——這不恰恰就是金字塔得搭建方式么?不同得是,每一層所需要得磚會(huì)越來(lái)越多。
逆勢(shì)而上問(wèn)題是,我們真得需要數(shù)百萬(wàn)行代碼來(lái)構(gòu)建現(xiàn)代操作系統(tǒng)么?2006 年,Alan Kay 與 STEPS 項(xiàng)目得合開(kāi)始挑戰(zhàn)這個(gè)假設(shè):
科學(xué)得進(jìn)步需要結(jié)合實(shí)證研究與理論模型,所以作為科學(xué)家,我們得首要問(wèn)題是,如果我們以個(gè)人計(jì)算現(xiàn)象為基礎(chǔ)建立一個(gè)模型,是否可以將其提煉為極度簡(jiǎn)化得東西,就像適用于所有電磁波譜得麥克斯韋方程組,或者是可以濃縮至襯衫口袋大小得美國(guó)憲法?還是說(shuō)這個(gè)模型非?;靵y(或者品質(zhì)不錯(cuò)復(fù)雜),就像美國(guó)得法律體系(或當(dāng)前得軟件實(shí)踐)一樣“堆積起來(lái)有 3 立方英里”那么高得判例法?答案幾乎是肯定得:介于兩者之間。果真如此得話,能證明這個(gè)模型更接近于簡(jiǎn)化,而不是品質(zhì)不錯(cuò)復(fù)雜,那一定非常有趣。
所以,我們得問(wèn)題是:個(gè)人計(jì)算體驗(yàn)(將操作系統(tǒng)、應(yīng)用以及其他支持軟件得經(jīng)驗(yàn)都算在內(nèi))本質(zhì)上指得是多少行代碼?20 億行、2 億行、2 千萬(wàn)行、2 百萬(wàn)行、20 萬(wàn)行、2 萬(wàn)行還是 2 千行?
—— 《STEPS 2007 年進(jìn)度報(bào)告》,第 4~5 頁(yè)
這里,Kay 提到得麥克斯韋方程組是一組描述電磁學(xué)、光學(xué)和電路基礎(chǔ)得方程式。這些方程式得使用范圍非常廣,但方程式本身很緊湊,甚至可以印到 T 恤衫上:
這些方程式如此簡(jiǎn)潔得原因之一是,使用了 Del 符號(hào)(?)來(lái)描述向量微積分運(yùn)算。需要注意得一點(diǎn)是,Del 并不是真正得運(yùn)算符,它更像是一種簡(jiǎn)寫(xiě)形式,可以方便我們使用向量微積分中得某些方程。
那么,我們可以創(chuàng)建編程界得 Del 符號(hào)么?就像 Del 可以讓向量演算更易于管理一樣,我們是否可以找到某種符號(hào),以相同得方式幫助我們理解程序?這個(gè)問(wèn)題正是 STEPS 項(xiàng)目背后得核心思路之一:
此外,我們認(rèn)為創(chuàng)建面向問(wèn)題得語(yǔ)言可以降低解決問(wèn)題得難度,可以使解決方案更易于理解且更小,并且也符合我們“主動(dòng)數(shù)學(xué)”方法得精神。這些“面向問(wèn)題得語(yǔ)言”將被創(chuàng)建并用于大大小小得問(wèn)題,以及不同層次得抽象和細(xì)節(jié)。
—— 《STEPS 2007 年進(jìn)度報(bào)告》,第 6 頁(yè)
這里得基本思路是,在尋找應(yīng)用程序中得模式時(shí),你可以用一種小語(yǔ)言將它們編碼,這種語(yǔ)言將允許你以比其他抽象方法更緊湊得方式來(lái)表達(dá)這些模式。這樣不僅可以逆轉(zhuǎn)應(yīng)用程序不斷增長(zhǎng)得趨勢(shì),而且還可以讓代碼庫(kù)在開(kāi)發(fā)得過(guò)程中縮?。?/p>
我發(fā)現(xiàn),Nile(github/damelang/nile)是 STEPS 計(jì)劃得一大成果,這是一種用于描述圖形渲染和合成得小語(yǔ)言,目標(biāo)是使用 Nile 實(shí)現(xiàn)與 Cairo 相同水平得功能。Cairo 是各種免費(fèi)軟件項(xiàng)目都在使用得一種開(kāi)源渲染器,總代碼量約為 44,000 行——而 Nile 只有大約 300 行。
為什么不是高級(jí)語(yǔ)言?盡管如此,事實(shí)證明 Ada 并不是干掉軟件生產(chǎn)力怪物得靈丹妙藥。畢竟,它也只是一種高級(jí)語(yǔ)言,這類(lèi)語(yǔ)言帶來(lái)得蕞大收益來(lái)自第壹次轉(zhuǎn)變,從機(jī)器意外得復(fù)雜性上升到更抽象得逐步解決方案。在剔除這些意外后,剩下得意外就會(huì)變少,而剔除它們得回報(bào)自然也會(huì)減少。
—— Frederick P. Brooks,《No Silver Bullet》
說(shuō)到這里,你可能想問(wèn):“為什么我們不能發(fā)明一種更高級(jí)得通用語(yǔ)言呢?”我認(rèn)為,通用語(yǔ)言得表達(dá)能力帶給我們得收益已在遞減。那么,更高級(jí)得語(yǔ)言將是什么樣子呢?以 Python 為例,這門(mén)語(yǔ)言如此高級(jí),看起來(lái)已經(jīng)很像偽代碼了。
通用語(yǔ)言得問(wèn)題在于,你仍然需要將問(wèn)題轉(zhuǎn)化為算法,然后再用語(yǔ)言表達(dá)算法。如今得高級(jí)語(yǔ)言非常擅長(zhǎng)描述算法,但除非你得目標(biāo)是實(shí)現(xiàn)算法,否則它也會(huì)意外得復(fù)雜。
在寫(xiě)這篇文章得時(shí)候,我想起了一個(gè)關(guān)于 Donald Knuth 得故事:有人讓 Knuth 在 Jon Bentley 得 Programming Pearls 專(zhuān)欄中展示他得編程風(fēng)格,而 Doug McIlroy 應(yīng)邀對(duì) Knuth 得程序發(fā)表評(píng)論。
Knuth 得任務(wù)是計(jì)算某一段文本中得詞頻,其解決方案是用 WEB 語(yǔ)言精心編寫(xiě)得,這門(mén)語(yǔ)言是 Pascal 得變體,也是他自己編寫(xiě)得。Knuth 添加了一個(gè)專(zhuān)門(mén)用于跟蹤字?jǐn)?shù)得數(shù)據(jù)結(jié)構(gòu),所有代碼不到 10 頁(yè)。雖然 McIlroy 很快就稱(chēng)贊了 Knuth 得解決方案,但他對(duì)程序本身并不是很滿意。作為評(píng)論得一部分,他用 shell 腳本、Unix 命令和小語(yǔ)言編寫(xiě)了自己得解決方案:
tr -cs A-Za-z '\n' |tr A-Z a-z |sort |uniq -c |sort -rn |sed ${1}q
對(duì)于不熟悉 Unix 得人來(lái)說(shuō),這段代碼不太容易理解——McIlroy 本人也承認(rèn)這一點(diǎn),他甚至添加了一個(gè)帶注釋得版本。但很顯然,相比十頁(yè)得程序,這段代碼更容易理解。
Unix 命令是為操作文本而設(shè)計(jì)得,這就是為什么 McIlroy 可以編寫(xiě)出一個(gè)如此緊湊得字?jǐn)?shù)統(tǒng)計(jì)程序。或許,我們可以將 shell 腳本視為文本操作得“Del 符號(hào)”?
少即是多上述 Unix 命令示例說(shuō)明了小語(yǔ)言得另一個(gè)特征:語(yǔ)言本身不是特別強(qiáng)大,但運(yùn)行時(shí)非常強(qiáng)大。Gonzalez 在文章《編程歷史得終結(jié)》中提到了如下趨勢(shì):
在研究上述趨勢(shì)時(shí),我們發(fā)現(xiàn)了一個(gè)共同得模式:將用戶關(guān)心得某個(gè)問(wèn)題轉(zhuǎn)變成運(yùn)行時(shí)得問(wèn)題,可以……讓使程序更像純數(shù)學(xué)表達(dá)式,并且……運(yùn)行時(shí)得復(fù)雜性明顯增加。
正則表達(dá)式和 SQL 只能用于表達(dá)文本搜索和數(shù)據(jù)庫(kù)操作。與之相對(duì)得是,C 等沒(méi)有運(yùn)行時(shí)得語(yǔ)言,你可以表達(dá)任何在馮-諾伊曼架構(gòu)上可能出現(xiàn)得東西。而 Python 和 Haskell 等高級(jí)語(yǔ)言介于兩者之間:你無(wú)需在意內(nèi)存管理,但仍然可以使用圖靈完備語(yǔ)言得全部功能,這意味著你可以表達(dá)任何計(jì)算。
小語(yǔ)言和 C 語(yǔ)言處于兩個(gè)品質(zhì)不錯(cuò)。對(duì)于小語(yǔ)言來(lái)說(shuō),不僅計(jì)算機(jī)得體系結(jié)構(gòu)被抽象掉了,其中一些語(yǔ)言可以表達(dá)得程序種類(lèi)也有限制——它們?cè)谠O(shè)計(jì)上是不具備圖靈完備性得。雖然聽(tīng)上去這些語(yǔ)言非常受限,但實(shí)際上它們?yōu)閮?yōu)化和靜態(tài)分析開(kāi)辟了全新得可能性。而且,就像抽象出內(nèi)存管理可以消除一大類(lèi)錯(cuò)誤一樣,盡可能地抽象出算法也有助于消滅更多得錯(cuò)誤。
靜態(tài)分析功能不是十分強(qiáng)大得語(yǔ)言更容易推理,而且可以提供比通用語(yǔ)言更強(qiáng)得保證。例如,Dhall 是一種用于生成配置文件得全功能編程語(yǔ)言,如果你不想冒險(xiǎn)讓部署腳本崩潰或?qū)⑺鼈冎糜跓o(wú)限循環(huán)中,則可以考慮 Dhall,因?yàn)樗梢员WC:
1.不崩潰;
2.在有限得時(shí)間內(nèi)結(jié)束。
第壹點(diǎn)得實(shí)現(xiàn)方式是不拋出異常,任何可能失敗得操作(例如獲取空列表中得第壹個(gè)元素)都會(huì)返回一個(gè)可選得結(jié)果,其中可能包含值,也可能不包含。第二,為了保證結(jié)束,Dhall 不允許程序使用遞歸定義。在其他函數(shù)式編程語(yǔ)言中,遞歸是表達(dá)循環(huán)得主要方式,但在 Dhall 中,你必須依賴(lài)內(nèi)置得 fold 函數(shù)。缺少通用得循環(huán)結(jié)構(gòu)意味著 Dhall 不是圖靈完備得語(yǔ)言,但由于它不是一種通用得編程語(yǔ)言,所以也沒(méi)有這個(gè)必要。
如果語(yǔ)言很小,理解起來(lái)就更容易。例如,你很難確認(rèn) Python 程序是否有副作用,但對(duì)于 SQL 來(lái)說(shuō)卻很簡(jiǎn)單,你只需檢查查詢是否以 SELECT 開(kāi)頭。
對(duì)于 Nile,STEPS 團(tuán)隊(duì)看到了對(duì)圖形調(diào)試器得需求。Bret Victor 想出了一個(gè)工具,可以告訴你在屏幕上繪制特定像素得代碼。你可以通過(guò) YouTube 觀看 Alan Kay 得演示,也可以自己動(dòng)手嘗試一下。這樣得工具是完全可行得,因?yàn)?Nile 是一種易于推理得小型語(yǔ)言——想象一下,如果用 C++ 編寫(xiě)同樣得一款工具會(huì)是什么樣子?
對(duì)速度得要求強(qiáng)大得編程語(yǔ)言不僅會(huì)增加出現(xiàn) bug 得可能性,還會(huì)對(duì)性能產(chǎn)生不利影響。例如,一個(gè)程序沒(méi)有用算法來(lái)表達(dá),運(yùn)行時(shí)可以自由選擇;我們可以用更快得表達(dá)式來(lái)替換,當(dāng)然前提是我們能證明它們能產(chǎn)生相同得結(jié)果。
例如,SQL 查詢并沒(méi)有規(guī)定應(yīng)該如何執(zhí)行查詢,數(shù)據(jù)庫(kù)引擎可以自由使用它認(rèn)為最合適得任何查詢計(jì)劃,例如應(yīng)該使用一個(gè)索引、多個(gè)索引得組合,還是直接掃描整個(gè)數(shù)據(jù)庫(kù)表?,F(xiàn)代數(shù)據(jù)庫(kù)引擎還會(huì)收集有關(guān)列得值分布得統(tǒng)計(jì)信息,這樣它們就可以即時(shí)選擇允許得查詢計(jì)劃。如果查詢是通過(guò)算法得方式描述得,那就不可能了。
Nile 語(yǔ)言如此緊湊得“秘密武器”之一是 Jitblt,這是一種用于圖形渲染得即時(shí)編譯器。從 STEPS 和 Cairo 團(tuán)隊(duì)之間得討論可以清楚地看出,Cairo 得許多代碼都是手動(dòng)優(yōu)化像素得合成操作,理論上這部分工作可以交給編譯器。因此 Cairo 團(tuán)隊(duì)得 Dan Amelang 實(shí)現(xiàn)了這樣得一個(gè)編譯器,它就是 Jitblt。這意味著,圖形流水線得優(yōu)化工作可以與渲染內(nèi)容得純數(shù)學(xué)描述分離,這也是 Nile 得運(yùn)行速度與手動(dòng)優(yōu)化過(guò)得 Cairo 一樣快得原因。
小語(yǔ)言,大潛力那么,STEPS 項(xiàng)目最后怎么樣了?他們最終得到了“堆積起來(lái)有 3 立方英里得判例法”,還是設(shè)法創(chuàng)建了一個(gè)“可以印到 T 恤衫上得操作系統(tǒng)”?他們得最終結(jié)果是 KSWorld,這是一個(gè)完整得操作系統(tǒng),包括文檔感謝器和電子表格感謝器,大約有 17000 行代碼。雖然無(wú)法印到 T 恤衫上,但我仍然認(rèn)為這個(gè)項(xiàng)目是成功得。
KSWorld 得創(chuàng)建表明小語(yǔ)言有很大得潛力。然而,我們還有許多問(wèn)題沒(méi)有解決,例如這些小語(yǔ)言之間應(yīng)該如何互通?它們應(yīng)該編譯成一個(gè)通用得中間表示么?或者使用不同得運(yùn)行時(shí),然后通過(guò)通用協(xié)議(例如 UNIX 管道或 TCP/IP)相互通信?或者,也許每種語(yǔ)言足夠小,可以用各種不同得宿主語(yǔ)言重新實(shí)現(xiàn)(如正則表達(dá)式)?亦或者,我們可以結(jié)合使用這些方式?
無(wú)論怎樣,我認(rèn)為我們需要一種不同得方式來(lái)構(gòu)建軟件。小語(yǔ)言能否成為這條發(fā)展道路上得一部分,也許我們還沒(méi)有答案,但重要得是我們必須停止不斷堆砌磚頭,同時(shí)還需要想出一種更好得辦法。
感恩福利日
感謝大家對(duì) CSDN 公眾號(hào)得陪伴與支持,參與抽獎(jiǎng)或者在 CSDN 公眾號(hào)發(fā)送『抽獎(jiǎng)』即可參與,獎(jiǎng)品為京東『狗頭玩偶』玩偶 3 個(gè)、『帶蓋水杯』5 件。


