【发布时间】:2013-01-29 19:40:13
【问题描述】:
我有一个开始变得更加复杂的 Go 项目,并希望以这样的方式布置文件系统以减轻痛苦。
有没有一些很好的例子来说明什么是有意义的?
【问题讨论】:
我有一个开始变得更加复杂的 Go 项目,并希望以这样的方式布置文件系统以减轻痛苦。
有没有一些很好的例子来说明什么是有意义的?
【问题讨论】:
我假设“项目”不是指 Go 包,而是指您开发的软件。 否则,您可以获得帮助 here 和 here。 然而,为 Go 编写包并没有太大的不同:使用包,为每个包创建一个文件夹并将这些包合并到您的应用程序中。
要建立自己的观点,您可以查看 github 上的热门 Go 存储库:https://github.com/trending/go。值得注意的例子是cayley 和zeus。
最流行的方案可能是在自己的目录中拥有一个主 Go 文件和许多模块和子模块。如果您有许多元文件(文档、许可证、模板等),您可能希望将源代码放入子目录中。这就是我到目前为止所做的。
2013 年 5 月更新:官方文档在“Code organization”部分中
Go 代码必须保存在工作区中。
工作空间是一个目录层次结构,其根目录有三个目录:
src 包含组织成包的 Go 源文件(每个目录一个包),pkg 包含包对象,并且bin 包含可执行命令。
go tool构建源包并将生成的二进制文件安装到pkg和bin目录。
src子目录通常包含多个版本控制存储库(例如 Git 或 Mercurial),用于跟踪一个或多个源包的开发。
bin/
streak # command executable
todo # command executable
pkg/
linux_amd64/
code.google.com/p/goauth2/
oauth.a # package object
github.com/nf/todo/
task.a # package object
src/
code.google.com/p/goauth2/
.hg/ # mercurial repository metadata
oauth/
oauth.go # package source
oauth_test.go # test source
2014 年 7 月更新:参见 Ben Johnson 中的“Structuring Applications in Go”
那篇文章包括以下提示:
将
main.go文件和我的应用程序逻辑组合在同一个包中会产生两个后果:
- 它使我的应用程序无法用作库。
- 我只能拥有一个应用程序二进制文件。
我发现解决此问题的最佳方法是在我的项目中简单地使用“
cmd”目录,其中每个子目录都是应用程序二进制文件。
camlistore/
cmd/
camget/
main.go
cammount/
main.go
camput/
main.go
camtool/
main.go
将
main.go文件移出根目录允许您从库的角度构建应用程序。您的应用程序二进制文件只是您的应用程序库的客户端。有时您可能希望用户以多种方式进行交互,以便创建多个二进制文件。
例如,如果您有一个“adder”软件包可以让用户将数字相加,您可能希望发布命令行版本和网页版本。
您可以通过像这样组织项目来轻松做到这一点:
adder/
adder.go
cmd/
adder/
main.go
adder-server/
main.go
用户可以使用省略号通过“go get”安装您的“adder”应用程序二进制文件:
$ go get github.com/benbjohnson/adder/...
瞧,您的用户安装了“
adder”和“adder-server”!
通常我的项目的类型都非常相关,因此从可用性和 API 的角度来看它更适合。
这些类型还可以利用它们之间未导出的调用,从而保持 API 小而清晰。
- 在每个文件中将相关类型和代码组合在一起。如果您的类型和功能组织良好,那么我发现文件往往在 200 到 500 SLOC 之间。这听起来可能很多,但我发现它很容易导航。 1000 SLOC 通常是我单个文件的上限。
- 在文件顶部组织最重要的类型,并在文件底部添加重要性递减的类型。
- 一旦您的应用程序开始超过 10,000 SLOC,您应该认真评估是否可以将其分解为更小的项目。
注意:最后的做法并不总是好的:
抱歉,我不能同意这种做法。
将类型与文件分离有助于代码管理、可读性、可维护性和可测试性。
也可以保证单一职责,遵循开闭原则……
不允许循环依赖的规则是强制我们有一个清晰的包结构。
(2013 年 2 月的替代方案,仅关于 src)
您可以在“GitHub Code Layout”中找到经典布局:
该应用程序和两个库都位于 Github 上,每个库都位于其自己的存储库中。
$GOPATH是项目的根目录 - 您的每个 Github 存储库都将在$GOPATH下方的多个文件夹中检出。您的代码布局如下所示:
$GOPATH/
src/
github.com/
jmcvetta/
useless/
.git/
useless.go
useless_test.go
README.md
uselessd/
.git/
uselessd.go
uselessd_test.go
README.md
src/github.com/jmcvetta/下的每个文件夹都是单独 git checkout 的根目录。
这引起了一些批评,在reddit page:
我强烈建议不要按照你的方式构建 repo,它会破坏“
go get”,这是 Go 最有用的东西之一。
为知道 Go 的人编写代码要好得多,因为他们最有可能是编译它的人。
而对于那些不知道的人,他们至少会对这种语言有所了解。将主包放在 repo 的根目录中。
将资产放在子目录中(以保持整洁)。
将代码的主要部分保存在一个子包中(以防有人想在您的二进制文件之外重用它)。
在 repo 的根目录中包含一个设置脚本,以便于查找。下载、构建、安装和设置仍然只有两个步骤。:
- “
go get <your repo path>”:下载并安装 go 代码,其中包含 assets 的子目录$GOPATH/<your repo path>/setup.sh:将资产分发到正确的位置并安装服务
【讨论】:
setup.sh 的一个(大)问题是 Go 是合理的跨平台,而 POSIX shell 脚本则不是。
Golang 的作者有一个 recommended approach,它定义了如何布局代码以最好地使用 go 工具并支持源代码控制系统
【讨论】:
$GOROOT的布局方式,而不是src/<project>目录中的代码。
您可能还应该看看这个 repo。它展示了许多如何构建 Go 应用程序的想法:https://github.com/golang-standards/project-layout
【讨论】: