什么是布局 Go 项目的明智方法

本文介绍了什么是布局 Go 项目的明智方法的处理方法,对大家解决问题具有一定的参考价值

问题描述

我有一个开始变得更加复杂的 go 项目,我想以这样一种方式来布置文件系统以减轻痛苦.

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

解决方案

2013 年 5 月更新:官方文档在代码组织"

<块引用>

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

  • src 包含组织成包的 Go 源文件(每个目录一个包),
  • pkg 包含包对象,以及
  • bin 包含可执行命令.
<块引用>

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

src 子目录通常包含多个版本控制存储库(例如 Git 或 Mercurial),用于跟踪一个或多个源包的开发.

bin/streak # 命令可执行todo # 命令可执行包/linux_amd64/code.google.com/p/goauth2/oauth.a # 包对象github.com/nf/todo/task.a # 包对象来源/code.google.com/p/goauth2/.hg/# mercurial 仓库元数据验证/oauth.go # 包源oauth_test.go # 测试源

<小时>

2014 年 7 月更新:参见在 Go 中构建应用程序" 来自 本·约翰逊

那篇文章包括以下提示:

将二进制文件与应用程序分开

<块引用>

main.go 文件和我的应用程序逻辑合并在同一个包中有两个结果:

  • 它使我的应用程序无法用作库.
  • 我只能拥有一个应用程序二进制文件.

我发现解决此问题的最佳方法是在我的项目中简单地使用cmd"目录,其中的每个子目录都是一个应用程序二进制文件.

camlistore/指令/凸轮/main.go凸轮/main.go校园/main.go凸轮工具/main.go

库驱动开发

<块引用>

main.go 文件移出您的根目录允许您从库的角度构建您的应用程序.您的应用程序二进制文件只是您应用程序库的客户端.

有时您可能希望用户以多种方式进行交互,因此您可以创建多个二进制文件.
例如,如果您有一个adder"包,可以让用户将数字加在一起,您可能希望发布命令行版本和网络版本.
您可以通过像这样组织您的项目轻松地做到这一点:

加法器/加法器指令/加法器/main.go加法器服务器/main.go

<块引用>

用户可以使用省略号通过go get"安装您的adder"应用程序二进制文件:

$ 去 github.com/benbjohnson/adder/...

<块引用>

瞧,您的用户安装了adder"和adder-server"!

不要对子包发疯

<块引用>

通常我的项目的类型都非常相关,因此从可用性和 API 的角度来看,它更适合.
这些类型还可以利用它们之间未导出的调用来保持 API 小而清晰.

  1. 在每个文件中将相关类型和代码组合在一起.如果您的类型和函数组织得很好,那么我发现文件往往在 200 到 500 SLOC 之间.这听起来可能很多,但我发现它很容易导航.1000 SLOC 通常是我对单个文件的上限.
  2. 在文件顶部组织最重要的类型,并在文件底部添加重要性递减的类型.
  3. 一旦您的应用程序开始超过 10,000 SLOC,您就应该认真评估是否可以将其分解为更小的项目.

注意:最后的做法并不总是好的:

<块引用>

抱歉,我不能同意这种做法.
将类型分离到文件有助于代码管理、可读性、可维护性、可测试性.
它还可以确保单一职责和遵循开放/封闭原则......
不允许循环依赖的规则是强制我们有一个清晰的包结构.

<小时>

(2013 年 2 月的替代方案,仅针对 src)
您可以在GitHub 代码布局"中找到经典布局:

<块引用>

应用程序和两个库都位于 Github 上,每个库都在自己的存储库中.
$GOPATH 是项目的根目录 - 您的每个 Github 存储库都将在 $GOPATH 下的几个文件夹中检出.

您的代码布局如下所示:

$GOPATH/来源/github.com/jmcvetta/无用/.git/没用的去useless_test.go自述文件没用的/.git/无用的d.gouselessd_test.go自述文件

<块引用>

src/github.com/jmcvetta/ 下的每个文件夹都是单独的 git checkout 的根目录.

这招来了一些批评,在这个 reddit 页面:

<块引用>

我强烈建议不要按照您的方式构建存储库,它会破坏go get",这是 Go 中最有用的功能之一.
为了解 Go 的人编写代码要好得多,因为他们最有可能是编译它的人.
而对于不了解这种语言的人,他们至少会感受一下这种语言.

将主包放在 repo 的根目录中.
将资产放在子目录中(以保持整洁).
将代码的内容保存在子包中(以防有人想在二进制文件之外重用它).
在存储库的根目录中包含一个设置脚本,以便于查找.

下载、构建、安装和设置仍然只有两步过程.:

  • "go get <your repo path>":下载并安装 go 代码,以及资产的子目录
  • $GOPATH//setup.sh:将资产分发到正确的位置并安装服务

I have a go project that is starting to become more complex, and want to lay the filesystem out in such a way to reduce pain.

Are there some good examples out there of what makes sense?

解决方案

Update May 2013: the official documentation is in the section "Code organization"

Go code must be kept inside a workspace.
A workspace is a directory hierarchy with three directories at its root:

  • src contains Go source files organized into packages (one package per directory),
  • pkg contains package objects, and
  • bin contains executable commands.

The go tool builds source packages and installs the resulting binaries to the pkg and bin directories.

The src subdirectory typically contains multiple version control repositories (such as for Git or Mercurial) that track the development of one or more source packages.

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


Update July 2014: see "Structuring Applications in Go" from Ben Johnson

That article include tips like:

Separate your binary from your application

combining the main.go file and my application logic in the same package has two consequences:

  • It makes my application unusable as a library.
  • I can only have one application binary.

The best way I’ve found to fix this is to simply use a "cmd" directory in my project where each of its subdirectories is an application binary.

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

Library driven development

Moving the main.go file out of your root allows you to build your application from the perspective of a library. Your application binary is simply a client of your application’s library.

Sometimes you might want users to interact in multiple ways so you create multiple binaries.
For example, if you had an "adder" package that that let users add numbers together, you may want to release a command line version as well as a web version.
You can easily do this by organizing your project like this:

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

Users can install your "adder" application binaries with "go get" using an ellipsis:

$ go get github.com/benbjohnson/adder/...

And voila, your user has "adder" and "adder-server" installed!

Don’t go crazy with subpackages

Usually my project’s types are all very related so it fits better from a usability and API standpoint.
These types can also take advantage of calling unexported between them which keeps the API small and clear.

  1. Group related types and code together in each file. If your types and functions are well organized then I find that files tend to be between 200 and 500 SLOC. This might sound like a lot but I find it easy to navigate. 1000 SLOC is usually my upper limit for a single file.
  2. Organize the most important type at the top of the file and add types in decreasing importance towards the bottom of the file.
  3. Once your application starts getting above 10,000 SLOC you should seriously evaluate whether it can be broken into smaller projects.

Note: that last practice isn't always good:

Sorry I just cant agree with this practice.
Separating type to files helps code management, readability, maintenancability, testability.
It may also ensure single responsibility and the follow of open/closed principle…
The rule for not allowing circular dependency is to force we have a clear structure of the packages.


(Alternative February 2013, regarding src only)
You can find the classic layout illustrated in "GitHub Code Layout":

The app and both libraries live on Github, each in its own repository.
$GOPATH is the root of the project - each of your Github repos will be checked out several folders below $GOPATH.

Your code layout would look like this:

$GOPATH/
    src/
        github.com/
            jmcvetta/
                useless/
                    .git/
                    useless.go
                    useless_test.go
                    README.md
                uselessd/
                    .git/
                    uselessd.go
                    uselessd_test.go
                    README.md

Each folder under src/github.com/jmcvetta/ is the root of a separate git checkout.

That attracted some criticisms though, in this reddit page:

I highly recommend not structuring the repo the way you have, it'll break "go get", which is one of the most useful things about Go.
It's far better to write your code for people who do know Go, since they're most likely to be the ones compiling it.
And for people who don't, they'll at least get a feel for the language.

Put the main package in the root of the repo.
Have the assets in a subdirectory (to keep things neat).
Keep the meat of the code in a subpackage (in case anyone wants to reuse it outside your binary).
Include a setup script in the root of the repo so it's easy to find.

It's still only a two step process to download, build, install, and setup.:

  • "go get <your repo path>": downloads and installs the go code, with a subdir for the assets
  • $GOPATH/<your repo path>/setup.sh: distributes the assets to the right place and installs the service

这篇关于什么是布局 Go 项目的明智方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

admin_action_{$_REQUEST[‘action’]}

do_action( "admin_action_{$_REQUEST[‘action’]}" )动作钩子::在发送“Action”请求变量时激发。Action Hook: Fires when an ‘action’ request variable is sent.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$_REQUEST['action']引用从GET或POST请求派生的操作。源码(Source)更新版本源码位置使用被使用2.6.0 wp-admin/admin.php:...

日期:2020-09-02 17:44:16 浏览:1169

admin_footer-{$GLOBALS[‘hook_suffix’]}

do_action( "admin_footer-{$GLOBALS[‘hook_suffix’]}", string $hook_suffix )操作挂钩:在默认页脚脚本之后打印脚本或数据。Action Hook: Print scripts or data after the default footer scripts.目录锚点:#说明#参数#源码说明(Description)钩子名的动态部分,$GLOBALS['hook_suffix']引用当前页的全局钩子后缀。参数(Parameters)参数类...

日期:2020-09-02 17:44:20 浏览:1070

customize_save_{$this->id_data[‘base’]}

do_action( "customize_save_{$this-&gt;id_data[‘base’]}", WP_Customize_Setting $this )动作钩子::在调用WP_Customize_Setting::save()方法时激发。Action Hook: Fires when the WP_Customize_Setting::save() method is called.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_data...

日期:2020-08-15 15:47:24 浏览:806

customize_value_{$this->id_data[‘base’]}

apply_filters( "customize_value_{$this-&gt;id_data[‘base’]}", mixed $default )过滤器::过滤未作为主题模式或选项处理的自定义设置值。Filter Hook: Filter a Customize setting value not handled as a theme_mod or option.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分,$this->id_date['base'],指的是设置...

日期:2020-08-15 15:47:24 浏览:898

get_comment_author_url

过滤钩子:过滤评论作者的URL。Filter Hook: Filters the comment author’s URL.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/comment-template.php:32610...

日期:2020-08-10 23:06:14 浏览:930

network_admin_edit_{$_GET[‘action’]}

do_action( "network_admin_edit_{$_GET[‘action’]}" )操作挂钩:启动请求的处理程序操作。Action Hook: Fires the requested handler action.目录锚点:#说明#源码说明(Description)钩子名称的动态部分$u GET['action']引用请求的操作的名称。源码(Source)更新版本源码位置使用被使用3.1.0 wp-admin/network/edit.php:3600...

日期:2020-08-02 09:56:09 浏览:877

network_sites_updated_message_{$_GET[‘updated’]}

apply_filters( "network_sites_updated_message_{$_GET[‘updated’]}", string $msg )筛选器挂钩:在网络管理中筛选特定的非默认站点更新消息。Filter Hook: Filters a specific, non-default site-updated message in the Network admin.目录锚点:#说明#参数#源码说明(Description)钩子名称的动态部分$_GET['updated']引用了非默认的...

日期:2020-08-02 09:56:03 浏览:864

pre_wp_is_site_initialized

过滤器::过滤在访问数据库之前是否初始化站点的检查。Filter Hook: Filters the check for whether a site is initialized before the database is accessed.目录锚点:#源码源码(Source)更新版本源码位置使用被使用 wp-includes/ms-site.php:93910...

日期:2020-07-29 10:15:38 浏览:833

WordPress 的SEO 教学:如何在网站中加入关键字(Meta Keywords)与Meta 描述(Meta Description)?

你想在WordPress 中添加关键字和meta 描述吗?关键字和meta 描述使你能够提高网站的SEO。在本文中,我们将向你展示如何在WordPress 中正确添加关键字和meta 描述。为什么要在WordPress 中添加关键字和Meta 描述?关键字和说明让搜寻引擎更了解您的帖子和页面的内容。关键词是人们寻找您发布的内容时,可能会搜索的重要词语或片语。而Meta Description则是对你的页面和文章的简要描述。如果你想要了解更多关于中继标签的资讯,可以参考Google的说明。Meta 关键字和描...

日期:2020-10-03 21:18:25 浏览:1726

谷歌的SEO是什么

SEO (Search Engine Optimization)中文是搜寻引擎最佳化,意思近于「关键字自然排序」、「网站排名优化」。简言之,SEO是以搜索引擎(如Google、Bing)为曝光媒体的行销手法。例如搜寻「wordpress教学」,会看到本站的「WordPress教学:12个课程…」排行Google第一:关键字:wordpress教学、wordpress课程…若搜寻「网站架设」,则会看到另一个网页排名第1:关键字:网站架设、架站…以上两个网页,每月从搜寻引擎导入自然流量,达2万4千:每月「有机搜...

日期:2020-10-30 17:23:57 浏览:1308