vivo 低代碼平臺(tái)【后羿】的探索與實(shí)踐
一、前言
青春才幾年,疫情占三年,后疫情時(shí)代,究竟需要什么樣的新技術(shù),才能真正解放IT生產(chǎn)力,我認(rèn)為是低代碼,一種可視化的應(yīng)用開發(fā)方法,即“用較少的代碼、以較快的速度來交付應(yīng)用程序”。
低代碼如果從表現(xiàn)形式來說確實(shí)不是新技術(shù),1980年就有了,但隨著前端各種新技術(shù)的出現(xiàn)及云原生時(shí)代的到來,低代碼讓我們看到了積極向上的一面;對用戶來說:圖形化操作,容易上手;內(nèi)置各種模板、組件,降低開發(fā)難度;可視化拖拽,開發(fā)效率高。對企業(yè)來說:能夠縮短產(chǎn)品周期;節(jié)省成本,提高效率;而且維護(hù)便利,即改即用。低代碼的優(yōu)勢這么的顯而易見,自然也會(huì)在 vivo 發(fā)揮它的價(jià)值。
隨著vivo互聯(lián)網(wǎng)用戶量級(jí)不斷增加,傳統(tǒng)開發(fā)已經(jīng)不能夠滿足井噴式的運(yùn)營需求,而后羿,正是我們探索解決方案過程中誕生的用于支撐運(yùn)營后臺(tái)業(yè)務(wù)高效高質(zhì)量落地的低代碼平臺(tái),目前已是vivo后臺(tái)業(yè)務(wù)首選的在線可視化開發(fā)平臺(tái),我們在平臺(tái)建設(shè)的過程中也沉淀了大量的經(jīng)驗(yàn),后面的內(nèi)容將會(huì)以后羿為背景來詳細(xì)展開。
接下來我們將從以下五個(gè)方面分別展開我們在低代碼方面的實(shí)踐:
- 前后端分離的低代碼方案
- 自研高性能渲染引擎
- 高效的可視化配置方案
- 千億級(jí)內(nèi)容投放
- 低代碼如何與傳統(tǒng)開發(fā)共存
二、前后端分離的低代碼方案
低代碼平臺(tái)常常前端部分要占據(jù)重頭戲,所以在早期,我們采用的是前端大包大攬的技術(shù)方案,但隨著業(yè)務(wù)量的劇增,我們遇到了各種各樣的訴求,比如后羿側(cè)是否可以輸出獨(dú)立頁面,或者支持純粹的服務(wù)端低代碼能力、產(chǎn)出獨(dú)立的接口服務(wù)等。為了解決問題及時(shí)響應(yīng)業(yè)務(wù)訴求,我們大刀闊斧的進(jìn)行了重構(gòu),在后續(xù)的版本,我們采用了前后端分離的低代碼方案,當(dāng)然,這種分離包括了“前后端開發(fā)分離"和“低代碼服務(wù)能力分離”,如下圖,我們能夠直觀的看到web開發(fā)兩種最基本的方式。
前后端分離較不分離的方式,分工更加明確,真正實(shí)現(xiàn)解耦;前端可以專注于頁面交互、用戶體驗(yàn)和兼容性,而后端則主要負(fù)責(zé)高并發(fā)、高可用、高性能、安全、存儲(chǔ)和業(yè)務(wù)邏輯,前后端分離的開發(fā)方式也是時(shí)下行業(yè)的主流選擇。我們再來看一下低代碼方式開發(fā)應(yīng)用的不同之處。
一種方式是產(chǎn)品視角,或者說是非開發(fā)的視角,當(dāng)我們在低代碼平臺(tái)搭建、開發(fā)業(yè)務(wù)時(shí),無需關(guān)心整個(gè)制品的具體分層和實(shí)現(xiàn)細(xì)節(jié),只需要使用平臺(tái)提供的能力來搭建我們所需的端側(cè)應(yīng)用即可,這種方式下用戶甚至無需具備專業(yè)的開發(fā)知識(shí)便可搭建出簡單的應(yīng)用,這種平臺(tái)往往也是無代碼平臺(tái)。
另一種則是開發(fā)視角,這種思維模式下,用戶至少會(huì)看到前端和后端兩種服務(wù),這兩種服務(wù)通常來說可能是頁面和接口,這種模式更加適合程序員,與日常開發(fā)思維保持一致,所以平臺(tái)學(xué)習(xí)成本也就很低,能夠簡單、快速的開發(fā)出更加復(fù)雜的應(yīng)用;后羿主要面向開發(fā)者,自然而然的采用了這種分層開發(fā)的模式。
低代碼平臺(tái)本身也需要開發(fā)者投入大量的開發(fā)精力,一個(gè)好的開發(fā)模式往往能夠事半功倍,目前流行的低代碼產(chǎn)品,大多是下圖所示兩大類實(shí)現(xiàn)方式。
前后端不分離實(shí)現(xiàn)會(huì)導(dǎo)致平臺(tái)的靈活性差、拓展性差、可集成度較低;反觀前后端分離實(shí)現(xiàn)的方式,我們可以設(shè)計(jì)簡單易懂的DSL,下發(fā)到開發(fā)側(cè)編譯轉(zhuǎn)換,發(fā)揮各自的優(yōu)勢;前后端版本迭代和優(yōu)化升級(jí)也可以做到互不干擾。
正如上圖,得益于前后端分離的分層架構(gòu),我們在前端服務(wù)層又分離出開發(fā)者平臺(tái)和運(yùn)營平臺(tái);開發(fā)者平臺(tái)專注于可視化搭建,運(yùn)營平臺(tái)面向最終的業(yè)務(wù)運(yùn)營;一個(gè)負(fù)責(zé)開發(fā)體驗(yàn),一個(gè)負(fù)責(zé)用戶體驗(yàn);后端則通過微服務(wù)架構(gòu)拆分出不同功能模塊,實(shí)現(xiàn)了平臺(tái)邏輯與業(yè)務(wù)邏輯的解耦。
前后端分離的方案,分層明確,解除耦合,而且前后端各自的服務(wù)也實(shí)現(xiàn)了邏輯分層,得益于這種架構(gòu),我們很輕松就實(shí)現(xiàn)了前后端低代碼能力的分離,來滿足更加復(fù)雜的業(yè)務(wù)訴求。
前文我們提到,前后端分離中還包括了前后端低代碼服務(wù)能力的分離。
如上圖所示,開發(fā)者平臺(tái)產(chǎn)出的DSL,傳遞到端側(cè),經(jīng)過各自的運(yùn)行時(shí)解析,便可以針對不同用戶提供不同的低代碼能力;這樣,用戶就可以使用平臺(tái)搭建頁面來連接自己的服務(wù),或者編排接口來為自己的頁面提供存儲(chǔ)服務(wù);既可以單獨(dú)配置頁面,也可以獨(dú)立使用接口服務(wù),這就是前后端低代碼能力的分離,前后端分別配置,也與傳統(tǒng)開發(fā)邏輯、思維方式一致,對開發(fā)者十分友好。
除此之外,前后端分離的方案,也帶來了其他的一些利好:前端側(cè)通過引入BFF層可輕松實(shí)現(xiàn)動(dòng)態(tài)接口代理、鑒權(quán)、日志;服務(wù)端也可以做接口的微服務(wù)化;通過功能拆分、組件懶加載等方式可以提升性能;也能夠更好的與傳統(tǒng)開發(fā)兼容,各施所長;前后端獨(dú)立部署更加靈活、高效;也更易被第三方應(yīng)用集成。
三、自研高性能渲染引擎
渲染引擎是由動(dòng)態(tài)表單渲染器、列表渲染器和動(dòng)態(tài)交互解釋器三部分組成的,他們能夠各司其職也可以相互配合,渲染引擎的主要作用就是將可視化操作生成的DSL翻譯成具有功能邏輯和交互的頁面、模板或組件。
先來看看表單渲染器,
眾所周知,表單場景一直都是前端中后臺(tái)領(lǐng)域最復(fù)雜的場景,通過自研的表單渲染引擎我們提供了表單數(shù)據(jù)管理、表單狀態(tài)管理、動(dòng)態(tài)渲染、組件聯(lián)動(dòng)等功能;基于JSONSchema驅(qū)動(dòng)的分層架構(gòu),實(shí)現(xiàn)了邏輯與UI框架解耦;通常,用戶只需要稍微了解幾個(gè)膠水層的API便可以快速上手;復(fù)雜的場景下,用戶還可以通過拓展組件屬性或開發(fā)自定義組件的方式來滿足需求;另外,我們還將表單實(shí)例掛載到了動(dòng)態(tài)交互的上下文,這樣我們就可以很輕松的實(shí)現(xiàn)各塊級(jí)組件聯(lián)動(dòng)和數(shù)據(jù)交互。
特別說明的是,自研完全是為了更加貼合業(yè)務(wù)需要,開源社區(qū)有很多優(yōu)秀的動(dòng)態(tài)解決方案,如formily2、x-render、formast,他們都有各自的優(yōu)缺點(diǎn),我們也是權(quán)衡了利弊之后選擇的自研,當(dāng)然我們也借鑒了x-render的api設(shè)計(jì)與formast的動(dòng)態(tài)語法表達(dá)式,我們追求的是簡單、好用、高性能及完全可控。
再來看看列表渲染器,
列表是前端中后臺(tái)領(lǐng)域又一個(gè)非常重要的場景,為了滿足各種各樣的列表需求,我們二次開發(fā)了vxe-table這個(gè)功能豐富的開源列表庫,各種工具,復(fù)雜表格、樹形表格、編輯表格、虛擬滾動(dòng)(ps:自定義渲染器的場景大數(shù)據(jù)的性能表現(xiàn)不佳)都是天然支持,我們額外內(nèi)置了圖片、視頻等15種常用的渲染場景;與表單渲染器相同,列表渲染器依然是基于json-schema驅(qū)動(dòng)的分層架構(gòu),學(xué)習(xí)成本極低,拓展簡單,也支持用戶自定義渲染器;同樣,我們也將列表實(shí)例掛載到了動(dòng)態(tài)交互的上下文,實(shí)現(xiàn)與其他塊級(jí)組件的聯(lián)動(dòng)和數(shù)據(jù)交互。
說到列表,我們提一下圖表,圖表你也可以理解為列表的另一種展現(xiàn)形式,有了列表的開發(fā)經(jīng)驗(yàn),圖表實(shí)現(xiàn)起來也十分輕松,只需要設(shè)計(jì)合理的DSL編譯后下發(fā)給第三方庫即可(如Echart),主要的思路還是和表單進(jìn)行聯(lián)動(dòng),由表單來驅(qū)動(dòng)查詢條件,執(zhí)行異步查詢,得到的數(shù)據(jù)經(jīng)過格式化后綁定到圖表即可。
有了表單和列表,已經(jīng)能夠搭出簡單頁面了,但是彈窗、按鈕交互、接口請求如何實(shí)現(xiàn)呢?動(dòng)態(tài)交互是前端低代碼最復(fù)雜也是最有趣的部分,下面就來揭開它的神秘面紗。
如上圖所示,由用戶點(diǎn)擊按鈕發(fā)起,彈出表單彈窗,填寫表單,發(fā)起接口請求,根據(jù)響應(yīng)結(jié)果提示和列表刷新,其中有的是用戶交互,有的則是程序在驅(qū)動(dòng);我們通過對這樣的動(dòng)態(tài)交互流程建模,可以抽象出流程源和一個(gè)個(gè)流程節(jié)點(diǎn);當(dāng)用戶觸發(fā)交互,一個(gè)個(gè)交互節(jié)點(diǎn)組成了動(dòng)態(tài)交互隊(duì)列,有序執(zhí)行,雖然實(shí)際情況可能會(huì)更復(fù)雜,有異步、有分支,但我們也僅僅通過不到30行的代碼便實(shí)現(xiàn)了整個(gè)動(dòng)態(tài)交互的驅(qū)動(dòng),我們把這個(gè)核心解決方案稱之為動(dòng)態(tài)交互解釋器,如下圖所示偽代碼。
同樣,動(dòng)態(tài)交互解釋器也是基于JSONSchema驅(qū)動(dòng)的分層架構(gòu),解釋器僅僅是一層膠水和內(nèi)置的交互流程節(jié)點(diǎn);執(zhí)行器主要的功能就是貯藏動(dòng)態(tài)節(jié)點(diǎn)、傳遞動(dòng)態(tài)上下文、解釋執(zhí)行動(dòng)態(tài)交互、流轉(zhuǎn)或終止流程。
前文我們多次提到了“將實(shí)例掛載到動(dòng)態(tài)交互上下文”,正如偽代碼中的ctx,這是一個(gè)響應(yīng)式的上下文,我們會(huì)根據(jù)不同的業(yè)務(wù)場景有選擇性的掛載表單、列表、圖表的實(shí)例及相關(guān)方法和諸如路由信息、全局狀態(tài)、應(yīng)用信息等其他用戶可能會(huì)需要的重要數(shù)據(jù),以便各流程節(jié)點(diǎn)可以實(shí)時(shí)的訪問實(shí)例和動(dòng)態(tài)修改對應(yīng)的實(shí)例,這樣就實(shí)現(xiàn)了各區(qū)塊間的聯(lián)動(dòng)交互。
動(dòng)態(tài)交互解釋器也支持自定義,在極其復(fù)雜的場景下我們可以通過添加自定義流程節(jié)點(diǎn)的方式來拓展功能,滿足需求。
四、高效的可視化配置方案
不同于其他低代碼平臺(tái),在后羿中,我們將頁面視為資源,按照資源級(jí)別來管理、發(fā)布我們的配置,這樣做的好處有兩個(gè):
- 第一、 我們可以根據(jù)資源的層級(jí)關(guān)系設(shè)計(jì)不同的導(dǎo)航風(fēng)格,可以是tab-history模式,也可以是面包屑模式,以及你能想到的任何菜單管理模式。
- 第二、 資源的管理與頁面的可視化配置解耦,管理更加高效;如上圖所示,除了可以隨時(shí)拖拽調(diào)整菜單結(jié)構(gòu),還可以一目了然的看到資源的詳細(xì)信息;得益于這種設(shè)計(jì),我們提供了針對資源級(jí)別的版本發(fā)布功能,可以實(shí)現(xiàn)一鍵迭代及線上熱更新;基于V消息的工單版本管理,安全高效可追溯,還能夠?qū)崿F(xiàn)秒級(jí)回退。
如上圖,我們還提供了模板、代碼片段功能,模板專注于同類型頁面的復(fù)用,代碼片段則專注于組件、功能邏輯的復(fù)用;通過復(fù)用,可以極大的降低開發(fā)時(shí)間,5分鐘搭建頁面不再是紙上談兵。
系統(tǒng)功能上我們提供了一鍵開啟常用的水印、菜單搜索、消息通知等功能,還可以配置多種類型客服信息,方便系統(tǒng)級(jí)的版本發(fā)布通知及日常的值班人員維護(hù)。
頁面內(nèi)容的配置我們采用了大家最習(xí)慣的從左到右的拖拽配置方式,可視化的配置方式便捷、高效,而且實(shí)時(shí)拖拽,即刻預(yù)覽。
動(dòng)態(tài)交互同樣支持可視化配置,流程的運(yùn)轉(zhuǎn)邏輯清晰的展示在畫布上,直觀又容易維護(hù)。
此外,我們還提供了一些貼心的功能:內(nèi)置動(dòng)態(tài)接口代理,一鍵開啟后,即可連接本地或mock服務(wù),開發(fā)調(diào)試非常方便;統(tǒng)一的服務(wù)配置入口,除了符合開發(fā)直覺, 也方便了系統(tǒng)層面的接口管理及復(fù)用,系統(tǒng)還會(huì)根據(jù)不同環(huán)境自動(dòng)執(zhí)行接口匹配。
我們提供了頁面結(jié)構(gòu)大綱視圖,只需點(diǎn)擊icon,便可以快速定位到組件,解決了復(fù)雜頁面查找組件的痛苦;
開發(fā)或迭代時(shí),對頁面的改動(dòng)無法追溯也是一個(gè)痛點(diǎn),于是我們內(nèi)置了版本比對,只需拖拽任意兩個(gè)版本到比對框,就可以實(shí)現(xiàn)兩者的精確比對,方便排查問題;每個(gè)版本也提供了版本快速回退,點(diǎn)擊即可一鍵回退。
右鍵功能也是提高配置效率的法寶,基于右鍵,我們提供了組件的復(fù)制粘貼,并且可以跨區(qū)塊、跨頁面、跨應(yīng)用的復(fù)制粘貼;右鍵也可以快速定位到組件的schema,修改schema也會(huì)實(shí)時(shí)同步到視圖;代碼片段的保存復(fù)用也是基于右鍵來提供。
得益于開發(fā)者平臺(tái)的分層設(shè)計(jì),只需按照編輯器協(xié)議配置,自定義組件同樣可以享受可視化的配置能力。
多層嵌套配置,是可視化中相當(dāng)痛苦的場景,于是我們提供了扁平化配置方案,比起層層堆疊的彈窗配置,配置更加方便,切換成本更低。
另外我們對新手用戶也十分友好,除了引導(dǎo)式配置,我們還提供了字段級(jí)功能說明及文檔指引,以降低配置門檻。
說到文檔(如上圖),這可能是很多低代碼平臺(tái)都會(huì)遇到的問題,我們認(rèn)為一個(gè)好的文檔必須要能夠指引用戶由淺入深的學(xué)習(xí)平臺(tái)的使用姿勢,否則會(huì)直接勸退一大批用戶,我們的用戶主要面向開發(fā)者,這里面還分離出前端、后端、應(yīng)用、AI、大數(shù)據(jù)等等,如何讓各崗位的同學(xué)都能夠找到想要的解決方案真的是很棘手,于是我們由淺入深,層層展開,簡單到手把手教學(xué),深入到整個(gè)核心庫的原理及實(shí)現(xiàn),并且還提供了海量的示例,包括數(shù)據(jù)聯(lián)動(dòng)、動(dòng)態(tài)交互、布局等等。
五、千億級(jí)內(nèi)容投放
內(nèi)容投放是否高效會(huì)直接影響用戶的選擇,后羿通過通用的 CURD 接口及可動(dòng)態(tài)插拔的業(yè)務(wù)模塊來實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)和處理。在用戶完成操作后統(tǒng)一執(zhí)行數(shù)據(jù)處理和入庫,并使用獨(dú)立的投放服務(wù)來快速分發(fā)到各業(yè)務(wù)系統(tǒng)。
對于五花八門的運(yùn)營數(shù)據(jù)我們會(huì)無差別的存放在MongoDB中;通過自定義的分倉策略來保證業(yè)務(wù)隔離和可擴(kuò)展;當(dāng)然也會(huì)涉及到數(shù)據(jù)的多級(jí)關(guān)聯(lián),自定義檢索等,多種手段的加持下才達(dá)到最后的精確分發(fā)。
后羿平臺(tái)承載了海量的業(yè)務(wù)數(shù)據(jù),面對巨大的用戶流量,我們必須保證投放的高可用。
如圖所示,我們在架構(gòu)上采用獨(dú)立鏡像服務(wù)來承載各個(gè)大流量業(yè)務(wù),各獨(dú)立服務(wù)又有本地緩存、磁盤緩存和獨(dú)立Redis集群來保證單體服務(wù)的高可用。
除了高可用,還要能夠支持高并發(fā),目前我們的QPS在百萬級(jí)別,每次請求可能會(huì)關(guān)聯(lián)查詢上百個(gè)表單,最終就會(huì)放大到千、萬億級(jí)別的表單查詢量。
我們通過異步加并發(fā)的方式提升服務(wù)的吞吐量,結(jié)合異步監(jiān)聽、動(dòng)態(tài)更新、定時(shí)重新加載等方式來提升系統(tǒng)的性能;多種手段的加持最終保證了服務(wù)的高并發(fā)。
對于個(gè)性化的業(yè)務(wù)訴求,我們還支持在后羿提供的SDK 上二次拓展,這部分與傳統(tǒng)的開發(fā)幾乎沒有區(qū)別。
六、低代碼如何與傳統(tǒng)開發(fā)共存
說到傳統(tǒng)開發(fā),那我們就來聊聊這個(gè)老生常談的話題:
- 低代碼如何與傳統(tǒng)開發(fā)共存?
- 低代碼會(huì)取代程序員嗎?
- 低代碼會(huì)不會(huì)干掉傳統(tǒng)開發(fā)?
- 首先我們要明確的是,兩者并不沖突!
低代碼也不是銀彈,而傳統(tǒng)開發(fā)有著天然的定制化優(yōu)勢,靈活且沒有限制,配套的技術(shù)也相當(dāng)成熟;所以我們認(rèn)為兩者共存,優(yōu)勢互補(bǔ)才能發(fā)揮更大的價(jià)值。
那后羿是如何實(shí)踐的呢?
一方面我們不斷的豐富場景模型,提高拓展能力和配置效率;另一方面則從底層架構(gòu)設(shè)計(jì)上兼容了傳統(tǒng)的定制化開發(fā);我們雙向支持iframe及微應(yīng)用,雙向意味著后羿產(chǎn)出的頁面可以嵌入到第三方應(yīng)用中,也接受第三方應(yīng)用嵌入到后羿中;并且支持頁面級(jí)、區(qū)塊級(jí)和組件級(jí)的嵌入。
這種設(shè)計(jì)除了可以發(fā)揮傳統(tǒng)開發(fā)優(yōu)勢,還能讓現(xiàn)存的老、舊應(yīng)用發(fā)揮余熱,簡單改造,就可以將他們集成到后羿,然后在此基礎(chǔ)上使用低代碼能力繼續(xù)維護(hù);得益于后羿將菜單與頁面內(nèi)容隔離設(shè)計(jì)的方案,我們可以輕松的實(shí)現(xiàn)與第三方應(yīng)用的兼容,不破換其自有的菜單管理體系。
傳統(tǒng)開發(fā)場景,為了讓大家專注于業(yè)務(wù)邏輯,我們打通了樹懶的資源快速部署能力,并且提供了多種類型的工程腳手架,支持腳本命令一鍵發(fā)布迭代;另外還支持素材托管,擁有獨(dú)立的業(yè)務(wù)空間,安全又便捷。
以上就是后羿的低代碼實(shí)踐經(jīng)驗(yàn),這么短的篇幅不足以揭開后羿的全貌,對于低代碼來說也只是杯水車薪,我們利用現(xiàn)有的資源、服務(wù)、基建(基建真的很重要)以最小的成本孵化出來了后羿低代碼平臺(tái),其實(shí)能做的還很多,我們也會(huì)持續(xù)探索,讓每個(gè)人都能享受到低代碼的樂趣。