扫码订阅《 》或入驻星球,即可阅读文章!

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
  • Go工程化规范设计

    • 前言
    • 开源规范
    • 文档规范
    • 版本规范
    • Git规范
    • 目录结构
    • 编码规范
    • 代码测试
    • 性能分析
    • API 设计
    • 项目管理
    • 研发流程
    • 参考资料
  • Go工程化标准实践

    • 前言
    • 项目结构
    • API 设计
    • 配置管理
    • 模块管理
    • 测试
    • 参考资料

扫码订阅《 》或入驻星球,即可阅读文章!

项目管理


Kyle

# Go 项目

# GOPATH

Go 1.11 之后,弱化了 GOPATH 规则,已有代码(很多库肯定是在 1.11 之前建立的)肯定符合这个规则,建议保留 GOPATH 规则,便于维护代码。

建议只使用一个 GOPATH。如果使用多个 GOPATH,编译生效的 bin 目录是在第一个 GOPATH 下。

# 依赖管理

Go 1.11 以上必须使用 Go Modules。

在提交代码时必须提交 go.sum 文件,不建议提交 vendor 目录。

# Makefile 设计

指代码工程项目的管理,一般使用 Makefile 管理 Go 项目。

# 规划实现功能

Go 项目的 Makefile 应实现:格式化代码、静态代码检查、单元测试、代码构建、文件清理、帮助等。如通过 docker 部署,还需要有 docker 镜像打包功能(注意支持不同的 CPU 架构和平台)。

为了能够更好地控制 Makefile 命令的行为,还需要支持 Options。可参考 IAM Makefile:iam/Makefile (opens new window),执行 make help 了解详情。

# 设计结构

建议分层设计,根目录下的 Makefile 聚合所有 Makefile 命令,具体实现则按功能分类放在另外的 Makefile 中。

复杂的 Shell 脚本可供 Makefile 调用,简单的命令可以直接集成在 Makefile 中。

├── Makefile
├── scripts
│   ├── gendoc.sh
│   ├── make-rules
│   │   ├── gen.mk
│   │   ├── golang.mk
│   │   ├── image.mk
│   │   └── ...
    └── ...

          include                 call   
/Makefile ------> makefile/xxx.mk ---> shell/xxx.sh
    |                                      ↑ 
    +--------------------------------------+ call
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 编写技巧

善用通配符和自动变量:便于修改、定位具体的 Makefile 文件。

tools.verify.%:
  @if ! which $* &>/dev/null; then $(MAKE) tools.install.$*; fi
1
2

善用函数:参考 iam/scripts/make-rules (opens new window)。

依赖工具:某个目标命令中用到某个工具,可将该工具放在目标的依赖中。当执行该目标时可以指定检查系统是否安装该工具,没有安装则自动安装。

.PHONY: format
format: tools.verify.golines tools.verify.goimports
  @echo "===========> Formating codes"
  @$(FIND) -type f -name '*.go' | $(XARGS) gofmt -s -w
  @$(FIND) -type f -name '*.go' | $(XARGS) goimports -w -local $(ROOT_PACKAGE)
  @$(FIND) -type f -name '*.go' | $(XARGS) golines -w --max-len=120 --reformat-tags --shorten-comments --ignore-generated .

# ...

tools.verify.%:
  @if ! which $* &>/dev/null; then $(MAKE) tools.install.$*; fi
  
# ...

.PHONY: install.golines
install.golines:
  @$(GO) get -u github.com/segmentio/golines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

常用功能放在 /Makefile 中,不常用的放在分类 Makefile 中。

编写可扩展的 Makefile:

  • 在不改变 Makefile 结构的情况下添加新功能。
  • 扩展项目时新功能可自动纳入到 Makefile 现有逻辑中。
# 执行 make go.build 时可构建 cmd/ 目录下的所有组件,当有新组件添加时,make go.build 仍然能够构建新增的组件。

COMMANDS ?= $(filter-out %.md, $(wildcard ${ROOT_DIR}/cmd/*))
BINS ?= $(foreach cmd,${COMMANDS},$(notdir ${cmd}))

.PHONY: go.build
go.build: go.build.verify $(addprefix go.build., $(addprefix $(PLATFORM)., $(BINS)))
.PHONY: go.build.%               

go.build.%:             
  $(eval COMMAND := $(word 2,$(subst ., ,$*)))
  $(eval PLATFORM := $(word 1,$(subst ., ,$*)))
  $(eval OS := $(word 1,$(subst _, ,$(PLATFORM))))           
  $(eval ARCH := $(word 2,$(subst _, ,$(PLATFORM))))                         
  @echo "===========> Building binary $(COMMAND) $(VERSION) for $(OS) $(ARCH)"
  @mkdir -p $(OUTPUT_DIR)/platforms/$(OS)/$(ARCH)
  @CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) $(GO) build $(GO_BUILD_FLAGS) -o $(OUTPUT_DIR)/platforms/$(OS)/$(ARCH)/$(COMMAND)$(GO_OUT_EXT) $(ROOT_PACKAGE)/cmd/$(COMMAND)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

将所有输出存放在一个目录下,方便清理和查找:例如 Go 编译后的二进制文件、测试覆盖率数据等。清理只需:

.PHONY: go.clean
go.clean:
  @echo "===========> Cleaning all build output"
  @-rm -vrf $(OUTPUT_DIR)
1
2
3
4

使用带层级的命名方式:可以实现目标分组管理。当 Makefile 有大量目标时,通过分组可以更好地管理;分组方便理解,通过组名一眼识别出该目标的功能类别;而且大大减小目标重名的概率。

.PHONY: gen.run
gen.run: gen.clean gen.errcode gen.docgo

.PHONY: gen.errcode
gen.errcode: gen.errcode.code gen.errcode.doc

.PHONY: gen.errcode.code
gen.errcode.code: tools.verify.codegen
    ...
.PHONY: gen.errcode.doc
gen.errcode.doc: tools.verify.codegen
    ...
1
2
3
4
5
6
7
8
9
10
11
12

做好目标拆分:将安装工具拆分成两个,即验证工具是否已安装和安装工具,可提高灵活性。

gen.errcode.code: tools.verify.codegen

tools.verify.%:    
  @if ! which $* &>/dev/null; then $(MAKE) tools.install.$*; fi  

.PHONY: install.codegen
install.codegen:              
  @$(GO) install ${ROOT_DIR}/tools/codegen/codegen.go
1
2
3
4
5
6
7
8

设置 OPTIONS:把一些可变的功能通过 OPTIONS 来控制。

# /Makefile 中定义 USAGE_OPTIONS 。定义 USAGE_OPTIONS 可以使开发者在执行 make help 后感知到此 OPTION,并根据需要进行设置。
define USAGE_OPTIONS    
                         
Options:
  ...
  BINS         The binaries to build. Default is all of cmd.
               ...
  ...
  V            Set to 1 enable verbose build. Default is 0.    
endef    
export USAGE_OPTIONS    

# scripts/make-rules/common.mk 通过判断有没有设置 V 选项,来选择不同的行为
ifndef V    
MAKEFLAGS += --no-print-directory    
endif

# 还可以通过下面的方法来使用 V 
ifeq ($(origin V), undefined)                                
MAKEFLAGS += --no-print-directory              
endif

# 或在 Makefile 中是直接使用的 Option
BINS ?= $(foreach cmd,${COMMANDS},$(notdir ${cmd}))
# ...
go.build: go.build.verify $(addprefix go.build., $(addprefix $(PLATFORM)., $(BINS)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

定义环境变量:多处同时生效,避免重复工作。

GO := go                                          
GO_SUPPORTED_VERSIONS ?= 1.13|1.14|1.15|1.16|1.17    
GO_LDFLAGS += -X $(VERSION_PACKAGE).GitVersion=$(VERSION) \    
  -X $(VERSION_PACKAGE).GitCommit=$(GIT_COMMIT) \       
  -X $(VERSION_PACKAGE).GitTreeState=$(GIT_TREE_STATE) \                          
  -X $(VERSION_PACKAGE).BuildDate=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')    
ifneq ($(DLV),)                                                                                                                              
  GO_BUILD_FLAGS += -gcflags "all=-N -l"    
  LDFLAGS = ""      
endif                                                                                   
GO_BUILD_FLAGS += -tags=jsoniter -ldflags "$(GO_LDFLAGS)" 
...
FIND := find . ! -path './third_party/*' ! -path './vendor/*'    
XARGS := xargs --no-run-if-empty 
1
2
3
4
5
6
7
8
9
10
11
12
13
14

调用自身:比如 A-Target 目标命令中需要完成操作 B-Action,而操作 B-Action 已经通过伪目标 B-Target 实现过。为了达到最大的代码复用度,最好的方式是在 A-Target 的命令中执行 B-Target。

tools.verify.%:
  @if ! which $* &>/dev/null; then $(MAKE) tools.install.$*; fi
  
# 默认情况下,Makefile 在切换目录时会输出:
# make tools.install.codegen
# ===========> Installing codegen
# make[1]: Entering directory `/home/colin/workspace/golang/src/github.com/marmotedu/iam'
# make[1]: Leaving directory `/home/colin/workspace/golang/src/github.com/marmotedu/iam'

# 可以设置 MAKEFLAGS += --no-print-directory 来禁止 Makefile 打印 Entering directory 等信息。
1
2
3
4
5
6
7
8
9
10
  • Go 项目
  • GOPATH
  • 依赖管理
  • Makefile 设计
  • 规划实现功能
  • 设计结构
  • 编写技巧