golang: 从 Uber Go 风格指南,摄取 API 设计营养

2019-10-16 09:29:51 +08:00
 guonaihong

昨天晚上快速看了 uber go 风格指南,发现最后一条技巧,对 API 设计有帮助,拿出来大家一起讨论下。

回顾

bad code

// package db

func Connect(
  addr string,
  timeout time.Duration,
  caching bool,
) (*Connection, error) {
  // ...
}

// Timeout and caching must always be provided,
// even if the user wants to use the default.

db.Connect(addr, db.DefaultTimeout, db.DefaultCaching)
db.Connect(addr, newTimeout, db.DefaultCaching)
db.Connect(addr, db.DefaultTimeout, false /* caching */)
db.Connect(addr, newTimeout, false /* caching */)

good code

type options struct {
  timeout time.Duration
  caching bool
}

// Option overrides behavior of Connect.
type Option interface {
  apply(*options)
}

type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
  f(o)
}

func WithTimeout(t time.Duration) Option {
  return optionFunc(func(o *options) {
    o.timeout = t
  })
}

func WithCaching(cache bool) Option {
  return optionFunc(func(o *options) {
    o.caching = cache
  })
}

// Connect creates a connection.
func Connect(
  addr string,
  opts ...Option,
) (*Connection, error) {
  options := options{
    timeout: defaultTimeout,
    caching: defaultCaching,
  }

  for _, o := range opts {
    o.apply(&options)
  }

  // ...
}

// Options must be provided only if needed.

db.Connect(addr)
db.Connect(addr, db.WithTimeout(newTimeout))
db.Connect(addr, db.WithCaching(false))
db.Connect(
  addr,
  db.WithCaching(false),
  db.WithTimeout(newTimeout),
)

技巧肢解

里面主要用了两种技巧

可变长参数的好处

gout https://github.com/guonaihong/gout

gout(流式 http client) 可以使用 SetCookies 可以设置一个或者多个 cookie。在大多数开源库里面用了两个函数实现类似功能。gout 这里用上可变长参数可以减少 API 个数。

gin 里面

在 gin(API 框架) Run 函数就是可变长参数经典用法,你可以用 router.Run()起个默认服务,也可以用 router.Run(":1234") 指定端口起服务。这里也可以减少 API 个数,写起来很爽。

上面举的例子可以归纳出,可变长参数用在,函数参数个数 >=0 的地方,很爽。

函数(接口)当配置

//TODO,中午再补上。

5113 次点击
所在节点    程序员
30 条回复
flybird
2019-10-16 09:38:16 +08:00
为啥我感觉第一种 bad code 更好呢,简单明了?
下面 啰啰嗦嗦 实现了一堆,道理上讲貌似更好,读起来太啰嗦。
dyllen
2019-10-16 09:39:15 +08:00
@flybird 估计这就是优雅吧,看起来高大上。上面的简单粗暴,像个粗人。
ylsc633
2019-10-16 09:53:32 +08:00
http://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html

我曾在这看到的.. 就学习(模仿)了一下.. 很装逼... 哈哈哈
reus
2019-10-16 09:59:24 +08:00
初期只有一两个参数,那当然第一种好

后期参数多了,就直接加 Option 结构体

用函数这种……没有十几二十个选项我是不会用的
reus
2019-10-16 10:00:53 +08:00
著名 go 开发者 Dave Cheney 写过相关博文: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
zunceng
2019-10-16 10:08:08 +08:00
挺好的

不过用了依赖注入以后这样就不好写了
reus
2019-10-16 10:13:15 +08:00
@zunceng 没错,用了依赖注入,第一种反而是最方便注入的
scnace
2019-10-16 10:13:36 +08:00
@reus 刚想发
zzlettle
2019-10-16 10:30:36 +08:00
个人感觉,go 的这种函数变接口的方式,不要到处用
能用简单直接,人类思维方式的语言来实现的,就用我们人能一眼看明白的方式来写代码
他这种写法,几乎一半以上实在炫技
就好像,同样是吃饭,用什么碗都可以,有钱人非要用黄金碗
其实重要的是你碗里面的东西

唯一的作用就是吓唬不懂得人
反人类
这就是为什么 python 运行效率不高,但是热度慢慢攀升到第一得原因
因为他是人类得语言
love
2019-10-16 10:35:51 +08:00
第二个看着太吓人了,在别的语言比如 Typescript 里简单明了且也有类型保证的传参方式在 Go 里怎么这么反人类。

看来写普通业务用 Go 实在不是一个好选择。
maichael
2019-10-16 10:38:47 +08:00
其实要看你的 API 面向谁开发。
zzlettle
2019-10-16 10:40:32 +08:00
说句现在央视里面常用得政治术语来形容
go 的这套语法风格
跟 python 的语法风格
区别就好像
是党指挥枪,还是枪指挥党
python 就是人类思维
是党指挥枪
所有方法函数,要围绕数据来运行
go 就是枪指挥党
所有方法函数,指挥其他的数据变量
人类天生的思维方式就是
数据驱动
就是我学习本领,掌握了方法
让方法为我而用
现在 go 的这套
就是我们人类围绕方法而改变自己

go 的这套语法真的不太适合初学者
wingoo
2019-10-16 10:47:04 +08:00
functional options 对于调用者友好, 开发者不友好
不过实现好一个单独的类库还是挺好用的
Mark3K
2019-10-16 10:50:33 +08:00
grpc 中用了大量的这类技巧,看看就能学会
chenqh
2019-10-16 13:15:07 +08:00
这么喜欢封装,不写 java 可惜了
optional
2019-10-16 13:17:47 +08:00
db.WithCaching ... 要用 builder 就彻底一点 db.ConnectionBuilder().Withxxx().Withxxx().connect();
chendy
2019-10-16 13:32:19 +08:00
看不太明白的 java 程序员表示:何不 Builder ?
gfreezy
2019-10-16 15:42:16 +08:00
为啥不用 Builder,好像更加简单直观,功能也更强大
wangxiaoaer
2019-10-16 15:49:10 +08:00
这个跟 js 的传入一个 options 对象作为参数差不多吧,但是代码看起来想死,尤其是那种隐式的接口实现。
clippit
2019-10-16 18:17:37 +08:00
@optional golang 里不兴链式调用

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/609761

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX