這是2023年11月10日我在悉尼GopherConAU 2023會議上的閉幕演講(視頻)[7],那一天也是Go開源14周年[8]的日子。本文中穿插著演示文稿中使用的幻燈片。
大家好!
首先,我要感謝Katie和Chewy讓我有幸為此次GopherConAU大會做閉幕演講。
2009年11月10日
今天是2023年11月10日,Go作為開源項目推出14周年的紀(jì)念日。
2009年11月10日那天,加州時間下午3點(如果沒記錯的話),Ken Thompson、Robert Griesemer、Russ Cox、Ian Taylor、Adam Langley、Jini Kim和我滿懷期待地看著網(wǎng)站上線。之后,全世界都知道我們在做什么了。
14年后的今天,有很多事情值得回顧。我想借此機會談?wù)勛阅且惶煲詠韺W(xué)到的一些重要經(jīng)驗。即使是最成功的項目,在反思之后,也會發(fā)現(xiàn)一些事情本可以做得更好。當(dāng)然,也有一些事情事后看來似乎是成功的關(guān)鍵所在。
首先,我必須明確的是,這里的觀點只代表我個人,不代表Go團(tuán)隊和Google。無論是過去還是現(xiàn)在,Go都是由一支專注的團(tuán)隊和龐大的社區(qū)付出巨大努力的結(jié)果。所以,如果你同意我的任何說法,請感謝他們。如果你不同意,請責(zé)怪我,但請保留你的意見。
鑒于本次演講的題目,許多人可能期待我會分析語言中的優(yōu)點和缺點。當(dāng)然,我會做一些分析,但還會有更多內(nèi)容,原因有幾個。
首先,編程語言的好壞很大程度上取決于觀點而不是事實,盡管許多人對Go或任何其他語言的最微不足道的功能都存在爭論。
另外,關(guān)于換行符的位置、nil的工作方式、導(dǎo)出的大小寫表示法、垃圾回收、錯誤處理等話題已經(jīng)有了大量的討論。這些話題肯定有值得討論的地方,但幾乎沒什么是還沒有被討論過的。
但我要討論的不僅僅是語言本身的真正原因是,語言并不是整個項目的全部。我們最初的目標(biāo)不是創(chuàng)造一種新的編程語言,而是創(chuàng)造一種更好的編寫軟件的方式[9]。我們對所使用的語言有意見——無論使用什么語言,每個人都是如此——但是我們遇到的基本問題與這些語言的特性沒有太大關(guān)系,而是與在谷歌使用這些語言構(gòu)建軟件的過程有關(guān)。
T恤上的第一只Gopher
新語言的創(chuàng)建提供了探索其他想法的新路徑,但這只是一個推動因素,而不是真正的重點。如果當(dāng)時我正在工作的二進(jìn)制文件不需要45分鐘來構(gòu)建 ,Go語言就不會出現(xiàn)。但那45分鐘不是因為編譯器慢(因為它不慢),也不是因為它所用的語言不好(因為它也不差)。緩慢是由其他因素造成的。
我們想解決的就是這些因素:構(gòu)建現(xiàn)代服務(wù)器軟件的復(fù)雜性:控制依賴性、與人員不斷變化的大型團(tuán)隊一起編程、可維護(hù)性、高效測試、多核CPU和網(wǎng)絡(luò)的有效利用等等。
簡而言之,Go不僅僅是一種編程語言。當(dāng)然,它是一種編程語言,這是它的定義。但它的目的是幫助提供一種更好的方式來開發(fā)高質(zhì)量的軟件,至少與14多年前的我們的環(huán)境相比。
時至今日,這仍然是它的宗旨。Go是一個使構(gòu)建生產(chǎn)軟件更容易、更高效的項目。
幾周前,當(dāng)我開始準(zhǔn)備這次演講時,我只有一個題目,除此之外別無其他。為了激發(fā)我的思路,我在Mastodon上向人們征求意見。不少人給予了回復(fù)。我注意到了一種趨勢:人們認(rèn)為我們做錯的事情都在語言本身,而我們做對的事情都在語言周邊,比如gofmt、部署和測試等。事實上,我覺得這令人鼓舞。我們試圖做的事情似乎已經(jīng)產(chǎn)生了效果。
但值得承認(rèn)的是,我們在早期并沒有明確真正的目標(biāo)。我們可能覺得這些目標(biāo)是不言自明的。為了彌補這一缺陷,我在2013年的SPLASH會議上發(fā)表了一場題為《谷歌的Go語言:面向軟件工程的語言設(shè)計[10]》的演講。
Go at Google
那場演講和相關(guān)的博客文章可能是對Go語言為何而生的最好詮釋。
今天的演講是SPLASH演講的后續(xù),回顧了我們在構(gòu)建語言之后所學(xué)到的經(jīng)驗教訓(xùn),并且可以更廣泛地應(yīng)用于更大的圖景。
那么......來談?wù)勔恍┙逃?xùn)。
首先,當(dāng)然,我們有:
以Go Gopher吉祥物開始可能看起來是一個奇怪的起點,但Go gopher是Go成功的最早因素之一。在發(fā)布Go之前,我們就知道我們想要一個吉祥物來裝飾周邊商品——每個項目都需要周邊商品——Renee French主動提出為我們制作一個這樣的吉祥物。在這一點上,我們做得非常正確。
下面最早的Gopher毛絨玩具的圖片:
The Gopher
這是Gopher的照片,它的第一個原型不太成功。
Gopher和它進(jìn)化程度較低的祖先
Gopher是一個吉祥物,它也是榮譽徽章,甚至是世界各地Go程序員的身份標(biāo)志。此時此刻,你正在參加一個名為GopherCon的會議,這是眾多GopherCon會議中的一個。擁有一個從第一天就準(zhǔn)備好分享信息的容易識別、有趣的生物,對Go的成長至關(guān)重要。它天真又聰明——它可以構(gòu)建任何東西!
它為社區(qū)參與該項目奠定了基調(diào),這是卓越的技術(shù)與真正的樂趣相結(jié)合的基調(diào)。最重要的是,Gopher是社區(qū)的一面旗幟,一面團(tuán)結(jié)起來的旗幟,尤其是在早期,當(dāng)Go還是編程界的新貴時。
這是幾年前Gopher參加巴黎會議的照片,看看他們多興奮!
盡管如此,在知識共享署名許可(Creative Commons Attribution license)下發(fā)布Gopher的設(shè)計也許不是最好的選擇。一方面,它鼓勵人們以有趣的方式重新組合他,這反過來又有助于培養(yǎng)社區(qū)精神。
Gopher model sheet
Renee創(chuàng)建了一個“模型表”來幫助藝術(shù)家在保持其精神原貌的同時進(jìn)行藝術(shù)創(chuàng)作。
一些藝術(shù)家利用這些特征制作了自己版本的Gopher并獲得了樂趣;Renee和我最喜歡的版本是日本設(shè)計師@tottie的和游戲程序員@tenntennen的:
@tottie的Gopher
@tenntennen 的gopher
但許可證的“歸屬”部分常常會導(dǎo)致令人沮喪的爭論,或者導(dǎo)致Renee的創(chuàng)作不屬于她,也不符合原作的精神。而且,說實話,這種歸屬往往只是不情愿地得到尊重,或者根本沒有得到尊重。例如,我懷疑@tenntennen是否因他的Gopher插圖被使用而獲得補償或是得到承認(rèn)。
gophervans.com: Boo!
因此,如果讓我們重來一次,我們會認(rèn)真思考確保吉祥物忠于其理想的最佳方法。維護(hù)吉祥物是一件很難的事,而且解決方案仍然難以捉摸。
但更多的是技術(shù)性的事情。
這里有一份我認(rèn)為我們在客觀上做對了的事情的清單,特別是在回顧的時候。并不是每一個編程語言項目都做了這些事情,但清單中的每一件對Go的最終成功都至關(guān)重要。我會試著言簡意賅,因為這些話題都已為人所熟知。
我們從正式的語言規(guī)范開始。這不僅可以在編寫編譯器時鎖定行為,還可以使多個編譯器實現(xiàn)共存并就該行為達(dá)成一致。編譯器本身并不是一個規(guī)范。你測試編譯器的依據(jù)是什么?
Web上的Go語言規(guī)范
哦,順便說一句,該規(guī)范的初稿是在這里編寫的,位于悉尼達(dá)令港一棟建筑的18層。我們正在Go的家鄉(xiāng)慶祝Go的生日。
Go有多個編譯器實現(xiàn),它們都實現(xiàn)相同的語言規(guī)范。有了規(guī)范就可以更容易地實現(xiàn)這一點。
有一天,伊恩·泰勒(Ian Taylor)發(fā)郵件通知我們,在閱讀了我們的語言規(guī)范草案后,他自己編寫了一個編譯器,這讓我們感到驚訝!
Subject: A gcc frontend for GoFrom: Ian Lance TaylorDate: Sat, Jun 7, 2008 at 7:06 PMTo: Robert Griesemer, Rob Pike, Ken ThompsonOne of my office-mates pointed me at http://.../go_lang.html . Itseems like an interesting language, and I threw together a gccfrontend for it. It's missing a lot of features, of course, but itdoes compile the prime sieve code on the web page.
這的確令人興奮,但更多的編譯器實現(xiàn)也隨之而來了,所有這些都因正式規(guī)范的存在而成為可能。
很多編譯器
擁有多個編譯器幫助我們改進(jìn)了語言并完善了規(guī)范,并為那些不太喜歡我們類似Plan-9的業(yè)務(wù)方式的其他人提供了替代環(huán)境。稍后會詳細(xì)介紹。如今有很多兼容的實現(xiàn),這很棒!
我們使Go應(yīng)用的交叉編譯變得輕而易舉,程序員可以在他們喜歡的任何平臺上工作,并交付到任何需要的平臺。使用Go可能比使用任何其他語言更容易達(dá)成這一點。很容易將編譯器視為運行它的機器的本地編譯器,但沒有理由這么認(rèn)為。打破這個假設(shè)具有重要意義,這對許多開發(fā)者來說都是新鮮事。
可移植性
我們努力使語言達(dá)到1.0版本的標(biāo)準(zhǔn),然后通過兼容性保證將其固定下來,這對Go的采用產(chǎn)生了非常明顯的影響!我不理解為什么大多數(shù)其他項目一直在抵制這樣做。是的,保持強大兼容性的確需要付出成本,但它可以阻止功能特性停滯,而在這個幾乎沒有其他東西保持穩(wěn)定的世界里,不必?fù)?dān)心新版本的Go會破壞你的項目,這足以令人感到欣喜!
Go兼容性承諾
盡管它的增長在某種程度上是偶然的,因為在一開始沒有其他地方可以安裝Go代碼,但擁有一個堅實、制作精良的標(biāo)準(zhǔn)庫,其中包含編寫21世紀(jì)服務(wù)器代碼所需的大部分內(nèi)容,這是一個重大資產(chǎn)。在我們積累了足夠的經(jīng)驗來理解還應(yīng)該提供什么之前,它使整個社區(qū)都使用相同的工具包。這非常有效,并有助于防止出現(xiàn)不同版本的庫,從而幫助統(tǒng)一社區(qū)。
標(biāo)準(zhǔn)庫
我們確保該語言易于解析,從而支持工具構(gòu)建。起初我們認(rèn)為Go需要一個IDE,但易于構(gòu)建工具意味著,隨著時間的推移,IDE將會出現(xiàn)在Go上。他們和gopls一起做到了,而且他們非常棒。
我們還為編譯器提供了一套輔助工具,例如自動化測試、覆蓋率和代碼審查(code vetting)。當(dāng)然還有g(shù)o命令,它集成了整個構(gòu)建過程,也是許多項目構(gòu)建和維護(hù)其Go代碼所需的一切。
此外,Go獲得了快速構(gòu)建的聲譽,這也沒有什么壞處。
我將gofmt作為一個單獨的項目從工具中拿出來,因為它是一個不僅在Go上而且在整個編程社區(qū)上留下了印記的工具。在Robert編寫gofmt之前(順便說一句,他從一開始就堅持這樣做),自動格式化程序的質(zhì)量不高,因此大多未被使用。
gofmt諺語
gofmt的成功表明了代碼自動格式化可以做得很好,今天幾乎每種值得使用的編程語言都有一個標(biāo)準(zhǔn)格式化程序。我們不再為空格和換行符爭論,這節(jié)省了大量時間了,這也讓那些花在定義標(biāo)準(zhǔn)格式和編寫這段相當(dāng)困難的代碼實現(xiàn)格式自動化上的時間顯得超值。
此外,gofmt還使無數(shù)其他工具成為可能,例如簡化器、分析器甚至是代碼覆蓋率工具。因為gofmt的內(nèi)容成為了任何人都可以使用的庫,所以你可以解析程序、編輯AST,然后打印完美的字節(jié)輸出,供人類和機器使用。
謝謝,羅伯特。
不過,恭喜你就夠了。接下來,我們來談?wù)勔恍└袪幾h的話題。
并發(fā)有爭議嗎?嗯,在我2002年加入谷歌的那年肯定有。John Ousterhout曾說過:線程很糟糕。許多人都同意他的觀點,因為線程似乎非常難以使用。
John Ousterhout不喜歡線程
谷歌的軟件幾乎總是避免使用它們,可以說是徹底禁止使用,而制定這一禁令的工程師引用了Ousterhout的言論。這讓我很困擾。自20世紀(jì)70年代以來,我一直在做類似的并發(fā)事情,有時候甚至沒有意識到,在我看來這很強大。但經(jīng)過反思,很明顯Ousterhout犯了兩個錯誤。首先,他的結(jié)論超出了他有興趣使用線程的領(lǐng)域,其次,他主要是在抱怨使用笨拙的低級包如pthread之類的線程,而不是抱怨這一基本思想。
像這樣混淆解決方案和問題是世界各地工程師常犯的錯誤。有時,提出的解決方案比它解決的問題更難,并且很難看到有更簡單的路徑。但我離題了。
根據(jù)經(jīng)驗,我知道有更好的方法來使用線程,或者無論我們選擇怎么稱呼它們,我甚至在Go語言出現(xiàn)之前就曾就此發(fā)表過演講。
Newsqueak中的并發(fā)
但我并不孤單,其他許多語言、論文甚至?xí)急砻鳎l(fā)編程可以做得很好,不僅我知道這一點。它只是還沒有在主流中流行起來,Go的誕生部分地就是為了解決這個問題。在那次臭名昭著的45分鐘構(gòu)建中,我試圖向一個非線程二進(jìn)制文件添加一個線程,這非常困難,因為我們使用了錯誤的工具。
回顧過去,我認(rèn)為可以公平地說,Go在讓編程界相信并發(fā)是一種強大工具方面發(fā)揮了重要作用,特別是在多核網(wǎng)絡(luò)世界中,它可以比pthread做得更好。如今,大多數(shù)主流語言都對并發(fā)提供了很好地支持。
Google 3.0
另外,Go的并發(fā)版本在導(dǎo)致它出現(xiàn)的語言線中有些新穎,因為它使goroutine變得平淡無奇。沒有協(xié)程,沒有任務(wù),沒有線程,沒有名稱,只有g(shù)oroutine。我們發(fā)明了“goroutine”這個詞,因為沒有適合的現(xiàn)有術(shù)語。時至今日,我仍然希望Unix的拼寫命令可以學(xué)會它。
順便說一句,因為我經(jīng)常被問到,讓我花一分鐘時間談?wù)刟sync/await。看到async/await模型及其相關(guān)風(fēng)格成為許多語言選擇支持并發(fā)的方式,我有點難過,但它肯定是對pthreads的巨大改進(jìn)。
與goroutine、channel和select相比,async/await對語言實現(xiàn)者來說更容易也更小,可以更容易地內(nèi)建或后移植到現(xiàn)有平臺中。但它將一些復(fù)雜性推回給了程序員,通常會導(dǎo)致Bob Nystrom所著名的“彩色函數(shù)[11]”。
你的函數(shù)是什么顏色的
我認(rèn)為Go表明了CSP這種不同但更古老的模型可以完美地嵌入到過程化語言中,沒有這種復(fù)雜性。我甚至看到它幾次作為庫實現(xiàn)。但它的實現(xiàn),如果做得好,需要顯著的運行時復(fù)雜性,我可以理解為什么一些人更傾向于不在他們的系統(tǒng)中內(nèi)置它。不管你提供什么并發(fā)模型,重要的是只提供一次,因為一個環(huán)境提供多個并發(fā)實現(xiàn)可能會很麻煩。Go當(dāng)然通過把它放在語言中而不是庫中解決了這個問題。
關(guān)于這些問題可能要講整場演講,但目前就這些吧。
并發(fā)的另一個價值在于,它使Go看起來像是全新的東西。如我所說,一些其他語言在之前已經(jīng)支持了它,但它們從未進(jìn)入主流,而Go對并發(fā)的支持是吸引初學(xué)者采用的一個主要因素,它吸引了以前沒有使用過并發(fā)但對其可能性感興趣的程序員。
這就是我們犯下兩個大錯誤的地方。
圖片
耳語的Gopher(Cooperating Sequential Processes)
首先,并發(fā)很有趣,我們很高興擁有它,但我們設(shè)想的使用案例大多是服務(wù)器相關(guān)的,意在在net/http等關(guān)鍵庫中完成,而不是在每個程序的所有地方完成。當(dāng)許多程序員使用它時,他們努力研究它如何真正幫助他們。我們應(yīng)該一開始就解釋清楚,語言中的并發(fā)支持真正帶到桌面的是更簡單的服務(wù)器軟件。這個問題空間對許多人很重要,但并非所有嘗試Go的人都是如此,這點指導(dǎo)不足是我們的責(zé)任。
相關(guān)的第二點是,我們用了太長時間來澄清并行和并發(fā)之間的區(qū)別——支持在多核機器上并行執(zhí)行多個計算,以及一種組織代碼的方式,以便很好地執(zhí)行并行計算。
無數(shù)程序員試圖通過使用goroutine來并行化他們的代碼以使其更快,但經(jīng)常對結(jié)果中的速度降低感到困惑。僅當(dāng)基礎(chǔ)問題本質(zhì)上是并行的時候,例如服務(wù)HTTP請求,并發(fā)代碼才會通過并行化而變快。我們在解釋這一點上做得很糟糕,結(jié)果讓許多程序員感到困惑,可能還趕走了一些人。
為了解決這個問題,我在2012年Waza上給Heroku的開發(fā)者大會做了一個題為“并發(fā)不是并行[12]”的演講。這是一次很有趣的演講,但它應(yīng)該更早發(fā)生。
對此表示歉意。但好處仍然存在:Go幫助普及了并發(fā)性作為構(gòu)建服務(wù)器軟件的一種方式。
很明顯,接口與并發(fā)都是Go中與眾不同的思想。它們是Go對面向?qū)ο笤O(shè)計的答案,采用最初關(guān)注行為的風(fēng)格,盡管新來者一直在努力使結(jié)構(gòu)體承擔(dān)這一角色。
使接口動態(tài)化,無需提前宣布哪些類型實現(xiàn)了它們,這困擾了一些早期評論者,并且仍然惱火一小部分人,但它對Go培育的編程風(fēng)格很重要。大部分標(biāo)準(zhǔn)庫都是建立在它們的基礎(chǔ)之上的,而更廣泛的主題如測試和管理依賴也高度依賴于它們慷慨的“歡迎所有人”的天性。
我覺得接口是Go中設(shè)計最好的部分之一。
除了一些早期關(guān)于接口定義中是否應(yīng)該包括數(shù)據(jù)的討論之外,它們在討論的第一天就已經(jīng)成形。
GIF 解碼器:Go接口的練習(xí)(Rob Pike和Nigel Tao 2011)
在這個問題上還有一個故事要講。
在Robert和我的辦公室里那著名的第一天,我們討論了關(guān)于多態(tài)性應(yīng)該怎么處理的問題。Ken和我從C語言中知道qsort可以作為一個困難的測試用例,所以我們?nèi)齻€人開始討論用我們這種初具雛形的語言如何實現(xiàn)一個類型安全的排序例程(routine)。
Robert和我?guī)缀跬瑫r產(chǎn)生了同樣的想法:在類型上使用方法來提供排序所需的操作。這個概念很快發(fā)展成了一個想法,即值類型擁有作為方法定義的行為,一組方法可以提供函數(shù)可以操作的接口。Go的接口幾乎立即就出現(xiàn)了。
sort.Interface
有一點沒人經(jīng)常提到:Go的sort函數(shù)是作為一個在接口上操作的函數(shù)實現(xiàn)的。這與大多數(shù)人熟悉的面向?qū)ο缶幊田L(fēng)格不同,但這是一個非常強大的想法。
這個想法對我們來說非常激動人心,它可能成為一個基礎(chǔ)的編程構(gòu)造,這令我們陶醉。當(dāng)Russ Cox加入時,他很快指出了I/O如何完美地融入這個想法,標(biāo)準(zhǔn)庫的發(fā)展非常迅速,在很大程度上依賴于三個著名的接口:空接口(interface{})、Writer和Reader,每個接口平均包含兩個第三個方法。那些微小的方法對Go來說是慣用法,無處不在。
接口的工作方式不僅成為Go的一個顯著特性,它們也成為我們思考庫、泛型和組合的方式。這是讓人興奮的事情。
但我們在這個問題上停止討論可能是一個錯誤。
你看,我們之所以走上這條路,至少在一定程度上是因為我們看到泛型編程太容易鼓勵一種傾向于在算法之前首先關(guān)注類型的思考方式。過早抽象而不是有機設(shè)計。容器而不是函數(shù)。
我們在語言中正確定義了通用容器——map,切片,數(shù)組,channel——而不給程序員訪問它們所包含的泛型。這可以說是一個錯誤。我們相信,我認(rèn)為仍然正確的是,大多數(shù)簡單的編程任務(wù)可以很好地由這些類型來處理。但有一些不能,語言提供的和用戶可以控制的之間的障礙肯定困擾了一些人。
簡而言之,盡管我不會改變接口的任何工作方式,但它們以需要十多年時間才能糾正的方式影響了我們的思維。Ian Taylor從一開始就推動我們面對這個問題,但在接口作為Go編程基石的情況下,這是相當(dāng)困難的。
評論者經(jīng)常抱怨我們應(yīng)該使用泛型,因為它們“很簡單”,在某些語言中可能確實如此,但接口的存在意味著任何新的多態(tài)形式都必須考慮到它們。找到一種可以與語言的其余部分很好地協(xié)同工作的前進(jìn)方法需要多次嘗試,幾次中止的實現(xiàn),以及許多小時、天數(shù)和周數(shù)的討論。最終,在Phil Wadler的帶領(lǐng)下,我們召集了一些類型理論家來提供幫助。即使在語言中有了可靠的泛型模型,作為方法集存在的接口也仍然存在一些遺留問題。
泛型版sort
如你所知,最終的答案是設(shè)計一個可以吸收更多多態(tài)形式的接口泛化,從“方法集合”過渡到“類型集合”。這是一個微妙但深刻的舉措,大多數(shù)社區(qū)似乎都可以接受,盡管我懷疑抱怨聲永遠(yuǎn)不會停止。
有時候要花很多年的時間來弄清楚一些事情,或者甚至弄清楚你并不能完全弄明白它。但你還是要繼續(xù)前進(jìn)。
順便說一句,我希望我們有一個比“泛型”更好的術(shù)語,它起源于表示一種不同的數(shù)據(jù)結(jié)構(gòu)中心多態(tài)風(fēng)格。“參數(shù)多態(tài)”是Go提供的該功能的正確術(shù)語,這是一個準(zhǔn)確的術(shù)語,但它難聽。于是我們依然說“泛型”,盡管它不太恰當(dāng)。
困擾編程語言社區(qū)的一件事是,早期的Go編譯器是用C語言編寫的。在他們看來,正確的方式是使用LLVM或類似的工具包,或者用Go語言本身編寫編譯器,這稱為自舉。我們沒有做這兩者中的任何一種,原因有幾個。
首先,自舉一種新語言要求至少其編譯器的第一步必須用現(xiàn)有語言完成。對我們來說,C語言是顯而易見的選擇,因為Ken已經(jīng)編寫了C編譯器,并且其內(nèi)部結(jié)構(gòu)可以很好地作為Go編譯器的基礎(chǔ)。此外,用自己的語言編寫編譯器,同時開發(fā)該語言,往往會產(chǎn)生一種適合編寫編譯器的語言,但這不是我們想要的語言。
早期的編譯器工作良好,它可以很好地引導(dǎo)語言。但從某種意義上說,它有點奇怪,實際上它是一個Plan 9風(fēng)格的編譯器,使用舊的編譯器編寫思想,而不是新的思想,如靜態(tài)單一賦值(SSA)[13]。生成的代碼平庸,內(nèi)部不太漂亮。但它是務(wù)實高效的,編譯器代碼本身體積適中,對我們來說也很熟悉,這使得我們在嘗試新想法時可以快速進(jìn)行更改。一個關(guān)鍵步驟是添加自動增長的分段堆棧。這很容易添加到我們的編譯器中,但是如果我們使用像LLVM這樣的工具包,考慮到ABI和垃圾收集器支持所需的更改,將這種更改集成到完整的編譯器套件中是不可行的。
另一個工作良好的區(qū)域是交叉編譯,這直接來自原始Plan 9編譯器套件的工作方式。
按照我們的方式行事,無論多么非正統(tǒng),都有助于我們快速前進(jìn)。有些人對這一選擇感到冒犯,但這對當(dāng)時的我們來說是正確的選擇。
對于Go 1.5版本,Russ Cox編寫了一個工具,可以半自動將編譯器從C轉(zhuǎn)換為Go。到那時,語言已經(jīng)完成,編譯器導(dǎo)向的語言設(shè)計的擔(dān)憂也就無關(guān)緊要了。有一些關(guān)于這個過程的在線演講值得一看。我在2016年的GopherCon上做了一個關(guān)于匯編器的演講,這在我畢生追求可移植性的過程中是一個高點。
Go匯編器設(shè)計(GopherCon 2016)
我們從C開始做了正確的事情,但最終將編譯器翻譯為Go,使我們能夠?qū)o所具有的所有優(yōu)勢帶到其開發(fā)中,包括測試、工具、自動重寫、性能分析等。當(dāng)前的編譯器比原始編譯器干凈得多,并且可以生成更好的代碼。但是,當(dāng)然,這就是自舉的工作原理。
請記住,我們的目標(biāo)不僅僅是一種語言,而是更多。
我們不尋常的做法絕不是對LLVM或語言社區(qū)中任何人的侮辱。我們只是使用了最適合我們?nèi)蝿?wù)的工具。當(dāng)然,今天有一個LLVM托管的Go編譯器,以及許多其他應(yīng)該有的編譯器。
我們從一開始就知道,要成功,Go必須是一個開源項目。但我們也知道,在弄清楚關(guān)鍵的思想和有一個工作的實現(xiàn)之前,私下開發(fā)會更高效。頭兩年對澄清我們在試圖實現(xiàn)什么,而不受干擾,是必不可少的。
向開源的轉(zhuǎn)變是一個巨大的改變,也很具教育意義。來自社區(qū)的投入是壓倒性的。與社區(qū)的接觸花費了大量的時間和精力,尤其是對Ian,不知怎么他找到時間來回答任何人提出的每一個問題。但它也帶來了更多。我仍然驚嘆在Alex Brainman的指導(dǎo)下,社區(qū)完全獨立完成的Windows移植的速度。那很神奇。
我們花了很長時間來理解轉(zhuǎn)向開源項目的影響,以及如何管理它。
特別是,公平地說,我們花了太長時間來理解與社區(qū)合作的最佳方式。本次演講的一個主題是我們的溝通不足——即使我們認(rèn)為我們正在進(jìn)行良好溝通——由于誤解和不匹配的期望,大量時間被浪費了。本可以做得更好。
但是,隨著時間的推移,我們說服了社區(qū)中的至少那一部分和我們在一起的人,我們的一些想法,雖然與常見的開源方式不同,但具有價值。最重要的是我們堅持通過強制代碼審查和對細(xì)節(jié)的窮盡關(guān)注來維護(hù)高質(zhì)量代碼。
Mission Control (drawing by Renee French)
一些項目的工作方式不同,它們快速接受代碼,然后在提交后進(jìn)行清理。Go項目則相反,力圖將質(zhì)量放在第一位。我相信這是更有效的方式,但它將更多的工作推回社區(qū),如果他們不理解其價值,他們就不會感到應(yīng)有的歡迎。在這方面還有很多東西要學(xué)習(xí),但我相信現(xiàn)在的情況已經(jīng)好多了。
順便說一句,有一個歷史細(xì)節(jié)不是廣泛為人知的。該項目使用過4個不同的內(nèi)容管理系統(tǒng):SVN、Perforce、Mercurial和Git。Russ Cox做了一份艱巨的工作,保留了所有歷史,所以即使今天,Git倉庫也包含了在SVN中做出的最早的更改。我們都認(rèn)為保留歷史很有價值,我要感謝他做了這項艱苦的工作。
還有一點。人們經(jīng)常認(rèn)為谷歌會告訴Go團(tuán)隊該做什么。這絕對不是真的。谷歌對Go的支持非常慷慨,但它不制定議程。社區(qū)的投入要大得多。谷歌內(nèi)部有一個巨大的Go代碼庫,團(tuán)隊用它來測試和驗證版本,但這是通過從公共倉庫導(dǎo)入谷歌完成的,而不是反過來。簡而言之,核心Go團(tuán)隊由谷歌支付薪水,但他們是獨立的。
Go的包管理開發(fā)過程做得并不好。我相信,語言本身的包設(shè)計非常出色,并且在我們討論的第一年左右的時間里消耗了大量的時間。如果你感興趣的話,我之前提到的SPLASH演講詳細(xì)解釋了它為什么會這樣工作。
一個關(guān)鍵點是使用純字符串來指定導(dǎo)入語句中的路徑,從而提供了我們正確認(rèn)為很重要的靈活性。但從只有一個“標(biāo)準(zhǔn)庫”到從網(wǎng)絡(luò)導(dǎo)入代碼的轉(zhuǎn)變是坎坷的。
修復(fù)云(Renee French 繪制)
有兩個問題。
首先,我們這些Go核心團(tuán)隊的成員很早就熟悉Google的工作方式,包括它的monorepo(單一代碼倉庫)和每個人都在負(fù)責(zé)構(gòu)建。但是我們沒有足夠的經(jīng)驗來使用具有大量包版本的包管理器以及嘗試解決依賴關(guān)系圖的非常困難的問題。直到今天,很少有人真正理解技術(shù)的復(fù)雜性,但這并不能成為我們未能從一開始就解決這些問題的借口。這尤其令人尷尬,因為我曾是一個失敗項目的技術(shù)負(fù)責(zé)人,為谷歌的內(nèi)部構(gòu)建做類似的事情,我應(yīng)該意識到我們面臨的是什么。
deps.dev
我在deps.dev上的工作是一種懺悔。
其次,讓社區(qū)參與幫助解決依賴管理問題的初衷是好的,但當(dāng)最終設(shè)計出來時,即使有大量的文檔和有關(guān)理論的文章,社區(qū)中的許多人仍然感到受到了輕視。
pkg.go.dev
這次失敗給團(tuán)隊上了一課,讓他們知道如何真正與社區(qū)互動,并且自此取得了很大的進(jìn)步。
不過,現(xiàn)在事情已經(jīng)解決了,新的設(shè)計在技術(shù)上非常出色,并且似乎對大多數(shù)用戶來說效果很好。只是時間太長,而且道路崎嶇不平。
我們事先沒有得到的另一件事是文檔。我們寫了很多文檔,并認(rèn)為我們做得很好,但很快就發(fā)現(xiàn)社區(qū)想要的文檔級別與我們的預(yù)期不同。
修理圖靈機的Gopher(Renee French 繪圖)
關(guān)鍵缺失的一部分是最簡單函數(shù)的示例。我們曾以為只需說明某個東西的功能就足夠了,但我們花費了太長時間才接受到展示如何使用它的價值更大。
可執(zhí)行的例子
不過,我們已經(jīng)吸取了教訓(xùn)。現(xiàn)在文檔中有很多示例,大部分是由開源貢獻(xiàn)者提供的。我們很早就做的一件事就是讓它們在網(wǎng)絡(luò)上可執(zhí)行。我在2012年的Google I/O大會上做了一次演講,展示了并發(fā)的實際應(yīng)用,Andrew Gerrand 編寫了一段可愛的Web goo,使得直接從瀏覽器運行代碼片段成為可能。我懷疑這是第一次這樣做,但Go是一種編譯語言,很多觀眾以前從未見過這個技巧。然后該技術(shù)被部署到博客和在線包文檔中。
Go playground
也許更重要的是我們對Go Playground的支持,這是一個免費的開放沙箱,供人們嘗試,甚至開發(fā)代碼。
我們已經(jīng)走了很長一段路。
回顧過去,很明顯很多事情都做得對,并且它們都幫助Go取得了成功。但還有很多事情可以做得更好,重要的是要承認(rèn)這些問題并從中學(xué)習(xí)。對于任何托管重要開源項目的人來說,雙方都有教訓(xùn)。
我希望我對這些教訓(xùn)及其原因的歷史回顧會有所幫助,也許可以作為對那些反對我們正在做的事情和我們?nèi)绾巫龅娜说囊环N道歉/解釋。
GopherConAU 2023 吉祥物,作者:Renee French
但在推出 14 年后,我們終于來了。公平地說,總的來說這是一個非常好的地方。
很大程度上是因為通過設(shè)計和開發(fā)Go作為一種編寫軟件的方式(而不僅僅是作為一種編程語言)做出的決定,我們已經(jīng)到達(dá)了一個新的地方。
我們到達(dá)這里的部分原因包括:
最重要的是,得益于令人難以置信的樂于助人且多元化的Gophers社區(qū)的支持。
多元化的社區(qū)(@tenntennen 繪圖)
也許這些問題最有趣的結(jié)果是,無論是誰編寫的Go代碼的外觀和工作原理都是一樣的,基本上沒有使用該語言的不同子集的派系,并且保證隨著時間的推移代碼可繼續(xù)編譯和運行。對于主要編程語言來說,這可能是第一次。
我們絕對做對了。
本文鏈接:http://www.www897cc.com/showinfo-26-57872-0.htmlGo語言之父的反思:我們做對了什么,做錯了什么
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com