Go 项目目录布局详解project-layout 标准目录结构的设计原则与实操指南【免费下载链接】project-layoutStandard Go Project Layout项目地址: https://gitcode.com/GitHub_Trending/pr/project-layout本文基于 Go 社区项目布局参考仓库 project-layout 的说明文档系统讲解 Go 应用项目推荐的目录组织方式包括/cmd、/internal、/pkg等核心代码目录的划分原则/configs、/init、/scripts、/build、/deployments、/test等工程支撑目录的用途以及 Go Modules 时代下的模块路径约束。读完后你将掌握一套可落地的大规模 Go 项目目录方案并知道哪些目录不该有。一、定位与适用前提不是官方标准而是社区模式集首先需要明确一个关键前提该布局不是由 Go 核心团队定义的官方标准而是 Go 生态中长期形成的、一组历史性的与新兴的项目布局模式historical and emerging project layout patterns。其中有些模式比另一些更流行。该仓库还包含若干增强项即一些在足够大的真实应用中常见的辅助目录。文档中给出了几条非常重要的使用边界初学者与小型项目请勿套用如果你正在学习 Go或者只是在做一个演示PoC或简单的小项目这套布局是过重的overkill。真正合理的起点是一个main.go文件加一个go.mod足矣。随项目成长而演进项目长大后必须保证代码结构良好否则会陷入隐藏依赖 全局状态的脏代码泥潭。多人协作时需要更多结构此时引入统一的包/库管理方式即本布局的价值所在。开源项目必须重视internal当你的项目是开源的、或已知其他项目会 import 你仓库中的代码时私有internal包和代码就很重要。按需裁剪克隆仓库后保留你需要的部分删除其余的。目录存在不等于你必须全部使用没有任何一个模式被用在每一个项目里连vendor模式都不是通用的。Go Modules 与模块路径约束从 Go 1.14 开始Go 模块Go Modules已可用于生产环境。除非有特定理由否则应使用 Go 模块使用模块后你就不必再操心$GOPATH以及项目放置位置的问题。该仓库自带的 go.mod 给出了模块声明的示范module github.com/YOUR-USER-OR-ORG-NAME/YOUR-REPO-NAME go 1.19文档对模块路径有两条要点说明示例go.mod假定项目托管在 GitHub 上但这并非硬性要求——模块路径可以是任意值模块路径的第一个组件应当包含一个点例如域名。当前版本的 Go 已不再强制这一约束但如果你在用稍旧版本的 Go 且构建失败不要感到意外原因多半在这里。文档同时引用了 Go 官方 issue #37554 与 #32819 作为进一步背景可在 Go 官方仓库检索这两个编号。此外该布局是刻意保持通用的并不试图强制某种具体的 Go 包结构例如它不覆盖 Clean Architecture 等更细粒度的架构分层。官方 Go 文档中也有Organizing a Go module一节提供关于项目组织与internal、cmd模式的权威说明。命名、格式与代码风格文档建议在动手前先跑gofmt格式化器与静态检查工具。注意原文档乌语版 README_ua.md当时推荐的是golint而主文档 README.md 已更新说明golint已被弃置且不再维护推荐使用仍在维护的staticcheck。checkgo-tools 工具集。命名、包组织与代码结构的进一步学习材料文档列举了多篇经典演讲与文章GopherCon EU 2018 Peter Bourgon 的工业级编程最佳实践、Kat Zien 的《How Do You Structure Your Go Apps》、Edward Muller 的《Go Anti-Patterns》、rakyll 的《Style guideline for Go packages》、Effective Go 命名章节等可据此延伸阅读。二、完整目录结构总览下面是该布局推荐的全部目录及其职责速览细节在各节展开目录分类职责/cmdGo 核心各主程序入口目录名与可执行文件名一致/internalGo 核心私有应用与库代码编译器强制不可被外部导入/pkgGo 核心允许被外部应用导入的公共库代码/vendorGo 核心应用依赖由go mod vendor等管理/api服务应用OpenAPI/Swagger 规范、JSON Schema、协议定义文件/webWeb 应用静态资源、服务端模板、SPA 等 Web 专属组件/configs通用应用配置文件模板或默认配置/init通用应用系统启动与进程管理器配置systemd、runit 等/scripts通用应用构建、安装、分析等操作的脚本/build通用应用打包/build/package与 CI/build/ci/deployments通用应用IaaS/PaaS/容器编排的部署配置与模板/test通用应用额外的外部测试程序与测试数据/docs其他设计与用户文档godoc 之外的文档/tools其他项目辅助工具/examples其他应用与公共库的示例/third_party其他外部辅助工具、fork 代码与第三方组件/githooks其他Git 钩子脚本/assets其他随仓库分发的图片、Logo 等资源/website其他项目站点数据未用 GitHub Pages 时/src不应存在Java 风格的src目录Go 项目应避免仓库本身以占位目录演示了骨架例如 internal 下的internal/app/_your_app_、internal/pkg/_your_private_lib_pkg 下的pkg/_your_public_lib_以及cmd/_your_app_读者可以对照占位符替换为自己的应用名。三、Go 核心代码目录/cmd主程序入口/cmd存放本项目的各个主应用。每个应用的目录名必须与你想要的可执行文件名一致例如/cmd/myapp产出myapp可执行文件。核心纪律是不要在应用目录里放大量代码。代码该去哪个目录取决于它对外的可复用性意图认为代码可以被其他项目 import 并复用 → 放进/pkg代码不可复用、或你不希望别人复用 → 放进/internal。文档特别提醒别人会做出让你惊讶的事所以要明确表达你的意图Youll be surprised what others will do, so be explicit about your intentions!常见形态是一个很小的main函数它只负责 import 并调用来自/internal与/pkg的代码然后结束别无其他。仓库中 cmd/README.md 进一步列出了 velero、moby、prometheus、influxdb、kubernetes、dapr、go-ethereum 等一批采用该模式的大型项目cmd目录示例可印证小 main 包承载逻辑是业界主流实践。/internal编译器强制的私有边界/internal存放私有的应用与库代码——即你不希望别人导入其应用或库的代码。关键点在于这个布局约束是由 Go 编译器自身强制执行的而非团队纪律该机制自 Go 1.4 起引入见 Go 1.4 release notes 中 internal packages 一节。两个容易忽略的细节不局限于顶层internal目录可以出现在项目树的任意层级一个项目可以有多个internal目录。从源码结构看判定规则是只要包路径中出现了internal路径元素该包就只能被以该internal的父目录为共同祖先的包导入。可选的二级结构可以为内部包再增加一层结构以区分离共享/非共享的内部代码。这不是必须的小项目尤其不必但它提供了包的预期用途的视觉提示。推荐分法应用自身代码 →/internal/app如/internal/app/myapp多个应用之间共享的代码 →/internal/pkg如/internal/pkg/myprivlib。仓库中的 internal/README.md 同样列出了 terraform、influxdb、jaeger、moby、minio 等使用internal的真实仓库作为参照并单列了/internal/pkg的示例hashicorp/waypoint。/pkg显式声明可被外部使用/pkg存放允许被外部应用使用的库代码如/pkg/mypubliclib。其他项目导入这些库时会默认它们是可用的、行为稳定的所以往这里放东西之前请三思 :-)。对pkg与internal的分工文档的判断是internal是保证私有包不可被导入的更优手段因为它由 Go 语言机制强制/pkg的价值在于显式沟通——向其他开发者表明该目录下的代码对他人是安全的、可依赖的。文档同时引用了 Travis Jeffery 的文章《Ill take pkg over internal》作为延伸阅读。当根目录中混杂大量非 Go 组件与目录时/pkg还能把所有 Go 代码聚拢在一处方便运行各类 Go 工具GopherCon 多篇演讲持同样观点。关于/pkg的争议与历史文档交代得很直白这是一个常见但并非被普遍接受的模式Go 社区中有人认为不该用pkg/README.md 甚至用上百个知名仓库的pkg目录列表来展示其流行度。对于真正很小的应用项目多一层嵌套带来的价值有限可以不用等根目录变得拥挤尤其非 Go 组件很多时再考虑引入。历史渊源早期的 Go 官方源码曾用pkg存放包社区项目随后开始模仿这一模式文档引用了 Brad Fitzpatrick 的推文提供上下文。/vendor依赖目录/vendor存放应用依赖可手工管理或用依赖管理工具管理例如内置的 Go 模块能力。go mod vendor命令会自动生成/vendor目录。两个操作性要点若未使用 Go 1.14该版本起自动启用 vendor 模式go build可能需要显式追加-modvendor标志如果你在开发的是库library不要提交你的应用依赖文档原话Dont commit your application dependencies if you are building a library。从 Go 1.13 起Go 启用了模块代理module proxy特性默认使用官方模块代理服务器。如果代理满足你的所有需求与约束如内网合规要求那么vendor目录可以完全不需要。四、服务应用与 Web 应用目录/api接口契约与协议定义/api用于存放OpenAPI/Swagger 规范文件、JSON Schema 文件与协议定义文件。api/README.md 中列出了 kubernetes 与 moby 两个典型项目的api目录示例——这两者的api目录都承载 API 版本规范与生成物印证了契约先行的用法。/webWeb 专属组件/web存放 Web 应用专属组件静态 Web 资源、服务端渲染模板、单页应用SPA。仓库中以web/app/、web/static/、web/template/三个子目录的占位结构演示了静态资源、模板与前端应用的落位方式。五、通用应用目录/configs配置模板与默认配置存放配置文件模板或默认配置。文档特别说明confd或consul-template之类的模板文件也应放在这里——即配置渲染引擎的模板与最终配置同目录管理部署时由模板引擎渲染出各环境的实际配置。/init系统启动与进程监管存放系统 init 配置systemd、upstart、sysvinit以及进程管理器/监管器配置runit、supervisord。这个目录的意义是把进程如何被拉起与被监管的运维知识固化在仓库里而不是散落在各台机器上。/scripts脚本层存放执行构建、安装、分析等操作的脚本。文档的核心论点这些脚本能让根级 Makefile 保持小而简单文档以 HashiCorp Terraform 的 Makefile 为典范。仓库中 Makefile 本身就是一行注释# note: call scripts from /scripts这正是理念的直接体现Makefile 只做入口转发具体逻辑全部下沉到 scripts 目录。scripts/README.md 还列举了 helm、cockroach、terraform 的scripts目录作为参考。/build打包与持续集成/build下分两块/build/package云镜像AMI、容器Docker、操作系统包deb、rpm、pkg的打包配置与脚本/build/ciCI 工具travis、circle、drone的配置与脚本。文档提醒了一个实操陷阱某些 CI 工具如 Travis CI对其配置文件的位置非常挑剔。尽量把配置文件放在/build/ci并在可行的情况下软链接到 CI 工具期望的位置从而兼顾目录整洁与工具约定。/deployments部署编排存放 IaaS、PaaS、系统与容器编排的部署配置与模板覆盖 docker-compose、kubernetes/helm、terraform 等。文档补充在一些仓库尤其是用 kubernetes 部署的应用里这个目录被命名为/deploy——阅读他人项目时注意这一别名。/test外部测试程序与测试数据/test存放额外的外部测试程序与测试数据区别于与源码同目录的单元测试_test.go。该目录的内部结构可自由组织但文档给出了两条 Go 工具链相关的命名规则非常实用大项目值得设一个数据子目录/test/data或者用/test/testdata——因为 Go 构建工具会自动忽略名为testdata的目录Go 同样会忽略以.或_开头的目录/文件因此测试数据目录的命名有更大灵活度这也解释了仓库中internal/app/_your_app_这类占位目录为什么用下划线命名。test/README.md 以 openshift/origin 为例测试数据位于/testdata子目录展示了该目录的真实形态。六、其他辅助目录/docs设计与用户文档是对 godoc 自动生成的 API 文档的补充。docs/README.md 列举了 hugo、openshift、dapr 的 docs 目录示例。/tools项目的辅助工具。注意这些工具可以import/pkg与/internal中的代码——因为它们在同一个模块内不受internal边界限制。tools/README.md 列出了 istio、openshift、dapr 示例。/examples应用与/或公共库的示例代码。examples/README.md 列出了 nats.go、docker-slim、packer 的示例目录。/third_party外部辅助工具、fork 来的代码及其他第三方组件例如 Swagger UI 这类前端静态组件。/githooksGit 钩子hooks脚本。/assets随仓库一起分发的其他资源如图片、Logo。/website如果你不使用 GitHub Pages项目站点的数据就放在这里。website/README.md 给出了 vault、perkeep 的 website 目录示例。七、不应出现的目录/src文档单列一节说明 Go 项目里不该有/src目录。原因与背景Java 习惯的误植一些 Go 项目出现src目录通常是因为开发者来自 Java 世界那里src是常见模式。文档明确建议避免让 Go 代码或 Go 项目看起来像 Java。与 Go 工作区的/src混淆不要混淆项目级/src与 Go 工作区workspace的/src。环境变量$GOPATH指向你的当前工作区非 Windows 系统默认$HOME/go该工作区包含顶层的/pkg、/bin、/src三个目录你的实际项目落在工作区的/src之下。如果你的项目内部又有一个/src最终路径会变成/some/path/to/workspace/src/your_project/src/your_code.go—— 双重src叠加语义混乱。虽然从 Go 1.11 起项目可以放在GOPATH之外但这并不意味着采用src布局是好主意。八、README 徽章建议原文档还给出了适合放在项目 README 中的徽章清单可作为开源项目的加分项Go Report Card对代码跑gofmt、go vet、gocyclo、golint、ineffassign、license、misspell等扫描并生成报告使用时需把徽章中的仓库引用替换为你自己的项目。GoDoc原文档中该项已被删除线标记弃用仅保留迁移说明。Pkg.go.devGo 发现与文档的新去处可用其徽章生成工具制作文档徽章。Release展示项目的最新 release 编号需替换为你项目的链接。九、适用建议与后续规划回到开头的核心判断这套布局是为足够大的真实应用准备的通用骨架——它刻意保持通用不强制具体包结构单文件main.gogo.mod才适合学习与 PoC。合理的演进路径是先用最小结构起步当项目变大、多人协作、需要对外输出库时再按克隆本仓库 → 保留需要的目录 → 删除其余的方式引入/internal、/pkg、/cmd等核心目录与/configs、/scripts、/build、/deployments等工程目录。文档结尾注明一个更有主见opinionated的项目模板——包含示例/可复用配置、脚本与代码——目前仍在开发中WIP。因此本布局应被视为目录级的参考标准而非开箱即用的完整工程模板。【免费下载链接】project-layoutStandard Go Project Layout项目地址: https://gitcode.com/GitHub_Trending/pr/project-layout创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考