type
status
date
slug
summary
tags
category
icon
password
前面写了两篇文章,分别介绍“主动/集中错误处理”和“流水线模式与链式调用”的设计思想。主要是用文字整理方案思路,体现逻辑完备性,大部分人难看懂写的啥,也不会关心设计思想,这篇是方案的用法介绍和规范说明,容易理解些。

效果对比

普通模式和base-error模式的对比示例,可以参考examples中的例子。
普通模式下,调用者一般是单方法调用,被动错误处理。
base-error模式下,调用者可以主动/集中处理错误,可以实现链式调用,增强可读性和提升开发效率。
上面的代码示例是调用者视角的,中间件开发者封装了一个Robot加工车间,可以对Robot进行装轮子(SetWheels)、喷漆(Paint)、充电(Charge)操作,以及检查Robot获取信息报告(GetReport)的操作。
调用者要做的事情,就是通过各种操作的组合,加工出自己想要的Robot产品。
在普通模式下,调用者只能通过单方法操作的错误值返回,判断是否操作出错,然后对出错进行处理。这样,就会导致大量的if err != nil要被编写,影响阅读,增加工作量。实际上这种工作量并非必要,也是被try-catch们吐槽的。而且,因为error返回占用了一个返回值,无法实现更加便利的链式调用。

base-error解决的问题

基于流水线模式的设计思路,实现了一种主动/集中错误处理和链式调用封装方案。
这种封装方案,特别适合有大量组合操作的中间件封装,方便中间件的调用者集中处理错误,以及使用链式调用,提升代码可读性和开发效率。
在上面的例子中,普通模式下,调用者相当于是对每个Robot的加工环节都得检查一遍有没有出错,然后自己把Robot搬到下一个加工环节。而base-error模式下,调用者只需要设计一条流水线,然后只检查Robot在流水线上加工有没有出错,模式自动会在出错的时候停止后面的操作,而把出错的环节报告给调用者。
主要的设计思想,在前面两篇文章都有阐述,方案整体的设计逻辑我认为是完备的,不会存在方案逻辑上给程序带来的出错风险。但是,毕竟不是语法层面的设计,而是开发模式上的设计,对中间件封装者和开发者都有一定的要求,需要符合模式的开发规范进行开发和调用。

使用规范

中间件封装

引包:import "github.com/yuanboshe/base-error/berr"
要点:
  1. 所有中间件封装都继承自BaseErr[T],其中T为中间件struct类型。
  1. 所有方法都要以if p.Err() != nil { return p }开头,用于检查错误,跳过后面的操作。
  1. 所有内部错误处理,都以p.SetErr()导入到err成员变量暂存。

中间件调用

要点:
  1. 所有中间件对象都需要InitAddr()进行对象地址初始化。
  1. 通过Err()检查错误,并对错误进行处理后,如果后续还要继续使用中间件对象,则需要SetErr(nil)清除错误。

设计思想

一切从用户(调用者)使用便利的角度出发,通过用户主动/集中错误处理,减少错误处理代码的编写,提升可读性和开发效率;通过链式调用,进一步增强代码的可读性和开发效率。
更详细的主动/集中错误处理设计思想参考一种优雅的Golang error设计模式,流水线模式和链式调用设计思想参考Golang流水线模式与链式调用
这里再对错误处理的思路进行一次补充:
开发过程中很多错误是我们没必要一开始就严肃对待的,因为开发阶段很多错误都是调用者不熟悉中间件特性,使用不当而导致的,这些错误只要发现了,纠正就能解决了。并且,调用者的开发思路,业务逻辑可能随时都会变化,很多可能的错误都会在这种变化中消失,前期认真对待就白白浪费了精力。更多的时候,错误提示,是为了帮我们纠正自己对中间件的使用方法,而每步操作都if err != nil显然是强迫开发者写大量重复代码,增加工作负担。try-catch类似的集中错误处理,通过大量测试覆盖发现可能产生的错误,再针对性处理,在实践中是更高效的,这也是被吐槽开历史倒车的原因。但try-catch确实容易带来偷懒和滥用的风险,还需要进一步完善。
ros2_ws工程开发与调试Golang流水线模式与链式调用
Loading...