近況:
最近項目太忙,所以更新得不多,但請放心,不會棄坑的,再說關注又不會懷孕對吧,更何況關注這個公眾號的男女比例 98 : 2.
所有擼過代碼都懂項目上線的苦,在上線前,代碼就像自己的親兒子,怎麼看都是那麼的完美。一上線,就人設崩塌,不停的在心中暗罵 “當時TMD怎麼想的”。最近都是在這種狀態下維持生活,你們是不是都能隔著螢幕聞到bug的味道?
image
即將發布的Go 1.11將加入對go mod的支援,解決了go一直存在的依賴管理的短板。不過這篇文章並不是要介紹go module本身,而是打算說一下go團隊和社區之間的衝突——你可以從中看到go team的做事風格,也可以當做是單純的八卦。
先說一下背景。Go作為Google內部孵化的項目,其對的設計非常符合Google內部的使用情境:所有的原始碼都在一個巨大的repo,依賴就是VCS裡面的路徑,構建的時候全部從最新原始碼編譯,最終只產出一個單一的可執行檔。然而並不是所有的公司都是像Google這樣使用Go,Google之外的使用者們需要更好的依賴管理,主要有:
依賴版本的控制,以不受相依模組代碼修改的影響,產生穩定的可預測的構建結果
穩定的依賴路徑,以在項目vcs地址改變或者fork vcs之後能夠相容
最早有http://gopkg.in/這樣的方案,通過一次跳轉指向真正的VCS地址,URL裡不同的版本跳轉到不同的分支。後來有了各種第三方的依賴管理工具,在vendor機制出現後,這些工具實現上把拉下來的依賴固化到vendor裡。之後,社區人員在Go團隊的認可下成立了包管理工具的委員會和工作群組,組織開發了dep,作為——或者說他們以為作為——官方的依賴管理實現。
然而到了18年Russ Cox又開發了vgo的實驗項目,這也引起了迷惑,Go出現了兩個官方的依賴管理工具? vgo和dep是什麼關係?隨著vgo最終標準化並進入Go 1.11稱為go module的實現,塵埃落定,dep所謂的官方只是社區開發人員的一廂情願,根正苗紅的只有vgo。
故事是這樣開始的。
vgo進入Go 1.11,Russ Cox 發了一個Twitter:
img
Russ Cox: 對於在Go 1.11裡的Go Module的實現方式我感到非常興奮。我上次瞅了一下最流行的大約1000個項目,93%的能夠直接轉換為Go Module。
Twitter發出來之後,Sam Boyer(dep的主要開發人員),轉推了一條(後面不放英文原文了,可以到文章後面的串連去看):
Sam Boyer: 最初的(舊項目到Go Module的)轉換從來不是問題,問題是從不拿工資的貢獻者們那裡偷走工作成果。
我上周GoSF的演講是關於這個的。現在視頻找不到了,不過我截了個圖。
Russ Cox回複了這條推:
Russ Cox: 我聽了你的演講。雖然我們談了很長時間,但是明顯你現在對於這一切,對於我還是感覺很受挫敗,很沮喪。對此我真的很抱歉,我知道那是什麼感受。
Sam Boyer: 你能這樣說我很感激。你肯定也很不容易,對於這件事造成的過分的壓力我也很抱歉。
但是這並不是你我之間的事情,我之所以在演講中提到你,是因為你是後來社區文化和機制爭論的源頭。
另一個Go社區的重要貢獻者,Peter Bourgon說:
Peter Bourgon: 因為私下認識事件中的一些人,我承認我是有偏向的。不過作為一個外人看到這個事故現場,我可能以後對Rust興趣更多一些了。為什麼Go團隊領導層總是拒絕從其他現代語言(的做法)中學習呢?
Russ Cox: Go並不是要滿足所有人的所有需求。如果你喜歡Rust的方式,就去用Rust吧。我也欣賞Rust,事實上我花了很多時間研究Rust,Swift中的好的地方,但是適合一個語言的未必適合其他語言。
Peter Bourgon: 是的。但是我想不到原因為什麼go的依賴管理沒有從其他的依賴管理中學習到任何東西。我從局外人的角度來看,Go歇斯底裡的嘗試不去達成任何其他人已經達成的共識,我不明白為什麼要這樣做。
並不僅僅是你的問題。我參與了dep開始之前的討論,在之前還一直在關注glide。我不知道為什麼go的依賴管理社區就是不從其他(包管理)已經遇到的問題中學習。
作為一個已經在提供開箱即用的工具方面證明了自己的語言和社區,我非常困惑為什麼這麼關鍵的一個部分(指包管理)幾乎是刻意的設計得這麼挫。
好吧,Peter Bourgon其實有點歪樓了。
Russ Cox:我們是一個小團隊,還有其他優先的事情要做。確實我們在這個領域晚了幾年,但是事情正在往好的方面發展,幾年之後再來看看我們做成什麼樣子。
Matt Farina(Glide作者)跳出來了
你說你們是一個小團隊,是因為你們把Go當做Google下麵糰隊的一個產品,Google這個團隊是小的。如果你們建立一個社區,藉助其他人的力量,那就是一個很大的團隊。比如Rust的依賴管理團隊就有不是Mozilla的人。
圍攻之下Russ Cox開啟了瘋狂發推模式,連發N條Twitter闡述前因後果。
Russ Cox:
非常有道理的批評。我們並沒有處理好依賴管理的社區進程。Go的核心團隊沒有今早和足夠的參與這個進程,沒有能夠引導平滑的落地。作為Go的技術負責人,這是我的責任,我為此道歉。
自從一開始寫下"go get",Go核心團隊就希望社區能夠接手依賴管理方面的事情。Keith Rarick的goven,之後是godep, 還有Matt Butcher'的glide, 已經Dave Cheney的gb,都是達到最終方案中的一步。
2015年春天Jason Buberel調研了這些方案,試圖尋找統一各種方案的方法。他收集的資訊說明了這些方案的主要問題缺乏在go工具鏈中的支援,也就是我們現在的vendor機制。
Jason收集的證據讓我和Rob Pike相信我們需要增加vendor機制,我們在1.5中作為實驗特性添加,在1.6中正式發布。
Daniel Theophanes領導編寫了vendor.json的格式標準,以便不同的依賴管理工具能夠互相互動。我把vendor作為社區的成功案例寫在了go blog中。但是我們沒有統一的語言來描述go的依賴關係。
2016年夏天,Gophercon上有有個go包管理的討論,最終建立了工作小組和顧問委員會。我那時候正在休陪產假,Andrew Gerrand代表Go團隊參與。
到11月份的時候,Andrew要去做其他的事情了,我開始參與。工作群組一開始就要馬上開發一個可使用的單獨工具,我想要確保總體的設計能夠是的最終良好的整合到go命令中。
2016年12月,我開始給Sam寫郵件討論設計。我希望把版本管理作為go build的一部分,以免使用者需要額外的流程。我問他是否這樣代價太高。我還寫了一個Version SAT問題的文章。
我們還討論了依賴同一個package多個版本造成的衝突問題,Sam高度評價了cargo(Rust的包管理工具)中的實踐。
我們還討論了和go工具鏈的整合需要go compile和build的支援,包括改變GOPATH和vendor的語義。
我說雖然最終整合到go中的會和現在的不一樣,dep依然有必要繼續開發,提供更多的經驗。Sam看起來是同意的。
2017年1月,dep要發布時名字改成了hoard,在討論中我再次提到dep不會簡單的整合到go變成go dep或者go hoard。
2017年三月,Sam發郵件給golang-nuts郵件組,帶了一個merging into go toolchain的連結。這個roadmap看起來就是要直接把dep 放到go的軟體包裡。
我在回複中重申了需要修改才能把dep整合到go toolchain,以及對Sam把dep當成了其本應的角色更官方的解決方案的顧慮。
Sam的回複中使用了"official experiment"這個詞,我現在依然覺得這個詞很合適。一個experiment是用來驗證一個假說,獲得關於某些東西更多的知識。
2017年6月,我和包管理的工作群組分享了一個文檔,關於對go工具整合的設想。Sam和其他人協助我發現了其中的一些缺陷。我現在把它發布在這裡。
幾天后我和工作群組的人見面討論這個設計。因為Andrew缺席所以我記了筆記給他。我現在把它發布在這裡。
我們在GopherCon contributor summit討論了dep。Matt Farina說我當時說如果我自己去搞能做的更好,我確認我沒有(說這句話)。印象裡我說的是dep需要修改才能整合到go命令。
討論的一個主題是關於dep的未來。我再次強調(包管理工作群組的)進程是為了更好的理解我們面臨的問題,以及最終在go命令中提供平滑的整合。
我認識到整合到go命令需要相當的工作量來修改go命令內部的一些東西,在2017年中期我花了一些時間來實現build cache,在go1.10中發布。build cache讓GOPATH/pkg過時了,在版本化的依賴中也不需要這個。
GopherCon之後我休假了,然後又去另外一個項目幫忙,之後回來完成了build cache。build cache能用之後,我就能驗證多版本的依賴問題了。這時已經是2017年11月。
11月晚些時候我給工作群組發了一份草稿,然後和他們見面瞭解他們的想法。我那時候還沒有寫代碼,我仍在試圖搞明白和go整合應該怎麼做。
草稿結尾建議dep支援semantic import versioning。Sam and Peter 爭論說修改已經太晚了,dep不做修改,應該整合為go dep。
我想要發表import versioning 的草稿,公開討論。Sam讓我等等,別破壞了他的假期。我同意了。12月開始,Sam和我每周碰兩次,討論go整合的問題。
既然dep不願意支援import versioning,我直接修改了go命令來驗證這個想法。我發現了import versioning和minimal version selection最佳結合的方式,並且實現了它。
2018年1月初我有了一個想要公開討論的設計,但還沒有可以驗證好壞的實現。但是Sam 2月3號在FOSDEM有一個關於dep的演講,我不想事情複雜化,所以我和Sam持續溝通但是沒有發布。
2月中旬我完成了可以工作的demo,並且確信設計沒有什麼大的問題。Sam的FOSDEM演講也結束了,所以我發布了我的設計和原型實現。炸了。
剩下的事情大家都知道了。設計修正了幾個月之後,成為正式的 proposal,被接受,然後實現,然後merge進主幹,在1.11中preview。
最初的go get已經有10年了,我們替換了它。我們的目標是建立一個能夠為go使用者繼續服務十年的工具,尤其是在代碼規模和Team Dev都越來越大的情況下。
Dep是個成功的實驗。它驗證了在Bundler 和 Cargo中使用的"tag versions, record Boolean constraints, solve with SAT"方式,我也從dep中學到了很多:
(列了很多條從dep學到的東西,這裡省略了,感興趣的自己去看Twitter上的原文)
為什麼Go團隊說go要支援版本(指sementic import versionging)呢?首先,我們建立了Go,我設計了Go命令。我們要保證的最重要的一件事是一致的願景,讓Go成為Go。願景的一部分是讓開發large-scale軟體更容易,包括internet-scale的開源項目。雖然現在說什麼方式是最好的還太早,但是我們可以從其他的系統中學習他們不scale的原因,並且避免掉。
無論或大或小,我們有個一修改go的流程:提Proposal。Go核心團隊協助支援重要的點,以符合Go的設計和願景。我們引導社區的討論去達成一致。
並不是任何時候社區都能達成一致,這時候Go核心團隊來做決定。原則上來說我是最終決定者,實際上Go團隊內部會長時間來討論達成內部的一致。
而Dep從來沒有一個Proposal。而Go Module Proposal,受到了社區廣泛的歡迎,雖然Sam和一小撮其他人不是這樣。我把決定的權利留給其他Proposal的reviewer,他們考慮其中的問題,最終接受了我的Proposal(好吧,誰敢不接受呢)。
Go Module的設計不是完美的,但是他解決了上述的問題,為下一個時代打下了良好基礎。我們非常願意和任何願意協助我們的人去改進它。
回顧過去,就像我一開始所說的,我們Go團隊沒能處理好社區進程,我為此道歉。我們應該持續參與和修正路線,以能夠整合到go工具鏈。
無論如何,我確實欽佩Rust團隊的社區參與。為了成功,他們明白關鍵點並且和社區貢獻者全力投入。而在這個進程中,太長的時間我沒有做到。
我們讓人難以接受的放棄了dep,讓Go module看起來是一個巨大的路線修正。整個社區知道結果後非常的震驚,因為我們之前只和包管理工作群組的人溝通到了。
我以為我只需要專註在技術細節上面,讓工作群組的人和社區交流,結果導致了整個社區都認為dep是官方的實現,雖然在我和工作群組的溝通中明確表明了不是這樣。
回想起來我犯的最大的錯誤,是沒有更廣泛和公開的討論dep的問題,我想讓工作群組對外用一個聲音說話。
看起來我只是和Sam以及工作群組的其他人討論dep和dep整合到go中需要做的事情,但這些都被Sam忽略了,結果是dep無法作為合適的實現整合到go中。
通過各種途徑,dep以go包管理的最終方案的名義出現在了大家面前,即使我們早在2016年12月就告訴Sam dep只是過程中的一步,並且是最終會被取代的。
如果公開的討論,大家的預期可能會不一樣。也許還會讓dep的設計變得更容易被go吸收和整合。
再次,我為在此期間所犯的所有錯誤道歉。我從中學到了很多,成功的社區合作需要做什麼,不需要做什麼。希望後面的進程能夠更好的運作。
太長了,簡單的總結一下:我有管理責任,我道歉。dep一開始就不是作為官方實現,是個實驗,你們想多了。我想要sementic import versioning,dep不支援,所以沒法把dep整合到go中。現在我搞了go module Proposal和原型實現(vgo),大家都說好。
下面圍觀的吃瓜群眾紛紛表示你不需要道歉,你乾的很好,項目乾的比這個差的多的去了。
Matt Farina又發了幾條Twitter回應:
首先感謝你公開的分享了這麼多的想法。
我想你沒有抓到我非常重要的一個點。在Gophercon的包管理工作群組會議你說dep程式碼太多了,go團隊維護不了。這說明了一個問題,Go的問題最終都是Go團隊決定的,其他人沒有話語權。在你的回複中你說的都是你做的工作,不管過去的還是最近的。關注點都是你和Go團隊的工作。導師-徒弟的關係怎麼變成讓社區參與主導,怎麼考慮社區意見?
社區是作為主導者的一份子,還是單純的產品使用者?依賴管理為什麼就不能是一個獨立的團隊?一個在這個問題上富有經驗並且聚焦這個問題的團隊。工具和複雜度在膨脹,為什麼不能交出一部分主導權給社區?其他的語言都是這麼做的。
還有vgo,或者說go module有各種各樣的問題,有些你對我承認過的。你快速構思出來的解決方案讓事情變得更加複雜,並且對go使用者不透明。
vgo和dep都有各自的問題。vgo的問題我和你認可的一些人談過,他們對此也有顧慮。這些顧慮主要是風格方面的。
Go的問題主要有兩個:
\1. Go是一個Google提供的產品,其他人可以使用,但是沒有話語權。小的高度控制的團隊和社區是分離的,嫌隙正在越來越大。
\2. 一個新的依賴管理模型(大概值得是import versioning),有不熟悉和沒有驗證過的問題
Peter Bourgon 在其自己的部落格上發表文章"A response about dep and vgo"回應。只摘關鍵區段
Russ Cox狂發Twitter從他的視角描述了dep/vgo的故事。再去爭論曆史不是愉快的事情,但是敘述中有一些微妙和重要的事情,這對於我很重要,因為我經曆過這些事情,我的記憶和這些敘述不一致。我認為它重要是因為Go團隊花了很多時間和精力去推廣社區文化,我認為這次事件,雖然有點亂有點複雜,是一個完美的證據證明他們還沒有搞清楚正確的方式。有一個精確的記錄非常重要,這樣將來才能夠盡量避免再出現類似的問題。
Russ一開始講了一些曆史,我跳過去直接到有爭論的地方。
(引用了2017年7月其分享設計文檔給工作群組,以及在 GopherCon上討論的Twitter)
當時我也在場,在contributor summit,主持了包管理工作群組的多次會談。我不記得Russ精確的字詞了,但是我記得最終的結果。當會議進程過半的時候,Russ來了,他說他現在明白他需要自己去解決問題,他可能剛剛開始搞了或者已經搞了一半了,他希望能夠給一些反饋。
明顯的印象是,Russ並不打算——至少還沒打算——參與到委員會中來,包括我們提供給他的研究成果,以及研究的原型實現dep。Russ有他自己的關於最終方案的理論,他更想自己驗證這些理論。這是在第一次委員會和Russ有意義的溝通,當時我們正在為我們最終得到了核心團隊的關注而興奮,保持著謹慎的樂觀,結果卻是噩耗的開始。
Matt寫到:
"我看到 Jess, Sam和其他人發出了一聲歎息,低下了頭。看起來就好像空氣被從房間裡抽幹了。我非常的沮喪,以至於直接告訴你,這不是正確的對待把時間和努力投入這個事情上的人們的方式。"
我也清楚的記得這個時刻,就像Matt所寫的一樣。
(引用2017年11月draft提議dep支援semantic import versioning的Twitter)
這絕對是不正確的:委員會沒有人想要把dep簡單的搞成go dep。我們是提議增加一些子命令的整合,作為初稿以讓討論繼續下去,但是我們從來沒有堅持在最終產品上加上一個類似於ensure這樣的子命令,從第一天開始所有人都清楚這個事情。
確實,我們從一開始就知道深度整合到go中是必要的。我們還知道要需要go命令的作者-Russ的同意才能提出Proposal,所以我們謹慎的把做決定延遲到了Russ參與會談之後。事實上,我們避免在我們認為是go工具領域做決定,以讓將來的整合變得容易。dep提出了很多的初稿,比如ensure,以在Russ缺席的時候工作能夠繼續下去。
當時關於semantic import versioning我們是有幾次討論,Russ沒有能夠說服委員會它是必要的,我們也沒有一致的同意修改dep支援它。可能這就是他記得的東西。
(文章好長中間關於細節的撕逼跳過去了。。想瞭解的看原文吧)
(引用關於不可接受的放棄了dep那段Twitter)
這麼說是不誠實的。路線的修正也震驚到了所有的包管理工作群組人員,因為直到vgo的文章出來之前,我們每個人依然有希望和期望核心團隊繼續和我們一起工作,以讓dep達到可以被接受的狀態,而不是提議一個全新的東西。
我們有意謹慎的避免在和核心團隊建立更正式的溝通渠道之前,提出一個Proposal。很多dep的開發工作實在(和核心團隊)完全沒有溝通的情況下進行的。我們——至少我自己——在vgo的文章出現之後,仍然希望Russ和Sam的技術衝突能夠解決,並提出一個dep的Proposal。請記住:到那時位置,Russ只有兩三次出現在我們的會議中,而這個會議已經進行兩年了。
Russ的技術主張我們肯定沒有忽視,我們廣泛的爭論了這些主張。他們只是沒有說服Sam和委員會。與其最佳化那些主張讓它們更有說服力,或是與委員會一起找到一個妥協點,Russ決定自己去實現自己的想法,拋開我們自己提出Proposal,並且直到完成之後才告訴我們。必須說明:作為Go的技術負責人,Russ當然有權利做所有的這些事情。但是這樣一個項目反映了什嗎?
(這裡再省略一段。。)
當dep委員會成立的時候,我竭盡所能的,讓它以及它推進的工作,儘可能的可靠和無懈可擊,以保護工作群組的信用,工作群組成員的聲譽,以及產出的產品的有效性。為了代替自核心團隊的指導,甚至基本的交流,我們決定:
- 從社區的領袖和專家中徵集成員
- 成立一個次級的顧問組支援所有相關的項目
- 花費了半年時間收集使用者反饋和進行領域內的研究
- 詳細Review了所有其他有意義的包管理工具
- 步調一致的進行設計,目標在所有的主要決策上達成一致
- 所有的一切,都煞費苦心的,公開的記錄文檔
我們做了所有的這一切,因為我們想要成為社區能夠更近一步,解決一直被核心團隊忽視的問題的典範。我無法找到比我們比我們所做過的事情更好的事情了。但是結果,這些努力就像我們從來沒有做過任何事一樣:核心團隊最終不參與進我們所貢獻的成果上面,而是堅持自己完成,本質上一個全新的重頭開始的項目。
我想dep/vgo的結局很好的說明了,雖然Go領導層很樂意接受對issue和無爭議的Proposal這樣的貢獻,但仍然在與大規模的自主自治的貢獻者鬥爭。權利掌握在Google的核心Team Dev裡。
如果有一天我做關於這個最終失敗的項目的演講,我要在最後放一頁投影片,上面有一個圖,一艘船在島上失事了,船長說: "你生命的意義就在於警告其他人"。我希望這個故事給別人一個警告:"如果你有興趣對Go做出大的實質性的貢獻,獨立的勤奮工作不能補償你那不是來自核心團隊的設計"。
也許一些讀者讀到這裡會說:“Perter,這不是很顯然的事情嗎”。可能是吧。(沒能認識到是)我的錯。
Addendum(作者看完在Reddit上的討論添加的):
這次引發的討論啟發了我。我想我對於發生的事情,有了更好的全景的視角。我認為dep團隊和核心團隊各自有完全不同的對對話的理解,直到vgo文章的出現讓量子態塌縮了。
Dep團隊相信dep和之前出現的工具是不一樣的,是一個經過研究和詳細考慮,社區驅動的最終go依賴管理解決方案。核心團隊認為dep和之前的工具本質上是同一類,是他們設計的最終的方案的前奏的一部分。
我相信dep團隊很清楚他們的地位,能夠從核心團隊的表述中能夠看出來是處於什麼樣的地位的。但是明顯(dep團隊成員)沒有能夠普遍的理解這個地位,直到為時已晚,直到已經太晚。唉,事後來看是很顯然的事情,但是當時誰又能夠看得透呢?
image