Go 里的海勒姆定律?非必要不修改......
大家好,我是煎魚。
在我們日常工作中,只要你維護過歷史比較悠久的項目??倳龅揭恍┥衿娴拇a。其中最莫過于在老代碼上,前人讓你不要改這塊邏輯的注釋。
在 Go 中也有一些約定俗成的代碼。周末看到了還有點意思,分享給大家。
“該文本不可變更”
在 net/http 標準庫中,有以下這段代碼:
func (e *MaxBytesError) Error() string {
// Due to Hyrum's law, this text cannot be changed.
return "http: request body too large"
}
注意看上面的注釋:“Due to Hyrum's law, this text cannot be changed.”。翻譯過來中文含義是:根據海勒姆定律,此文本不可更改。
大家看到可能會犯迷糊。海勒姆定律是什么?教科書上可沒有教過這玩意。
海勒姆定律是什么
海勒姆定律(Hyrum's Law) 是一種軟件開發領域的概念。由 Google 工程師 Hyrum Wright 提出,他在一次演講中討論接口設計和演化問題時提出了這一觀察并得到了驗證。
核心描述是:
- 無論接口的官方文檔或開發者如何嚴格定義接口的行為,接口的實際行為都會影響其用戶。
- 所有可能的用戶依賴接口實際行為的方式,最終都會受到接口的實現約束,而不僅僅是其文檔描述。
簡單來講,接口的所有行為,無論是顯式定義的還是隱式存在的,都會被用戶依賴。
即便某些行為不是接口規范的一部分,只要接口表現出了某種行為,使用它的系統或代碼可能就會開始依賴這種行為。
Go 源碼中的案例
結合前面的案例來看,原作者意識到錯誤消息無法隨意更改,因為可能有某些地方的某些用戶依賴于該錯誤消息。
雖然調整錯誤消息看起來微不足道,但這種改動可能會對依賴這一特定消息的用戶造成意想不到的問題。
這種情況下,一個看似無關緊要的描述修改:"http: request body too large",可能會導致用戶的業務代碼的中斷。從而影響 Go1 的兼容性保障和程序運行。
那 Go 源碼里還有沒有其他地方有類似的描述呢?挺多的。如下幾個,請看注解中的 “Hyrum's Law” 部分。
1、crypto/rsa/rsa.go[1]:
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
// Note that while we don't commit to deterministic execution with respect
// to the random stream, we also don't apply MaybeReadByte, so per Hyrum's
// Law it's probably relied upon by some. It's a tolerable promise because a
// ...
2、crypto/rsa/pss.go[2]:
func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) {
// Note that while we don't commit to deterministic execution with respect
// to the rand stream, we also don't apply MaybeReadByte, so per Hyrum's Law
// it's probably relied upon by some. It's a tolerable promise because a
// ...
3、internal/weak[3]:
Using go:linkname to access this package and the functions it references
is explicitly forbidden by the toolchain because the semantics of this
package have not gone through the proposal process. By exposing this
functionality, we risk locking in the existing semantics due to Hyrum's Law.
總結
“海勒姆定律” 和 Go 源碼中的 “被動實踐” 都很好的印證了。只要你開放出去的東西,無論是接口,又或是參數。都有可能神不知鬼不覺中被用戶依賴了。當你一旦作出變更時,就有可能產生不兼容。導致第三方系統出錯或者產生臟數據,要進行洗數據。
為什么我會知道?因為最近我有一個朋友他遇到了(doge。當然,最好在設計系統或接口時,就要盡可能的減少依賴非預期行為的可能性!
參考資料
[1]crypto/rsa/rsa.go: https://github.com/golang/go/blob/5123f38e050c5ee7130d459ea247d998a838b5a1/src/crypto/rsa/rsa.go#L517
[2]crypto/rsa/pss.go: https://github.com/golang/go/blob/5123f38e050c5ee7130d459ea247d998a838b5a1/src/crypto/rsa/pss.go#L294
[3]internal/weak: https://github.com/golang/go/blob/5123f38e050c5ee7130d459ea247d998a838b5a1/src/internal/weak/pointer.go#L24