成爲一名 Gopher 的 7 個階段

一天上班時,我們在工作聊天室裏討論 Go 編程語言。有一次,我對一個同事的幻燈片進行了評論,說了一些話。

「我認爲這就像是成爲 Go 程序員的七個階段中的第三階段。」

很自然地,我的同事們想知道其餘的階段,所以我簡單地概述了一下 [1]。以下是成爲 Go 程序員的七個階段,並附有更多的背景資料;看看你是否能在這條路上看到自己。

第一階段:你相信你可以讓 Go 做面向對象的編程

在最初運行 A Tour of Go[2] 之後,你開始思考 「現在,我怎樣才能使這種語言的行爲更像面向對象的語言……?」畢竟,你已經習慣了那些東西。你想編寫健壯的代碼。你想要多態性。

「一定有辦法的!」你說,然後你找到了結構嵌入 [3]。它允許你巧妙地將包圍對象的方法委託給嵌入對象,而不必重複編寫代碼。很好!

當然,這不是真的。結構嵌入只允許你 委託 方法的調用。即使你看起來像在做多態方法調度,這種關係也不是 IS-A(繼承)。它是 HAS-A(包含),所以方法調用的接收者不是包圍的對象。接收者始終是方法調用被委託給的嵌入式對象。

你不能在 Go 中進行面向對象的編程。階段。

第二階段:你相信 goroutines 會解決你所有的問題

你被 Go 的承諾所吸引,認爲它可以讓你輕鬆地運行併發代碼,它通過 goroutines[4] 做到了這一點!你所需要做的就是使用 go 關鍵字,你可以讓幾乎所有的函數或方法調用併發運行。那麼,你想通過使盡可能多的代碼並行運行來最大限度地提高你的代碼效率是很自然的。因爲你通過讓你的函數調用自動創建 goroutines 來隱藏這一事實,所以調用者甚至不需要意識到這一點。

是的,所以它可能會使你的代碼變得更復雜,但是看,現在所有的東西都在併發地運行了!這就是 Go。

Go 允許你在不犧牲效率的情況下創建數以百萬計的 goroutines,但你真的不應該因爲可以使用 goroutines 而使用它。併發代碼_比_只在單線程中運行的代碼更難維護和調試。我的意思是,你有沒有認真考慮過,當你從多個 goroutines 中同時訪問共享對象時,你的共享對象是否真的被正確同步了?你確定執行的順序是絕對正確的嗎?你真的檢查過這些 goroutines 在不再需要時是否真的退出了嗎?

Goroutines 最好只在必要時使用,除非你的需求決定了你要在內存中做所有的事情或類似的事情,否則你不應該放棄使用好的舊的多進程模型。

最後,儘量不要在用戶背後催生 goroutines,特別是當你在寫一個庫的時候。明確地使用 go 調用通常會給用戶更多的靈活性和權力。

goroutines 只能讓你走到這裏。只有在真正有意義的時候才使用它們。

第三階段:你相信,代替面向對象的編程,接口會解決你所有的問題

在對不能使你的對象以多態的方式行爲感到失望之後,你突然意識到接口所提供的能力 [5]。接口允許你描述 API;一定有辦法利用它來編寫更健壯的代碼。

所以現在當你寫庫的時候,你爲所有東西都定義了接口。你只輸出接口,並擁有私有結構,這樣封裝就很完美了。這也會讓你在切換底層實現時有更大的靈活性,因爲現在你已經成功地將 API 和它的實現解耦了。

接口 確實 給了你很大的權力,但它不是一個全能的解決方案。它仍然沒有提供面向對象編程意義上的真正的多態性。你還受限於這樣一個事實,即接口只能定義 API,而你不能將任何數據與之關聯。

另外,儘管在一些合理的情況下,只導出接口而不是具體的結構體是有意義的,但它真的不應該成爲你的默認操作模式。當接口很小的時候是最好的(相對於描述爲一個對象定義的整個方法列表而言)。另外,如果你不小心,你將不得不寫很多額外的代碼來實現接口,或者寫需要很多類型斷言的代碼。

爲了最大限度地利用接口,你應該只在你想讓某些類型可以互換時才使用它們。

第四階段:你相信 channels 會解決你所有的問題

在你花了很多時間思考如何讓 Go 按你的方式工作之後,你現在正在尋找那個缺失的部分,以使一切都按你的方式工作。「 等等,還有 channels[6]!」

channels 隱含地正確處理了併發訪問。你相信通過巧妙地使用 channels 來處理同步、返回值(la future/promises),以及用各種 channels 的 select 語句進行流控制,你應該能夠解決到目前爲止的許多障礙。

同樣,channels 是非常有用的,但它們的作用只和它們最初的目的一樣,即提供一個在 goroutines 之間傳遞數值的基元。

我相信你會發現很多 Go 的習性都在使用通道:用於超時、阻塞 I/O、同步技巧等等。但是,因爲通道是併發結構,濫用它們會導致更復雜的、難以調試的代碼。

第五階段:你現在認爲 Go 並不像人們所說的那樣強大

“爲什麼?爲什麼寫 Go 代碼這麼痛苦?它不允許我以我一直以來的方式寫代碼”。

你感到很沮喪。沒有多態性。併發是很難的。通道並不能解決你的問題。你甚至不明白爲什麼 Go 會存在。你覺得你已經被剝奪了其他語言提供的所有好的工具和結構。

你認爲更強大的工具來表達抽象的想法是絕對必要的。Go 就是不適合。

Go 是絕對有主見的。我的前一門語言是 Perl,有一段時間我無法相信 Go 的侷限性有多大。所以是的,如果你變得很沮喪,我可以理解。

但這是因爲這門語言確實有侷限性,還是_因爲你試圖讓這門語言按照你認爲的方式工作,而沒有考慮到語言作者希望你做什麼?_

第六階段:你意識到 1-5 階段都只是你的想象力

在某個時候,你勉強決定按照大多數標準庫的寫法 [7] 來寫 Go 代碼。你也放棄了聰明的嘗試,開始寫簡單的代碼。

然後你就想到了。你只是不想接受 Go 的方式。

一切都開始變得有意義了。

說實在的,學習 Go 確實需要一些不學習的東西。我不得不放棄學習面向對象的編程,同時也要接受這樣一個事實:無論語言給你提供多少有用的工具,編寫併發代碼對凡人來說都太難了。我也不得不停止學習使用異常。

我沒有向 Go 的作者覈實,所以這只是我的看法,但我相信這門語言的重點是讓開發者更難寫出複雜的代碼。它讓你有足夠的能力來編寫執行復雜任務的代碼,但_通過拿走某些關鍵工具,你最終寫出的代碼更簡單,更難搞。_

一旦我決定接受功能和結構的現狀,寫 GO 代碼就變得容易多了,而且肯定會更有趣。

第七階段:你現在很平靜

你已經接受了 Go 的方式。你現在寫所有的東西,包括你通常會用 Perl/Ruby/Python 寫的東西,都用 Go。你意識到 if err != nil 已經不再困擾你了。你只在必要時使用 goroutines 和 channel。

你與 Gopher 融爲一體 [8]。你感受到了它的光輝之氣,當你意識到它允許你用如此雄偉的語言寫代碼時,你會哭。

恭喜你。現在你是一個 Go 程序員了。


儘管這聽起來有點口無遮攔,但這些都是我在習慣 Go 時感受或經歷的實際問題。也許你同意,也許你不同意,但第六階段對我來說其實是這樣的。我最終放棄了讓 Go 像 想的那樣工作,決定_按 Go 告訴我_的方式來寫。這聽起來很傻,但在那之後,事情真的開始變得有意義了。

希望新手 Gophers 能少浪費一些時間來琢磨如何扭曲語言而受挫。祝你駭客愉快


原文地址:https://opensource.com/article/17/9/seven-stages-becoming-go-programmer

譯文地址:https://learnku.com/go/t/65253


那麼你覺得你處於哪個階段呢?歡迎留言討論。

參考資料

[1]

我簡單地概述了一下: https://gist.github.com/lestrrat/689e1fd0ec913582a733c446a041b0e4

[2]

A Tour of Go: https://tour.golang.org/

[3]

結構嵌入: https://golang.org/doc/effective_go.html#embedding

[4]

goroutines: https://golang.org/doc/effective_go.html#goroutines

[5]

接口所提供的能力: https://golang.org/doc/effective_go.html#interfaces

[6]

channels: https://golang.org/doc/effective_go.html#channels

[7]

按照大多數標準庫的寫法: https://golang.org/pkg/

[8]

你與 Gopher 融爲一體: https://blog.golang.org/gopher

Go 招聘 Golang 相關求職和招聘,以及面試題、經驗分享,Go 語言其他知識和職場也是值得分享的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/4NKmf7JjtgP2PsqMJoYCIQ