Golang项目结构与代码组织

一般结构

- 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

更多关于包的命名和组织以及其他代码结构的建议:

文件夹设计

主要设计

/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 模板文件放在这里。

/init

System init(systemd,upstart,sysv)和 process manager/supervisor(runit,supervisor)配置。

/scripts

执行各种构建、安装、分析等操作的脚本。

这些脚本保持了根级别的 Makefile 变得小而简单(例如, https://github.com/hashicorp/terraform/blob/master/Makefile )。

有关示例,请参见  /scripts 目录。

/build

打包和持续集成。

将你的云( AMI )、容器( Docker )、操作系统( deb、rpm、pkg )包配置和脚本放在 /build/package 目录下。

将你的 CI (travis、circle、drone)配置和脚本放在 /build/ci 目录中。请注意,有些 CI 工具(例如 Travis CI)对配置文件的位置非常挑剔。尝试将配置文件放在 /build/ci 目录中,将它们链接到 CI 工具期望它们的位置(如果可能的话)。

/deployments

IaaS、PaaS、系统和容器编排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些存储库中(特别是使用 kubernetes 部署的应用程序),这个目录被称为 /deploy

/test

额外的外部测试应用程序和测试数据。你可以随时根据需求构造 /test 目录。对于较大的项目,有一个数据子目录是有意义的。例如,你可以使用 /test/data 或 /test/testdata (如果你需要忽略目录中的内容)。请注意,Go 还会忽略以“.”或“_”开头的目录或文件,因此在如何命名测试数据目录方面有更大的灵活性。

有关示例,请参见  /test 目录。

/docs

设计和用户文档(除了 godoc 生成的文档之外)。

有关示例,请参阅 /docs 目录。

/tools

这个项目的支持工具。注意,这些工具可以从 /pkg 和 /internal 目录导入代码。

有关示例,请参见 /tools 目录。

/examples

你的应用程序和/或公共库的示例。

有关示例,请参见 /examples 目录。

/third_party

外部辅助工具,分叉代码和其他第三方工具(例如 Swagger UI)。

/githooks

Git hooks。

/assets

与存储库一起使用的其他资产(图像、徽标等)。

/website

如果你不使用 Github 页面,则在这里放置项目的网站数据。

有关示例,请参见 /website 目录

针对设计

/api -服务应用程序目录

OpenAPI/Swagger 规范,JSON 模式文件,协议定义文件。

有关示例,请参见 /api 目录。

/web – Web 应用程序目录

特定于 Web 应用程序的组件:静态 Web 资产、服务器端模板和 SPAs。

注意

一般不使用/src文件夹;

上一篇
下一篇