V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
dzdh
V2EX  ›  Go 编程语言

新手项目组织的疑惑

  •  
  •   dzdh · 2022-05-30 09:54:26 +08:00 · 3690 次点击
    这是一个创建于 909 天前的主题,其中的信息可能已经有所发展或是发生改变。

    新手,用一个月左右看了看语法 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)
        
        <- 等待信号
    }
    

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

    25 条回复    2022-05-31 13:19:15 +08:00
    hteen
        1
    hteen  
       2022-05-30 10:00:02 +08:00   ❤️ 2
    iseki
        2
    iseki  
       2022-05-30 10:04:30 +08:00
    我喜欢在外卖把数据库连接初始化好,然后丢进 model 包里。这样将来如果测试时需要对数据库对象 mock ,可以很容易做到
    wheeler
        3
    wheeler  
       2022-05-30 10:05:50 +08:00 via iPhone
    数据库初始化放 main 不能吗? init 塞数据库初始化是坏实践。
    wheeler
        4
    wheeler  
       2022-05-30 10:08:13 +08:00 via iPhone
    “怎么做能让 admin 和 sshserver 两个 net.Listen 任意一个有问题就整个退出呢”

    用 channel 不能吗?
    dzdh
        5
    dzdh  
    OP
       2022-05-30 10:09:34 +08:00
    @wheeler #4
    所以我弄了个共用的 context, cancel 但是总觉得有啥问题
    dzdh
        6
    dzdh  
    OP
       2022-05-30 10:10:11 +08:00
    @iseki 有啥小 demo 可以瞻仰一下的嘛
    saltbo
        7
    saltbo  
       2022-05-30 10:12:58 +08:00
    /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 里就比较干净
    securityCoding
        8
    securityCoding  
       2022-05-30 10:24:09 +08:00
    @wheeler init 做外部资源类初始化就是埋雷,哪天下游炸了就有意思了。
    wheeler
        9
    wheeler  
       2022-05-30 10:29:19 +08:00 via iPhone
    @dzdh 不好意思,没明白。能贴完整代码吗?
    weiwenhao
        10
    weiwenhao  
       2022-05-30 10:43:59 +08:00
    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 摆出来不就好了。
    sophos
        11
    sophos  
       2022-05-30 10:53:26 +08:00
    这个可以参考一下: https://github.com/douyu/jupiter-layout
    lxz6597863
        12
    lxz6597863  
       2022-05-30 10:59:25 +08:00
    任意一个有问题就整个退出 golang.org/x/sync/errgroup
    sciel
        13
    sciel  
       2022-05-30 11:20:32 +08:00
    goframe 工程目录结构可以参考一下 https://goframe.org/pages/viewpage.action?pageId=30740166
    Gota
        14
    Gota  
       2022-05-30 12:00:24 +08:00
    我之前写过一篇和微服务组织相关的博客,也有配套的 DEMO 代码,可以参考看看: https://blog.igota.net/posts/20220422/
    dzdh
        15
    dzdh  
    OP
       2022-05-30 12:36:13 +08:00
    @lxz6597863 #12 支持主动退出吗?比如 ctrl-c
    Macolor21
        16
    Macolor21  
       2022-05-30 13:21:04 +08:00   ❤️ 3
    搞来搞去,又变成了 Java 那样的工程化分层。
    这种帖子下,又没人吐槽这种分层了。
    zackkson1991
        17
    zackkson1991  
       2022-05-30 13:38:59 +08:00   ❤️ 2
    我实践告诉我, "Java 那套"DAO ,Service ,Controller 的分层还是很清晰的,而且拓展性还是很不错的。虽然我的项目不大。我觉得很多人说这是属于“Java 那套分层”。但是我认为不是输入 java 的, 而是属于大多数软件的工程项目的。
    然后, 我想不到有比这个更好的文件结构了。
    yuancoder
        18
    yuancoder  
       2022-05-30 13:59:10 +08:00
    我是根据模块功能划分目录,然后在 main 方法里依次调用模块相关的初始化方法,全局的 config ,logger 之类的都是直接使用的
    dzdh
        19
    dzdh  
    OP
       2022-05-30 14:36:51 +08:00
    @wheeler #9

    bootstrap.setupadmin(config, context, cacnel) 是

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

    这样总感觉有点问题,感觉不伦不类的
    dzdh
        20
    dzdh  
    OP
       2022-05-30 14:38:02 +08:00
    @wheeler #3

    放到 main? 现在就是
    在 main 里
    model.Initialize(..) { gorm.Open..
    Biwood
        21
    Biwood  
       2022-05-30 19:30:19 +08:00
    个人非常讨厌过多的文件夹嵌套,超过三层的文件夹我基本就要疯了,最好是文件夹都在顶层,实在不得已再开第二层,Go 语言的哲学就是简单直接、灵活、可扩展,千万别过度设计
    Macolor21
        22
    Macolor21  
       2022-05-30 22:53:34 +08:00
    @zackkson1991 #17 https://www.v2ex.com/t/851925 这可不是我说的
    lesismal
        23
    lesismal  
       2022-05-31 09:51:40 +08:00
    对于应用服务,internal 可能不是好点子,一旦多个仓库想共用,没法 import 它
    LoNeFong
        24
    LoNeFong  
       2022-05-31 10:17:42 +08:00
    工程化实践可以参考一下 bilibili 毛剑的课
    ShiJh
        25
    ShiJh  
       2022-05-31 13:19:15 +08:00 via iPhone
    go clean template GitHub 上面的了解一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   923 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 21:10 · PVG 05:10 · LAX 13:10 · JFK 16:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.