关于 Go Web 项目的项目结构

2023-07-25 10:00:15 +08:00
 gitrebase

想搞 DDD ,但自觉无能,就借鉴了一下 DDD 的分层思想,搞出了如下的结构

├── adaptor
│   ├── mq
│   ├── rpc
│   ├── task // 定时任务
│   └── web
├── config
├── handler
│   └── user.go
├── infrastructure
│   ├── cache
│   │   └── user.go
│   ├── message
│   ├── mp
│   ├── remote
│   └── repository
│       └── user.go
├── main.go
├── manager
│   └── user.go
├── model
│   ├── bo
│   ├── dto
│   ├── po
│   └── vo
└── service
    ├── event // 事件总线(事件模型)
    └── user.go

但还是感觉不是很对?

比如 service 下,如果 user.go 、post.go 等不同模块的都放在一个 service 包下,那这个 service 包的内聚性堪忧;如果 service 下各建子包,那命名上感觉又有点奇怪(比如路径是 service/user ,但是 package 如果是 user 就可能和 handler 、repository 等包下面的 user 重复了,如果是 userservice 又感觉看着好怪?)

想问问万能的 V 友们有什么指点或建议吗

6012 次点击
所在节点    Go 编程语言
52 条回复
motecshine
2023-07-25 10:05:23 +08:00
简单易用的语言被搞出 花来了,这么多文件夹,还有什么 dto bo ,根本不知道在干啥,复杂的事情做简单是件很难得事情
gitrebase
2023-07-25 10:07:17 +08:00
@motecshine 感谢您的回复!我个人对 dto bo 那些也不是很了解,请问如果不设置这些的话应该怎么搞呀
lasuar
2023-07-25 10:09:43 +08:00
楼上+1 ,成熟的 gopher 有合理并简洁的项目目录结构规划,而不是照搬 java 那套。对于 ddd ,楼主也是了解个半桶水,ddd 压根没有所谓明确的分层结构,各种网文 ddd 架构都是玩家 yy 的,ddd 如同太极一样,只重其意不重其招,建议专门找两本 ddd 书看看,拒绝网文,从你我做起。
gitrebase
2023-07-25 10:13:02 +08:00
@lasuar 唔,可能我描述的不是很清,我不是想搞 DDD ,就是想设计一下一个 Go Web 项目的目录结构,不过感谢您的建议,今年就找两本专业的书看看
swulling
2023-07-25 10:15:12 +08:00
contradictspiral
2023-07-25 10:18:33 +08:00
可以参考下 GoFrame 的,感觉对单体 go web 应用来说设计的挺好,文档中也有很多作者的思考
lasuar
2023-07-25 10:19:15 +08:00
https://github.com/golang-standards/project-layout

如果一定要找个标准模仿,可以看看找个 4w 星的 repo 。

>多说几句,在任何时候都照搬某个标准也是没啥意义的。要掌握每个目录的意义, 并在确实需要的时候才规划,并且根据各种因素进行迭代变更;根据项目进展而演进项目架构,从无到有,从有到无,从单一到多个,从多个到合并为一个,从分散到聚合,从高度聚合到再度分离。。。这样才能在项目开发的各个阶段最大化开发效率,并且不会影响开发人员对项目布局的架构认知(考验项目主程的水平)。
weiwenhao
2023-07-25 10:19:22 +08:00
❯ tree .
.
├── cmd
│   └── root.go
├── controller
│   └── user
│   └── user.go
├── go.mod
├── go.sum
├── main.go
├── middleware
├── model
│   ├── model.go
│   └── user.go
├── router
│   └── v1.go
├── service
└── util
└── helper.go

平面架构了解一下, 总之就是在项目根目录下加主要模块, 比如定时任务,就加 jobs. 需要什么就加什么模块. 另外 model 的核心库是 gorm, router 的核心库是 gin, cmd 目录的核心库是 spf13/cobra
NX2023
2023-07-25 10:22:59 +08:00
@weiwenhao 和佬的想法一致😀
gitrebase
2023-07-25 10:24:48 +08:00
@lasuar 感谢佬的回复,受益匪浅
gitrebase
2023-07-25 10:26:10 +08:00
@weiwenhao 佬,扁平化的话,每个包的内聚性是不是不太好呀,比如 user.go 里的私有内容就能被 post.go 访问到了
6IbA2bj5ip3tK49j
2023-07-25 10:28:57 +08:00
去写 java 吧,求求你了。
wkong
2023-07-25 10:29:20 +08:00
开源项目
https://github.com/TangSengDaoDao/TangSengDaoDaoServer

项目结构:

├── assets
| ├── assets // 项目里用到的一些资源文件,比如系统账号头像,文件助手头像,系统群头像等等
| ├── resources // 文件服务需要初始化的一些资源文件 比如用户默认头像。
| ├── sql // 项目里的所有 sql 脚本
| └── web // 系统用到的 web 的一些 html 文件
├── configs // 项目里的所有配置
| ├── push // 苹果推送的证书放置目录
| └── tsdd.yaml // 项目的配置文件
├── docker // docker 相关的脚本
├── docs // 项目文档/截图
├── internal
| ├── api ==================== 项目所有对外的 API(业务代码基本都在这个目录下) ====================
| | ├── api.go // api 的所有模块的入口文件
| | ├── base // 基础模块
| | ├── channel // 频道模块
| | ├── common // 常用模块
| | ├── file // 文件服务模块
| | ├── group // 群组模块
| | ├── message // 消息模块
| | ├── qrcode // 二维码模块
| | ├── report // 举报模块
| | ├── robot // 机器人模块
| | ├── source // 来源模块
| | ├── statistics // 统计模块
| | ├── user // 用户模块
| | └── webhook // webhook 模块
| ================================================================================
| ├── config // 贯穿项目全局的上下文对象和配置对象
| ├── server // 服务启动
| | └── server.go
| └── testutil // 单元测试工具类
| └── test.go
├── pkg // 项目里的一些公共的包
├── testenv // 项目基础设施环境
| └── docker-compose.yaml
└── main.go // 项目入库 main.go 文件
NX2023
2023-07-25 10:30:55 +08:00
@gitrebase #11 这可以分模块化,大平层是简单项目最好,要分模块的话可以每个 module 有自己的 router model controller
me1onsoda
2023-07-25 10:33:18 +08:00
一眼 Javaer
gitrebase
2023-07-25 10:35:19 +08:00
@xgfan 佬,如果在 Go 里,有什么项目结构上的建议吗
weiwenhao
2023-07-25 10:36:35 +08:00
@gitrebase

1. controller 排版有问题, 应该是 controller/user/user.go . 也就是一个模块一个 package

2. model 下面全部都放在 package model 下面. 是为了方便处理模型之间的关联关系, 比如 user 的多个 posts . 相反的 post 属于 user 也可以在 post 模型定义, 不会出现引用循环. 我自己是这么用的,写起来比较简单快捷.

```go
type struct User {
Posts []*Post `gorm:"-:migration" json:"posts,omitempty"`

}

// user 相关的方法就用接收器来写, 需要对外访问的就大写, 不需要对外访问的就小写.

func (u *User) xxx() {
}

```

3. 另外访问的层级关系需要严格限定,避免造成引用的循环. router -> controller -> service -> model 或者 router ->controller -> model

util 模块则可以在任意模块被访问的,和业务无关的通用模块

4. 不是很熟悉面向对象的内聚之类的, 我的原则是写起来和看起来简单一点就行.
1055619878
2023-07-25 10:37:24 +08:00
可以参考下 go-zero
gitrebase
2023-07-25 10:37:39 +08:00
@me1onsoda 不否认写过 Java ,但是现在要写 Go 了,想主动寻求改变,但对 Go 的风格不是很了解,请问佬有什么项目结构上的建议与指点吗
crysislinux
2023-07-25 10:37:49 +08:00
别的不说,你这个 infra 底下 repository 不是很合理呀,按我的理解 infra 底下都是放一些类似 driver 的东西,比如数据库的 client ,Redis 的 client ,rpc 库。repository interface 属于 domain 里的,然后在 service 里实现。
简单项目大可不必搞这么复杂。不过直接平铺老实说心里确实也没啥底。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/959430

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX