聊聊Go 应用程序设计标准
1.介绍
众所周知 Go 语言官方成员 Russ Cox 曾向 Go 社区回应并没有 Go 应用程序设计标准。但是,为什么本文还要使用这个标题呢?
因为团队达成一个共识(标准),制定一些团队成员都要遵循的规则,可以使我们的应用程序更容易维护。本文介绍一下我们应该怎么组织我们的代码,制定团队的 Go 应用程序设计标准。
需要注意的是,它不是核心 Go 开发团队制定的官方标准。
2.定义 domain 包
为什么需要定义 domain 包?因为我们开发的 Go 应用程序,可能不只是包含一个功能模块,并且可能不同的功能模块之间还需要互相调用,所以,我们需要 domain(领域)包,例如我们开发一个博客应用程序,我们的 domain 包括用户、文章、评论等。这些不依赖我们使用的底层技术。
需要注意的是,domain 包不应该包含方法的实现细节,比如操作数据库或调用其他微服务,并且 domain 包不可以依赖应用程序中的其他包。
我们可以定义 domain 包,把结构体和接口放在 domain 包,例如:
package domain
import "context"
type User struct {
Id int64 `json:"id"`
UserName string `json:"user_name" xorm:"varchar(30) notnull default '' unique comment('用户名')"`
Email string `json:"email" xorm:"varchar(30) not null default '' index comment('邮箱')"`
Password string `json:"password" xorm:"varchar(60) not null default '' comment('密码')"`
Created int `json:"created" xorm:"index created"`
Updated int `json:"updated" xorm:"updated"`
Deleted int `json:"deleted" xorm:"deleted"`
}
type UserUsecase interface {
GetById(ctx context.Context, id int) (*User, error)
GetByPage(ctx context.Context, count, offset int) ([]*User, int, error)
Create(ctx context.Context, user *User) error
Delete(ctx context.Context, id int) error
Update(ctx context.Context, user *User) error
}
type UserRepository interface {
GetById(ctx context.Context, id int) (*User, error)
GetByPage(ctx context.Context, count, offset int) ([]*User, int, error)
Create(ctx context.Context, user *User) error
Delete(ctx context.Context, id int) error
Update(ctx context.Context, user *User) error
}
细心的读者朋友们可能已经发现,以上代码在「Go 语言整洁架构实践」一文中,它是被划分到 models 包。是的,因为当时我们的示例项目是 TodoList,它仅包含一个功能模块。
但是,当我们开发一个包含多个功能模块的应用程序时,为了方便功能模块之间相互调用,更建议将所有功能模块的结构体和接口存放到 domain 包。
3.按照依赖关系划分包
在「Go 语言整洁架构实践」一文中,提到在 Repository 层存放操作数据库和调用微服务的代码,我们可以在 Repository 层按照依赖关系划分包,比如我们的应用程序需要操作 MySQL 数据库,我们可以定义一个 mysql 包。
示例代码:
package mysql
import (
"context"
"go_standard/domain"
"xorm.io/xorm"
)
type mysqlUserRepository struct {
Conn *xorm.Engine
}
func NewMysqlUserRepository(Conn *xorm.Engine) domain.UserRepository {
_ = Conn.Sync2(new(domain.User))
return &mysqlUserRepository{Conn}
}
func (m *mysqlUserRepository) GetById(ctx context.Context, id int) (res *domain.User, err error) {
// TODO::implements it
return
}
func (m *mysqlUserRepository) GetByPage(ctx context.Context, count, offset int) (data []*domain.User, nextOffset int, err error) {
// TODO::implements it
return
}
func (m *mysqlUserRepository) Create(ctx context.Context, user *domain.User) (err error) {
// TODO::implements it
return
}
func (m *mysqlUserRepository) Delete(ctx context.Context, id int) (err error) {
// TODO::implements it
return
}
func (m *mysqlUserRepository) Update(ctx context.Context, user *domain.User) (err error) {
// TODO::implements it
return
}
阅读上面这段代码,我们可以发现 mysql 包主要作为 domain 包和操作数据库的方法实现之间的适配器,这种包布局方式,隔离了我们 MySQL 的依赖关系,从而方便了未来迁移到其他数据库的实现。比如,我们未来想把数据库切换为 PostgreSQL,我们可以再定义一个 postgresql 包,提供 PostgreSQL 的支持。
4.共享 mock 包
因为我们的依赖项通过我们的 domain 包定义的接口与其他依赖项隔离,所以我们可以使用这些连接点来注入 mock 实现。可以使用 mock 库生成 mock 代码,也可以自己编写 mock 代码。
5.使用 main 包将依赖关系连接起来
最后,我们使用 main 包将这些彼此孤立的包连接起来,将对象需要的依赖注入到对象中。
package main
import (
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
_userHttpDelivery "go_standard/user/delivery/http"
_userRepo "go_standard/user/repository/mysql"
_userUsecase "go_standard/user/usecase"
"xorm.io/xorm"
)
func main() {
db, err := xorm.NewEngine("mysql", "root:root@/go_standard?charset=utf8mb4")
if err != nil {
return
}
r := gin.Default()
userRepo := _userRepo.NewMysqlUserRepository(db)
userUsecase := _userUsecase.NewUserUsecase(userRepo)
_userHttpDelivery.NewUserHandler(r, userUsecase)
}
6.总结
我们遵循以上 4 个规则设计 Go 应用程序,不仅可以有效帮助我们在编写代码时避免循环依赖,还可以提升应用程序的可阅读性、可维护性和可扩展性。
值得一提的是,本文旨在建议团队制定成员都要遵循的规则,作为团队的 Go 应用程序设计标准,而不是建议大家必须遵循本文介绍的 4 个规则。
相关文章
- Jgit的使用笔记
- 利用Github Action实现Tornadofx/JavaFx打包
- 叹息!GitHub Trending 即将成为历史!
- 微软软了?开源社区讨论炸锅,GitHub CEO 亲自来答
- GitHub Trending 列表频现重复项,前后端都没去重?
- Photoshop Elements 2021版本软件安装教程(mac+windows全版本都有)
- (ps全版本)Photoshop 2020的安装与破解教程(mac+windows全版本都有)
- (ps全版本)Photoshop cc2018的安装与破解教程(mac+windows全版本,包括2023
- 环境搭建:Oracle GoldenGate 大数据迁移到 Redshift/Flat file/Flume/Kafka测试流程
- 每个开发人员都要掌握的:最小 Linux 基础课
- 来撸羊毛了!Windows 环境下 Hexo 博客搭建,并部署到 GitHub Pages
- 超实用!手把手入门 MongoDB:这些坑点请一定远离
- 【GitHub日报】22-10-09 zustand、neovim、webtorrent、express 等4款App今日上新
- 【GitHub日报】22-10-10 brew、minio、vite、seaweedfs、dbeaver 等8款App今日上新
- 【GitHub日报】22-10-11 cobra、grafana、vue、ToolJet、redwood 等13款App今日上新
- Photoshop 2018 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2017 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2020 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2023 资源免费下载(mac+windows全版本都有,包括最新的2023)
- 最新版本Photoshop CC2018软件安装教程(mac+windows全版本都有,包括2023