Golang Go语言新手项目组织的疑惑

发布于 1周前 作者 yibo5220 来自 Go语言

新手,用一个月左右看了看语法 demo 啥的各种小 demo 看了看觉得自己行了。

然后想写个项目( ssh 跳板机)练练手,在项目组织上又迷糊了,现在这么组织的

├── go.mod
├── go.sum
├── internal
│   ├── admin
│   │   ├── resources
│   │   │   └── assets
│   │   │       └── FS.go  < FS=embed *.js *.css **/*.js **/*.css
│   │   └── server.go
│   ├── bootstrap.go
│   ├── config
│   │   └── config.go
│   ├── model
│   │   ├── init.go
│   │   └── models.go
│   └── ssh
│       ├── clients.go
│       ├── error.go
│       ├── forward.go
│       ├── handler.go
│       └── server.go
├── main.go

想实现 在 main.go里 调用 bootstrap.setupadmin() bootstrap.setupsshserver() 同时也是为了方便的以后能把 admin 和 sshserver 分离开。

那我在什么时候初始化数据库连接呢?放在 model.init 里? init 方法的话,我在哪传入配置信息呢?(数据库地址啊、密码啊啥的)。现在是 model.init.go 里是 Initialize(cfg *internal.Config.Global)

所以完整的 main.go 是这样的

func main() {
    cfgfilepath = // parseflag
if cfg, err = ioutil.ReadAll(cfgfilepath) err!=nil {panic
config.Global.LoadConfig(cfg)

model.Initialize(config.Global)

// 支持信号退出用
context = context.withcancel(...

// 这两个里是 go func..
model.SetupAdmin(config.Global, context)
model.SetupSSHServer(config.Global, context)

&lt;- 等待信号

}

这样组织代码有问题吗?怎么做能让 admin 和 sshserver 两个 net.Listen 任意一个有问题就整个退出呢


Golang Go语言新手项目组织的疑惑

更多关于Golang Go语言新手项目组织的疑惑的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

26 回复

更多关于Golang Go语言新手项目组织的疑惑的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我喜欢在外卖把数据库连接初始化好,然后丢进 model 包里。这样将来如果测试时需要对数据库对象 mock ,可以很容易做到

数据库初始化放 main 不能吗? init 塞数据库初始化是坏实践。

“怎么做能让 admin 和 sshserver 两个 net.Listen 任意一个有问题就整个退出呢”

用 channel 不能吗?

#4
所以我弄了个共用的 context, cancel 但是总觉得有啥问题

有啥小 demo 可以瞻仰一下的嘛

/internal/app/ssh
/internal/app/admin
/internal/pkg/config
/internal/pkg/model
/internal/pkg/dao

1. 不要在 model 里做数据库操作,数据库操作应该放到 dao 里。model 里只做赋值及数据结构转换之类的操作。在 model 里做数据库操作,盲猜 php 的习惯。

2. config 你都 Global 了,还传啥传,直接在对应的包里使用就好了

3. dao.init 放到 main 里也行。还有人喜欢放 init 里,但我个人比较反感这种,因为不是显式调用,很容易忽略。更好的方式是封装个 Engine 或者 App 之类的 struct ,然后再 main 里调用它,这样 main 里就比较干净

init 做外部资源类初始化就是埋雷,哪天下游炸了就有意思了。

不好意思,没明白。能贴完整代码吗?

github.com/spf13/cobra // 做启动入口
github.com/spf13/viper // 做配置
github.com/robfig/cron // 做定时任务
github.com/gin-gonic/gin // 做 http 服务的

mysql/redis/es 等等数据库都是用连接池的方式初始化,也就是入口处初始化一次就好啦。确实不推荐用原生的 init, 自己再创建 Init ,需要的时候手动调用就好了。不然你 ./test version 就调用了一堆 init 方法。

相关结构推荐扁平化,比如你这个 internal 感觉没啥必要呀,你这就一个编译入口 main 直接把 admin,config,model,ssh 摆出来不就好了。

任意一个有问题就整个退出 golang.org/x/sync/errgroup

我之前写过一篇和微服务组织相关的博客,也有配套的 DEMO 代码,可以参考看看: https://blog.igota.net/posts/20220422/

#12 支持主动退出吗?比如 ctrl-c

搞来搞去,又变成了 Java 那样的工程化分层。
这种帖子下,又没人吐槽这种分层了。

我实践告诉我, "Java 那套"DAO ,Service ,Controller 的分层还是很清晰的,而且拓展性还是很不错的。虽然我的项目不大。我觉得很多人说这是属于“Java 那套分层”。但是我认为不是输入 java 的, 而是属于大多数软件的工程项目的。
然后, 我想不到有比这个更好的文件结构了。

我是根据模块功能划分目录,然后在 main 方法里依次调用模块相关的初始化方法,全局的 config ,logger 之类的都是直接使用的

#9

bootstrap.setupadmin(config, context, cacnel) 是

func setup…
srv := ssh.NewServer()
go func { select { <-context.Done: srv.shutdown
srv.ListenAndServe()

这样总感觉有点问题,感觉不伦不类的

#3

放到 main? 现在就是
在 main 里
model.Initialize(…) { gorm.Open…

个人非常讨厌过多的文件夹嵌套,超过三层的文件夹我基本就要疯了,最好是文件夹都在顶层,实在不得已再开第二层,Go 语言的哲学就是简单直接、灵活、可扩展,千万别过度设计

对于应用服务,internal 可能不是好点子,一旦多个仓库想共用,没法 import 它

工程化实践可以参考一下 bilibili 毛剑的课

go clean template GitHub 上面的了解一下

作为IT领域的GO语言专家,对于Golang新手在项目组织上的疑惑,我有以下建议:

  1. 项目结构:建议按照Go语言的模块化特性来组织项目。可以创建一个主目录,下面包含src(源代码)、pkg(包)、bin(可执行文件)等子目录。src目录中再按照功能模块或包来划分不同的子目录。
  2. 依赖管理:使用Go Modules来管理项目的依赖关系。这有助于确保依赖的版本一致性,避免兼容性问题。通过go mod init初始化模块,go mod tidy整理依赖。
  3. 错误处理:Go语言中没有异常机制,因此错误处理需要手动进行。建议在代码中通过if语句检查错误,并及时处理。同时,利用错误传递机制,在函数间传递错误信息。
  4. 代码质量和测试:编写清晰易懂的代码,使用有意义的变量和函数名,遵循一致的代码风格和命名规范。此外,编写单元测试来验证代码的正确性,并在代码修改后及时进行测试。
  5. 文档和注释:为项目编写详细的文档和注释,解释代码的功能和使用方法。这有助于其他开发者理解和维护代码。

总之,作为Golang新手,在项目组织上应注重结构清晰、依赖管理、错误处理、代码质量和测试以及文档和注释等方面。希望这些建议能对你有所帮助。

回到顶部