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语言,只要提供相关的项目模板,就可以用于生成任何语言的项目。
- cookiecutter-golang: 根据最佳实践创建基于golang新项目的模板
$ 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
参考资料
Experimenting with project templates
又有新功能!Go 将有生成新模板的 gonew 工具链
《Go语言精进之路:从新手到高手的编程思想、方法和技巧》
《100个Go语言典型错误》
《Go 语言项目开发实战》
原文链接: https://juejin.cn/post/7369909173938929673
文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17390.html