【青训营】golang工程实践 | 青训营笔记

150 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

1. 依赖管理

1.1 依赖管理方式

1. GOPATH

$GOPATH用来放置项目依赖包的源代码,不区分项目,其中有以下内容:

  • bin,项目编译的二进制文件。
  • pkg,项目编译的中间产物,加速编译。
  • src,项目源码,go get下载最新版本的包到src目录下。

由于不区分项目,无法实现package的多版本控制。

  1. Go Vendor

项目目录下增加 vendor 文件夹,所有依赖包副本形式放在$ProjectRoot/vendor

依赖寻址方式:先从vendor找,再从GOPATH找

通过每个项目引入一份依赖的副本,解决了多个项目需要同一个package依赖的冲突问题。

问题:不能清晰标识依赖的版本。

3. Go Module

通过go.mod文件管理依赖包版本。

通过go get/go mod指令工具管理依赖包。

可以定义版本规则和管理项目依赖关系。

1.2 依赖管理三要素

  1. 配置文件,描述依赖 go.mod
  2. 中心仓库管理依赖库 Proxy
  3. 本地工具 go get/mod

1.3 依赖配置

1. go.mod配置

module example/project/app //依赖管理单元
go 1.16 // 原生库
require{ // path+version
    example/lib1 v1.0.2
    example/lib2 v1.0.0 // indirect
}

2. version

// 语义化版本// 基于 commit 的伪版本

3. indirect

关键字indirect

直接依赖、间接依赖

4. incompatible

+incompatible

5. 依赖分发

回源、Proxy

可以通过使用版本标签来发布v1.0.0版本。

git tag v1.0.0
git push --tags

6. GOPROXY

GOPROXY="https://proxy1.cn, https://proxy2.cn, direct"

7. go get

go get example.org/pkg

选项 @...

8. go mod

  • go mod init 初始化,创建go.mod文件
  • go mod download 下载模块到本地缓存
  • `go mod tidy 增加需要的依赖,删除不需要的依赖

2. 测试

回归测试、集成测试、单元测试

2.1 单元测试

1. 规则

  • 测试文件xxx_test.go
  • 测试函数func TestXxx(*testing.T)
  • 初始化逻辑 TestMain(m *testing.M)

2. 例子

func TestHelloTom(t *testing.T) {
    output := HelloTom()
    expectOutput := "Tom"
    assert.Equal(t, expectOutput, output)
}

go test

3. 覆盖率

go test judgement_test.go judgement.go --cover 最后会给出覆盖率的结果

4. Tips

一般覆盖率 50%~60%,较高覆盖率 80%。

测试分支相互独立、全面覆盖。

测试单元粒度足够小,函数单一职责。

2.2 单元测试-Mock

单元测试,要求 幂等+稳定。但是如果单元测试依赖 File/DB/Cache,结果是不稳定的。

可以通过monkey包对函数进行Mock,

Patch()Unpatch

func TestProcessFirstLineWithMock(t *testing.T) {
    monkey.Patch(ReadFirstLine, func() string {
        return "line110"
    }) // 将一个函数替换为另一个函数
    defer monkey.Unpatch(ReadFirstLine)
    line := ProcessFirstLine()
    assert.Equal(t, "line000", line)
}

2.3 基准测试

BenchmarkXxx(*testing.B)

func BenchmarkSelect(b *testing.B) {
    InitServerIndex()
    b.ResetTimer()
    for i := 0; i < b.N; i++ { // 
        Select()
    }
}
func BenchmarkSelectParallel(b *testing.B) {
    InitServerIndex()
    b.ResetTimer()
    b.RunParallel(func(pb *testing.PB) { // 并行测试
        for pb.Next() {
            Select()
        }
    })
}
func BenchmarkFastSelectParallel(b *testing.B) {
    InitServerIndex()
    b.ResetTimer()
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            FastSelect()
        }
    })
}

3. 项目实战

3.1 需求设计

1. 需求描述

展示话题(标题、文字描述)和回帖列表。

暂不考虑前端页面实现,仅仅实现一个本地Web服务。

话题和回帖数据用文件存储。

2. 用例分析

浏览消费用户,浏览话题页面:1、标题;2、回帖列表

3. E-R图

实体-关系图,Topic、Post,一对多

4. 分层结构

  • 数据层:Repository 数据 Model,外部数据的增删改查,File
  • 逻辑层:Service 业务 Entity,处理核心业务的逻辑输出
  • 视图层:Controller 视图view,处理和外部的交互逻辑,Client

5. 组件工具

Gin 高性能 go web 框架

https://github.com/gin-gonic/gin#installation

Go Mod

go mod init

go get gopkg.in/gin-gonic/gin.v1@v1.3.0