编程与软件工程peter.bourgon.org
六年后的 Go 最佳实践
Go best practices, six years in
2016 — 2018,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
Peter Bourgon 是 Go 语言资深开发者(Go Kit、oklog 作者),这篇长文总结了他在 Go 中工作六年积累的工程实践:项目结构、包设计、配置与依赖注入、测试、日志等。文章基于 2016 年的 Go 生态写成,其中不少观点(如避免 init 和包级全局变量)在社区引发了广泛讨论。
为什么经久不衰:它把一位核心社区成员多年踩坑得来的经验浓缩成可操作的原则,即使部分工具链建议已过时,关于包设计和依赖管理的思考至今仍是 Go 工程实践的重要参考。
HN 评论精选
以幽默的“四阶段”讽刺 Go 从初见惊艳到逐渐补齐缺失工具、最终趋同于 Java 的循环。
Go 开悟的几个阶段:1) 天哪,这跟早期 Java 一样,语言设计者是不是嗑了什么?测试框架呢?依赖注入呢?构建系统呢?2) 天哪,这跟早期 Java 一样,太爽了!所有 Go 代码我都能看懂,终于体会到“少即是多”“更差就是更好”!3) 几个月后:受够了四行写一个测试断言、写几百行 mock 结构体,测试 95% 都是搭建代码,于是自己写断言库、DI 库、依赖管理工具、构建工具、代码生成工具……4) 遥远的未来:当 Go 固执的设计者终于承认当初想法有缺陷,加上的新特性让这门语言越来越像 Google 内部另一门广泛使用的语言。使命完成?(半开玩笑,我日常还是很喜欢用 Go 的)
nvarsj查看英文原文
The stages of go enlightenment: 1. Holy crap, this is like coding in early Java days, what the heck were the language designers smoking?! They just ignored everything! Where's my testing framework! DI?! Build system, dependency management?! WTF. 2. Holy crap, this is like coding in the early Java days! This is awesome! I can understand all golang code I read! Everything is so simple and easy. I finally get "less is more", and "worse is better"! 3. (Many months later) Oh god, I'm getting so sick of writing this test assertion in 4 lines over and over, and writing 100s of lines of mock structs. My tests are 5% substance and 95% setup. Okay let's write a junit/mockito assertion library. Oh crap, I'm having to manually wire everything everywhere and it's such a pain. Let's write a DI library. Ugh my project is getting too big and `go get` just doesn't cut it - time to use a dependency management library. Ugh, makefiles only go so far, time to write a build tool. Ugh code generation and metacoding is nonexistent, let's write our own code generation tool so we don't have to hand build 100s of types. ETC. 4. (Distant future) As golang's stubborn designers finally accept some flaws in their original thinking, they add features to make the language look a lot like another widely used language at the Googplex. Mission accomplished? P.S. This is somewhat tongue in cheek - I do enjoy using golang day to day. It is a refreshing change :).
肯定文章整体价值,但指出 /pkg 目录、日志依赖性论述等技术细节上的错误。
总体是很好的建议,除了包管理器部分,今天依然适用。但有几点异议:1) 不要把内部库放在 /pkg,它在 GOPATH 中有“编译缓存”的特殊含义,没必要冒险;2) 文中关于 fmt.Printf 无全局状态、log.Printf 是依赖的说法是错的——stdout 及其缓冲区和锁与全局 logger 对象完全一样,log.Printf 基本就是 fmt.Printf 的别名;3) 希望在讲构造函数时提到函数式选项模式。
bbatha查看英文原文
This is generally great advice, and aside from the package manager recommendations is still relevant today. I do take issue with a few things though. 1. Don't put your internal libraries in /pkg. /pkg has special GOPATH meaning as "compilation cache". Its not an actual name conflict, but why bother risking it. 2. This is just wrong: > fmt.Printf is self-contained and doesn’t affect or depend on global state; in functional terms, it has something like referential transparency. So it is not a dependency. Obviously, f.Bar is a dependency. And, interestingly, log.Printf acts on a package-global logger object, it’s just obscured behind the free function Printf. So it, too, is a dependency. stdout (and the buffer, and mutex on it) are exactly the same as the global log object. In fact, `log.Printf` is more or less just an alias to `fmt.Printf`[0] 3. I wish it had mentioned the functional options pattern in the part about constructors[1] 0: https://github.com/golang/go/blob/b77aad089176ecab971d3a72f0357ed0abc81f4a/src/log/log.go#L294 1: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
指出“配置解析应集中在 main”是跨语言的通用教训,并举 Python 反例佐证。
“只有 func main 有权决定用户可用的 flag”这一条适用于所有语言。我曾用一个 Python 包,它认为既然任何地方都能访问 sys.argv,就该自己解析 sys.argv 来配置行为。很长一段时间里,官方建议是:先自己解析 sys.argv,再修改它,然后才进入这个库。
MereInterest查看英文原文
> Only func main has the right to decide the flags that will be available to the user. This one applies to every language. I was working with a python package that decided that, since `sys.argv` was available from anywhere, it should parse `sys.argv` to configure its own behavior. For a long time, their suggestion was to first parse `sys.argv` yourself, then to modify it before going into the library.
以生产环境使用者的身份印证文中风格的价值,并指出社区对“无 init”原则的采纳度不足。
在 Kolide 我们大量使用 Go Kit,因此也采纳了 Peter 在这里推荐的很多风格,并在此基础上逐步扩展出自己的风格指南和公司通用库。Go Kit 和 oklog 的代码是地道 Go 的绝佳范例。遗憾的是社区整体并不遵循“不用 init/不用包级全局变量”,这有时导致引入开源 Go 库时体验不佳。
zalmoxes查看英文原文
At [Kolide](https://kolide.com/) we're heavy users of Go Kit, and as a result have also adopted a lot of the style Peter recommends here. We've been slowly expanding on it with a style guide and company specific set of common libraries [here](https://github.com/kolide/kit#kolide-kit). My coworker also wrote a [blog post](https://blog.kolide.com/using-go-for-scalable-operating-system-analytics-cb170d85b1c5) on how Go has been fantastic for us and references the above style guide. The code from go kit and [oklog](https://github.com/oklog/oklog) are great examples of idiomatic Go. Unfortunately the community at large doesn't really follow the "no init"/"no package global vars", which can sometimes lead to bad experiences importing opensource Go libs.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选