1. 首页
  2. 后端

Go知识点:项目布局

  Go知识点:项目布局

==========

项目布局(project layout)/项目结构(project structure)表示项目中源码文件和目录的组织方式。对于项目布局,其实并没有强制性的约定,只是约定好规范后,可以减少不必要的重复沟通,有利于提高整体的效率。在Go语言中,项目结构更加重要,因为它决定了项目内部包的布局及包依赖关系是否合理,同时还会影响到外部项目对该项目中包的依赖与引用。

说明:如果只是简单程序(脚本程序或概念验证),将所有源码文件平铺在同一个目录中,执行go run main.go即可。

项目布局

1,Go官方推荐的项目布局

Go官方文档“Organizing a Go module”中根据项目类型给出几种项目布局建议。

Basic package

一个项目只包含一个导出包。可以是单文件,也可以是多文件(所有文件都位于同一个目录中,并且声明为同一个包名)。包名与模块名的最后一个路径组件匹配。

project-root-directory/
    go.mod
    modname.go
    modname_test.go
    [auth.go]
    [auth_test.go]
    [hash.go]
    [hash_test.go]

// go.mod
module github.com/someuser/modname

// modname.go and other .go files
package modname
// ... package code here

导入包:import “github.com/someuser/modname”

Basic command

一个项目只包含一个命令行程序。包名为main包,main.go.go或modname.go文件中包含main函数。

project-root-directory/
    go.mod
    main.go.go|modname.go
    [client.go]
    [auth.go]
    [auth_test.go]

// go.mod
module github.com/someuser/modname

// main.go.go|modname.go
package main
func main() {
    // ... main code here
}

// other .go files
package main
// ... package code here

安装命令:go install github.com/someuser/modname@latest

Package or command with supporting packages

对于较大的包或命令可以将某些功能拆分到内部包(internal)中。所有保存在internal目录下的包仅能被其父目录下的包(含所有层次的子目录)使用,外部包无法使用。

project-root-directory/
    go.mod
    modname.go
    modname_test.go
    internal/
        auth/
            auth.go
            auth_test.go
        hash/
            hash.go
            hash_test.go

// go.mod
module github.com/someuser/modname

// modname.go
package modname
import "github.com/someuser/modname/internal/auth"
import "github.com/someuser/modname/internal/hash"

// auth.go
package auth

// hash.go
package hash

Multiple packages

一个项目包含多个导出包。

project-root-directory/
    go.mod
    modname.go
    modname_test.go
    auth/
        auth.go
        auth_test.go
        token/
            token.go
            token_test.go
    hash/
        hash.go
    internal/
        trace/
            trace.go

Multiple commands

一个项目包含多个命令行程序。

project-root-directory/
    go.mod
    prog1/
        main.go
    prog2/
        main.go
    internal/
        ... shared internal packages

Packages and commands in the same repository

一个项目同时包含多个导出包和多个命令行程序。

project-root-directory/
    go.mod
    modname.go
    modname_test.go
    auth/
        auth.go
        auth_test.go
    internal/
        ... internal packages
    cmd/
        prog1/
            main.go
        prog2/
            main.go

Server project

服务器项目需要关心许多方面,例如协议(protocols)、部署(deployments)、前端文件(front-end files)、容器化(containerization)、脚本(scripts)等,可能存在许多非Go文件和目录,项目结构往往存在很大差异。这里主要关注Go语言编写的项目部分。

服务器项目通常不会包含导出包,建议将实现服务器逻辑的包放在internal目录中,将所有命令行程序放在cmd目录中。

project-root-directory/
    go.mod
    internal/
        auth/
            ...
        metrics/
            ...
        model/
            ...
    cmd/
        api-server/
            main.go
        metrics-analyzer/
            main.go
        ...
    ... the project's other directories with non-Go code

2,Go社区推荐的项目布局

project-layout是Go社区提出的应用程序项目的通用布局。说明:对于小型项目,并不需要包含全部目录,保留需要的内容,删除其他所有的内容。

$ tree --dirsfirst --noreport -F project-layout
project-layout
├── api/
├── assets/
├── build/
│   ├── ci/
│   └── package/
├── cmd/
│   └── _your_app_/
├── configs/
├── deployments/
├── docs/
├── examples/
├── githooks/
├── init/
├── internal/
│   ├── app/
│   │   └── _your_app_/
│   └── pkg/
│       └── _your_private_lib_/
├── pkg/
│   └── _your_public_lib_/
├── scripts/
├── test/
├── third_party/
├── tools/
├── vendor/
├── web/
│   ├── app/
│   ├── static/
│   └── template/
├── website/
├── go.mod
├── LICENSE.md
├── Makefile
└── README.md

Go目录(Go Directories)

  • /cmd:存放应用程序对应的main包源码文件,每个应用程序对应一个子目录。有些项目命名为app

main包应该尽量简洁,仅做一些命令行参数解析、资源初始化、日志设施初始化、数据库连接初始化等工作,之后就会将程序的执行权限交给更高级的执行控制对象。

  • /internal:存放项目自身使用,不可以被外部项目使用的内部包
  • /pkg:存放项目自身使用,可以被外部项目使用的外部包。有些项目命名为/lib

由于Go语言项目自身在1.4版本中去掉了pkg这一层目录,因此有一些项目直接将包平铺到项目根路径下,但笔者认为对于一些规模稍大的项目,过多的包会让项目顶层目录不再简洁,显得很拥挤,因此个人建议对于复杂的Go项目保留pkg目录。—《Go语言精进之路:从新手到高手的编程思想、方法和技巧》

  • /vendor:存放项目自身的第三方依赖包。go module中可选目录,go mod vendor命令可以自动创建/vendor目录

服务应用程序目录(Service Application Directories)

  • /api:API协议文件,例如OpenAPI/Swagger规范,JSON模式文件,协议定义文件

Web应用程序目录(Web Application Directories)

  • /web:特定于Web应用的组件:Web静态资源、服务器端模板和单页Web应用(Single-Page App,SPA)

通用应用程序目录(Common Application Directories)

  • /configs:配置文件模板或默认配置。etcd+confd和consul+consul-template
  • /scripts:执行各种构建、安装、分析等操作的脚本。Makefile会调用这些脚本
  • /build :打包和持续集成(Continuous Integration,CI)
  • /deployments:部署配置和模板。有些项目命名为deploy
  • /test :额外的外部测试应用程序和测试数据。Go中的单元测试与源码文件在同一个包中,公共API测试或集成测试等应该位于/test中
  • /init:系统初始化(systemd、upstart、sysv)和进程管理(runit、supervisord)的配置(非容器化部署)

其他目录(Other Directories)

  • /docs:设计文档和用户文档(除了godoc生成的文档之外)
  • /examples:示例代码
  • /tools:项目支持工具。这些工具可以从/pkg和/internal目录导入代码。
  • /third_party :外部辅助工具,分支代码(forked code)和其他第三方实用工具(例如Swagger UI)
  • /githooks :Git钩子
  • /assets :其他资源(例如图像、徽标等)
  • /website :项目网站数据

文件(Files)

  • Makefile:项目管理工具(call scripts from /scripts)
  • LICENSE.md:授权协议(针对开源项目)
  • README.md:项目说明和注意事项
  • go.mod:go module的配置文件,记录模块路径、第三方依赖包及其版本号(实现可重现构建)
  • go.sum:go module的配置文件,记录每个依赖包的版本号和哈希值(实现安全一致性)

说明:Go语言不像其他语言那样有/src目录,其原因是/src太通用。

项目脚手架

使用项目脚手架(project skeleton)或项目模板(project template)快速初始化项目目录,减少重复工作,提升开发效率。

1,gonew

gonew是Go官方提供的通过项目模板创建项目的命令行工具。gonew没有规定标准项目布局,只是基于项目模板(go module)创建项目目录,支持自定义项目模板。

$ go install golang.org/x/tools/cmd/gonew@latest
# 下载项目模板
$ gonew golang.org/x/example/hello
gonew: initialized golang.org/x/example/hello in ./hello

# 下载项目模板,更改module path,指定存放目录
$ gonew golang.org/x/example/hello your.domain/myprog myhello
gonew: initialized your.domain/myprog in myhello

$ diff -r hello/ myhello/
diff -r hello/go.mod myhello/go.mod
1c1
< module golang.org/x/example/hello
---
> module your.domain/myprog
diff -r hello/hello.go myhello/hello.go
30c30
<     "golang.org/x/example/hello/reverse"
---
>     "your.domain/myprog/reverse"
diff -r hello/reverse/example_test.go myhello/reverse/example_test.go
10c10
<     "golang.org/x/example/hello/reverse"
---
>     "your.domain/myprog/reverse"

执行流程

语法:gonew srcmod[@version] [dstmod [dir]] // version默认为latest,dstmod默认为srcmod,dir默认为path.Base(dstMod)

  • go mod download -json srcmod@version
  • copy from module cache into new directory, making edits as needed.

使用golang.org/x/mod/module包检查模块路径是否有效

使用golang.org/x/mod/modfile包更新和格式化go.mod文件

模板示例

https://github.com/golang/example/tree/master/hello
https://github.com/golang/example/tree/master/helloserver
https://github.com/golang/example/tree/master/outyet
https://github.com/ServiceWeaver/template
https://github.com/GoogleCloudPlatform/go-templates

2,cookiecutter

cookiecutter(饼干切割器)是一个通过项目模板创建项目的命令行工具。cookiecutter本身是基于Python语言编写的,但它使用范围并不局限于Python语言,只要提供相关的项目模板,就可以用于生成任何语言的项目。

$ pip3 install cookiecutter -i https://pypi.tuna.tsinghua.edu.cn/simple
$ cookiecutter https://github.com/lacion/cookiecutter-golang.git # 也可以指定本地压缩文件cookiecutter cookiecutter-golang.zip
  [1/15] full_name (Luis Morales): leitiannet
  [2/15] github_username (lacion): leitiannet
  [3/15] app_name (mygolangproject): cookiecutter-demo
  [4/15] project_short_description (A Golang project.): cookiecutter demo
  [5/15] docker_hub_username (lacion): leitiannet
  [6/15] docker_image (lacion/alpine-base-image:latest): 
  [7/15] docker_build_image (lacion/alpine-golang-buildimage): 
  [8/15] Select docker_build_image_version
    1 - 1.13
    2 - 1.12.9
    3 - 1.11.9
    Choose from [1/2/3] (1): 1
  [9/15] Select go_mod_or_dep
    1 - mod
    2 - dep
    Choose from [1/2] (1): 1
  [10/15] use_docker (y): y  
  [11/15] use_git (y): n
  [12/15] use_logrus_logging (y): y
  [13/15] use_viper_config (y): y
  [14/15] use_cobra_cmd (y): y
  [15/15] Select use_ci
    1 - travis
    2 - circle
    3 - none
    Choose from [1/2/3] (1): 3
$ tree --dirsfirst --noreport -F cookiecutter-demo/
cookiecutter-demo/
├── cmd/
│   ├── root.go
│   └── version.go
├── config/
│   └── config.go
├── log/
│   └── log.go
├── version/
│   └── version.go
├── AUTHORS.md
├── CONTRIBUTING.md
├── Dockerfile
├── go.mod
├── main.go
├── Makefile
└── README.md
$ cd cookiecutter-demo/
$ make build
$ ./bin/cookiecutter-demo

3,kratos

Kratos是一套轻量级Go微服务框架,包含大量微服务相关框架及工具。kratos new通过kratos-layout项目模板快速创建项目。

$ go install github.com/go-kratos/kratos/cmd/kratos/v2@latest
$ kratos new kratos-demo
$ tree --dirsfirst --noreport -F kratos-demo/
kratos-demo/
├── api/
│   └── helloworld/
│       └── v1/
│           ├── error_reason.pb.go
│           ├── error_reason.proto
│           ├── greeter_grpc.pb.go
│           ├── greeter_http.pb.go
│           ├── greeter.pb.go
│           └── greeter.proto
├── cmd/
│   └── kratos-demo/
│       ├── main.go
│       ├── wire_gen.go
│       └── wire.go
├── configs/
│   └── config.yaml
├── internal/
│   ├── biz/
│   │   ├── biz.go
│   │   ├── greeter.go
│   │   └── README.md
│   ├── conf/
│   │   ├── conf.pb.go
│   │   └── conf.proto
│   ├── data/
│   │   ├── data.go
│   │   ├── greeter.go
│   │   └── README.md
│   ├── server/
│   │   ├── grpc.go
│   │   ├── http.go
│   │   └── server.go
│   └── service/
│       ├── greeter.go
│       ├── README.md
│       └── service.go
├── third_party/
│   ├── errors/
│   │   └── errors.proto
│   ├── google/
│   │   ├── api/
│   │   │   ├── annotations.proto
│   │   │   ├── client.proto
│   │   │   ├── field_behavior.proto
│   │   │   ├── httpbody.proto
│   │   │   └── http.proto
│   │   └── protobuf/
│   │       ├── compiler/
│   │       │   └── plugin.proto
│   │       ├── any.proto
│   │       ├── api.proto
│   │       ├── descriptor.proto
│   │       ├── duration.proto
│   │       ├── empty.proto
│   │       ├── field_mask.proto
│   │       ├── source_context.proto
│   │       ├── struct.proto
│   │       ├── timestamp.proto
│   │       ├── type.proto
│   │       └── wrappers.proto
│   ├── openapi/
│   │   └── v3/
│   │       ├── annotations.proto
│   │       └── openapi.proto
│   ├── validate/
│   │   ├── README.md
│   │   └── validate.proto
│   └── README.md
├── Dockerfile
├── go.mod
├── go.sum
├── LICENSE
├── Makefile
├── openapi.yaml
└── README.md
$ cd kratos-demo
$ go generate ./...
$ go build -o ./bin/ ./... 
$ ./bin/kratos-demo -conf ./configs

参考资料

Organizing a Go module

Experimenting with project templates

我来告诉你Go项目标准结构如何布局

Go项目目录该怎么组织?官方终于出指南了!

Go项目初始化不再困扰你:gonew全方位解析

又有新功能!Go 将有生成新模板的 gonew 工具链

上帝视角看 “Go 项目标准布局” 之争

Standard Go Project Layout

《Go语言精进之路:从新手到高手的编程思想、方法和技巧》

《100个Go语言典型错误》

《Go 语言项目开发实战》

Awesome Go:Project Layout

Cookiecutter

Kratos

原文链接: https://juejin.cn/post/7369909173938929673

文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17390.html

QR code