The Go Programming Language
› http://golang.org/
› Go Playground
Go Projects
› Revel Web Framework
dzdh

新手项目组织的疑惑

  •  
  •   dzdh · May 30, 2022 · 4907 views
    This topic created in 1621 days ago, the information mentioned may be changed or developed.

    新手,用一个月左右看了看语法 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 replies  •  2022-05-31 13:19:15 +08:00
    iseki
    iseki
    May 30, 2022
    2
    我喜欢在外卖把数据库连接初始化好,然后丢进 model 包里。这样将来如果测试时需要对数据库对象 mock ,可以很容易做到
    wheeler
    wheeler
    May 30, 2022 via iPhone
    3
    数据库初始化放 main 不能吗? init 塞数据库初始化是坏实践。
    wheeler
    wheeler
    May 30, 2022 via iPhone
    4
    “怎么做能让 admin 和 sshserver 两个 net.Listen 任意一个有问题就整个退出呢”

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

    bootstrap.setupadmin(config, context, cacnel) 是

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

    这样总感觉有点问题,感觉不伦不类的
    dzdh
    dzdh
    OP
    May 30, 2022
    20
    @wheeler #3

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