Junedayday Blog

六月天天的个人博客

0%

【每周小结】2023-Week7

本周的总结发得比较晚,花在打磨编程思考部分的时间比较多。

虽然最终版本也不是很满意,不过也算达到了阶段性交付的水平。

Go技巧 - 并发代码的单元测试

Go语言开发的过程中,我们或多或少会引入并发模式,常见的如gochannelsync.WaitGroup等。这些并发原语使用起来很方便,但常常会阻碍相关代码的单元测试,如依赖的channel发生阻塞,mutex被锁等,导致想验证的重要代码根本跑不到。

这里,我介绍一下自己的三个心得,用一句话概括,合理利用分层进行拆分,屏蔽并发逻辑

没有分层的基础或工具库不在本次的讨论范围内,但也可以借鉴这里的思想。

多协程的逻辑交由上层控制

如下,原先的业务逻辑代码包括了两块处理逻辑:

1
2
3
4
5
6
7
func Foo(){
// 逻辑A

go func(){
// 逻辑B
}()
}

由于逻辑B相关的代码无法验证,所以这个单元测试能做的很有限。这时,通过分层,我们将代码拆分为两部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 上层代码 - 使用基础的并发特性,没有必要做单元测试
func Foo() {
FooA()

go FooB()
}

// 下层代码 - 做严格的单元测试
func FooA() {
}

func FooB() {
}

此时的单元测试就变得直观了。

锁类逻辑由下层对象封装

业务代码常常会包含锁,这就导致很多函数中有大量的LockUnLock操作,容易在单元测试里验证一些逻辑时发生死锁。

1
2
3
4
5
6
func Foo() {
// do a
m.Lock()
defer m.UnLock()
// do b
}

从抽象层面来说,业务逻辑的核心代码尽量减少锁这种 底层的并发原语,把它们放在业务逻辑里也很影响阅读体验。这时,将锁划分到下层会让代码逻辑更清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 下层对象
type FooA struct {
}

type FooB struct {
// 锁
sync.Mutex
}

// 业务代码
func Foo() {
// 这里不包含锁逻辑
fooA.Do()
// 这里包含锁逻辑
fooB.DO()
}

从使用锁的角度来说,LockUnLock之间的逻辑应尽量短,所以很适合放在底层对象、交由它自行控制,也能缩短锁的影响范围。

同层抽离出核心控制函数

Go语言中,有一些并发特性、尤其以channel为代表,很难通过分层解决。例如

1
2
3
4
5
6
7
8
9
10
11
12
func Foo() {
var c chan int
// 发送消息
go func(){
// send to c
}()

// 接收消息
go func(){
// receive from c
}()
}

这里的channel更多的是一种具有业务特性的并发控制,单独抽出一个 核心控制函数 就能提升整体的可读性与可测试性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 核心控制函数
func Foo() {
var c chan int

// 发送逻辑
go func() {
a := logicA()
c <- a
}

// 接收逻辑
go func() {
a := <- c
logicB(a)
}
}

// 以下逻辑均不包含channel,方便单元测试
func logicA() int {
}

func logicB(a int) {
}

核心控制函数很难通过单元测试完整验证,更考验的是开发人员对Go并发编程的基本功。

小结

以上三点是我在工作过程中的经验心得,帮助我解决了很多并发代码中的单元测试问题。它们不一定是最佳实践,但希望能对各位遇到相关问题时有一些启发。

编程思考 - 平台开发的三个阶段

如今, 平台开发 这个词已经广泛应用在程序员圈子内。在我看来,相关的开发者可以分为三个阶段:

  1. 初级阶段:根据用户的需求明细写过程性的CRUD,实现功能
  2. 中级阶段:以OpenAPI的方式向多业务、多用户提供能力
  3. 高级阶段:定制核心能力+复用通用能力

其中,很多人往往走到中级阶段后就阻塞不前了,并且心得意满、认为平台的已经处于最终形态。但是,平台如果长期处于中级阶段,相关弊端会随着时间推移越发凸显,例如:

  • 没有技术壁垒 - 越是通用,越是普通,很容易被开源产品取代
  • 调用方的使用成本高 - 开放接口往往透传各类参数,使用方成本高
  • 无法贴合一线业务创造价值 - 平台以甲方自居,不去理解业务的使用场景

我见过许多工作了近10年仍处于中级阶段的工程师,他们的技术能力十分高超,但很难在职业发展的道路上再进一步,关键就是在于对平台的认知 - 平台的核心价值是靠 为业务创造的价值 来间接体现的,而不是靠 平台自身的能力 来直接评价

工作生活 - 少给自己找借口的机会

年后,我完整地跑了2次十公里,过程中也有近10次跑了不到一半就放弃。我的跑步配速不快,理应每次都能达成目标,那为什么还有这么多次半途而废呢?

我回顾了这几次的经历,总结如下:一旦我想要中途放弃,借口总是能找到的;所以,在整个跑步的过程中,保持一个稳定、平和的心态,不要让放弃的想法有可趁之机。

Github: https://github.com/Junedayday/code_reading

Blog: http://junes.tech/

Bilibili: https://space.bilibili.com/293775192

公众号: golangcoding

二维码