golang best practice(最佳实践) 之 web服务整体框架及模块目录结构

基本框架最佳实践及脚手架

library选择(not why A not B problem, only just need one problem,familiar)

logger: zap
web framework: gin
orm: xorm
ioc framework: fx,支持开发模块化
ACL: casbin
kv: boltdb
process local cache with: go-cache

test library

https://github.com/smartystreets/goconvey
https://github.com/bouk/monkey

模块化

component:

  1. define by interface
  2. add real implement or mock
  3. inject interface by ioc framework (go.uber.org/fx)
use cache as and example

cache: define by interface

// Cache Cache
type Cache interface {
 Put(prefix, key string, value interface{})
 Get(prefix, key string) (interface{}, bool)
}
// Module Module
var Module = fx.Options(
    fx.Provide(NewCache))

then inject into container by

app := fx.New(logger.Module, database.Module, cache.Module, config.Module,
 dao.Module, handler.ModuleWithDep, router.Module, fx.Populate(&errC))

// test demo
app := fx.New(logger.Module, database.Module, config.Module, fx.Options(handler.ModuleWoDep, **user.TestModule**), router.Module, fx.Populate(&errC))

ioc to get it by constructor

// NewHandler NewHandler
func NewHandler(user user.Service, cache cache.Cache) *Handler {
 return &Handler{
  userSvc: user,
  cache:   cache,
 }
}

模块目录结构

├── project
│   ├── ReadMe.md
│   ├── cmd
│   │   ├── client
│   │   ├── cmd
│   │   └── main.go
│   ├── common // put cross-cutting edge module here
│   │   ├── cache
│   │   │   └── cache.go
│   │   ├── config
│   │   │   ├── cmd_flags.go
│   │   │   ├── config.go
│   │   │   ├── config_test.go
│   │   │   ├── define.go
│   │   │   └── test_data
│   │   │       ├── paas.yaml
│   │   │       └── paas_dev.yaml
│   │   ├── const.go
│   │   ├── database
│   │   │   └── db.go
│   │   ├── errors
│   │   │   └── error.go
│   │   └── logger
│   │       └── logger.go
│   ├── config
│   │   ├── ReadMe.md
│   │   ├── config.yaml
│   │   └── config_dev.yaml
│   ├── dao // all xorm db operation inside dao dir
│   │   ├── convert  // convert between struct
│   │   │   └── ReadMe.md
│   │   ├── export.go
│   │   ├── generate.sh
│   │   ├── internal
│   │   ├── models   // xorm reverse auto gen file and self added model
│   │   ├── templates // xorm reverse config inside 
│   │   │   └── goxorm
│   │   │       ├── config
│   │   │       └── struct.go.tpl
│   │   └── user   // example Dao
│   │       ├── dao.go  // define interface 
│   │       └── export.go
│   ├── doc  // put swagger definition inside
│   │   └── ReadMe.md 
│   ├── go.mod
│   ├── go.sum
│   ├── handler // web handler, mostly wrapper for module
│   │   ├── export.go
│   │   ├── helper
│   │   │   └── common.go
│   │   ├── test
│   │   │   └── test.go
│   │   └── user
│   ├── module // business logic module
│   │   ├── ReadMe.md
│   │   ├── base
│   │   │   ├── helper.go
│   │   │   └── service.go
│   │   ├── pam
│   │   └── user
│   │       ├── definition
│   │       │   └── service.go
│   │       ├── export.go
│   │       ├── impl
│   │       │   └── user_impl.go
│   │       └── mock
│   │           └── user_mock.go
│   └── router  // gin framework related
│       ├── middleware
│       │   ├── logger.go
│       │   └── request_id.go
│       └── router.go
├── test // integrate test inside
│   ├── ReadMe.md
│   ├── go.mod
│   └── simple_test.go
└── util
    ├── collection
    │   └── string.go
    └── go.mod

related library

require (
    github.com/gin-gonic/gin v1.3.0                  // web framework
    github.com/go-sql-driver/mysql v1.4.0
    github.com/go-xorm/xorm v0.7.1                // orm
    github.com/lib/pq v1.0.0
    github.com/mitchellh/mapstructure v1.1.2   // unmarshal
    github.com/spf13/pflag v1.0.3                     // cmd flag
    github.com/spf13/viper v1.3.1                     // configuration library satisfy 12app requirement
    go.uber.org/fx v1.8.0                                   // DI framework
    go.uber.org/zap v1.9.1                                // structured log library
    gopkg.in/yaml.v2 v2.2.2                              // config file format
)

reference

modern app基本要求 https://12factor.net/
模块化组织 https://zhuanlan.zhihu.com/p/39326315
日志 https://medium.com/@gosamv/using-gos-context-library-for-logging-4a8feea26690
https://medium.com/@iNatata/use-struct-as-enum-in-go-6a314ae78678

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268