最近写了一个程序,因为很急(好像没有什么急事。。。),所以我复制了这个程序的一部分,然后把它粘在一起。从。写完代码感觉代码一塌糊涂,自己都快哭了。真的是写在心里,别骂我,先是骂了之前做这个项目的人,项目一塌糊涂,然后代码开始运行,顺利交接后,就变成骂自己了因为笨,这样写也不是不可以!不是不能用,而是在这个过程中先不提项目中的业务逻辑和界面设计是否不合理。我觉得时间紧,人员变动快的时候,正常人会尽快坚持下去,不行就再打包一层,不要修复线上问题。让我哭傻的一件事是Go的错误处理太傻了。我在一个程序里写了七八个错误的判断。我用伪代码给大家描述一下:err,file:=接收一个文件(file)iferr!=nil{返回错误码对应的日志}err,fh:=openuploadfile(file)iferr!=nil{返回错误码对应的日志}err,data:=记录文件中的行解析/转换(row)iferr!=nil{logging返回错误码对应}err,data3:=调整第三方接口获取数据iferr!=nil{logging返回对应的错误码}err,data2:=调整其他内部服务获取数据iferr!=nil{返回日志中对应的错误码}err:=写入库iferr!=nil{返回日志中对应的错误码}上面的例子一点都不夸张,相信你在项目中肯定见过,如果是做业务开发的话会更常见。看到这里肯定有人会问,Go的错误处理是这样的,第一天能不能看到,还傻傻的哭。哎,不是说降本提效后,人手减少了一半。我们这群没有混队伍的虚线组长又开始自己写代码了。他们以前很愚蠢,很愚蠢。另外,之前的系统,项目分层,服务隔离,都是一起工作的。不会像上面那样在控制层调整那么多业务对象,把傻代码凑在一起……感觉立马不一样了。.所以我就在想,有没有什么设计模式之类的东西可以把这些东西隐藏起来,应该有吧,没有什么是代码包裹一层解决不了的,不行就包裹两层..。嘿,为什么?一不小心说出了设计模式的精髓。Go优雅处理错误的几种方案。这几天在网上看了很多。Go错误处理,但基本上都是讲如何自定义封装错误,传递错误等等,讲Go代码怎么写。比较优雅漂亮的文章比较少。最好的是LeftEarMouse先生在他的博客中介绍的两种方法。一种是使用函数式编程Closure来抽象出同样的iferr!=nil代码来重新定义一个函数,但是这种方法会导致新的问题——需要引入内部函数和一个错误变量,就不多说了,如果你是感兴趣的可以查看原博文。这里直接介绍另外一个比较好的方案,对项目的侵入性不是很大,给大家。Go语言官方库bufio中Scanner对象错误处理的实现可以给我们一些启发,大概是这样实现的。scanner:=bufio.NewScanner(input)forscanner.Scan(){token:=scanner.Text()//处理令牌}iferr:=scanner.Err();err!=nil{//processtheerror}从上面的代码可以看出,scanner在操作底层I/O时,for循环中没有iferr!=nil,有scanner。Err()在退出循环后检查。好像是用结构的方式。我们看一下Scanner类型的定义:typeScannerstruct{rio.Reader...//其他字段省略errerror}这个类型内部持有一个错误。迭代执行Scan方法时,遇到错误后会转到这个错误Errorsareloggedin。func(s*Scanner)Scan()bool{...//省略其余代码for{iferr!=nil{s.setErr(err)returnfalse}}func(s*Scanner)Err()error{ifs.err==io.EOF{returnnil}returns.err}所以我们可以继续这个想法。比如上面这个读取业务对象的例子,相信大家也很容易理解。但其使用场景只能简化对同一业务对象连续操作下的错误处理。对于多个业务对象,还是需要各种iferr!=nil的方式。那么就没有办法了,我们之前说过一次:没有什么是代码包裹一层解决不了的,不行就包裹两层。然后再做一层包装。下面是我解决这个问题的一点理解。我将使用DDD中的一些分层概念来解决这个问题。Easersolution刚才例子的问题是,它只适用于减少单个业务对象逻辑操作中的iferr!=nill判断。为此,我们可以将涉及多个业务对象的操作放在一个应用服务中,把刚才在业务对象中做的错误处理判断放到应用服务中,这样在业务对象中,比如Model等底层模块,你仍然可以按照正常的流程写代码,而不用先开始每个方法的判断。这里提前告诉大家,在一些架构设计中,应用服务和领域服务分为两个概念。两者的概念完全不同。应用服务是通过面向产品需求的用例来实现的。他们负责业务用例流的任务协调,也就是我们实现API。当控制层经常调用应用服务时,可以在一个应用服务中放置多个不同的业务对象。域服务专用于一个域,就不多解释了。DDD和COLA框架的实现我也看了几本,还是一知半解。简而言之,请记住多个业务对象可以通过应用程序服务进行协调以执行任务。同时,将上面添加到业务对象的错误处理分离到应用服务层,让业务对象专注于自己的职责。在这种情况下,你的服务层代码可能不得不变成这样。然后我们的控制层调用应用服务层获取结果,此时判断整个需求任务执行过程中是否有错误。记录错误并向客户端返回错误响应。Go错误处理的基础之前分享过一篇关于Go程序错误处理的一些建议里面讲到我们应该如何用好Go的错误接口,自定义错误,包裹整个错误链等相关技巧。结合本文的内容,大家可能对错误处理有了更全局的认识,在此推荐给大家。小结今天想和大家分享一些自己学习和思考的一些事情,让Go代码的错误处理更加优雅。其实大家可以发现,我们把多个iferr!=nil分散到多个方法中,这样代码至少比在一个方法中写七八个错误判断要好看。
