Go语言中常见100问题-#12 Project misorganization

2022-12-18 12:36:58 浏览数 (1)

项目结构混乱

创建一个好的Go项目结构并不是一件容易的事情,由于Go语言在设计包和模块方面提供了很大的自由度,因此在这方面没有通用的最佳实践。本文将首先讨论创建项目的常用组织结构,然后讨论一些最佳实践,给出改进项目组织方式的方法。

项目结构

Go语言维护者对构建Go项目结构没有严格的约定,在github上有一个称为标准Go项目结构的模板(https://github.com/golang-standards/project-layout)),注意该模板不是Go官方提供的。如果我们的项目很小(只有几个文件),或者公司和项目组已经指定了项目结构规范,重新调整或迁移到上述模板格式可能不值得。如果项目还没有结构规范,那前面这个结构值得参考借鉴。现在我们来看看这个结构模板的布局,都有些什么内容:

  • /cmd 项目主要的应用程序. foo应用程序的main.go应该位于/cmd/foo/main.go中。
  • /internal 私有的应用程序代码库,这里面的代码是不希望被其它人导入的。
  • /pkg 外面的应用程序可以使用的代码库,是向其它人公开的公共代码。
  • /test 存储测试数据和代码。Go语言中的单元测试文件与源文件通常都在一个包中。但像公共API测试或集成测试代码应该存放在/test中。
  • /configs 存放配置文件
  • /docs 存放设计和用户文档
  • /examples 应用程序或公共库函数的实例程序
  • /api api接口定义文件(Swagger, Protocol Buffers等)
  • /web web应用程序的资源文件(静态图片等)
  • /build 打包和持续集成(CI)文件
  • /scripts 用于分析、安装等脚本文件
  • /vendor 应用程序的依赖文件(例如Go模块的依赖库)

可以看到上面的标准结构中没有/src目录,这是因为/src目录太泛了,因此采用了/cmd、/internal和/pkg这种目录。

「NOTE:在2021年,Go语言的核心维护者 Russ Cox对上面的项目结构表达反对意见。尽管它号称是Go项目标准结构,但不是官方的标准,有误导人嫌疑。对于项目结构,没有强制性约定必须采用上述模板。我们必须意识到这一个点,唯一注意的是项目中的各个模块结构要保持一致,达成统一。避免在不同的结构之间发生迁移,这会浪费时间。」

包组织结构

在Go语言中,没有子包的概念。但是,我们可以在子目录中创建包。下面是标准库net中的目录结构。net既充当包,又充当包含其他包的目录。但是net/http包不继承net或对net包具有特定的访问权限。外界能看到net/http中可导出的元素。子目录的主要好处是将包中代码保存在具有高内聚性的地方。

代码语言:javascript复制
/net
    /http
        client.go
        ...
    /smtp
        auth.go
        ...
    addrselect.go
    ...

对于Go包的组织形式,有不同的观点。例如,我们应该按业务类型还是按层来组织应用程序,这取决于自己的喜好。我们可能倾向于按业务类型(例如客户业务,合同业务等)对代码进行分组,或者我们倾向于遵循六边形原则对其进行分组。只要选择出了适合我们的方法,保持统一即可。

对于软件包,我们应该遵循一些最佳实践。首先,应该避免过渡设计,因为这可能会使得项目过于复杂。当我们搞清楚了项目包含的内容后,最好使用一个简单的形式组织并让项目不断的发展,而不是强迫自己预先制定完美的结构。

包的粒度是另一个需要考虑的重要因素,我们应该避免有几十个包含一两个文件的小包。如果这样设计,可能错过了这些包之间的一些逻辑联系,使得项目更难让人理解。此外,我们也应该避免使用包含很多文件的大包。总之,对于包的粒度,我们不应该走极端,导致包极小或极大。

包的命名也应该谨慎考虑。众所周知,命名是程序开发中一件困难的事情。为了帮助用户理解Go项目,我们应该根据它提供的内容命名包,而不是它包含的内容。此外,包名要有意义。因此,包的名称应该简短、简洁和富有表现力,按照惯例,应该是一个小写单词。

对于包导出什么,规则非常简单。我们应该尽可能减少应该导出的内容,以减少包之间的耦合并隐藏不必要导出的元素。如果不确定是否要导出一个元素,应该默认它不导出,在后面发现需要导出时,再调整代码支持将其导出。我们还要注意一些特殊情况,例如,当我们对一个结构体对象调用 encoding/json 标准库对其进行序列化或反序列化时,该结构体对象的字段需要是可导出的(即首字母要大写),否则会忽略该字段。

组织好一个项目结构并不是一件简单的事情,遵循上述这些规则有助于我们更容易维护。记住一点,保持结构一致对于简化可维护非常有帮助。因此,应确保代码库中的代码尽可能保持一致。

0 人点赞