当前位置: 首页 > news >正文

Go项目的目录结构基本布局

前言


       随着项目的代码量在不断地增长,不同的开发人员按自己意愿随意布局和创建目录结构,项目维护性就很差,代码也非常凌乱。良好的目录与文件结构十分重要,尤其是团队合作的时候,良好的目录与文件结构可以减少很多不必要的麻烦。项目目录结构规范的的本质是提高了代码的可读性,最终目的是提高团队协作效率,降低工程维护成本。

      我们知道 java 项目结构是请求达到路由层控制器 controller,然后 controller 会去调用 service 层逻辑代码,然后 service 层会去调用 dao 层的接口方法,其实 dao 层都是以接口的形式提供,然后这些接口里头的都是操作数据库的方法,然后与 dao 层对应着的有一个 mapper,mapper 是以 xml 形式提供的,与 dao 层中的接口相对应,xml 中实际就是实现了 dao 接口中的这些具体方法,xml 中会与指定的 dao 接口中指定的方法进行绑定,xml 中会去写 sql 逻辑。具体请看架构师技能1:Java工程规范、浅析领域模型VO、DTO、DO、PO、优秀命名

     
 

一、Go语言自身项目的基本结构


首先我们先看Go语言自身项目的基本结构。

Go项目的项目结构自1.0版本发布以来一直十分稳定,直到现在Go项目的顶层结构基本没有大的改变。go项目大致结构如下,GitHub - golang/go: The Go programming language

$ tree -LF 1 ~/go/src/github.com/golang/go
./go
├── api/
├── doc/
├── lib/
├── misc/
├── src/

├── test

├── PATENTS
├── LICENSE
├── CONTRIBUTING.md
└── README.md

作为Go语言的“创世项目”,其项目结构的布局对后续的其他Go语言项目具有重要的参考意义,尤其是早期Go项目中src目录下面的结构,更是在后续被Go社区作为Go应用项目结构的模板被广泛使用。我们以早期的Go 1.3版本的src目录下的结构为例:

$ tree -LF 1 ./src
./src
├── all.bash*
├── all.bat
├── all.rc*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── lib9/
├── libbio/
├── liblink/
├── make.bash*
├── make.bat
├── Make.dist
├── make.rc*
├── nacltest.bash*
├── pkg/
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
└── sudo.bash*

src目录下面的结构三个特点:

1)代码构建的脚本源文件放在src下面的顶层目录下;

2)src下的二级目录cmd下面存放着go工具链相关的可执行文件(比如:go、gofmt等)的主目录以及它们的main包源文件;

3)src下的二级目录pkg下面存放着上面cmd下各工具链程序依赖的包、go运行时以及go标准库的源文件

在Go 1.3版本以后至今,Go项目下的src目录中发生了几次结构上的变动:

Go 1.4版本中删除了Go源码树中src/pkg/xxx中pkg这一层级目录而直接使用src/xxx;

Go 1.4版本在src下面增加internal目录,用于存放无法被外部导入仅Go项目自用的包;

Go 1.6版本在src下面增加vendor目录,但Go项目自身真正启用vendor机制是在Go 1.7版本中。vendor目录中存放了go项目自身对外部项目的依赖,主要是golang.org/x下的各个包,包括:net、text、crypto等。该目录下的包会在每次Go版本发布时做更新;

Go 1.13版本在src下面增加了go.mod和go.num,实现了go项目自身的go module迁移,go项目内所有包被放入名为std的module下面,其依赖的包依然是golang.org/x下的各个包

// Go 1.13版本go项目src下面的go.mod
module std
 
go 1.12
 
require (
    golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68
    golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
    golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8 // indirect
    golang.org/x/text v0.3.2 // indirect
)
下面是最新的Go 1.16版本src目录下的完整布局:

├── Make.dist
├── README.vendor
├── all.bash*
├── all.bat
├── all.rc*
├── bootstrap.bash*
├── buildall.bash*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── cmp.bash
├── go.mod
├── go.sum
├── internal/
├── make.bash*
├── make.bat
├── make.rc*
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
├── testdata/
...
└── vendor/
 

Go 1.14 Go Modules 投入使用后,就无需担心 $GOPATH 以及项目放置的位置。所以项目的 vendor 可以忽略了,建议直接使用 module 来管理依赖

二、优秀开源 的go项目结构样例


1、Docker

https://github.com/moby/moby

├── api      // 存放对外公开的 API 规则

├── builder  // 存放构建脚本等

├── cli      // 命令行的主要逻辑

├── cmd      // 存放可执行程序,main 包放这个目录中

├── contrib  // 存放一些有用的脚本或文件,但不是项目的核心部分

├── docs    // 存放文档

├── internal // 只在本项目使用的包(私有)

├── pkg     // 本项目以及其他项目可以使用的包(公有)

├── plugin  // 提供插件功能

2、Kubernetes

https://github.com/kubernetes/kubernetes

├── api

├── build  // 存放构建脚本等

├── cmd

├── docs

├── pkg

├── plugin

├── test    // 单元测试之外的测试程序、测试数据

├── third_party // 经过修改的第三方的代码

3、Gogs

https://github.com/gogs/gogs

├── cmd

├── conf    // 对配置进行解析

├── docker  // 存放 docker 脚本

├── models  // MVC 中的 model

├── pkg

├── public  // 静态公共资源,实际项目会将其存入 CDN

├── routes  // 路由

├── scripts // 脚本文件

├── templates // 存放模板文件

总体上这些优秀开源项目,没有统一一致的目录结构方式,但大体上,有一些通用的地方,这就有

project-layout/README_zh.md at master · golang-standards/project-layout · GitHub做参考。

三、通用项目目录结构参考


参考:

project-layout/README_zh.md at master · golang-standards/project-layout · GitHub

1、web服务应用程序目录

/api

OpenAPI/Swagger 规范,JSON 模式文件,协议定义文件。

/web

特定于 Web 应用程序的组件:静态 Web 资产、服务器端模板和 SPAs。

2、通用应用目录

/configs

配置文件模板或默认配置。

将你的 confd 或 consul-template 模板文件放在这里。

/init

System init(systemd,upstart,sysv)和 process manager/supervisor(runit,supervisor)配置。

/scripts

执行各种构建、安装、分析等操作的脚本。

这些脚本保持了根级别的 Makefile 变得小而简单(例如, terraform/Makefile at main · hashicorp/terraform · GitHub )。

有关示例,请参见  /scripts 目录。

/build

打包和持续集成。

将你的云( AMI )、容器( Docker )、操作系统( deb、rpm、pkg )包配置和脚本放在 /build/package 目录下。

将你的 CI (travis、circle、drone)配置和脚本放在 /build/ci 目录中。请注意,有些 CI 工具(例如 Travis CI)对配置文件的位置非常挑剔。尝试将配置文件放在 /build/ci 目录中,将它们链接到 CI 工具期望它们的位置(如果可能的话)。

/deployments

IaaS、PaaS、系统和容器编排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些存储库中(特别是使用 kubernetes 部署的应用程序),这个目录被称为 /deploy

/test

额外的外部测试应用程序和测试数据。你可以随时根据需求构造 /test 目录。对于较大的项目,有一个数据子目录是有意义的。例如,你可以使用 /test/data 或 /test/testdata (如果你需要忽略目录中的内容)。请注意,Go 还会忽略以“.”或“_”开头的目录或文件,因此在如何命名测试数据目录方面有更大的灵活性。

有关示例,请参见  /test 目录。

我们可以参考project-layout/README_zh.md at master · golang-standards/project-layout · GitHub

3、其他目录

/docs

设计和用户文档(除了 godoc 生成的文档之外)。

有关示例,请参阅 /docs 目录。

/tools

这个项目的支持工具。注意,这些工具可以从 /pkg 和 /internal 目录导入代码。

有关示例,请参见 /tools 目录。

/examples

你的应用程序和/或公共库的示例。

有关示例,请参见 /examples 目录。

/third_party

外部辅助工具,分叉代码和其他第三方工具(例如 Swagger UI)。

/githooks

Git hooks。

/assets

与存储库一起使用的其他资产(图像、徽标等)。

/website

如果你不使用 Github 页面,则在这里放置项目的网站数据。

有关示例,请参见 /website 目录。

4、不应该拥有的目录

/src

有些 Go 项目确实有一个 src 文件夹,但这通常发生在开发人员有 Java 背景,在那里它是一种常见的模式。如果可以的话,尽量不要采用这种 Java 模式。你真的不希望你的 Go 代码或 Go 项目看起来像 Java:-)

不要将项目级别 src 目录与 Go 用于其工作空间的 src 目录(如 How to Write Go Code 中所述)混淆。$GOPATH 环境变量指向你的(当前)工作空间(默认情况下,它指向非 windows 系统上的 $HOME/go)。这个工作空间包括顶层 /pkg/bin 和 /src 目录。你的实际项目最终是 /src 下的一个子目录,因此,如果你的项目中有 /src 目录,那么项目路径将是这样的: /some/path/to/workspace/src/your_project/src/your_code.go。注意,在 Go 1.11 中,可以将项目放在 GOPATH 之外,但这并不意味着使用这种布局模式是一个好主意。

四、代码架构


我们在《架构设计1:谈谈架构》已经提到代码架构,主要定义内容:

一、代码单元:
        1、配置设计
        2、框架、类库。
二、代码单元组织:
       1、编码规范,编码的惯例。
       2、项目模块划分
       3、顶层文件结构设计,比如mvc设计。
       4、依赖关系

 我们再次只提分层依赖和目录规范结构:

1、代码分层和依赖

       代码分层,让不同层次的代码做不同的动作。层次清晰的代码,提高可读性,从代码结构就大概能了解到代码是如何分层,每层大概功能是什么。例如java常用的Controller、Service、Mapper/Dao三层代码结构,其各层的代码逻辑范围。

2、默认上层依赖于下层

    依赖规则规定上层的代码可以依赖下层,但是下层的代码不可以依赖上层。也就是说下层逻辑不可以依赖任何上层定义的变量,函数,结构体,类,模块等等代码实体。

 通过分层,一个庞大系统切分成不同部分,便于分工合作和维护。

        应用层:主要负责具体的业务逻辑处理

         服务层:提供可复用的服务

         数据层:负责数据的存储和访问
       假如说,最上层应用层处使用了 go 语言的 gorm 三方库,并定义了 gorm 相关的数据库结构体及其 tag 等。那么下层数据层不可以引用任何外层中 gorm 相关的结构体或方法,甚至不应该感知到 gorm 的存在。

 但是,分层架构也有一些挑战:①必须合理规划层次边界和接口;②禁止跨层次的调用及逆向用。   《架构设计5:架构模式-分层模式》   《架构设计5:架构模式-分层模式》   《架构设计5:架构模式-分层模式》

3、参考的项目目录结构

可以参考,可以根据自己团队和实际项目来做改动,规范的最主要目的是统一认知。

├── app/application // App层,处理Adapter层适配过后与框架、协议等无关的业务逻辑
├   ├── api 处理OpenAPI 接口请求
├   ├── web  请求Web页面请求
├   ├── consumer  //(可选)处理外部消息
├   ├── scheduler/task  //处理定时任务,比如Cron格式的定时Job
├── domain // Domain层,最纯粹的业务实体及其规则的抽象定义
│   ├── interface/gateway // 领域网关,model的核心逻辑以Interface形式在此定义,交由biz层去实现
│   └── model // 领域模型实体
├── biz/module 业务/业务模块层
├   └──module1
├        ├──dao 数据库层
├        ├──model 业务模型
├        ├──entity 数据库模型
├        ├──service 业务逻辑
├        └──manager 复用逻辑
├── configs 配置
├── init    //系统初始化
├── pkg
├── public  // 静态公共资源,实际项目会将其存入 CDN
├── build  打包和持续集成
├── scripts // 脚本文件:执行各种构建、安装、分析等操作的脚本
├── test // 单元测试之外的测试程序、测试数据
├── plugin 各种插件
├── util/tools 工具包
├── main.go 项目运行入口
└── pkg // 各层可共享的公共组件代码

相关文章:

Go项目的目录结构基本布局

前言 随着项目的代码量在不断地增长,不同的开发人员按自己意愿随意布局和创建目录结构,项目维护性就很差,代码也非常凌乱。良好的目录与文件结构十分重要,尤其是团队合作的时候,良好的目录与文件结构可以减少很多不必要…...

CHAPTER 1 Linux Filesystem Management

Linux Filesystem Management1 文件系统是什么2 文件系统的组成3 inode详解1. inode到底是什么2. inode的内容3. inode的大小4. inode的号码5. 硬链接6. 软链接4 存储区域5 常见文件系统的类型1. 根文件系统2. 虚拟文件系统3. 真文件系统4. 伪文件系统5. 网络文件系统1 文件系统…...

RocketMQ架构篇 - 读写队列与生产者如何选择队列

读、写队列 创建主题时,可以指定 writeQueueNums(写队列的个数)、readQueueNums(读队列的个数)。生产者发送消息时,使用写队列的个数返回路由信息;消费者消费消息时,使用读队列的个…...

华为OD机试真题Python实现【通信误码】真题+解题思路+代码(20222023)

通信误码 题目 信号传播过程中会出现一些误码,不同的数字表示不同的误码 ID,取值范围为 1~65535,用一个数组记录误码出现的情况,每个误码出现的次数代表误码频度,请找出记录中包含频度最高误码的最小子数组长度。 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD…...

【单目3D目标检测】MonoDDE论文精读与代码解析

文章目录PrefacePros and ConsAbstractContributionsPreliminaryDirect depth estimationDepth from heightPespective-n-point(PnP)PipelineDiverse Depth EstimationsRobust Depth CombinationOutput distributionSelecting and combining reliable de…...

复习 Kotlin 从小白到大牛 第二版 笔记要点

4.2.2 常量和只读变量 常量和只读变量一旦初始化就不能再被修改。在kotlin中,声明常量是在标识符的前面加上val或const val 关键字。 1. val 声明的是运行时变量,在运行时进行初始化 2.const val 声明的是编译时常量,在编译时初始化 val …...

X264简介-Android使用(二)

X264简介-Android使用(二) 4、Ubuntu上安装ffmpeg: 检查更新本地软件包(如果未更新,reboot Vmware): sudo apt update sudo apt upgrade官网下载的source文件安装: http://ffmpe…...

【独家】华为OD机试 - 统计差异值大于相似值二元组个数(C 语言解题)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

掌握好Framework 才是王道~

现在面试对Android开发者的要求越来越高了!从最开始的阿里、头条、腾讯等大厂,到现在的互联网车企,面试总喜欢问道 Framework底层原理的相关问题 Android Framework的三大核心功能: 1、View.java:View工作原理,实现包…...

Codeforces Round 856 (Div. 2) A — C

Codeforces Round 856 (Div. 2) 文章目录A. Prefix and Suffix Array题目大意题目分析codeB. Not Dividing题目大意题目分析codeC. Scoring Subsequences题目大意题目分析codeA. Prefix and Suffix Array 题目大意 给出一个字符串所有的非空前后缀,判断原字符串是…...

2022年MathorCup数学建模B题无人仓的搬运机器人调度问题解题全过程文档加程序

2022年第十二届MathorCup高校数学建模 B题 无人仓的搬运机器人调度问题 原题再现 本题考虑在无人仓内的仓库管理问题之一,搬运机器人 AGV 的调度问题。更多的背景介绍请参看附件-背景介绍。对于无人仓来说,仓库的地图模型可以简化为图的数据结构。 仓库…...

开源项目的演进会遇到哪些“坑”?KubeVela 从发起到晋级 CNCF 孵化的全程回顾

作者:孙健波、曾庆国 点击查看:「开源人说」第五期《KubeVela:一场向应用交付标准的冲锋》 2023 年 2 月,**KubeVela [ 1] ** 经过全体 ToC 投票成功进入 CNCF Incubation,是云原生领域首个晋级孵化的面向应用的交付…...

MSDP实验配置

目录 配置MSDP 配置PIM SM协议 配置各PIM SM域内的静态RP 配置MSDP对等体 配置域内的MSDP对等体 AR8和AR9建立EBGP邻居 配置域间的MSDP对等体 进行实验验证 什么是MSDP MSDP(Multicast Source Discovery Protocol)组播源发现协议的简称 用来传递…...

惊!初中生也来卷了……

大家好,我是良许。 前两天在抖音直播的时候,突然来了一位不速之客…… 他自称是初中生,一开始我还有点不太相信,直到跟他连麦,听到他还略带一些稚嫩的声音,我才知道,他没有骗我…… 他说他想学…...

kafka相关配置介绍

kafka默认配置 每个kafka broker中配置文件server.properties默认必须配置的属性如下: broker.id0 num.network.threads2 num.io.threads8 socket.send.buffer.bytes1048576 socket.receive.buffer.bytes1048576 socket.request.max.bytes104857600 log.dirs/tmp/…...

【PyTorch】教程:torch.nn.Hardtanh

torch.nn.Hardtanh 原型 CLASS torch.nn.Hardtanh(min_val- 1.0, max_val1.0, inplaceFalse, min_valueNone, max_valueNone) 参数 min_val ([float]) – 线性区域的最小值,默认为 -1max_val ([float]) – 线性区域的最大值,默认为 1inplace ([bool]) …...

神垕古镇景区5A级十年都没有实现的三大主因

钧 瓷 内 参 第40期(总第371期) 2023年3月5日 神垕古镇景区5A级十年都没有实现的三大主因 这是2013年,禹州市市政府第一次提出创建5A级景区到今年三月份整整十年啊! 目前神垕古镇景区是4A级景区,5A级一直进行中&a…...

react函数组件常用的几个钩子函数useState、useEffect、useRef、useCallback

react框架react框架包括包括两大类:类组件函数组件。类组件构成:constructor自定义方法。调用方法通过this.方法名()。constructor(superstate)构造器里面必有super字段。render()方法里面写页面布局。函数组件构成:各种钩子函数return()方法…...

4N60-ASEMI高压MOS管4N60

编辑-Z 4N60在TO-220封装里的静态漏极源导通电阻(RDS(ON))为2.5Ω,是一款N沟道高压MOS管。4N60的最大脉冲正向电流ISM为16A,零栅极电压漏极电流(IDSS)为1uA,其工作时耐温度范围为-55~150摄氏度。4N60功耗(…...

现代神经网络(VGG),并用VGG16进行实战CIFAR10分类

专栏:神经网络复现目录 本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络…...

Java代码弱点与修复之——Dereference null return value(间接引用空返回值)

弱点描述 Dereference null return value,间接引用空返回值。是Coverity Scan静态代码分析工具中的一个警告,表示代码中有对可能为空(null)的方法或函数返回值进行间接引用(Dereference)操作。 该类型的漏洞可能会导致 NullPointerException 异常,并且会导致程序崩溃或…...

【冲刺蓝桥杯的最后30天】day3

大家好😃,我是想要慢慢变得优秀的向阳🌞同学👨‍💻,断更了整整一年,又开始恢复CSDN更新,从今天开始更新备战蓝桥30天系列,一共30天,如果对你有帮助或者正在备…...

光伏发电嵌入式ARM工控机

随着智慧电力技术的不断发展和普及,越来越多的电力设备和系统需要采用先进的控制和监测技术来实现自动化管理和优化运行。其中,嵌入式 ARM 控制器技术在智慧电力领域中得到了广泛应用。同时,导轨安装也是该技术的重要应用场景之一。 导轨安装…...

推荐 7 个 Vue.js 插件,也许你的项目用的上(五)

当我们可以通过使用库轻松实现相同的结果时,为什么还要编写自定义功能?开发人员最好的朋友和救星就是这些第三方库。我相信一个好的项目会利用一些可用的最佳库。Vue.js 是创建用户界面的最佳 JavaScript 框架之一。这篇文章是关于 Vue.js 的优秀库系列的…...

1.1基于知识图谱的项目实战:优酷搜索泛查询意图优化

NLU的技术实现主要分为在线识别和离线数据挖掘两块。 1.在线识别 NLU的在线识别技术栈如下图所示,共由下述2个部分组成: 第一个部分是Slot Filling(成分分析),负责对query进行实体识别和槽位抽取;第二部分Inention Detection(意图识别),根据提取的槽位进行意图的判定(目…...

[java Spring JdbcTemplate配合mysql实现数据批量删除

之前的文章 java Spring JdbcTemplate配合mysql实现数据批量添加和文章java Spring JdbcTemplate配合mysql实现数据批量修改 先后讲解了 mysql数据库的批量添加和批量删除操作 会了这两个操作之后 批量删除就不要太简单 我们看到数据库 这里 我们用的是mysql工具 这里 我们有…...

uos 20 统信 fprintd 记录

uos 20 统信 fprintd 记录 sudo busctl deepin-authenticate.service /usr/lib/systemd/system/deepin-authenticate.service [Unit] DescriptionDeepin Authentication[Service] Typedbus BusNamecom.deepin.daemon.Authenticate ExecStart/usr/lib/deepin-authenticate/d…...

vue移动端h5,文本溢出显示省略号,且展示‘更多’按钮

问题: 元素宽度100%,宽度会随着浏览器缩放而变化。元素内文本超过4行时显示省略号,同时展示‘更多’按钮,点击更多按钮展示全部文本。如下图所示 超出四行显示省略号(…)的代码 .content{overflow:hidden;text-overflow: elli…...

php宝塔搭建部署实战兰空图床程序网站PHP源码

大家好啊,我是测评君,欢迎来到web测评。 本期给大家带来一套Lsky Pro兰空图床程序网站PHP的源码。感兴趣的朋友可以自行下载学习。 技术架构 PHP8.0 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码,宝塔添加…...

软件测试面试:拿到一个产品(版本)如何开展测试?

产品提测后,如何开展测试? 我们都了解软件测试的执行流程,......提测-冒烟测试-详细测试-提交缺陷报告-回归测试,但软件测试并不总是线性过程,它甚至可能是螺旋结构,不断地试错,不断地迭代&…...