首頁  >  文章  >  後端開發  >  Go 設計哲學:少即是多,哪來的?

Go 設計哲學:少即是多,哪來的?

Golang菜鸟
Golang菜鸟轉載
2023-08-07 16:39:04543瀏覽

之前在 Go 社區分享知識和經驗時,經常會聽見諸如:less is more、少即是多,大道至簡、大道不停地至簡等黑話。

甚至討論 Go issues 和提案時,都會有人用 “less is more” 來反駁或做為論點支撐,非常的有意思。大家都會很好奇,出處是哪裡,是什麼意思?

金句出處

如此根深蒂固的社區文化觀念,想必是有核心的人提出。說出這句話的作者就是他:

Go 設計哲學:少即是多,哪來的?

有人認得嗎?

他是 Go 語言之父的 Rob Pike。

Rob Pike 在多個場合提到類似 「少即是多」 的觀點,該觀點廣為流傳。

Go 設計哲學:少即是多,哪來的?

分享的場合諸如:

  • #在2012 年,Go SF 會議上分享的是《Less is exponentially more[1]》,這是最早的公開觀點整理而成的文章分享。
  • 在2015 年,dotGo 會議上分享的是《Simplicity is Complicated[2]》,持續不斷灌輸文化,分享觀點。

此觀點的各類變型語句在業界廣為流傳,形成了 Go 社群獨特的 「文化」。

當然,從社群反響來看,有褒有貶。

演講內容

此處引用Rob Pike 的《Less is exponentially more[3]》,正文部分@MIKESPOOK[4] 翻譯,我在這裡重新整理、修剪、引用、配圖,就不重複造輪子了,明確聲明。

如下圖:

Go 設計哲學:少即是多,哪來的?

背景

#這是我(下指Rob Pike)在2012 年六月,舊金山Go 會議上的演講內容。

這是一個私人演講。我並未代表 Go 專案團隊的任何人在此演講,但我首先要感謝團隊為 Go 的誕生和發展所做的一切。

同時,我也要感謝舊金山 Go 社群給我這個演講機會。

Go 讓我最驚訝的地方

#在幾個星期之前我被問到:「在推出Go 之後,什麼令你感到最為驚奇?」

我立刻有了一個答案:儘管我們希望C 程式設計師來了解Go 並作為一個可選的語言,但是更多的Go 程式設計師來自如於Python、Ruby,只有很少來自C 。

我們(Ken,Robert 和我)自己曾經是 C 程式設計師,我們設計新的語言是為了解決那些我們寫的軟體中遇到的問題。

Go 設計哲學:少即是多,哪來的?

而這些問題,其他 C 程式設計師似乎不太在意,這看起來有些矛盾。

為什麼要開發Go

今天我想要談談是什麼促使我們創建了Go,以及為什麼本來就不應該是這樣會我們驚訝的結果。

我承諾討論 Go 會比討論 C 多,即使你不了解 C 也仍然完全跟得上主題。

答案可以歸納為:你認為少既是多,還是少就是少

貝爾實驗室的故事

這裡有一個真實的故事作為隱喻。如下:

  1. 貝爾實驗室最初以三個數字來識別:111 表示物理研究,127 表示電腦科學研究,等等。
  2. 在上世紀八十年代早期,一篇如期而至的備忘錄聲明由於我們所了解的研究正在增長,為了便於識別我們的工作,必須再添加一位數。因此,我們的中心變成 1127。
  3. Ron Hardin 開玩笑半認真的說道,如果我們真的更好的了解了這個世界,我們可以減少一位數,使得 127 僅為 27。

當然管理階層沒有聽到這個笑話,又或者他們不願意聽到,但是我想這其中確有大的智慧。少既是多。你理解得越好,越含蓄。

請務必記住這個思路。

開發Go 的背景

#C 編譯等待

回到2007 年9 月,我在一個巨大的Google C 程式(就是你們都用過的那個)上做一些瑣碎但是很核心的工作。

我在那個巨大的分散式叢集上需要花大約 45 分鐘進行編譯。

C 新特性改進

收到一個通知說幾個受僱於Google 的為C 標準化委員會工作的人將會做一場報告。

他們將向我們介紹那時還被稱為 C 0x(就是現在眾所周知的 C 11)中將會有哪些改進。

Go 設計哲學:少即是多,哪來的?

在長達一個小時的報告中,我們聽說了諸如有已經在計劃中的 35 個特性之類的事情。

事實上有更多,但只有 35 個特性在報告中進行了描述。當然有些特性很小,但是意義重大,值得在報告中提出。

還有一些非常微妙且難以理解,如:

  • 左右值參考(rvalue references)。
  • 可變參數範本(variadic templates。
  • #使用者定義資料標識(user-defined literals)。

##這時我問了自己一個問題:C 委員會真得相信C 的問題在於沒有足夠的特性

#肯定的說,在另一個Ron Hardin 的玩笑中,簡化語言的成就遠大於添加功能。當然這有點可笑,不過請務必記住這個思路。

##實驗性語言嘗試

就在這個C 報告會的幾個月前,我自己也進行了一場演講,你可以在YouTube 上看到,關於我在上世紀80 年代開發的一個玩具性質的並發語言。這個語言被叫做Newsqueak,它是Go 的前輩了。

我進行這次報告是因為在Newsqueak 中缺失的一些想法,在為Google 工作的時候我再次思考了這些它們。我當時確信它們可以使得編寫服務端程式碼變得更加輕鬆,使得Google 能從中獲得收益。

事實上我

曾嘗試在C 中實現這些思路,但是失敗了。要將C 控制結構和並發操作聯繫起來太困難了,最終這導致很難看到真正的優勢。

#雖然我承認我從未真正熟練的使用C ,但是純粹的C 仍然讓所有事情看起來過於笨重。所以我放棄了這個想法。

但那場 C 0x 報告讓我再次思考這個問題。有一件令我十分困擾的事情(同時我相信也在困擾著 Ken 和 Robert)是新的 C 記憶體模型有原子類型。

感覺上在一個已經負擔過重的類型系統上加入如此微觀的描述細節的集合是絕對的錯誤。這同樣是短視的,幾乎能確信硬體在接下來的十年中將迅速發展,將語言和當今的硬體結合的過於緊密是非常愚蠢的。

Go 初始團隊

在報告後我們回到了辦公室。我啟動了另一個編譯,將椅子轉向 Robert,然後開始溝通關鍵的問題。

在編譯結束前,我們已經把 Ken 拉了進來,並且決定做些什麼。

我們不準備繼續寫 C 了,而且我們——尤其是我,希望在寫 Google 程式碼的時候能夠做輕鬆的寫作並發。

同時我們也想勇往直前的駕馭“大編程”,後面會談到。

Go 特性討論

我們在白板上寫了一堆想要的東西,和其必要條件。忽略了語法和語義細節,設想了藍圖和全局。

我這裡還有那時的一個令人神混魂顛倒的郵件。

這裡摘錄了一部分:

  • Robert:起點是 C,修復一些明顯的缺陷,移除雜物,加入一些缺失的特性。

  • Rob:命名為 “go”。你們可以編造這個名字的來由,不過它有很好的底子。它很短,容易拼寫。工具:goc, gol, goa。如果有互動式除錯器/解釋器,可以就叫做 “go”。副檔名是 .go。

  • Robert:空介面為 interface{}。它們實作了所有的接口,所以這個可以用來代替 void *。

我們並沒有正確描繪全部的東西。例如,描繪 array 和 slice 花了差不多一年的時間。但是這個語言特色的大多數重要的東西都在開始的幾天裡確定下來。

注意 Robert 說 C 是起點,不是 C 。我不確定,不過我相信他是指 C,尤其是 Ken 在的情況下。

不過事實是,最終我們並沒有從 C 作為起點。我們從頭開始,僅僅借鑒瞭如運算符、括號、大括號、和部分關鍵字。 (當然也從我們所知道的其他語言中吸取了精髓。)

無論如何,我們現在同 C 做著相反的事情,解構全部,回到原點重新開始。我們並未嘗試去設計一個更好的 C ,甚至更好的 C。只是一個對於我們在意的那種類型的軟體來說更好的語言。

最終,它成為了一個與 C 和 C 完全不同的語言。每個發布版本都越來越不同。

Go 特性清單

我製作了一個 Go 中對 C 和 C 進行的重要簡化的清單:

  • 規範的語法(無需用於解析的符號表)。
  • 垃圾收集(唯一)。
  • 沒有頭檔。
  • 明確依賴
  • 無迴圈依賴。
  • 常數只能為數字。
  • int 和 int32 是不同的型別。
  • 字母大小寫設定可見性。
  • 任何類型都可以有方法(沒有類別)。
  • 沒有子類型繼承(沒有子類別)。
  • 套件層級初始化和定義好的初始化順序。
  • 檔案編譯到一個套件中。
  • 套件層級的全域表達與順序無關。
  • 沒有算術轉換(常數做了輔助處理)。
  • 隱含的介面實作(無需「implements」定義)。
  • 嵌入(沒有向父類別的升級)。
  • 方法如同函數一樣進行定義(沒有特的別位置要求)。
  • 方法就是函數。
  • 介面只包含方法(沒有資料)。
  • 方法僅透過名字來匹配(而不是透過類型)。
  • 沒有建構或析構方法。
  • 後自增和後自減是語句,而不是表達式。
  • 沒有前自增或前自減。
  • 賦值不是表達式。
  • 依照賦值、函數呼叫定義時的順序執行(沒有「sequence point」)。
  • 沒有指標運算。
  • 記憶體總是零值初始化。
  • 對局部變數取位址合法。
  • 方法沒有「this」。
  • 分段的堆疊。
  • 沒有靜態或其他型別註解。
  • 沒有模板。
  • 沒有異常。
  • 內建 string、slice、map。
  • 陣列邊界檢查。

除了這個簡化清單和一些未提及的瑣碎內容,我相信,Go 相比 C 或 C 是​​更有表達力的。少既是多。

但是即使這樣也不能丟掉所有東西。仍然需要建構類型運作的方式,在實踐中恰當的語法,以及讓庫的交互更好這種令人感到忌諱不可言喻的事情。

我們也加入了一些C 或C 沒有的東西,例如slice 和map,複合聲明,每個檔案的頂級表達式(一個差點被忘記的重要東西),反射,垃圾收集,等等。當然,還有並發。

無法想像沒有泛型

當然明顯缺少的是型別層次化。請容許我對此爆那麼幾句粗口。

在 Go 最初的版本中,有人告訴我他無法想像用一個沒有泛型範式的語言來運作。就像之前在某些地方提到過的,我認為這絕對是神奇的評論。

公平的說,他可能正在用自己的方式來表達他非常喜歡 STL 在 C 中為他做的事情。在辯論的前提下,讓我們先相信他的觀點。

他說寫像 int 清單或 map string 這樣的容器是一個無法忍受的負擔。我覺得這是個神奇的觀點。

即使是那些沒有泛型範式的語言,我也只會花很少的時間在這些問題上。

物件導向的方式

但是更重要的是,他說類型是放下這些負擔的解決途徑。類型。不是函數多型,不是語言基礎,或其他協助,只用型別。

這就是卡住我的細節問題。

從 C 和 Java 轉過來 Go 的程式設計師懷念工作在類型上的程式設計方式,尤其是繼承和子類,以及所有相關的內容。可能對類型來說,我是門外漢,不過我真得從未發現這個模型十分具有表達力。

我已故的朋友 Alain Fournier 有一次告訴我說他認為學術的最低級形式就是分類。那你知道嗎?類型層次化就是分類。

你必須對哪塊進哪個盒子作出決策,包括每個類型的父級,不論是 A 繼承自 B,還是 B 繼承自 A。

一個可排序的陣列是一個排序過的陣列還是一個陣列表達的排序器?如果你堅信所有問題都是由類型驅動設計的,那麼你就必須做出決策。

我相信這樣思考程式設計是荒謬可笑的。核心不是東西之間的祖先關係,而是它們可以為你做什麼。

當然,這就是介面進入 Go 的地方。但是它們已經是藍圖的一部分,那是真正的 Go 哲學。

如果說 C 和 Java 是關於型別繼承和型別分類的,Go 就是關於組合的。

Unix pipe 的最終發明者Doug McIlroy 在1964 (!) 這樣寫到:

我們應該像連接花園裡的龍頭和軟管一樣,用某種方式一段一段的將訊息資料連結起來。這同樣是 IO 使用的辦法。

這也是 Go 使用的辦法。 Go 用了這個主意,並且將其向前推進了一大步。這是一個關於組合與連結的語言。

一個顯而易見的例子就是介面為我們提供的組合元件的方式。只要它實現了方法 M,就可以放在適當的地方,而不關心它到底是什麼東西。

另一個重要的例子是並發如何連接獨立運行的計算。而且也有一個不同尋常(但非常簡單)的類型組合模式:嵌入。

這就是 Go 特有的組合技術,滋味與 C 或 Java 程式完全不同。

C /Java 的大程式模式

#有一個與此無關的Go 設計我想提一下:Go 被設計用於幫助編寫大程序,由大團隊編寫和維護。

有一個觀點叫做“大程式設計”,不知怎麼回事 C 和 Java 主宰了這個領域。我相信這只是一個歷史的失誤,或是工業化的意外。但是一個廣泛被接受的信念是物件導向的設計可以做些事情。

我完全不相信那個。大軟體確實需要方法論保駕護航,但是用不著如此強的依賴管理和如此清晰的接口抽象,甚至如此華麗的文檔工具,但它不比強大的依賴管理、清晰的接口抽象和優秀的文檔工具來得更重要,而這些沒有一樣是C 做好的事情(儘管Java 明顯做得更好)。

我們還不知道,因為沒有足夠的軟體採用 Go 來編寫,不過我有自信 Go 將在大程式設計領域脫穎而出。時間證明一切。

為什麼Go 不被C 程式設計師喜歡

#現在,回到我演講一開始提到的那個令人驚奇的問題:

為什麼Go,一個被設計成用來摧毀C 的語言,並為並未獲得C 程式設計師的芳心?

撇開玩笑不說,我認為那是因為 Go 和 C 有著完全不同的哲學。

C 是讓你的指尖解決所有的問題

我在 C 11 的 FAQ 上引用了這段內容:

C 與那些巨大增長的特別編寫的手工程式碼相比,具有更加廣泛的抽象,優雅、靈活並且零成本的表達能力。

這個思考的方向與 Go 的方向不同。零成本不是目標,至少不是零 CPU 成本。 Go 的主張更多考慮的是最小化程式設計師的工作量

Go 不是無所不包的。你無法透過內建獲得所有東西。你無法精確控制每個細微的執行。例如沒有 RAII。而可以用垃圾收集作為代替。也沒有記憶體釋放函數。

你得到的是功能強大,但是容易理解的,容易用來建立一些用於連接組合解決問題的模組

這可能最終不像你使用其他語言編寫的解決方案那麼快,那麼精緻,在思想體系上那麼明確,但它確實會更加容易編寫,容易閱讀,容易理解,容易維護,並且更加安全。

換句話說,當然,有些過於簡單:

  • Python 和Ruby 程式設計師:轉到Go 是因為他們並未放棄太多的表達能力,但是獲得了性能,並與並發共舞。
  • C 程式設計師:無法轉到 Go 是因為他們經過艱辛的戰鬥才獲得對其語言的精確控制能力,而且也不想放棄任何已經獲得的東西。對於他們,軟體不僅僅是關於讓工作完成,而是關於用一個確定的方式完成。

那麼問題是,Go 的成功能否反駁他們的世界觀?我們應該在一開始的時候就意識到了一點。

那些為 C 11 的新特性而興奮的人們是不會在意一個沒有這麼多特性的語言。即便最後發現這個語言能夠比他們所想像的提供更多。

謝謝大家。

總結

一直以來對 Go 的哲學 “less is more” 非常的好奇,來源是何處,意義又是什麼?

在春節期間閱讀和梳理了一遍,雖然演講內容比較多,也偏向口語化。但本質上 Rob Pike 所說的 “less is more” 是比較有趣的東西。

核心觀點在於:“Go 與C 的觀念完全不同,希望程式設計師的工作量最小化,自身少量的特性,應當能夠連接組合解決問題,更具表達力,而不是堆功能” 。

#

以上是Go 設計哲學:少即是多,哪來的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:Golang菜鸟。如有侵權,請聯絡admin@php.cn刪除