【问题标题】:What is a sensible way to layout a Go project [closed]什么是布局 Go 项目的明智方法[关闭]
【发布时间】:2013-01-29 19:40:13
【问题描述】:

我有一个开始变得更加复杂的 Go 项目,并希望以这样的方式布置文件系统以减轻痛苦。

有没有一些很好的例子来说明什么是有意义的?

【问题讨论】:

    标签: go project


    【解决方案1】:

    我假设“项目”不是指 Go 包,而是指您开发的软件。 否则,您可以获得帮助 herehere。 然而,为 Go 编写包并没有太大的不同:使用包,为每个包创建一个文件夹并将这些包合并到您的应用程序中。

    要建立自己的观点,您可以查看 github 上的热门 Go 存储库:https://github.com/trending/go。值得注意的例子是cayleyzeus

    最流行的方案可能是在自己的目录中拥有一个主 Go 文件和许多模块和子模块。如果您有许多元文件(文档、许可证、模板等),您可能希望将源代码放入子目录中。这就是我到目前为止所做的。

    【讨论】:

    • @aussiegeek,我不是 Go 专家,但我确实成功应用了 nemo 在我自己的代码中提出的建议 - 想法是您可以在您的项目 under 下拥有模块目录,您只需要使用它们的完整前缀来引用它们 - 相对于 $GOPATH/src 或使用它们的 go get-表名称。
    • doozerd 不是一个很好的例子,即使它的测试很弱。
    • @InancGumus 我鼓励你提出一个更好的例子。
    • thisthis
    【解决方案2】:

    2013 年 5 月更新:官方文档在“Code organization”部分中

    Go 代码必须保存在工作区中。
    工作空间是一个目录层次结构,其根目录有三个目录:

    • src 包含组织成包的 Go 源文件(每个目录一个包),
    • pkg 包含包对象,并且
    • bin 包含可执行命令。

    go tool 构建源包并将生成的二进制文件安装到 pkgbin 目录。

    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 小而清晰。

    1. 在每个文件中将相关类型和代码组合在一起。如果您的类型和功能组织良好,那么我发现文件往往在 200 到 500 SLOC 之间。这听起来可能很多,但我发现它很容易导航。 1000 SLOC 通常是我单个文件的上限。
    2. 在文件顶部组织最重要的类型,并在文件底部添加重要性递减的类型。
    3. 一旦您的应用程序开始超过 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 脚本则不是。
    • jmcvetta 结构不会破坏 go get,因为 uselessd 导入了 useless,go get 将通过 go get .../uselessd 安装两者。但我同意,如果 useless 是一个专门为 uselessd 制作的库,那么将它作为子文件夹或兄弟姐妹保存在单个 git repo 中更有意义。
    • @PuerkitoBio 我同意。我在版本控制和基于组件的管理 (stackoverflow.com/a/933735/6309) 方面的培训使我更倾向于每个 repo 一个组件,因此是这个答案的第二部分。
    【解决方案3】:

    Golang 的作者有一个 recommended approach,它定义了如何布局代码以最好地使用 go 工具并支持源代码控制系统

    【讨论】:

    • 这是$GOROOT的布局方式,而不是src/<project>目录中的代码。
    【解决方案4】:

    您可能还应该看看这个 repo。它展示了许多如何构建 Go 应用程序的想法:https://github.com/golang-standards/project-layout

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-15
      • 1970-01-01
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多