跳到主要内容

Golang 库开发

· 阅读需 3 分钟

指导原则

  1. 开发库,写代码反而是简单的部分
    1. 总有计划外的工作
    2. 总有新的 feature
    3. 总有要修的 bug
  2. 人们衡量开源库的质量基本方式
    1. 基本的代码质量, go vet, go fmt, go lint
    2. 测试覆盖率
    3. 文档
    4. Issue open / closed 的数量
    5. GitHub star 数量多并不意味着质量高
  3. 开源库的四大要素, 可用性/可读性/灵活性/可测性

库的四大要素

可用性: 从使用者角度出发思考问题

比如要写一个 HTTP GET Request ,先创建再发送

import "net/http"

req, err := http.NewRequest(
http.MethodGet, "https://www.google.com", nil /* no body */)
if err != nil {
return err
}
client := &http.Client{}
res, err := client.Do(req)

但是,这种代码会经常被用到,反复写的话会很冗长,那么为什么不直接提供 GET 的接口呢?

import "net/http"

client := &http.Client{}
res, err := client.Get("https://www.google.com")

可读性

灵活性

还是 GET 的例子,如果要加 request logging

import "net/http"

client := &http.Client{}
res, err := client.Get("https://www.google.com")

有一个可替换的 RoundTripper interface

type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
// If nil, DefaultTransport is used.
Transport RoundTripper
type RoundTripper interface {
RoundTrip(*Request) (*Response, error)
}

这样只需要指定一个 loggingRoundTripper 就可以了,不需要 wrap

import "net/http"

client := &http.Client{Transport: loggingRoundTripper}
res, err := client.Get("https://www.google.com")

可测性

  • 不仅要自己保证自己可测
  • 还提供 test helper 给 caller 用

向后兼容

  • 任何 exported entity
    • 重命名、移除
    • 函数参数类型的修改
    • interface 加一个 method

这些都有可能导致 breaking change,这个时候就需要 semantic version 了

版本控制

Semantic Versioning 2.0.0 | Semantic Versioning

MAJOR.MINOR.PATCH
  • patch: a bug fix
  • minor: a new non-breaking change
  • major: a breaking change

Stable / Unstable?

  • v < 1.0 unstable
    • 从 0.1.0 开始,每个 release 的时候 increment MINOR,bug fix 的时候 increment PATCH
  • v >= 1.0 stable 正式版 release 1.0

Version Bump 很难,在 micro services 大系统中的核心库大概会花 6 个月到 1 年来更新所有的 dependencies

^1.1 is short for >= 1.1, < 2;
~0.2 is short for >= 0.2, < 0.3

Pin to version range vs Lock exact version

Want to keep learning more?