自動化生成代碼的秘密

我做過兩個自動化生成代碼的項目待秃,scaffoldredis-orm拜秧。
scaffold 主要是通過數(shù)據(jù)庫表定義來生成基于表的增刪改查的基礎(chǔ)管理工作;
redis-orm 是通過yaml的結(jié)構(gòu)定義文件生成關(guān)系型數(shù)據(jù)庫與redis的常規(guī)操作實現(xiàn)章郁。
公司里還有一套微服務(wù)的自動化生成框架枉氮,能夠快速的通過protobuf的定義文件生成項目的框架代碼。

自動化生成代碼有個最大的優(yōu)點:減少程式化的編碼暖庄。所謂程式化的編碼就是聊替,通常這些編碼的工作量會隨著業(yè)務(wù)量的增長線性增長,同時又是最沒有技術(shù)含量的工作培廓。所以通過開發(fā)自動化生成工具非常有必要惹悄,減少無謂的工作量同時大大提升工作效率,把大家解放出來做更有意義的事肩钠。

不論是我寫的自動化生成工具或是公司的微服務(wù)框架生成工具還是其它一些官方工具泣港,都有一個共同原理,所謂自動化生成代碼的秘密价匠,即

通過結(jié)構(gòu)化的元數(shù)據(jù)生成模式代碼

這句話中有兩個關(guān)鍵詞:

  • 結(jié)構(gòu)化的元數(shù)據(jù)
    結(jié)構(gòu)化的元數(shù)據(jù)的來源可以是:

    • 數(shù)據(jù)表定義
      例子: scaffold
    • 結(jié)構(gòu)化的配置文件(yaml, toml 等等)
      例子: redis-orm
    • 服務(wù)接口定義(Thrift, ProtoBuffer等等)
      例子:grpc当纱、micro
    • 程序代碼中的類型、對象踩窖、接口等等
      例子:stringer坡氯、mock
  • 模式代碼
    模式代碼,即所有生成的代碼是符合一定規(guī)律的洋腮,而這種規(guī)律就是基于元數(shù)據(jù)而言的箫柳。

最簡單的例子

官方的工具stringer就是一個自動化生成代碼工具,主要用途是通過枚舉值的變量名生成String函數(shù)接口啥供,常用場景就是在定義程序狀態(tài)碼中使用悯恍。其中,結(jié)構(gòu)化的元數(shù)據(jù)就是枚舉類型的定義滤灯。

package codes

type Code uint32

//go:generate stringer -type=Code

const (
  OK Code = 0
  Canceled Code = 1
  Unknown Code = 2
  InvalidArgument Code = 3
)

這是一個簡化版的GRPC狀態(tài)碼的例子坪稽,在文件所屬目錄下通過以下stringer命令即可生成代碼文件code_string.go

$: stringer -type Code

生成的代碼如下:

// Code generated by "stringer -type Code"; DO NOT EDIT

package codes

import "fmt"

const _Code_name = "OKCanceledUnknownInvalidArgument"

var _Code_index = [...]uint8{0, 2, 10, 17, 32}

func (i Code) String() string {
    if i >= Code(len(_Code_index)-1) {
        return fmt.Sprintf("Code(%d)", i)
    }
    return _Code_name[_Code_index[i]:_Code_index[i+1]]
}

原代碼函數(shù)有一句注釋的語句:

//go:generate stringer -type=Code

通過該語句鳞骤,可以在命令行中執(zhí)行如下命令窒百,效果相同:

$: go generate

一個小技巧,在制作自動化生成代碼工具的過程中有時候會很有用豫尽。

微服務(wù)框架的自動化

微服務(wù)現(xiàn)在很火篙梢,如何開發(fā)一個微服務(wù)框架的自動化生成工具呢?

首先美旧,我們要清楚什么是框架渤滞?

框架是對接口的抽象

這是我個人對框架的總結(jié),通過將項目中變化的部分通過接口抽象出來榴嗅,提供給開發(fā)者妄呕,將不變的或者配置可變的放入框架中。

其實嗽测,grpc 已經(jīng)是一個簡單的微服務(wù)框架了绪励,只是功能比較單一,僅僅通過protobuf的定義生成客戶端與服務(wù)端代碼框架唠粥。它是怎么做到的疏魏?

管道的概念,做服務(wù)端的人都非常熟悉晤愧〈竽可以用管道的概念類比一下grpc框架代碼的生成過程

protoc | protoc-gen-go | plugin:grpc

protoc編譯器通過讀取protobuf協(xié)議與接口配置官份,輸出結(jié)構(gòu)化元數(shù)據(jù)給 protoc-gen-go只厘,由它生成 go 代碼,在protoc-gen-go中會用到 plugin:grpc 的插件實現(xiàn)grpc框架代碼的定制生成舅巷。

當(dāng)然懈凹, protoc-gen-go 調(diào)用 plugin:grpc 不是通過管道的方式。

要實現(xiàn)微服務(wù)框架的自動化的關(guān)鍵全在 plugin:grpc 中了悄谐。因為 plugin:grpc 就是一個代碼生成器介评。你想要的所有內(nèi)心戲全部可以在這里實現(xiàn)。包括:

  • 服務(wù)發(fā)現(xiàn)
  • 上下文定制
  • 錯誤處理
  • 日志
  • 統(tǒng)計

全部可以在框架里實現(xiàn)爬舰,僅僅暴露簡單的接口供開發(fā)人員開發(fā)们陆。

為了讓生成代碼更加精煉、可讀性更強情屹,共用的一些函數(shù)都會通過公用包的形式實現(xiàn)坪仇。

在安裝GRPC的過程中,有這樣一條安裝命令:

$: go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

其中垃你,包proto就是protoc生成go代碼提供的公用包椅文。

** 結(jié)構(gòu)化元數(shù)據(jù) **

有時候閱讀代碼可以幫助我們理解protobuf協(xié)議喂很。在公司的微服務(wù)框架里用到了custom option. 在官方文檔說,這個屬性對于大部分開發(fā)者都是不會用到的皆刺。因為這個屬性僅有在需要開發(fā)自己的框架代碼時才會使用到少辣。編寫模式代碼中,可以通過custom option控制框架代碼的生成羡蛾。

** 模式代碼 **

除了結(jié)構(gòu)化的元數(shù)據(jù)漓帅,模式代碼的質(zhì)量直接影響了項目本身的質(zhì)量。模式代碼保持精煉痴怨,可讀性強都是一些基本要求忙干。不貼代碼了,具體代碼參見grpc.go.

如何編寫自己的Plugin浪藻,除了參考GRPC本身的Plugin實現(xiàn)捐迫,還可以參考這個項目
micro/protobuf.

自動化生成代碼常見的坑

在開發(fā)自動化生成代碼工具的過程中,關(guān)鍵一步是編寫模式代碼爱葵。通常模式代碼一定是通過不斷的迭代才能達到所謂的完美弓乙。所以,在不斷迭代的過程中钧惧,就會出現(xiàn)暇韧,很痛苦的,改變接口浓瞪。

如果只是生成的代碼改變接口可能影響面還比較小懈玻,只需要相應(yīng)的修改調(diào)用方代碼即可。但是如果生成代碼中調(diào)用的公用包接口發(fā)生改變了乾颁,可能以前生成的代碼就會發(fā)生故障涂乌。這也是我真實碰到過的一個坑。為了防止類似錯誤英岭,可以通過版本控制的辦法解決湾盒。

通過對倉庫打tag,利用gopkg.io實現(xiàn)版本控制诅妹,是非撤9矗快捷且高效的解決辦法.

如何用好自動化代碼生成工具

用好自動化代碼生成工具的關(guān)鍵,除了對生成代碼本身要很熟悉外吭狡,還需要了解生成工具編寫的模式代碼尖殃。了解自動化代碼生成工具的原理是非常必要的。

其實框架越強大划煮,對于業(yè)務(wù)而言越有利送丰,但對喜歡偷懶的程序員而言是不利的。所以利用偷懶來的時間弛秋,閱讀框架代碼非常必要器躏。

歸根結(jié)底俐载,自動化編程是一項泛化編程技術(shù),以前在c++中是件高端而隱秘的事登失,將程序執(zhí)行期的代碼移至編譯期生成遏佣。如今,在go語言中壁畸,可以通過模板包template光明正大的干這件事了。

以上茅茂,就是我在開發(fā)和使用自動化代碼生成工具中學(xué)到的些許經(jīng)驗捏萍,全當(dāng)拋磚引玉,歡迎指教空闲。


本文首發(fā)扯扯皮個人簡書博客, 歡迎關(guān)注令杈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市碴倾,隨后出現(xiàn)的幾起案子逗噩,更是在濱河造成了極大的恐慌,老刑警劉巖跌榔,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件异雁,死亡現(xiàn)場離奇詭異,居然都是意外死亡僧须,警方通過查閱死者的電腦和手機纲刀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來担平,“玉大人示绊,你說我怎么就攤上這事≡萋郏” “怎么了面褐?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長取胎。 經(jīng)常有香客問我展哭,道長,這世上最難降的妖魔是什么闻蛀? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任摄杂,我火速辦了婚禮,結(jié)果婚禮上循榆,老公的妹妹穿的比我還像新娘析恢。我一直安慰自己,他們只是感情好秧饮,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布映挂。 她就那樣靜靜地躺著泽篮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柑船。 梳的紋絲不亂的頭發(fā)上帽撑,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音鞍时,去河邊找鬼亏拉。 笑死,一個胖子當(dāng)著我的面吹牛逆巍,可吹牛的內(nèi)容都是我干的及塘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锐极,長吁一口氣:“原來是場噩夢啊……” “哼笙僚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灵再,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肋层,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后翎迁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栋猖,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年汪榔,在試婚紗的時候發(fā)現(xiàn)自己被綠了掂铐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡揍异,死狀恐怖全陨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衷掷,我是刑警寧澤辱姨,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站戚嗅,受9級特大地震影響雨涛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懦胞,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一替久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躏尉,春花似錦蚯根、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒂誉。三九已至,卻和暖如春距帅,著一層夾襖步出監(jiān)牢的瞬間右锨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工碌秸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绍移,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓讥电,卻偏偏與公主長得像蹂窖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子允趟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 我做過兩個自動化生成代碼的項目恼策,scaffold和redis-orm鸦致。scaffold 主要是通過數(shù)據(jù)庫表定義來生...
    一艘慢船閱讀 1,521評論 0 12
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理潮剪,服務(wù)發(fā)現(xiàn),斷路器分唾,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,110評論 25 707
  • 1 如果用現(xiàn)在的熱詞抗碰,沈小怡當(dāng)年是我迷妹。 2012年绽乔,我在上海培訓(xùn)PPT弧蝇,發(fā)現(xiàn)課堂上坐著一位美女,聽得非常認真折砸,...
    秋葉大叔閱讀 790評論 2 8
  • 昨天的認真梳理了自己煩躁的原因看疗,覺得自己內(nèi)心有抗拒去完成那個一直待完成的方案。今天到辦公室一做下就把方案打開睦授,寫到...
    Rachel_瑞秋閱讀 277評論 1 4