前言

新手程序员大概有如下特点

  1. if嵌套经常超过3层、经常出现重复代码、单个函数代码特别长。
  2. 只会crud,对语言特性和语言的边界不了解。
  3. 不懂面向对象原则和设计模式,以为copy代码就算学会了,常见的是代码职责不明确或者写出万能类
  4. 不知道数据结构和算法的重要性,以为靠硬件能解决运行慢的问题
  5. 架构不懂,搭建框架不会,搭建环境不会,使用的软件底层原理一问三不知

其实吧,很多人干了很多年,看似是老手,平时工作看似很忙,其实做的都是最简单的活。

这就像去锻炼,有的人每天练的很积极,准时打卡,频繁发朋友圈,貌似是正能量,结果是几年下来体型还是那样,该减的肥肉没少,要增的肌肉没加,为什么会这样?因为从来都是挑最简单最轻松的练

貌似吐槽多了,下面演示一下如何将一坨烂事务代码重构得优雅

需求

执行一个事务,需要调用one、two、three、four、five几个方法,任意一个方法失败,都回滚事务

下面是这些方法的简单模拟,我们用尽可能少的代码模拟一个操作

//开启事务
func beginTransaction() {
fmt.Println("beginTransaction")
} //回滚事务
func rollback() {
fmt.Println("rollback")
} //提交事务
func commit() {
fmt.Println("commit")
} //执行one操作
func one() (err error) {
fmt.Println("one ok")
return nil
} //执行two操作
func two() (err error) {
fmt.Println("two ok")
return nil
} //执行three操作
func three() (err error) {
fmt.Println("two ok")
return nil
} //执行four操作
func four() (err error) {
fmt.Println("four ok")
return nil
} //执行five操作
func five() (err error) {
err = errors.New("five panic")
panic("five")
return err
}

烂代码示例

下面演示开启一个事务,依次执行one、two、three、four、five 5个操作,前四个成功,第五个失败

这是新手程序员常见使用事务的代码风格,其实也不光是事务,所有的代码都可能长下边这样

func demo() (err error) {
beginTransaction()
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
fmt.Printf("%v panic\n", e)
rollback()
}
}()
if err = one(); err == nil {
if err = two(); err == nil {
if err = three(); err == nil {
if err = four(); err == nil {
if err = five(); err == nil {
commit()
return nil
} else {
rollback()
return err
}
} else {
rollback()
return err
}
} else {
rollback()
return err
}
} else {
rollback()
return err
}
} else {
rollback()
return err
}
}

重构套路

一、提前return去除if嵌套

通过提前返回error,来去掉一些else代码,减少嵌套,如下

代码

func demo() (err error) {
beginTransaction()
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
fmt.Printf("%v panic\n", e)
rollback()
}
}()
if err = one(); err != nil {
rollback()
return err
}
if err = two(); err != nil {
rollback()
return err
}
if err = three(); err != nil {
rollback()
return err
} if err = four(); err != nil {
rollback()
return err
}
if err = five(); err != nil {
rollback()
return err
}
commit()
return nil
}

先解决嵌套

二、goto+label提取重复代码



代码

func demo() (err error) {
beginTransaction()
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
fmt.Printf("%v panic\n", e)
rollback()
}
}()
if err = one(); err != nil {
goto ROLLBACK
}
if err = two(); err != nil {
goto ROLLBACK
}
if err = three(); err != nil {
goto ROLLBACK
}
if err = four(); err != nil {
goto ROLLBACK
}
if err = five(); err != nil {
goto ROLLBACK
}
commit()
return nil
ROLLBACK:
rollback()
return err
}

三、封装try-catch统一捕获panic

上面的代码其实还有一点问题

  1. defer里有rollback的代码
  2. goto虽然好,但是不建议使用

我们可以对panic和defer进行封装,模拟一下try-catch,实现如下





可以看到,rollback只调用了一次,完美的进行了事务代码重构

try-catch.go代码

package exception

type Block struct {
Try func()
Catch func(interface{})
Finally func()
} func (t Block) Do() {
if t.Finally != nil {
defer t.Finally()
}
if t.Catch != nil {
defer func() {
if r := recover(); r != nil {
t.Catch(r)
}
}()
}
t.Try()
}

使用代码

	exception.Block{
Try: func() {
beginTransaction()
if err = one(); err != nil {
panic(err)
}
if err = two(); err != nil {
panic(err)
}
if err = three(); err != nil {
panic(err)
}
if err = four(); err != nil {
panic(err)
}
if err = five(); err != nil {
panic(err)
}
err = nil
commit()
},
Catch: func(e interface{}) {
rollback()
fmt.Printf("%v panic\n", e)
err = fmt.Errorf("%v", e)
},
}.Do()
return err
}

这样,我们就可以用非常少的代码实现事务,并且简单清晰好维护,以上为chenqionghe原创,light weight baby

golang如何优雅的编写事务代码的更多相关文章

  1. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...

  2. C#和JAVA中编写事务代码

    C#  DAL层代码,运行多条增删改,使用事务操作: /// <summary> /// 运行 多条增删改 (非查询语句) /// </summary> /// <par ...

  3. (转).Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    原文地址:http://www.cnblogs.com/1996V/p/7798111.html 示例一和示例二,主要是来讲解 TransactionScope 是什么,为什么要用Transactio ...

  4. 使用lambda表达式优雅你的事务代码

    我们在实现业务逻辑时,经常会有这种需求: 1.在当前事务A中开启新事务B,事务B中发生异常不可以回滚A,事务B成功执行后返回事务B的返回值: 2.在当前事务A中开启新事务B,事务B中发生异常要求回滚A ...

  5. 使用 Golang 编写链代码 (v0.6 )

    https://www.ibm.com/developerworks/cn/cloud/library/cl-ibm-blockchain-chaincode-testing-using-golang ...

  6. 最新的JavaScript核心语言标准——ES6,彻底改变你编写JS代码的方式!【转载+整理】

    原文地址 本文内容 ECMAScript 发生了什么变化? 新标准 版本号6 兑现承诺 迭代器和for-of循环 生成器 Generators 模板字符串 不定参数和默认参数 解构 Destructu ...

  7. 如果让莎士比亚、海明威编写JavaScript代码

    本文作者Angus Croll是Twitter工程师.JavaScript迷.文学迷,并且非常喜欢作家海明威.他在梦中"梦见"一些名人编写JavaScript代码,不同的作家呈现出 ...

  8. Guava 教程1-使用 Google Collections,Guava,static imports 编写漂亮代码

    原文出处: oschina (API:http://ifeve.com/category/framework/guava-2/ JAR DOC Source 链接:http://pan.baidu.c ...

  9. 如何更规范化编写Java 代码

    如何更规范化编写Java 代码 Many of the happiest people are those who own the least. But are we really so happy ...

随机推荐

  1. Airtest常见的素定位不到

    一.为什么发这博客 前几天业务需要需要操作云手机进行爬取没办法只有混进airtest官方群边学习边进行开发,蛮简单的东西(可能是我之前会selenium,appuim关系吧),但是群里会有很多问题,关 ...

  2. python(内置高阶函数)

    1.高阶函数介绍: 一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),如果满足其一,则为高阶函数. 常见的高阶函数:map().sorted( ...

  3. MongoDB 部署以及操作

    目录 1.MongoDB简介 2.MongoDB优势 3.MongoDB安装 3.MongoDB用户管理 3.1.Mongodb创建超级管理员 3.2.MongoDB创建读写用户 3.3.Moongo ...

  4. Codeforces Round #632 (Div. 2)

    Codeforces Round #632 (Div. 2) 这一场打的好差呀,这几次艰难上的分全部掉回去了,感觉就像一夜回到了解放前. 说实话,就是被B卡到了,没看到只能从小的放到大的... Lit ...

  5. spring mvc从后台往前台传参数的三种方式

    第一种:使用Model对象(常用) 第一步:使用model对象往前台传递数据 第二步:在jsp中接收从后台传递过来的参数 第二种:使用HttpServletRequest对象 第一步:使用HttpSe ...

  6. Spring官网阅读(十六)Spring中的数据绑定

    文章目录 DataBinder UML类图 使用示例 源码分析 bind方法 doBind方法 applyPropertyValues方法 获取一个属性访问器 通过属性访问器直接set属性值 1.se ...

  7. 王颖奇 20171010129《面向对象程序设计(java)》第十五周学习总结

    实验十五  GUI编程练习与应用程序部署 实验时间 2018-12-6 学习总结: 理论部分: ◼ JAR文件◼ 应用程序首选项存储◼ Java Web Start JAR文件: 1.Java程序的打 ...

  8. 测试开发专题:spring-boot统一异常捕获

    java异常介绍 异常时相对于return的一种退出机制,可以由系统触发,也可由程序通过throw语句触发,异常可以通过try/catch语句进行捕获并处理,如果没有捕获,则会导致程序退出并输出异常栈 ...

  9. 003_python的str切片,str常用操作方法,for循环,集合,深浅copy

    基础数据类型 基础数据类型,有7种类型,存在即合理. 1.int 整数 主要是做运算的 .比如加减乘除,幂,取余  + - * / ** %... 2.bool布尔值 判断真假以及作为条件变量 3.s ...

  10. 一道题带你搞定Python函数中形参和实参问题

    昨天在Python学习群里有位路人甲问了个Python函数中关于形参和实参一个很基础的问题,虽然很基础,但是对于很多小白来说不一定简单,反而会被搞得稀里糊涂.人生苦短,我用Python. 为了解答大家 ...