[Golang]如何优雅的管理几十个UDF(API)

组内一个服务中有个叫算子的模块,所谓算子可以理解为UDF(User Defined Function),这个模块的核心思想是:在做业务需求时,把业务拆解为几块通用的业务代码(UDF),不同的代码块承担不同的业务功能。这些代码块提供出不同的配置项(或者叫“函数签名”),用户传入对应的参数调用这块代码。

这样做的好处是:后续接业务需求时只需要通过编排算子配置就可以复用通用算子。业务不复杂时,单个算子即可支持业务;业务复杂时,通过多个算子组合为pipeline支持业务。

编个🌰,现在有个业务需求:用户下单后需要统计用户当天完单量,并给下游发送用户的单量消息,下游营销系统根据用户的完单量给用户推送不同的优惠策略。

对整个业务流程做一下抽象:

image.png

这里编排schema和转发MQ都是不涉及存储的纯计算型业务需求。现在把这两个功能抽象成算子:

第一个算子为"编排schema",功能是把各种参数编排成一个string格式的字符串并返回。其配置schema可能长这样:

{
    "calc_param": ["user_id", "finish_cnt", "time_stamp"],
    "calc_options": {
        "template": "{\"user_id\":\"{{user_id}}\",\"finish_cnt\":\"{{finish_cnt}}\",\"time_stamp\":\"{{time_stamp}}\"}"
    }
}

第二个算子为"发送MQ",功能是把输入的string格式的字符串作为生产者发送到一个MQ中。其配置schema可能长这样:

{
    "calc_param": ["last_calc_string_res"],
    "calc_options": {
        "topic_name": "an_awesome_topic"
    }
}

把这两个算子组成一个json list,作为一个业务配置,服务读取配置就实现业务需求了,整个过程中不用写一行代码。

理想很丰满,实现很骨感。在实际开发迭代中,由于团队扩张、人员流动、代码注释缺失的问题,算子模块出现了三个问题:

  1. 有人不知道系统中有哪些通用算子
  2. 通用算子使用成本较高(测试文件(如果有) or 看算子源码)
  3. 通用算子维护成本较高(写完代码之后需要写wiki,更新完代码之后需要改wiki)

这两个问题导致的结果是:有的需求可以通过一些通用算子的配置组合支持业务,但是在不熟悉的情况下有的人会选择写一坨"定制算子(全是具体的业务逻辑)"去支持需求。

这么做倒是无可厚非,相比于纯写配置一行代码都不开发而言,一天写300行业务代码支持一个业务可能更会带来成就感,且上线之后也不出Bug就完事了呗,条条大路通罗马嘛;)

但这样做有点不符合组内系统的核心思想,还是应该去建设更加通用的算子,当通用算子积累到一定程度,并以一种合理的方式被管理起来,那最终的业务收益就可能变成这样:RD在平台上通过拖拉拽组合通用算子就可以支持业务,在系统建设足够完善的情况下,一人一天支持100个业务需求都不在话下;)

所以现在就有一个不太痛的痛点:需要把算子模块管理起来。如果在基于一开始的设想:

算子 == UDF

那完全可以学习编程语言管理UDF的方式对算子模块进行管理,具体的解决方案为:

痛点 方案
新同事不知道系统中有哪些通用算子 对通用算子打上不同的分类标签:比如上面的 编排schema 算子可以打上"字符串操作" tag;发送MQ 算子 可以打上 "MQ操作"、"外部rpc" tag
通用算子使用成本过高 搞一个算子平台,提供REPL的能力供用户使用算子
通用算子维护成本过高 问题发生的本质原因是:代码与wiki编写过程是剥离的,那就把这两个过程放在一起,把wiki放在代码里,并写一些元编程的代码生成这份wiki。

实际上这个算子模块管理系统是必须的:在系统刚开始迭代时,系统里可能只有几个通用算子,这时你的使用成本很低,这就好比你随时记得你喜欢的Go语言里有json.Unmarshaljson.Marshalhttp.ListenAndServestrings.Split这几个系统函数。

但是随着业务的发展,你的系统也会迭代,最终你的代码里可能有几十个、上百个UDF,如果不把算子按照类型管理起来,你就需要随时记忆这么多的UDF,这就好比 你可能并不记得你喜欢的Go语言的strings包里还有一个叫做EqualFold的系统函数,即使你有一个模糊的印象,那你使用时候也得去看看wiki里是怎么写的。

对于如何把代码编写wiki维护这两个割裂的步骤放在一起,在下有一些不成熟的想法。在这里写一种思路:

对于每一种段子,都抽象出其配置schema和参数schema,所谓的schema在Golang中即结构体,我们在结构体中写多种tag记录各个属性的元信息,并通过反射把这些元信息同步到DB中,元信息落库后,就可以和前端同学合作建立酷炫的管理平台管理算子了。

Go的反射及其不好用,这里简单写一些反射代码,把上文那两个算子配置读取结构体元信息这块表示一下:

package main

import (
    "fmt"
    "reflect"
)

type MQOption struct {
    TopicName string `json:"topic_name" comment:"消息队列名称"`
}

func getStructTag(v interface{}, tag string) {
    structVal := reflect.ValueOf(v).Elem()
    structType := structVal.Type()
    fmt.Println(structType, structVal)

    for i := 0; i < structVal.NumField(); i++ {
        fieldType := structType.Field(i)
        fmt.Println("fieldType", fieldType)
        field := structVal.FieldByName(fieldType.Name)
        fmt.Println("field", field)

        comment := fieldType.Tag.Get(tag)
        fmt.Println("tag", comment)
    }
}

func main() {
    mo := new(MQOption)
    getStructTag(mo, "comment")
}

// ------------ output ------------
//      main.MQOption {}
//      fieldType {TopicName  string json:"topic_name" comment:"消息队列名称" 0 [0] false}
//      field
//      tag 消息队列名称
// ------------ output ------------

上面这块代码只是玩具,不建议用于生产环境,如果对这块有兴趣,可以去github上找开源项目。

欢迎关注我的公众号:薯条的自我修养

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容