1.代码结构
代码分层结构是一个老生常谈的话题,好的代码结构能够使得系统易于理解、开发及维护,如果代码结构很混乱就会使得不同层级的代码块耦合,导致难以维护和拓展。
比较经典的代码结构(宏观)有web的mvc模式分层结构,将代码分为controller路由层、model模型层、view视图层。
更加具体地来看,对于微服务来说(不考虑前后端一体化情况),后端只有controller及model层, 可以细化为:
- controller层:路由层,定义接口的路由
- service层:逻辑层,定义服务的逻辑
- dao层:数据层,定义数据库间的交互
- entity层:实体层,定义数据po、dto、vo等结构
- utils层:工具层,定义各类工具
2.golang:微服务代码分层结构
这里分享一下工作中常用到的golang微服务代码分层结构,以及每一层结构的定义及能做的事情、不能做的事情。
由于golang是不支持包之间循环依赖的,所以从hanlders到pkgs,均为单向依赖。下面介绍各个层级的含义,以及要做的事情。
2.1.pkg
pkg包存放与业务逻辑无关的工具包,如格式化工具、结构体转换工具等。
pkg/
|- formatter/
|- formatter.go
|- converter/
|- converter.go
- converter.go
func obj2string(obj interface{}) (string, error) {
bytes, err := json.marshal(&obj)
if err != nil {
return "", err
}
return string(bytes), nil
}
2.2.entity
entity包存放领域实体及其相关方法及枚举。
- entity包只能提供最基本的和实体相关的方法,如定义了user结构体,提供isvaliduser方法判断该user是否有效等。
- entity包不依赖于其他任何包(基础类库、pkgs包)除外,只提供最基础的领域模型定义。
entity/
|- user.go
|- item.go
- user.go
type usertype string
const (
usertypeadmin usertype = "admin"
usertypenormal usertype = "normal"
)
type user struct {
usertype usertype
userid int64
username string
}
func (u *user) isadmin() bool {
return u.usertype == usertypeadmin
}
2.3.dao
dao包存放于数据库交互的所有代码,即数据的增、删、改、查。
- dao包包含领域模型的所有数据crud操作
- dao包不包含业务逻辑相关的操作
dao/
|- dao.go
|- user_dao.go
- dao.go
var userdao userdaoif
func initdao() {
userdao = new(userdao)
}
- user_dao.go
type userdaoif interface {
getuser(userid int64) (*entity.user, error)
createuser(user *entity.user) error
}
type userdao struct{}
// createuser implements userdaoif
func (*userdao) createuser(user *entity.user) error {
panic("unimplemented")
}
// getuser implements userdaoif
func (*userdao) getuser(userid int64) (*entity.user, error) {
panic("unimplemented")
}
2.4.policies
policies包存放和业务逻辑校验、实体验证相关的代码。
policies/
|- policy.go
|- user_policy.go
- policy.go
var userpolicy userpolicyif
func init() {
userpolicy = new(userpolicy)
}
- user_policy.go
type userpolicyif interface {
canlogin(userid int64) bool
canregister(userid int64) bool
}
type userpolicy struct{}
// canlogin implements userpolicyif
func (*userpolicy) canlogin(userid int64) bool {
panic("unimplemented")
}
// canregister implements userpolicyif
func (*userpolicy) canregister(userid int64) bool {
panic("unimplemented")
}
2.5.services
services存放业务逻辑相关代码,是整个项目中逻辑最复杂的部分。
services/
|- service.go
|- user/
|- user_service.go
|- item/
|- item_service.go
- service.go
var userservice userserviceif
func init() {
userservice = new(userservice)
}
- user_service.go
type userserviceif interface {
userlogin(u *entity.user) error
}
type userservice struct{}
// userlogin implements userserviceif
func (*userservice) userlogin(u *entity.user) error {
panic("unimplemented")
}
2.6.handlers
handlers定义了各类对外处理器入口,如http、rpc、eventbus等处理器。
- handlers中的处理器只做三件事情:接受请求解析入参、调用services完成业务逻辑、构造响应参数
- handlers不包含业务代码逻辑,应该简单地作路由使用
handlers/
|- handler.go
|- rpc/
|- user_rpc.go
|- http/
|- item_http.go
2.7.其他包
- conf包:存放相关的配置文件,如config_prod.yaml等
- script包:存放系统相关的脚本,如编译脚本build.sh等
- cmd包:存放相关的可直接运行的go脚本,如刷数脚本reflush.go等
发表评论