1.代码结构

代码分层结构是一个老生常谈的话题,好的代码结构能够使得系统易于理解、开发及维护,如果代码结构很混乱就会使得不同层级的代码块耦合,导致难以维护和拓展。

比较经典的代码结构(宏观)有Web的MVC模式分层结构,将代码分为Controller路由层、Model模型层、View视图层。

go fyne 所以组建代码demo_开发语言

更加具体地来看,对于微服务来说(不考虑前后端一体化情况),后端只有Controller及Model层, 可以细化为:

  • controller层:路由层,定义接口的路由
  • service层:逻辑层,定义服务的逻辑
  • dao层:数据层,定义数据库间的交互
  • entity层:实体层,定义数据PO、DTO、VO等结构
  • utils层:工具层,定义各类工具

2.Golang:微服务代码分层结构

这里分享一下工作中常用到的Golang微服务代码分层结构,以及每一层结构的定义及能做的事情、不能做的事情。

go fyne 所以组建代码demo_go项目分层_02

由于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等