脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - 如何优雅的组织Golang项目结构

如何优雅的组织Golang项目结构

2023-12-05 13:58程序新视界 Golang

一个Go项目的结构设计始终遵循Go语言的简洁高效理念。一个合理和良好的布局可以提高代码的可读性,简化依赖管理,并优化编译过程。像cmd、internal和docs这样的目录是标准Go项目的基础,起着不同的作用。

一个Go项目的结构设计始终遵循Go语言的简洁高效理念。一个合理和良好的布局可以提高代码的可读性,简化依赖管理,并优化编译过程。

像cmd、internal和docs这样的目录是标准Go项目的基础,起着不同的作用。比如,cmd目录是可执行文件的入口,docs是所有相关文档的入口,而internal包含项目私有代码。适当的包划分可以避免循环依赖,便于单元测试和代码复用。

然而,这种Go项目布局可能导致过多的目录层级和包划分,会给管理工作带来负担,并有时让初学者感到不知所措。

因此,在设计时如何把握什么算是“合理”,就成了关键。

这篇文章,让我们尝试在目录结构和包设计中找到简洁和功能之间的平衡,使项目能够在变化中健康迭代。

标准布局

像cmd和internal这样的目录结构是由一些Go语言社区的开发者在系统总结之前进行了总结,并在标准Go项目布局中得到了进一步的概括,该项目已经获得了超过4万个star。尽管其起源是一个提示,但标准布局已经成为Go项目目录结构的事实标准。

这并不是由核心Go开发团队定义的官方标准。

my-app/ # Root directory of the project
|── cmd/ # Executables directory
└── myapp/ # Main application package
└── main.go # Main application entry point
|── internal/ # Private application and library code
└── package1/ # Internal package 1
|── pkg/ # Library code that can be exported
└── package2/ # External package 2
|── api/ # API protocol definitions directory
|── configs/ # Configuration files directory
|── deployments/ # Deployment configurations and scripts
|── scripts/ # Scripts for build, install, analysis, etc.
|── build/ # Packaging and Continuous Integration
|── tests/ # Additional external test apps and test data
|── docs/ # Design and user documents
|── tools/ # Supporting tools for the project
|── examples/ # Application or public library examples
|── third_party/ # External helper tools, forked code, and other 3rd party utilities
|── githooks/ # Git hooks
|── assets/ # Other assets like images, logos, etc.
|── vendor/ # Dependency package directory (if using vendor mode)
|── go.mod # Module dependency file
|── go.sum # Module checksum file for dependency verification

如果你经常阅读源代码,你会轻易地发现,大多数在GitHub上知名的Go开源项目基本上都遵循上述布局,比如Kubernetes这个大型Go项目。

如何优雅的组织Golang项目结构图片

让我们简单看一下。

  • 与Go模块相关的go.mod和go.sum是必不可少的。
  • pkg目录包含api、apis、kubectl等包,可应用于外部项目,比如基于Kubernetes的开发。
  • cmd包含了Kubernetes中各种命令行的main方法入口,比如kubectl.go。
  • api目录存储与openApiv3相关的json文件。
  • test目录包含所有的e2e和集成测试代码,根据不同的包进行了分别存储。
  • third_party存储第三方引用的工具,比如protobuf。
  • vendor用于存储外部依赖,比如k8s.io、etcd等。
  • docs目录目前为空。

当然,Kubernetes项目并不完全遵循标准布局,因为其规模较大。例如,许多Kubernetes脚本存储在build和cluster目录中,而不是scripts目录。还有一些用于特定需求的目录,比如hacks和staging。

官方布局

2023年发布的文章《组织Go模块》揭示了Go团队对布局的不同观点,提供了根据项目复杂性设计目录结构的参考,涵盖了具有少量Go文件、单个cmd命令或简单包的项目,以及具有多个cmds和多个包的项目。

对它们进行总结如下,并将其作为下一节的官方布局。

my-module/                 # Root directory for the module with go.mod
├── go.mod                 # Module's dependency file
├── go.sum                 # The module's checksums for dependency validation
├── cmd/                   # Directory for commands (each subdirectory here is a main package)
│   └── my-app/            # Main application for this module
│       └── main.go        # Main application entry point
├── internal/              # Internal packages meant for use only within this module
│   └── mylib/             # An internal package example
│       └── mylib.go       # The package's specific code
├── api/                   # API protocol definitions, e.g., protocol buffer files
├── web/                   # Web application specific components: static files, server-side templates, SPAs, etc.
├── pkg/                   # Library code that's ok to use by external applications (deprecated by some in the community)
│   └── mypkg/             # An example package that could be imported by other applications
│       └── mypkg.go       # Package code
├── README.md              # Project README file
├── LICENSE                # License file
├── .gitignore             # Specifies intentionally untracked files to ignore
└── ...                    <-- Other directories and files as needed

标准布局与官方布局

这两种布局有一些共同的思想。

  • 模块化。不同的功能会被放入不同的包中,以提高可重用性。
  • 提高可见性。根据功能将不同的包存储在不同的目录中,以提高可读性。

基于这些概念,标准布局中有一个通用的cmd目录来存储命令行代码,子包用于保存多个命令,internal目录用于保存不对外共享的代码。目录路径和包名称与main.go作为入口文件保持一致。

但是,它们对于像pkg和util这样的目录有不同的考虑,例如,Russ Cox反对以pkg和util等模糊方式命名软件库。此外,由于社区的贡献,标准布局比官方建议覆盖范围更广,添加了像scripts和build这样的目录。

Go-Clean-Template

标准布局和官方布局都是通用的,将项目分为cmd项目和非cmd项目,因此对于包含entity和dao等多个包的复杂项目(如使用Go开发的Web项目),它们并不是首选。go-clean-template则专为这类Web项目量身定制。

go-clean-template/       <-- Root directory of the project
├── cmd/                 <-- Main application entry points
│   └── appname/         <-- Specific startup logic and configuration for 'appname' app
│       └── main.go      <-- Main application startup entry
├── internal/            <-- Internal modules, not importable by external applications
│   ├── entity/          <-- Entities (business objects) of the application
│   ├── usecase/         <-- Use case layer containing business logic interfaces
│   ├── repository/      <-- Data storage interfaces
│   ├── handler/         <-- HTTP handlers for receiving requests and calling use cases
│   └── config/          <-- Configuration related code
├── pkg/                 <-- Public library code that can be imported by other projects
├── test/                <-- External testing code
├── .dockerignore        <-- Specifies files to ignore in Docker builds
├── .gitignore           <-- Specifies intentionally untracked files to ignore in Git
├── Dockerfile           <-- Docker configuration file for containerization
├── go.mod               <-- Go module dependencies file
├── go.sum               <-- Checksums for Go module dependencies
└── Makefile             <-- Makefile containing automation commands

作为标准布局的扩展,go-clean-template保留了pkg目录,以便更好地管理众多公共库。它明确定义了像entity、repository、config等子包,省去了我们为它们命名的工作。它还有像test和integration-test这样的目录,用于放置相应的测试代码,提高可读性。

小结

本文带大家深入研究了组织Go代码库的三种布局:

标准布局提供了一个由社区驱动的、广泛适用的结构,非常适合需要清晰关注点分离的大型项目。

官方布局由Go的创建者认可,强调简洁和灵活性,适用于各种项目,特别是那些优先考虑模块管理的项目。

基于Clean Architecture原则的go-clean-template在需要将业务逻辑、数据访问和接口层明确分离以提高可维护性和可测试性的项目中表现出色。

这三种范式适应不同的项目需求,每种都提供了一套可自适应和组合的指南。选择其中之一取决于具体项目的要求、规模和复杂性。

原文地址:https://mp.weixin.qq.com/s/0FSbKhl78THvOjDLkfu4AQ

延伸 · 阅读

精彩推荐
  • GolangGo结合Gin导出Mysql数据到Excel表格

    Go结合Gin导出Mysql数据到Excel表格

    本文主要介绍了Go结合Gin导出Mysql数据到Excel表格,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    行人已6882022-08-04
  • Golang一篇文章把 Go Map 赋值和扩容扒干净!

    一篇文章把 Go Map 赋值和扩容扒干净!

    今天我们一起简单了解一下基础概念,再开始研讨 map 的重点内容。我相信这样你能更好的读懂这篇文章。...

    脑子进煎鱼了11122021-09-28
  • Golanggolang实现各种情况的get请求操作

    golang实现各种情况的get请求操作

    这篇文章主要介绍了golang实现各种情况的get请求操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    千年恨8432021-03-07
  • GolangGolang error使用场景介绍

    Golang error使用场景介绍

    我们在使用Golang时,不可避免会遇到异常情况的处理,与Java、Python等语言不同的是,Go中并没有try...catch...这样的语句块,这个时候我们如何才能更好的处...

    烟草的香味.7392023-05-30
  • GolangGo java 算法之括号生成示例详解

    Go java 算法之括号生成示例详解

    这篇文章主要为大家介绍了Go java 算法之括号生成示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    黄丫丫11732022-11-11
  • Golanggolang 切片截取参数方法详解

    golang 切片截取参数方法详解

    这篇文章主要介绍了golang 切片截取参数方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    样子201817772021-03-26
  • GolangGo语言中sync.Mutex的使用方法

    Go语言中sync.Mutex的使用方法

    本文主要介绍了golang中sync.Mutex的实现方法,mutex主要有两个 method:Lock()和Unlock(),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考...

    水淹萌龙11762023-03-07
  • Golanggo特性之数组与切片的问题

    go特性之数组与切片的问题

    这篇文章主要介绍了go特性之数组与切片的问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以...

    老陈未老6442021-02-07