一般结构
- go_project
- cmd
- pkg
- internal
- go.mod && go.sum
- Makefile
结构示例
Docker
- mody/mody
- api // 存放对外公开的 API 规则
- builder // 存放构建脚本等
- cli // 命令行的主要逻辑
- cmd // 存放可执行程序,main 包放这个目录中
- contrib // 存放一些有用的脚本或文件,但不是项目的核心部分
- docs // 存放文档
- internal // 只在本项目使用的包(私有)
- pkg // 本项目以及其他项目可以使用的包(公有)
- plugin // 提供插件功能
Frp
- fatedier/frp
- assets
- client
- cmd
- conf
- doc
- hack
- pkg
- server
- test/e2e
- web
Kubernetes
- kubernetes/kubernetes
- api
- build // 存放构建脚本等
- cmd
- docs
- pkg
- plugin
- test // 单元测试之外的测试程序、测试数据
- third_party // 经过修改的第三方的代码
建议
面向包的设计和验证#TODO
创建新包的适宜情况:
- 启动程序的方式有多种时;
- 希望提取更详细的实现时;
- 在紧密联系的事物之间,添加前缀时;
模块化
按类型组织
通过放入基于自身结构的不同分类包,以组织高度复杂的代码;常会设置repositories 或 model 包。
常见问题:
会不得不将尚未有更优位置存放的函数或结构体放于utils或helpers中;
为解决跨包可访问性问题,不得不将非常多包中的类型、常量、函数设为public;
好处:
从开发角度看,自然且易于理解;
坏处:
没有重点,缺乏结构逻辑,在复杂后维护较困难(包多且互相依赖性强);
不得不过多设置暴露包中类型、常量、函数等;
按组件组织
组件在这里即实现独立特性(feature)的少乃至无外依赖性的一部分程序;可以将其参照插件(plugin)理解,某一组件缺失后整体程序仍能运行一部分功能。
常见问题:
加入要求跨包调取数据或函数的新功能时,困惑于包的独立性要求,需要谨慎设计,通过类似接口调用的方式实现跨包调取;
好处:
健壮性高(包独立性强),可维护性高;
从使用者、读者角度看,有一定结构逻辑,易于理解;
坏处:
从开发角度看,决策与设计需要一定能力,要求谨慎思考功能、接口等依赖性问题;
============================================================================
A Chinese Post about Package-Oriented-Design guidelines and Architecture layer
更多关于包的命名和组织以及其他代码结构的建议:
- GopherCon EU 2018: Peter Bourgon – Best Practices for Industrial Programming
- GopherCon Russia 2018: Ashley McNamara + Brian Ketelsen – Go best practices.
- GopherCon 2017: Edward Muller – Go Anti-Patterns
- GopherCon 2018: Kat Zien – How Do You Structure Your Go Apps
文件夹设计
主要设计
/cmd
cmd 包是项目的主干,是编译构建的入口,main 文件通常放置在此处。cmd 下可以允许挂载多个需要编译的应用,只需要在不同的包下编写 main 文件即可。需要注意的是,cmd 中的代码应该尽量「保持简洁」,main 函数中可能仅仅是参数初始化、配置加载、服务启动的操作。
/pkg
pkg 中存放的是可供项目内部/外部所使用的公共性代码,例如:用来连接第三方服务的 client 代码等。也有部分项目将该包命名为 lib,例如:consul 项目 ,所表示的含义其实相同。
/internal
golang特性目录,该包申明其中的代码为项目私有内部使用,与pkg, public相对,是一种项目级的代码保护
go.mod && go.sum
go.mod 与 go.sum 是采用 go modules 进行依赖管理所生成的配置文件。不推荐使用 vendor,dep 等依赖管理方式所生成的目录。
Makefile
Makefile 文件通常存放项目的编译部署脚本。Go 的编译命令虽然简单,但总是手写命令还是效率低下,因此使用 Makefile 写编译部署脚本是工程实践中常见的方式
通用设计
/configs
配置文件模板或默认配置。
将你的 confd
或 consul-template
模板文件放在这里。
System init(systemd,upstart,sysv)和 process manager/supervisor(runit,supervisor)配置。
执行各种构建、安装、分析等操作的脚本。
这些脚本保持了根级别的 Makefile 变得小而简单(例如, https://github.com/hashicorp/terraform/blob/master/Makefile
)。
有关示例,请参见 /scripts
目录。
打包和持续集成。
将你的云( AMI )、容器( Docker )、操作系统( deb、rpm、pkg )包配置和脚本放在 /build/package
目录下。
将你的 CI (travis、circle、drone)配置和脚本放在 /build/ci
目录中。请注意,有些 CI 工具(例如 Travis CI)对配置文件的位置非常挑剔。尝试将配置文件放在 /build/ci
目录中,将它们链接到 CI 工具期望它们的位置(如果可能的话)。
IaaS、PaaS、系统和容器编排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些存储库中(特别是使用 kubernetes 部署的应用程序),这个目录被称为 /deploy
。
额外的外部测试应用程序和测试数据。你可以随时根据需求构造 /test
目录。对于较大的项目,有一个数据子目录是有意义的。例如,你可以使用 /test/data
或 /test/testdata
(如果你需要忽略目录中的内容)。请注意,Go 还会忽略以“.”或“_”开头的目录或文件,因此在如何命名测试数据目录方面有更大的灵活性。
有关示例,请参见 /test
目录。
/docs
设计和用户文档(除了 godoc 生成的文档之外)。
有关示例,请参阅 /docs
目录。
这个项目的支持工具。注意,这些工具可以从 /pkg
和 /internal
目录导入代码。
有关示例,请参见 /tools
目录。
你的应用程序和/或公共库的示例。
有关示例,请参见 /examples
目录。
外部辅助工具,分叉代码和其他第三方工具(例如 Swagger UI)。
Git hooks。
与存储库一起使用的其他资产(图像、徽标等)。
如果你不使用 Github 页面,则在这里放置项目的网站数据。
有关示例,请参见 /website
目录
针对设计
/api
-服务应用程序目录
OpenAPI/Swagger 规范,JSON 模式文件,协议定义文件。
有关示例,请参见 /api
目录。
/web
– Web 应用程序目录
特定于 Web 应用程序的组件:静态 Web 资产、服务器端模板和 SPAs。
注意
一般不使用/src文件夹;