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