第三届字节青训营后端专场第二课笔记 | 青训营笔记

164 阅读3分钟

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

课程内容分为四部分,

  1. 并发编程
  2. 依赖管理
  3. 单元测试
  4. 项目实战

项目地址为(GitHub - Moonlight-Zhao/go-project-example at V0)

开发环境使用windows10/11 + WSL2, go编辑器为 VSCode + go 插件。vscode可以使用remote-wsl插件连接WSL。

并发编程

并发 vs 并行

两者是不是一回事,这个问题取决于讨论的领域。就操作系统这方面而言,

  • 并发指多线程程序在一个核的CPU上运行;
  • 并行指多线程程序在多个核的CPU上运行。

go通过GMP模型,有实现高并发的能力。

goroutine

go 实现的协程, 协程:用户态,轻量级。 协程切换比线程切换快主要有两点:

  1. 协程切换完全在用户空间进行,线程切换涉及特权模式切换,需要在内核空间完成;
  2. 协程切换相比线程切换需要切换的上下文较少。基本只涉及CPU上下文,少量的栈空间

协程间通信

go提倡使用通信来共享内存,而不是共享内存实现通信

go提供的方案有以下两种:

  1. channel
  2. Sync(lock)

其它,协程等待:WaitGroup。

依赖管理

背景

go的项目依赖管理主要经历了以下三个阶段:

  1. GOPATH
  2. GO Vendor
  3. GO MODULE
  • GOPATH方式的主要缺陷:当不同的项目依赖不同的包版本时,无法很好的处理。这是因为全局共用相同的包文件。
  • GO Vendor方式的主要缺陷:没有很好地考虑依赖链,例如A<-B_V1,A<-C, C<-B_V2,那么此时A的Vendor下应该放哪个版本的B呢?可能会有不兼容。

依赖管理三要素

  • 配置文件,描述依赖:go.mod
  • 中心仓库管理依赖库:proxy
  • 本地工具: go get/mod

go.mod

对于如何写go.mod,可自行查阅相关资料。 应当了解以下知识点:

  • 由哪几部分组成:依赖管理基本单元、原生库、单元依赖
  • 依赖配置项构成:包地址+version(语义化版本/基于commit的伪版本)
  • 依赖配置项的附加关键词:indirect、incompatible

依赖图

下面是个小例子

image.png

proxy

增加一个依赖包代理,主要原因和目的如下:

image.png

image.png

具体配置如下

image.png

工具

自行查阅 go get,go mod 两个命令的使用。

测试

分类

  1. 回归测试(回归到场景中使用测试)
  2. 集成测试(对服务暴露的接口进行自动化集成测试)
  3. 单元测试(对各个函数功能进行测试) 从上到下覆盖率上升

单元测试

流程:输入->测试单元->输出->校对 作用:保证质量,提升效率(更正定位问题)

对于测试中比较结果是否正确,推荐使用包 github.com/stretchr/testify/assert

来自一个go测试框架 stretchr/testify: A toolkit with common assertions and mocks that plays nicely with the standard library (github.com)

mock测试

对于单元测试的依赖,一般有下面两个要求,

幂等:重复运行一个测试,结果应该一样

稳定:单元测试能在任何时间稳定运行

因此需要使用mock,来模拟读写文件、缓存、数据库等。

推荐一个用于快速mock的包 bouk/monkey: Monkey patching in Go (github.com)

基准测试

项目实战

一个项目的开发流程是:需求设计->代码开发->测试

前置技能

项目背景和需求

  1. 实现一个展示话题(标题,文字描述)和回帖列表的后端 http 接口;
  2. 本地文件存储数据

项目地址为Moonlight-Zhao/go-project-example at V0 (github.com)

具体设计

本项目使用三层结构:数据层-逻辑层-视图层,即Repository-Service-Controller

  • 数据层:画出话题和帖子的ER关系图,设计Topic 和 Post 两个结构体和其方法。设计一个索引机制,相关函数有根据文件初始化索引、查询等。设计一个实体结构体(PageInfo),其包含一个Topic,和一个PostList。
  • 在逻辑层,考虑一个服务的流程是:参数校验、准备数据、组装实体,一一实现,其中可以使用go协程来提高并发。
  • 在视图层,主要就是构建View对象(PageData),判断是否填入业务错误码。
  • 路由,即开启网络服务,可以借助Gin配置。 整个Web服务的启动流程就是:初始化数据索引、初始化引擎配置、构建路由、启动服务。