Russ Cox 的 2017 年 Go 開發計劃
注: Russ Cox目前是Go Team的leader
我的目標是幫助開發者。我想確保我們Go團隊所做的工作對Go開發人員有重大積極的影響。這聽起來很容易,但是有很多問題,例如:花費太多時間清理或優化不需要的代碼;只回應最常見或最近的投訴或要求;或過分側重于短期改進。重要的是確保我們的開發工作集中在最有效的地方。
這篇文章概述了我今年的幾個重點。這只是個人的看法,而不是Go團隊的。
發布本文的一個原因是想收集反饋。如果你有任何想法或建議,請隨時評論或新建GitHub issue。
另一個原因是讓大家明白我們知道這些問題很重要。人們常常認為Go團隊缺乏行動是因為我們認為一切都是完美的,而實際上是我們有其他更高優先級的工作要做。
Type aliases 類型別名
在大型代碼庫重構期間將類型從一個包移動到另一個包時存在重復的問題。 我們試圖用通用別名來解決它,這至少引入兩個問題:我們沒有解釋該變化帶來的問題,我們沒有及時交付,所以并沒有在1.8發布該功能。 前事不忘,后事之師,我做了一個 演講 并寫了一篇關于type aliases基本問題的 文章 ,并開始在Go issue tracker 上發起有關解決方案的討論。 現在看起來更有限的type aliases是正確的選擇。 我想確保type aliases可以順利隨Go 1.9發布。
Package management 包管理
我設計了 goinstall(它成為“go get”)工具。自那以后發生了很多變化。 特別是其他語言生態系統真正提升了人們對包管理的期望,開源世界大多數人同意語義化版本,這為推斷版本兼容性提供了基礎。 Go需要在這里做得更好,有一組代碼貢獻者一直在努力解決這一問題。 我想確保這些想法都很好地集成到標準的Go工具鏈中,并使包管理成為人們喜歡Go的理由。
Build Improvement
go構建系統的設計存在一些早該被修復的缺點。這里有三個代表性的例子,我打算重新設計go命令來解決這些問題。
build速度太慢,因為go命令不積極地緩存build結果。許多人沒有意識到用go install可以保存build結果,而go build不是。因此他們運行重復的go build命令會減慢構建過程。當修改依賴的時候,同樣的情況也發生在go test(應使用go test -i)。
測試結果也應該被緩存:如果測試的輸入沒有改變,那么通常不需要重新運行測試。這將使得在很少或沒有變化時運行“all tests”的開銷降低。
在GOPATH以外應該與在GOPATH內的工作一樣。特別是可以git clone一個repo,運行go命令,并使它們工作正常。軟件包管理只是使這一點變得更重要:您需要能夠在不同版本的包(比如v1和v2)上工作,而不需要為它們分配完全獨立的GOPATH。
代碼語料庫
從前面type aliases部分提到的文章和演講可以看到很多語料庫的實際使用。 我們還定義vet的插件必須針對真實程序中經常發生的問題。 我想看到對實際實踐的分析成為我們討論和評估Go變化的標準方式。
現在沒有一個商定的代碼語料庫用于這些分析(每個人都必須首先創建自己的),對每個人來說這都是一個太繁重的工作。 我想開放一個單獨的,自包含的Git repo,其中包括我們的用于分析的官方基準語料庫。 一個可能的起點可能是GitHub上的前100個Go語言庫。
Automatic vet
Go帶有go vet這個強大的工具。 當vet有輸出的時候,你應該檢查vet輸出。 每個人都必須運行它。 特別是,我認為我們可以在go測試期間運行vet,而不必減慢編譯 - 編輯 - 測試周期。 如果我們能做到這一點,并且我們啟用的vet檢查限制為100%準確,我們可以讓pass vet成為運行測試的前提條件。 開發人員不需要記得去運行go vet。 他們運行go test。
Errors & best practices
Go error的一部分是調用的函數以及相關的可用context,包括正在嘗試的操作(例如函數名稱及其參數)。 例如,這個程序:
err := os.Remove("/tmp/nonexist") fmt.Println(err)
輸出如下:
remove /tmp/nonexist: no such file or directory
然而并非所有的go代碼都像os.Remove這樣加入context,大部分代碼都是這樣:
if err != nil { return err }
沿著調用堆棧,拋棄有用的context(像remove /tmp/nonexist 等)。 我想嘗試理解我們對包含context的期望是否錯誤,或者我們可以做一些事情來幫助編寫返回更友好錯誤的代碼。
在社區中還存在關于剝離錯誤context接口的各種討論。 我想嘗試理解什么時候有意義,以及是否應該通過該建議。
Context & best practices
我們在Go 1.7中添加了新的context包,用于保存請求相關的信息,如超時,取消狀態和認證信息。一個獨立的context是不可變的(像一個單獨的字符串或int):它只能導出一個新的,更新后的context,并且將該context傳遞到調用棧或者(較不常見的)傳回調用者。context現在諸如database/sql和net/http之類的API中使用,主要是為了當調用者不再對結果感興趣時可以停止處理請求。超時信息適合在context中保存,但是數據庫選項不是,因為不太可能在請求期間執行的所有可能的數據庫操作。當前時鐘源或日志接收器怎么辦?是否適合存儲在上下文中?我想嘗試理解和描述適合使用context的場景。
內存模型
go內存模型相比其他語言需要更多的編譯器參與工作。 我認為核心編譯器和運行時開發人員都同意這些原子行為應該大致與C ++ seqcst atomics或Java volitiles相同,我們仍然需要仔細地在內存模型中寫下來,也可能是寫一篇長博客。
Immutability
race detector是Go最受歡迎的功能之一。 但沒有race會更好。 如果有一些合理的方法來將不變性集成到Go,這樣程序員可以做出明確的檢查斷言什么可以和不能寫,從而消除編譯時的某些競爭。 Go已經有一個不可變類型-string(string是不可變[]byte的類型)。 雖然我不認為今年會引入這一變化,但我想更好地了解該解決方案。 Javari,Midori,Pony和Rust都在解決方案討論中提出了有趣的觀點,除此之外還有大量的研究論文。
從長遠來看,如果我們可以靜態地消除競爭,那將消除對大部分內存模型的需要。 這可能是一個不可能實現的夢想,但我想更好地了解該解決方案。
沒有什么比Go是否應該支持泛型(或者多少年前應該發生)這一問題 更加能引起Go和非Go開發者激烈的爭論。 我不相信Go團隊曾經說過“Go不需要泛型”。我們所說的是Go面臨的更高優先級的問題。 例如,更好的軟件包管理支持將對大多數Go開發人員產生比增加泛型更大的直接積極影響。 但我們確實明白,對于Go來說缺乏參數多態性是一個顯著的障礙。
就個人而言,我想能夠編寫一般的channel處理函數,如:
// Join makes all messages received on the input channels // available for receiving from the returned channel. func Join(inputs ...<-chan T) <-chan T // Dup duplicates messages received on c to both c1 and c2. func Dup(c <-chan T) (c1, c2 <-chan T)
我還希望Go支持高級數據處理抽象(類似于FlumeJava或C#的LINQ),在編譯時捕獲類型錯誤,而不是在運行時。泛型還會帶增加來通用數據結構或算法實現的可能,但我個人覺得廣泛的應用程序更引人注目。
為了找到正確的方式為go添加泛型,我們已經努力了多年。一些人建議暫停設計通用參數多態性(如chan T)以及string和[]byte。如果后者通過不變性的參數化來處理(如在前面部分中所描述的)則可能簡化對于泛型的設計的需求。
當我在2008年開始考慮Go的泛型時,學習的主要例子是C#,Java,Haskell和ML。沒有一種方法是完美的。現在,還有更新的嘗試,包括Dart,Midori,Rust和Swift。
這是幾年來,我們探索的設計空間。考慮到對不可變性的理解和其他語言的實現,這可能是再次審視泛型的時候了。我不認為泛型將在今年引入,但我想說我可以更好地理解相關的解決方案。
來自:http://mp.weixin.qq.com/s/cScBWaFIvCLftakOy6fZAQ