作者:vivo 網際網路前端團隊- Wang Ning
本文根據王寧老師在「2022 vivo開發者大會"現場演講內容整理而成。公眾號回覆【2022 VDC】獲取網際網路技術分會場議題相關資料。
本文主要從前後端分離的低程式碼方案、自研高效能渲染引擎、高效的視覺化設定方案、千億級內容投放、低程式碼如何與傳統開發共存等五個維度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及微應用,雙向意味著后羿產出的頁面可以嵌入到第三方應用中,也接受第三方應用嵌入到后羿中;並且支援頁面級、區塊級和元件級的嵌入。
這種設計除了可以發揮傳統開發優勢,還能讓現存的老、舊應用發揮餘熱,簡單改造,就可以將他們整合到后羿,然後在此基礎上使用低程式碼能力繼續維護;得益於后羿將選單與頁面內容隔離設計的方案,我們可以輕鬆的實現與第三方應用的相容,不破換其自有的選單管理體系。
傳統開發場景,為了讓大家專注於業務邏輯,我們打通了樹懶的資源快速部署能力,並且提供了多種型別的工程腳手架,支援指令碼命令一鍵釋出迭代;另外還支援素材託管,擁有獨立的業務空間,安全又便捷。
以上就是后羿的低程式碼實踐經驗,這麼短的篇幅不足以揭開后羿的全貌,對於低程式碼來說也只是杯水車薪,我們利用現有的資源、服務、基建(基建真的很重要)以最小的成本孵化出來了后羿低程式碼平臺,其實能做的還很多,我們也會持續探索,讓每個人都能享受到低程式碼的樂趣。