Tony Bai · Go 语言第一课
Tony Bai
资深架构师,tonybai.com 博主
21492 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 59 讲
开篇词 (1讲)
结束语 (1讲)
Tony Bai · Go 语言第一课
15
15
1.0x
00:00/00:00
登录|注册

05|标准先行:Go项目的布局标准是什么?

小结
注意早期Go可执行程序项目的典型布局
现在的Go项目的典型结构布局
Go项目的演进
Go创世项目结构
Go项目布局标准

该思维导图由 AI 生成,仅供参考

你好,我是 Tony Bai。
在前面的讲解中,我们编写的 Go 程序都是简单程序,一般由一个或几个 Go 源码文件组成,而且所有源码文件都在同一个目录中。但是生产环境中运行的实用程序可不会这么简单,通常它们都有着复杂的项目结构布局。弄清楚一个实用 Go 项目的项目布局标准是 Go 开发者走向编写复杂 Go 程序的第一步,也是必经的一步。
但 Go 官方到目前为止也没有给出一个关于 Go 项目布局标准的正式定义。那在这样的情况下,Go 社区是否有我们可以遵循的参考布局,或者事实标准呢?我可以肯定的告诉你:有的。在这一节课里,我就来告诉你 Go 社区广泛采用的 Go 项目布局是什么样子的。
要想了解 Go 项目的结构布局以及演化历史,全世界第一个 Go 语言项目是一个最好的切入点。所以,我们就先来看一下 Go 语言“创世项目”的结构布局是什么样的。

Go 语言“创世项目”结构是怎样的?

什么是“Go 语言的创世项目”呢?其实就是 Go 语言项目自身,它是全世界第一个 Go 语言项目。但这么说也不够精确,因为 Go 语言项目从项目伊始就混杂着多种语言,而且以 C 和 Go 代码为主,Go 语言的早期版本 C 代码的比例还不小。
我们先用 loccount 工具对 Go 语言发布的第一个 Go 1.0 版本分析看看:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Go语言项目的布局标准对于编写复杂的Go程序至关重要。虽然Go官方并未给出正式定义,但Go社区有着一套广泛采用的布局标准。文章首先介绍了Go语言的“创世项目”结构布局,强调了其对后续Go项目布局的重要影响。随后,文章详细分析了Go语言项目布局的演化历史,包括Go 1.4版本删除pkg目录、引入internal目录,Go 1.6版本增加vendor目录以及Go 1.13版本引入go.mod和go.sum。这些演进主要体现在简化结构布局和优化包依赖管理方面,对改善Go开发体验起到了重要作用。总的来说,Go语言项目的源码布局以及演化对Go社区项目的布局具有重要的启发意义,形成了公认的Go项目的典型结构布局。 文章详细介绍了Go可执行程序项目和库项目的典型结构布局,包括cmd目录、pkg目录、go.mod和go.sum文件等元素的作用和布局方式。对于可执行程序项目,强调了cmd目录存放可执行文件的main包源文件,以及vendor目录在Go 1.5版本引入的重要作用。而对于库项目,强调了不推荐在项目中放置vendor目录,而是通过go.mod文件明确表述依赖的module或包。此外,还介绍了早期Go可执行程序项目的典型布局,强调了pkg目录的“聚类”作用。 通过详细介绍不同类型项目的典型布局,为读者提供了全面了解Go项目布局标准的指南。文章内容详实,对于想要了解Go项目布局标准的读者具有很高的参考价值。文章以Go语言项目布局为主线,深入浅出地介绍了其演化历史和典型结构布局,为读者提供了全面了解和掌握Go项目布局标准的指南。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Tony Bai · Go 语言第一课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(52)

  • 最新
  • 精选
  • Nlife
    老师,这句话"一个 Go 项目里的 internal 目录下的 Go 包,只可以被本项目内部的包导入。项目外部是无法导入这个 internal 目录下面的包的。" 能否再讲解具体一些呢?比如后续我们的课程中是否会讲到这块的实践操作?

    作者回复: 举个例子,假设我们有两个go module,两个module的结构如下: . ├── module1 │   ├── go.mod │   ├── internal │   │   └── pkga │   ├── pkg1 │   └── pkg2 └── module2 ├── go.mod └── pkg1 module1中的internal/pkga包可以被module1的pkg1和pkg2包所导入。 但无法被module2的pkg1包所导入。

    2021-10-22
    5
    61
  • Geek_c1467d
    另外goalng标准布局可以参考下这个:https://github.com/golang-standards/project-layout

    作者回复: 这个已经被Go官方否了,https://github.com/golang-standards/project-layout/issues/117#issuecomment-828503689。

    2021-10-22
    3
    28
  • Bynow
    这部分东西讲解的循序渐进,太棒了,是很多晚上噶好难过没有涉及到的,讲解的可以看出来这这水平和积累,这门课太值了。爱了

    作者回复: 感谢支持。你的收获对我来说就是最大的鼓励。

    2021-10-23
    2
    19
  • Linuaa
    老师可以讲讲 ”Reproducible Build“ 吗,看了一些文章感觉抓不到重点。谢谢老师~

    作者回复: 可重现构建,顾名思义,就是针对同一份go module的源码进行构建,不同人,在不同机器(同一架构,比如都是x86-64),相同os上,在不同时间点都能得到相同的二进制文件。

    2021-10-23
    18
  • 郭纯
    对于最小的布局 我觉的只要这几个文件就好了 main.go. go.mod go.sum. 既然是小项目代码量不多所有代码在 main.go 文件就好。

    作者回复: Go语言技术负责人Russ Cox曾谈过这个问题,他认为一个项目的最小布局至少有一个go.mod,一个LICENSE(针对开源项目)。然后就像你说的,在项目根目录下放置go代码即可。对于tiny项目,一个main.go也是可以的。

    2021-10-22
    16
  • 光明
    这一节虽然没有搞懂太多,反复看了3遍,后发现这一章节,是现行很多 GO 语言书籍中缺少部分。非常感谢Tony 老师的这么细致有详细的讲解。细微之处见真功夫。

    作者回复: 👍

    2022-02-05
    13
  • alexgreenbar
    这些难道不是一门语言一开始就应该解决的问题吗?10多年过去了,go居然还在纠结这个,在这点上,感觉go的创建者们故意忽视了软件工业过去20年的积累,不比较语言本身,只考虑构建:java有maven,rust有cargo,并且它们都有集中可访问的repository用于分享,go到现在都没有这个机制,也是服了。

    作者回复: 我觉得你提到的是两件事: 1. go项目标准布局的事儿 到目前为止,Go官方并没有给出书面标准。文中内容也是基于Go项目自身以及Go社区的主流实践整理而得的。 Go语言技术负责人Russ Cox曾谈过这个问题,但他仅给出对于go项目最小布局的观点,他认为一个项目的最小布局至少有一个go.mod,一个LIC ENSE(针对开源项目)。其他都有程序员自行确定。不可否认,没有基本标准布局,这的确给规模稍大一些的项目的开发人员带来困惑。 2. 没有统一的集中的module/包库 Go没有,且也是故意这么设计的。你提到Go团队故意忽视了软件工业过去20年的积累,但从Go团队角度来看,这是他们的一种解决安全风险的方案。可以看看这篇文章:https://tonybai.com/2022/04/02/how-go-mitigates-supply-chain-attacks 从今年来npm暴露出的一系列安全问题来看,集中库的确也存在各种各样的问题。

    2022-04-21
    8
  • Long_hz
    老师你好,请问一下loccount 工具编译的时候缺少go.mod需要怎么解决?

    作者回复: loccount只是一个代码统计工具,你可以用其他类似的工具替代。如果非要编译loccount工具,并且它没有go.mod的话,可以下载loccount工具源码后,在你的本地为其创建一个go.mod,然后编译试试。

    2021-10-22
    2
    7
  • lesserror
    Tony Bail 老师的这一讲关于Go项目的布局标准的讲解非常专业。极客时间孔令飞老师的专栏,对这一布局方式很很好的实践。 有以下疑问,烦请老师抽空解答一下: 1. “ 这些依赖包是缓存在 vendor 目录下的”。那我可以是否可以理解为,接是把这些包的源码文件下载到本地的vendor目录中呢? 2. “库项目仅通过 go.mod 文件明确表述出该项目依赖的 module 或包以及版本要求就可以了。” 请问一下,go.mod文件中还能表述依赖的 module吗? 我看go.mod文件中的内容一般不都是依赖的第三方包和版本吗? 3. 使用vendor的优势是什么?对比使用 go module形式,只是访问第三方包的源码路径的不同吗? 4. 老师,后面的项目代码会在这一讲的目录基础上来构建吗?这一讲没有实际的代码操作,如果没有实际的操作感受,很容易遗忘这些概念。

    作者回复: 感谢认真的思考和棒棒的问题,我也认真回答一下:) 1. 是的,如果采用vendor模式,依赖包会缓存在vendor目录下。 2. 在go module机制进入go之前,也就是gopath构建模式时代,我们谈到的所有依赖都是包与包的版本;但go module引入后,所有的版本信息都绑定在module上,所以你在go.mod中看到的require块中的依赖都是module与module的版本,不再是包。 3. 06和07讲会提到。 4. 06,07讲会有例子。

    2021-10-22
    2
    6
  • qinsi
    诶,ESR也写go了?

    作者回复: 是的。loccount就是它的作品。他还用go编写了将gcc代码从svn仓库无损(提交历史)地迁移到git的工具。可以看看他切换到go的感悟:https://gitlab.com/esr/reposurgeon/blob/master/GoNotes.adoc

    2021-10-22
    6
收起评论
显示
设置
留言
52
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部