【每周小结】2023-Week7
本周的总结发得比较晚,花在打磨编程思考部分的时间比较多。
虽然最终版本也不是很满意,不过也算达到了阶段性交付的水平。
Go技巧 - 并发代码的单元测试
在Go
语言开发的过程中,我们或多或少会引入并发模式,常见的如go
、channel
、sync.WaitGroup
等。这些并发原语使用起来很方便,但常常会阻碍相关代码的单元测试,如依赖的channel
发生阻塞,mutex
被锁等,导致想验证的重要代码根本跑不到。
这里,我介绍一下自己的三个心得,用一句话概括,合理利用分层进行拆分,屏蔽并发逻辑。
没有分层的基础或工具库不在本次的讨论范围内,但也可以借鉴这里的思想。
多协程的逻辑交由上层控制
如下,原先的业务逻辑代码包括了两块处理逻辑:
func Foo(){
// 逻辑A
go func(){
// 逻辑B
}()
}
由于逻辑B相关的代码无法验证,所以这个单元测试能做的很有限。这时,通过分层,我们将代码拆分为两部分:
// 上层代码 - 使用基础的并发特性,没有必要做单元测试
func Foo() {
FooA()
go FooB()
}
// 下层代码 - 做严格的单元测试
func FooA() {
}
func FooB() {
}
此时的单元测试就变得直观了。
锁类逻辑由下层对象封装
业务代码常常会包含锁,这就导致很多函数中有大量的Lock
、UnLock
操作,容易在单元测试里验证一些逻辑时发生死锁。
func Foo() {
// do a
m.Lock()
defer m.UnLock()
// do b
}
从抽象层面来说,业务逻辑的核心代码尽量减少锁这种 底层的并发原语,把它们放在业务逻辑里也很影响阅读体验。这时,将锁划分到下层会让代码逻辑更清晰:
// 下层对象
type FooA struct {
}
type FooB struct {
// 锁
sync.Mutex
}
// 业务代码
func Foo() {
// 这里不包含锁逻辑
fooA.Do()
// 这里包含锁逻辑
fooB.DO()
}
从使用锁的角度来说,Lock
与UnLock
之间的逻辑应尽量短,所以很适合放在底层对象、交由它自行控制,也能缩短锁的影响范围。
同层抽离出核心控制函数
在Go
语言中,有一些并发特性、尤其以channel
为代表,很难通过分层解决。例如
func Foo() {
var c chan int
// 发送消息
go func(){
// send to c
}()
// 接收消息
go func(){
// receive from c
}()
}
这里的channel
更多的是一种具有业务特性的并发控制,单独抽出一个 核心控制函数 就能提升整体的可读性与可测试性:
// 核心控制函数
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
并发编程的基本功。
小结
以上三点是我在工作过程中的经验心得,帮助我解决了很多并发代码中的单元测试问题。它们不一定是最佳实践,但希望能对各位遇到相关问题时有一些启发。
编程思考 - 平台开发的三个阶段
如今, 平台开发 这个词已经广泛应用在程序员圈子内。在我看来,相关的开发者可以分为三个阶段:
- 初级阶段:根据用户的需求明细写过程性的CRUD,实现功能
- 中级阶段:以
OpenAPI
的方式向多业务、多用户提供能力 - 高级阶段:定制核心能力+复用通用能力
其中,很多人往往走到中级阶段后就阻塞不前了,并且心得意满、认为平台的已经处于最终形态。但是,平台如果长期处于中级阶段,相关弊端会随着时间推移越发凸显,例如:
- 没有技术壁垒 - 越是通用,越是普通,很容易被开源产品取代
- 调用方的使用成本高 - 开放接口往往透传各类参数,使用方成本高
- 无法贴合一线业务创造价值 - 平台以甲方自居,不去理解业务的使用场景
我见过许多工作了近10年仍处于中级阶段的工程师,他们的技术能力十分高超,但很难在职业发展的道路上再进一步,关键就是在于对平台的认知 - 平台的核心价值是靠 为业务创造的价值 来间接体现的,而不是靠 平台自身的能力 来直接评价。
工作生活 - 少给自己找借口的机会
年后,我完整地跑了2次十公里,过程中也有近10次跑了不到一半就放弃。我的跑步配速不快,理应每次都能达成目标,那为什么还有这么多次半途而废呢?
我回顾了这几次的经历,总结如下:一旦我想要中途放弃,借口总是能找到的;所以,在整个跑步的过程中,保持一个稳定、平和的心态,不要让放弃的想法有可趁之机。
Github: https://github.com/Junedayday/code_reading Blog: http://junes.tech/ Bilibili: https://space.bilibili.com/293775192 公众号: golangcoding
相关文章
- Java要抛弃祖宗的基业,Java程序员危险了!
- 十大 Java 语言特性
- JVM 三色标记算法,原来是这么回事!
- 聊聊 Spring 事务控制策略以及 @Transactional 失效问题避坑
- 写给 Java 程序员的前端 Promise 教程
- 写给 Java 程序员的前端 Promise 教程,你学会了吗?
- Java 中为什么不全部使用 Static 方法?
- Java 池化技术你了解多少?
- Java 服务 Docker 容器化优秀实践
- Spring Boot + EasyExcel导入导出,简直太好用了!
- 我们一起聊聊 Java 内存泄漏
- CentOS 下安装 Docker 极简教程
- JDK 19 功能集冻结:Java 19 只有七个新特性
- 关于 CMS 垃圾回收器,你真的懂了吗?
- 为什么会有这么多编程语言?
- 改善Java代码的八个建议
- 接口流量突增,如何做好性能优化?
- Java 以编程方式创建JAR文件
- POJO、Java Bean是如何定义的
- Spring 的 Bean 明明设置了 Scope 为 Prototype,为什么还是只能获取到单例对象?