稍微有点标题党,不过很短,能够看mysql
最近一直在参加开发公司新运营系统的引擎部分,写了不少不少代码,也逐渐产生了一些本身对此类业务的解决方案的简单想法。运营系统干的事,其实就是支持运营人员配置活动。所谓活动其实能够简单定义为:一系列条件都知足就执行某个(些)动做。对应到程序员的黑话就是:一坨if else以后执行某(几)个函数。git
说到写if else,大多数程序员可能都会会心一笑,毕竟不论写啥系统,代码里大部分语句仍是if else。业务系统就是对PM的需求堆if else,基础服务就是对OS资源和网络问题堆if else。愈来愈多的需求形成了代码的膨胀,如何来管理这坨if else,就衍生出了设计模式:经过各类手段来把if else划分到更小的粒度。固然,尚未任何一套方法论能够解决if else复杂性的问题,由于if else反映的实际上是真实业务的需求,它其实表明了业务的复杂性。就像鲁迅或者马云或者巴菲特说的:“不论用什么方法,if else不会凭空消失,只会从一个地方转移到另外一个地方”。可是,在面对特定的场景,特定的业务,代码的阅读性、可维护性以及扩展性是能够获得提高的。程序员
规则引擎不是一个新东西,并且已经存在了很长时间了,市面上也有各类规则引擎。好比你们经常使用的iptables,就是一种规则引擎,crontab也是一种规则引擎。咱们平时写的业务逻辑,其实也是规则引擎,只是用一种不那么明显的方式来体现。好比:“若是重置的密码没有包含大小写和标点符号,就不让提交”,“若是用户是抽奖送的VIP虽然不播广告但给他弹窗”……这些业务逻辑,不管怎么优化,要处理的代码分支是必定存在的。规则引擎经过自定义的一套语法(DSL),提供了编程语言所不具有的语法糖,来最大限度减小开发量。同时大部分规则都须要支持用户随意配置,所以DSL大可能是解释执行。用户在后台配置一条规则好比,游戏中用户在线1000分钟后扣20的点卡:github
When
{
?customer: Customer(totalTime >=1000);
}
Then
{
execute {?customer.setAmount(getAmount()-20.00);
}
复制代码
市面上比较经常使用的几款规则引擎都属于很是重量级的,用户必须去学习它的DSL才能使用,固然基本上都是JAVA的包。这有一篇文章是几款规则引擎的比较。没有深度用过,我也无法对此进行评价,但因为其概念实在太多且使用场景受限,我以为它始终是个临时方案,毕竟“大道至简”。并且DSL会越写越复杂,真正用到语法糖的地方仍是少数,到最后变成另外一种蹩脚的并且领域受限的编程语言了。虽然如此,但因为其规则可动态增长,老规则便于复用,对于提供通用解决方案的一些软件公司来讲,规则引擎仍是颇有吸引力的。毕竟代码不须要动,加一些规则就能再次销售。sql
可是对于进行业务开发的RD来讲,其实需求很简单,若是一个东西:express
那么这即是一个有吸引力的解决方案,若是它能再快点儿,那就是一个绝妙的主意了。对于减小if else,我以为Linq是一个很是好的方案。编程
Linq是C#中的一种常见技术,用过的都以为爽。它就是一种语法糖,编译器会编译成真正的代码而不是在运行期解释执行,所以效率也很高。Linq代码大概就是这样:c#
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
// Define the query expression.
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
select score;
复制代码
能够看到,在代码中一些逻辑若是能这样表达,那代码将会变得很是简单。linq基本上就是把sql语句搬到了C#中,惟一的区别就是它把select放在了最后而sql是在前面。这其实也是由于IDE智能提示的需求,而不是查询结构自己要这么设计。把select放在最后,IDE就知道你前面用过哪些变量,就能够分析出你能够select什么从而进行提示。可是Linq是C#中的技术,和编译器是强相关的,想移植到别的语言,仍是很不容易的。固然,社区也是有一些尝试的,好比go的移植版linq-go。然而,你懂的,因为go自己不支持泛型,编译器也不支持linq语法,所以使用起来固然仍是比较蹩脚,并且确定是interface{}和类型推断满天飞了……设计模式
其实咱们经常使用的sql中的where部分是完备的,Linq也是把sql搬到了C#中。换句话说,sql的where部分其实能够组合任意的布尔逻辑。全部RD都会使sql,并且是常常使sql,既然想从编译器的方向搞事情太麻烦(尤为是go是一门以简单著称的语言,官方对于加关键字是深恶痛绝的,更别说语法糖了),那么把mysql查询功能干掉,解释执行where比较的那部分功能作成一个函数提供出来呢,好比查询一我的是否是顶级程序员能够这么查:bash
sql := `sex='male' and ( dislike in ('girl', 'woman', 'female') or hobby in ('dress up', 'makeup') )`
复制代码
可是因为没有表数据,那么真正用于比较的数据就须要业务方本身来提供了,以上功能能够写为:
func isTopProgrammer(userInfo User) bool {
sql := `sex='male' and ( dislike in ('girl', 'woman', 'female') or hobby in ('dress up', 'makeup') )`
ok,_ := yql.Match(sql, map[string]interface{}{
"sex": userInfo.Sex,
"dislike": userInfo.Dislike,
"hobby": userInfo.Hobbies,
})
return ok
}
复制代码
yql其实就是我最近搞的一个lib(求star,求pr,求指导),帮你执行sql的比较。
若是这么搞,其实业务逻辑中常常变更的部分能够抽象到配置文件里,好比:
// 先定义好不一样case的处理函数
type handleFunc func(map[string]interface{}) error var handlers = map[int]handleFunc {
1: sendEmail,
2: sendCoupon,
3: sendSms,
4: sendAlert2Boss,
5: runAway,
}
// 从当前请求中解析数据
data := resolveDataFromPostParams(request.Body)
// 从配置文件加载规则
rules := loadRuleFromConf()
//枚举每条规则进行匹配,若是匹配成功则执行对应handler
for _,rule := range rules {
success,err := yql.Match(rule.SQL, data)
if nil != err || !success {
continue
}
handler := handlers[rule.ID]
handler(data)
break
}
复制代码
固然这种方式也有利有弊,好比说,把规则分离到配置文件中,在debug时得几个文件之间跳来跳去地看代码,比较蛋疼(少写点bug就好了,哈哈)。优势之一好比说能够利用推送平台实时更新配置文件,从而达到代码热更新的目的。
其实yql还有不少应用场景(我感受),固然也有一些不足,好比功能还比较单一,解释执行,快不快其实也没和谁对比过……不过但愿你们可以尝试尝试,若是可以提高工做效率,仍是不错的。求关注,求star