Go 标准项目布局(project-layout):从 cmd 到 internal 的目录组织完整指南

发布时间:2026/9/7 15:05:42
Go 标准项目布局(project-layout):从 cmd 到 internal 的目录组织完整指南 Go 标准项目布局project-layout从 cmd 到 internal 的目录组织完整指南【免费下载链接】project-layoutStandard Go Project Layout项目地址: https://gitcode.com/GitHub_Trending/pr/project-layout本文基于 project-layout 仓库的印尼语版布局文档 README_id.md系统讲解 Standard Go Project Layout 的设计动机、各目录的职责与取舍并结合仓库自身的目录树、go.mod 与各子目录 README 给出可落地的实操依据。读完后你将能为 Go 项目建立一套清晰、可扩展且意图明确的目录结构明确哪些代码该进cmd、internal、pkg哪些非 Go 资产该进configs、deployments、scripts。一、先明确这份布局的定位与适用前提在按模板建目录之前必须先理解这份文档反复强调的三条定位这不是 Go 核心团队定义的官方标准。它是一套在 Go 生态中历史性与新兴的“通用项目布局模式”的集合其中一些模式比另一些更流行。仓库同时指出官方 Go 团队也提供了关于如何组织 Go 模块、项目被导入或被安装时意味着什么的通用指南internal与cmd两个目录模式正是其中的重点。对初学者和小型 PoC这套布局是“过度设计”。文档明确建议学习 Go 或为自己写一个简单项目时一个main.go加上go.mod就足够了。只有当项目长大、多人协作、出现隐式依赖与全局状态、或你的仓库开始被其他项目 import 时才需要引入这种包/库管理方式。“按需取用”是第一原则。文档的原话是克隆仓库、留下你需要的部分、删掉其余的“存在”不等于“必须全部使用”——这些模式没有一条是被所有项目采用的连vendor模式都不算普遍。1.1 与 Go Modules 的配合文档指出自 Go 1.14 起 Go Modules 已具备生产就绪水平除非有特定理由否则应使用 Go Modules一旦使用就不再需要关心$GOPATH与项目放在哪里。仓库自带的 go.mod 给出了模板的默认形态module github.com/YOUR-USER-OR-ORG-NAME/YOUR-REPO-NAME go 1.19需要注意该go.mod假设项目托管在 GitHub但这不是强制要求——模块路径可以是任何值模块路径的第一个组件名称中应包含一个点。当前版本的 Go 已不再强制但使用稍旧版本时若缺失该点可能导致构建失败。文档建议查阅 Go 官方 issue 37554 与 32819 了解细节在 Go 官方 issue 追踪器中可检索到对应讨论。1.2 风格与命名的起点当你在命名、格式化与代码风格上需要帮助时文档给出的起点是先运行gofmt与golint英文版 README.md 中该条已更新为推荐使用仍在维护的staticcheck因为标准 lintergolint已弃停维护再结合以下资料阅读Go 官方names命名规范、Effective Go 的命名章节、Go 官方博客的包命名文章、CodeReviewComments评审清单以及社区广为流传的《Style guideline for Go packages》rakyll/JBD。文档还列出了多场 GopherCon 演讲作为延伸阅读Peter Bourgon 的工业级编程最佳实践、Kat Zien 的《How Do You Structure Your Apps》、Edward Muller 的反模式等均聚焦包命名与代码组织。最后一句定位性说明值得记住这份布局是刻意保持通用的它不试图强加任何特定的 Go 包结构也属于社区协作成果——发现新模式或认为既有模式需要更新时应通过提 issue 参与。二、仓库自证project-layout 本身就是一个该布局的实例最直观的学习方式就是看仓库自己的目录树。从根目录结构可以确认模板将“Go 代码区”与“非 Go 资产区”分离得非常彻底. ├── api/ # OpenAPI/Swagger 等接口规格 ├── assets/ # 仓库级图片、logo 等资产 ├── cmd/ │ └── _your_app_/ # 主应用入口下划线前缀表示 Go 忽略 ├── configs/ # 配置文件模板/默认配置 ├── deployments/ # IaaS/PaaS/容器编排配置 ├── docs/ # 设计与用户文档 ├── examples/ # 公共库示例 ├── githooks/ # Git hooks ├── init/ # systemd/upstart 等系统初始化配置 ├── internal/ │ ├── app/_your_app_/ # 私有应用代码 │ └── pkg/_your_private_lib_/ # 私有共享库 ├── pkg/ │ └── _your_public_lib_/ # 可被外部导入的公共库 ├── scripts/ # 构建/安装/分析脚本 ├── test/ # 外部测试应用与测试数据 ├── third_party/ # 外部工具、fork 代码 ├── tools/ # 项目支撑工具 ├── web/ │ ├── app/ # 前端 SPA │ ├── static/ # 静态资源 │ └── template/ # 服务端模板 ├── website/ # 项目站点数据 ├── Makefile └── go.mod注意cmd/_your_app_、internal/app/_your_app_、internal/pkg/_your_private_lib_、pkg/_your_public_lib_均以_前缀命名——这不是排版习惯而是利用“Go 会忽略以.或_开头的目录”这一规则见下文/test一节让模板目录不干扰构建使用者只需改名即可。根目录 Makefile 的内容只有一行注释# note: call scripts from /scripts这正是/scripts一节所述实践的落地具体脚本放在scripts/中根级 Makefile 保持极简只做分发。三、Go 核心目录3.1/cmd主应用入口/cmd存放项目的主应用规则如下每个应用一个子目录目录名即你期望的产物可执行文件名例如/cmd/myapp应用目录里不要放大量代码。如果某段代码认为可以被其他项目 import 复用它应进入/pkg如果不可复用或不希望被复用放入/internal。“别人会做出让你惊讶的事所以把你的意图说清楚”常见形态是一个很小的main函数只负责 import 并调用/internal与/pkg中的代码别无其他。仓库的 cmd/README.md 列出了采用该模式的大型开源项目作为参照velero、moby、prometheus、influxdb、kubernetes、dapr、go-ethereum 等它们的共同点都是“薄 main 厚包”。3.2/internal编译器强制的私有边界/internal存放你不希望被其他应用或库 import的私有应用与库代码。文档强调两点这一布局模式由 Go 编译器本身强制执行——将包放入任一internal目录后除非共享同一祖先路径否则其他包无法 import 它。这是 Go 1.4 release notes 中确立的internal包机制也是所有 Go 文档中唯一被赋予编译器特殊待遇的目录名你不限于顶层internal——项目树的任意层级都可以存在internal目录这使每个子系统都能独立划定私有边界。internal/README.md 进一步给出了一个可选的细化结构用于视觉上区分“共享”与“非共享”的内部代码小项目可不做实际应用代码放/internal/app例如/internal/app/myapp应用间共享的内部代码放/internal/pkg例如/internal/pkg/myprivlib。仓库自身正是这一结构的样板internal/app/_your_app_与internal/pkg/_your_private_lib_并存。3.3/pkg对外承诺“可用”的公共库/pkg存放允许外部应用使用的库代码例如/pkg/mypubliclib。文档的态度是克制的其他项目会默认这些库能稳定工作后再 import所以往这里放东西前要三思从“强制不可 import”角度internal是更可靠的手段因为它由 Go 保证而/pkg的价值在于**显式传达“这里的代码可以安全地被他人使用”**的意图。/pkg还有工程实用价值当根目录里堆满非 Go 组件时把 Go 库代码聚拢在一处便于运行各类 Go 工具。该模式并非被社区普遍接受——文档直言这是一种常见但存在争议的布局如果你的应用很小、多一层嵌套没有价值完全可以不用它等项目足够大、根目录足够“拥挤”尤其有大量非 Go 组件时再引入。历史渊源早期 Go 源码树自身使用pkg存放包社区项目随后纷纷效仿形成了这一模式。仓库的 pkg/README.md 罗列了大量采用pkg模式的主流仓库containerd、kubernetes、moby、etcd、helm、k3s、prometheus 系、dapr、cilium、keda 等百余例同时明确表态“每有一个用它的主流仓库就能找到十个不用的用不用由你决定”并指出即使有争议多数开发者也能看懂这个约定。3.4/vendor依赖管理/vendor存放应用依赖可手工管理也可用工具管理——文档特别提到内置的 Go Modules 就是这样的工具执行go mod vendor即可生成/vendor目录。配套要点若不使用 Go 1.141.14 起 vendor 模式默认开启可能需要在go build命令上追加-modvendor标志如果你在构建的是库不要提交应用依赖自 Go 1.13 起module proxy 功能已启用默认使用官方模块代理服务器。如果代理满足你的全部需求与约束那么你可能根本不需要vendor目录。四、服务与 Web 应用目录4.1/api存放 OpenAPI/Swagger 规格文件、JSON schema 文件、协议定义文件。仓库 api/README.md 指出 kubernetes 与 moby 是两个典型参照。4.2/web存放 Web 应用专属组件静态 Web 资源、服务端模板与 SPA。仓库的 web/README.md 给出同样的三要素描述而模板自身将web/预置为三个子目录——app/SPA 代码、static/静态资源、template/服务端模板正好与说明一一对应。五、通用应用目录5.1/configs配置文件模板或默认配置confd与consul-template的模板文件应放在这里。模板预置了 configs/ 目录。5.2/init系统 init 配置systemd、upstart、sysv与进程管理器/监督者配置runit、supervisord。5.3/scripts执行构建、安装、分析等操作的脚本。这些脚本的存在使根级 Makefile 保持小巧简单文档以 HashiCorp Terraform 的 Makefile 为参照。仓库的 scripts/README.md 给出 helm、cockroach、terraform 等示例项目而仓库自身 Makefile 仅一行注释指向/scripts是“根 Makefile 只做分发”原则的直接体现。5.4/build打包Packaging与持续集成CI云AMI、容器Docker、操作系统deb、rpm、pkg的打包脚本与配置放/build/packageCItravis、circle、drone脚本与配置放/build/ci。文档提醒部分 CI 工具如 Travis CI对配置文件位置要求严格若可行应把配置放在/build/ci再软链到工具期望的位置。5.5/deploymentsIaaS、PaaS、系统与容器编排的部署配置和模板docker-compose、kubernetes/helm、mesos、terraform、bosh。文档同时提示在部分仓库尤其是以 kubernetes 部署的应用中该目录被称为/deploy。模板预置了 deployments/ 目录。5.6/test存放额外的外部测试应用与测试数据目录内部结构可自由组织。对较大项目建议设立数据子目录。文档给出一个实用细节若希望 Go 工具忽略某目录内容使用/test/testdatatestdata被 go test 约定忽略或/test/data由于 Go 同样忽略以.或_开头的目录和文件你在测试数据目录命名上还有更多灵活度。test/README.md 以 OpenShift Origin 为例其测试数据位于/testdata子目录。六、其他目录6.1/docs设计与用户文档补充而非替代 godoc 生成的文档。docs/README.md 列出 hugo、openshift、dapr 等参照。6.2/tools项目自身的支撑工具。注意这些工具可以 import/pkg与/internal中的代码这使得“工具复用业务逻辑而不被外部滥用”成为可能。6.3/examples面向你的应用和/或公共库的示例。examples/README.md 引用 nats.go、docker-slim、packer 等示例。6.4/third_party外部辅助工具、被 fork 的代码及其他第三方工具例如 Swagger UI。6.5/githooksGit hooks 存放处。6.6/assets与仓库配套的其他资产图片、logo 等。6.7/website如果项目不使用 GitHub Pages这里存放项目站点数据。website/README.md 提供示例。七、不应该拥有的目录/src文档专设一节“Directories You Shouldnt Have”明确反对在项目中使用src目录Go 项目出现src通常是因为开发者来自 Java 世界那里这是常见模式。文档建议尽可能避免这种移植——“你不希望你的 Go 代码看起来像 Java”更重要的是避免概念混淆项目级/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 配置 Badges文档最后给出了项目 README 中常用徽章清单及各自用途使用时把示例中的github.com/golang-standards/project-layout替换为你的项目引用Badge作用Go Report Card使用gofmt、go vet、gocyclo、golint、ineffassign、license、misspell扫描你的代码并展示结果GoDoc已废弃文档中以删除线标注曾提供 GoDoc 生成文档的在线版本现已让位于 pkg.go.devPkg.go.devGo 发现与文档的新去处可通过其 badge 生成工具制作徽章Release展示项目最新 release 版本号九、小结如何把这份布局用到自己的项目按文档给出的决策路径执行即可起步main.gogo.mod模块路径首个组件保留一个点成长把业务逻辑移入/internal可进一步分internal/app与internal/pkg用编译器的internal机制守住私有边界被外部使用时把确定承诺稳定的 API 移入/pkg把接口规格放/api工程化配置进/configs系统单元进/init脚本进/scripts根 Makefile 只留分发打包与 CI 进/build部署物进/deployments测试数据进/test/testdata全程遵守不建src目录按需取用而非全盘照搬vendor在 module proxy 可用时可以不提交。文档结尾还提到Notes一个更“有主张”的项目模板附带可复用的示例配置、脚本与代码仍在开发中后续可关注仓库更新。【免费下载链接】project-layoutStandard Go Project Layout项目地址: https://gitcode.com/GitHub_Trending/pr/project-layout创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考