Go 簡單性的價值:來自對 Go 倍加青睞的谷歌軟體工程師的自述

2019-11-27   Go語言中文網

Go 語言最近幾年逐漸獲得越來越多的開發者的喜歡。在 Go 社區前不久剛剛慶祝Go誕生10周年生日之際,谷歌雲軟體工程師 Benjamin Congdon 發表個人博客(11 月 11 日發表),表達了自己對 Go 倍加青睞的一些原因。他表示,「簡潔」是他喜歡使用Go語言最重要的原因。原文連結:https://benjamincongdon.me/blog/2019/11/11/The-Value-in-Gos-Simplicity/ 以下是譯文:

使用 Go 幾年後,我真的很欣賞它的簡單性。我幾個月前開始在工作中使用 Go,發現它真的很容易實現疊代,甚至是比 Python 和 Java 更為複雜的疊代。

當 Go 社區慶祝其成立 10 周年(https://blog.golang.org/10years)時,我正在思考是什麼使 Go 變得獨一無二。我認為 Go 的許多真正力量來自其設計師的理念:高度強調向前兼容性,該語言沒有損害可讀性的特性,並且隨手可得。你真正需要的一切它都提供了(包括基本測試庫,可靠的聯網和同步原語以及模板等)。

向前兼容性和依賴性

我認為,相較近期的語言,Go 具有最完善的版本控制和依賴關係。我從未因為 Go 的版本更新而遇到破壞兼容性的情況。這很重要。在相似的時間段內,由於 Rust 的 API 更改,臭名昭著的 Python 2 到 3 過渡,我的項目中斷了,老實說,如果 npm 升級後我的任何舊 JS 項目讓我感到吃驚。

藉助 Go,我注意到庫趨於穩定,這似乎讓人擔憂。因為在 Python 和 JavaScript 領域,如果你看到 3 年未更新的庫,則表明該庫已死。而在 Go 生態系統中,你可能可以使用它。在其他社區中被視為停滯或忽視的事物,在 Go 這裡反而是復興的標誌。

我還注意到,在 Go 中,我需要更少的依賴項,而我的依賴項本身也具有更少的依賴項。Go 沒有將儘可能多的邏輯導出到外部依賴項的文化。Go 社區比其他地方更容易接受代碼重複。這可能令人沮喪。有時,你只想要一個執行某種類型的環境或分析的庫。很多時候,你需要自己編寫該功能,或者從 StackOverflow 答案中複製/粘貼該功能。總的來說,我認為這一點還是利大於弊。更少的依賴項意味著項目閒置幾個月之後被迫中斷的可能性更低。

現在,這對於其他語言、社區可能有點不公平。Rust 尚未達到 Go 所具有的穩定性,這可能是因為它還不是一種成熟的語言,但它正朝著這一方向發展。Python 3 本身已向前兼容,我希望 Python 核心開發人員能從中學到關於硬破損的教訓。在這方面,我對 Javascript 不太抱有希望,但是據說 WebAssembly 和 ES10 將解決我們所有的問題。

Go 的依賴管理並不是沒有問題。有一陣子,dep 和 glide 的破裂確實很煩人。並且,儘管 Go Modules 很棒,但社區仍未達到 100% 的採用率。在使用 Go Modules 之前,將所有內容都保留在 $GOPATH 下的要求非常煩人,以至於我推遲了多年進入 Go 的工作。現在情況已經好轉並顯示出改善的跡象。

就向前兼容性而言,自 Go1 發布以來,所有 Go 代碼都可以得到兼容性的保證[1],這會一直運行到 Go2,直到將來的某個不確定的時間點。這是一個強有力的承諾,至少到目前為止,這讓我對這種語言的使用很放心。

「你不需要它」(但你可能想要它)

在使用 Go 一段時間後,我開始想要一些 Go 語言根本不支持的額外功能。嗯,我對 C++ 模板的排斥程度不亞於任何一個人,但是擁有基本的集合類泛型這個要求也不過分,對吧?

開箱即用的唯一兩個通用數據結構是切片(slice)和映射(map)。那是否要編寫自己的數據結構?要麼必須針對特定類型進行設置,要麼需要盯著一個全是 interface{} 的欄位。這兩種方法都各有所長,但有時候,我希望可以只導入類型安全的、通用的、雙向 map。

Go 將「你根本不需要」[2]發揮到了極致。「需要」是這裡的重點詞。你「不需要」泛型,但幾乎可以肯定你想要它。這樣的語法糖在錯誤處理、函數式編程和運算符重載上都是上上之選。

那句「陳詞濫調」怎麼說來著?有時「少即是多」。除了命名返回值[3]之外,我想不出 Go 語言中的任何讓用戶抓狂的功能了。令人印象深刻的是,Go 核心開發人員對在 Go 中模仿其他語言的開發人員群體表現出了極大了約束。Go2[4] 的未來對我來說真的很令人興奮,因為我很期待看到已經習慣的「下一代」 Go 是什麼樣子。

包括了足夠你需要的

對於 Go 令人讚嘆的另一點是,它提供了幾乎所有你需要的。

go test 是一個很好的(儘管是基本的)測試框架。你無需成為 JUnit 的領域專家,也無需在 nose 和 unittest 之間進行選擇。為方便起見,有一些測試斷言庫,例如 testify[5],你可以引入它們,但「你並不必須要」。

類似地,Go 的 sync 包涵蓋了你可能需要的大多數同步原語,http提供了可用於生產環境的 HTTP 伺服器和客戶端(甚至支持 HTTP2),而且 encoding 包有足夠多的子包可以處理 json、xml、csv 以及許多其他常見格式的數據。

格式化,格式化,格式化(老外也強調重要的事情說三遍)

最後,如果我不提到gofmt,我會很失落。在格式化方面,我有點挑剔。我並不特別在意使用哪些規則,但是我非常在乎一致性。Go 的內部格式化工具 gofmt 已被社區廣泛採用,並提供了足夠的一致性,使 Go 的代碼「看起來」符合 Go 的習語,而不會看代碼看得要抓狂。

就個人而言,我發現使用gofmt可以更輕鬆地閱讀開源 Go 代碼。每個項目仍然有自己的處理方式,但是每個項目都遵循相同的格式約定。從美學上講,這讓人很高興。


所以,我喜歡 Go。曾經有一段時間,我對 Zen of Python[6] 非常著迷,並且對其他語言不屑一顧。我期待 Go 的美好未來,我可能以後會在 Rust 流行起來之後,去用 Rust 趕一波時髦,因為我確實喜歡一些類似於函數式的編程。

但是現在,我非常願意繼續使用 Go 語言。

文中連結

[1]保證: https://golang.org/doc/go1compat

[2]「你根本不需要」: https://www.martinfowler.com/bliki/Yagni.html

[3]命名返回值: http://tour.studygolang.com/basics/7

[4]Go2: https://github.com/golang/go/wiki/Go2

[5]testify: https://github.com/stretchr/testify

[6]Zen of Python: https://www.python.org/dev/peps/pep-0020/

喜歡本文的朋友,歡迎關注「Go語言中文網」:

Go語言中文網啟用微信學習交流群,歡迎加微信:274768166