低代碼開發(fā)平臺核心組件集成和協(xié)同分析
今天準(zhǔn)備再寫一篇關(guān)于低代碼開發(fā)平臺的文章,在前面講云原生整體解決方案的時(shí)候,我談到過低代碼開發(fā)平臺,但是對里面的一些核心組件以及組件間的集成沒有展開描述,而這些剛好是一個(gè)低代碼開發(fā)平臺設(shè)計(jì)和實(shí)現(xiàn)的關(guān)鍵內(nèi)容。
低代碼平臺概述
對于低代碼開發(fā)平臺,百度詞條有一個(gè)基礎(chǔ)定義,如下:
低代碼開發(fā)平臺(LCDP)是無需編碼(0代碼)或通過少量代碼就可以快速生成應(yīng)用程序的開發(fā)平臺。通過可視化進(jìn)行應(yīng)用程序開發(fā)的方法(參考可視編程語言),使具有不同經(jīng)驗(yàn)水平的開發(fā)人員可以通過圖形化的用戶界面,使用拖拽組件和模型驅(qū)動的邏輯來創(chuàng)建網(wǎng)頁和移動應(yīng)用程序。低代碼開發(fā)平臺在完成業(yè)務(wù)邏輯、功能構(gòu)建后,即可一鍵交付應(yīng)用并進(jìn)行更新。
如果再對這個(gè)定義里面的關(guān)鍵內(nèi)容做下提取,其核心包括:
- 無須編碼或少量編碼
- 可視化和可配置化,通過組裝或配置構(gòu)建應(yīng)用
在這兩點(diǎn)之外,還有一個(gè)關(guān)于過程支撐層面的,即整個(gè)開發(fā)完成的應(yīng)用上線或交付過程應(yīng)該足夠簡單和自動化,包括上面提到的可以實(shí)現(xiàn)配置立即生效,實(shí)現(xiàn)一鍵交付等。
當(dāng)前有很多提供低代碼開發(fā)平臺的服務(wù)商,各家的方案或整體架構(gòu)雖然有差異,但是本質(zhì)的內(nèi)容基本還是一致,即一切皆是可配置,可建模的。
可以設(shè)想下開發(fā)一個(gè)簡單功能的過程,基本也就是數(shù)據(jù)庫表設(shè)計(jì),前端界面設(shè)計(jì),編寫邏輯層代碼和接口實(shí)現(xiàn)業(yè)務(wù)規(guī)則,掛接流程引擎實(shí)現(xiàn)流程,配置功能和數(shù)據(jù)權(quán)限等。
所以任何一個(gè)低代碼開發(fā)平臺都需要圍繞這個(gè)核心去抽象和建模,找出共性的和業(yè)務(wù)無關(guān)的東西進(jìn)行技術(shù)沉淀,即我們常說的。
完全標(biāo)準(zhǔn)的東西直接標(biāo)準(zhǔn)化
非標(biāo)準(zhǔn)但是同樣場景的東西,通過抽象差異來實(shí)現(xiàn)參數(shù)化配置
大家可以看到,實(shí)際我們LCDP平臺的構(gòu)建基本就是圍繞上面思路展開。那么一個(gè)LCDP平臺的核心要素究竟是啥,具體我重新畫了一張圖來說明。
即LCDP平臺的核心包括了上圖中的數(shù)據(jù)建模,表單建模,流程建模,權(quán)限建模,報(bào)表建模和規(guī)則建模幾個(gè)關(guān)鍵部分的內(nèi)容,通過這些建模組件,包括這些組件之間本身的協(xié)同來完成一個(gè)完整業(yè)務(wù)系統(tǒng)和功能的構(gòu)建。
對象建模驅(qū)動
一個(gè)好的低代碼開發(fā)平臺應(yīng)該是以對象建模為驅(qū)動的,這個(gè)有點(diǎn)類似于很早以前談到的MDA模型驅(qū)動架構(gòu)的思想。即首先進(jìn)行對象建模,這里的對象更偏業(yè)務(wù)對象或領(lǐng)域?qū)ο?,一個(gè)對象本身可以對應(yīng)到多張數(shù)據(jù)庫表,可以是層次結(jié)構(gòu)表,也可以是管理結(jié)構(gòu)表。
對象建模完成,朝前可以暴露領(lǐng)域服務(wù)能力接口,朝后可以對接數(shù)據(jù)庫進(jìn)行持久化。當(dāng)暴露領(lǐng)域服務(wù)能力接口的時(shí)候更加容易實(shí)現(xiàn)前端和后端邏輯之間的徹底分離和解耦,同時(shí)在領(lǐng)域服務(wù)實(shí)現(xiàn)內(nèi)部也更容易進(jìn)行相關(guān)的事務(wù)控制。
在采用對象建模后,實(shí)際在后端模型和前端界面之間增加了一個(gè)對象服務(wù)層,對象服務(wù)通過API接口方式對外提供,這個(gè)和SOA分層應(yīng)用構(gòu)建思路是吻合的。
在對象建模完成后,對象本身朝下可以生成數(shù)據(jù)庫表,朝上可以發(fā)布API接口服務(wù)。而對于表單建模不再直接和數(shù)據(jù)庫表關(guān)聯(lián),而是直接引用對應(yīng)的API接口服務(wù),在這種情況下對應(yīng)API接口服務(wù)本身也會啟用強(qiáng)服務(wù)契約模式進(jìn)行定義和設(shè)計(jì)。
當(dāng)有了獨(dú)立的接口層的時(shí)候,可以看到要實(shí)現(xiàn)上層功能組合或組裝將變得更加容易和方便,即我們可以提供一個(gè)類似傳統(tǒng)BPEL流程或服務(wù)編排的工具,可視化來進(jìn)行上層業(yè)務(wù)的接口組裝和編排。
表單和流程引擎集成
當(dāng)前市面上很多低代碼平臺本身即是從傳統(tǒng)的BPM軟件或工作流引擎平臺演變而來的,因此流程引擎本身是低代碼平臺底層很重要的一個(gè)技術(shù)服務(wù)能力支持。
對于流程引擎本身和組織模型綁定緊密,以進(jìn)行相應(yīng)的細(xì)粒度數(shù)據(jù)權(quán)限控制和流程動態(tài)權(quán)限控制,在這里先不描述具體的組織引擎和流程引擎集成點(diǎn),而重點(diǎn)分析表單和流程引擎的集成。
表單設(shè)計(jì)掛接流程
可以先看下最簡單的一個(gè)場景,即表單設(shè)計(jì)和流程設(shè)計(jì)本身即分離的,可以提前先設(shè)計(jì)好流程模板,產(chǎn)生一個(gè)流程模板ID,然后開始進(jìn)行表單設(shè)計(jì)。表單設(shè)計(jì)完成后,可以選擇一個(gè)流程模板ID進(jìn)行掛接。
在這種場景下表單在提交的時(shí)候啟動流程本身也簡單,即:
- //GenerateFormID();
- //Form.Save();
- //StartWorkflow(Formid,WorkflowTemplateID,Userid);
流程審核人填寫擴(kuò)展信息
如果掛接的流程,所有流程節(jié)點(diǎn)的處理人都是簡單的審核通過不通過,填寫要給處理意見,那么上面的處理方式完全滿足。但是更多情況下審核時(shí)候需要填寫擴(kuò)展信息。
比如一個(gè)供應(yīng)商創(chuàng)建申請單,流轉(zhuǎn)到采購經(jīng)理處審核的時(shí)候,采購經(jīng)理需要確定供應(yīng)商的等級,并上傳供應(yīng)商相關(guān)資質(zhì)信息。供應(yīng)商等級和供應(yīng)商資質(zhì)兩個(gè)數(shù)據(jù)項(xiàng)本身是屬于供應(yīng)商對象建模的基礎(chǔ)數(shù)據(jù)項(xiàng)信息,但是不在單據(jù)提交的時(shí)候維護(hù),而是在審核時(shí)維護(hù)。
在這種場景下可以看到不能簡單的在表單和流程模板之間建立簡單的關(guān)聯(lián)和映射,而是應(yīng)該在表單數(shù)據(jù)項(xiàng)和流程節(jié)點(diǎn)之間進(jìn)行映射。單獨(dú)數(shù)據(jù)項(xiàng)進(jìn)行映射粒度太細(xì),因此可以在表單設(shè)計(jì)的時(shí)候引入數(shù)據(jù)分組,處理數(shù)據(jù)分組和流程活動節(jié)點(diǎn)之間的映射即可。
如上圖,對表單數(shù)據(jù)進(jìn)行分組,并建立流程活動節(jié)點(diǎn)和表單分組之間的映射和授權(quán)關(guān)系。整體的表單提交和審批流程就變化為:
- 申請人提交表單信息,只能看到基本信息
- 審批1進(jìn)入審批,可以看到擴(kuò)展分組,并對數(shù)據(jù)維護(hù)再提交審批結(jié)果
- 審批2進(jìn)入可以看到三個(gè)分組信息,但是只能對擴(kuò)展分組2進(jìn)行數(shù)據(jù)維護(hù),并審核提交結(jié)果
- 流程監(jiān)控中,對于已經(jīng)執(zhí)行到的節(jié)點(diǎn),擴(kuò)展分組信息可見
即以上既實(shí)現(xiàn)基于流程的參與人動態(tài)權(quán)限控制,同時(shí)又實(shí)現(xiàn)了流程參與人可以在審核流程的過程中對流程表單信息進(jìn)行維護(hù)和填寫。擴(kuò)展分組信息在維護(hù)后仍然保持在基礎(chǔ)的對象數(shù)據(jù)表,而非流程實(shí)例表中,流程實(shí)例表僅僅只負(fù)責(zé)狀態(tài)流轉(zhuǎn)和下一個(gè)階段流程參與人計(jì)算等。
動態(tài)權(quán)限+數(shù)據(jù)權(quán)限控制
動態(tài)權(quán)限簡單來說就是你在處理流程節(jié)點(diǎn)過程中有權(quán)限查看表單數(shù)據(jù),但是處理完成后你的權(quán)限即回收?;蛘哒f你僅僅能夠看你審核和處理的表單,而不是所有的供應(yīng)商表單數(shù)據(jù)。而數(shù)據(jù)權(quán)限則是確認(rèn)你具體可以看到整個(gè)數(shù)據(jù)對象的哪些數(shù)據(jù)項(xiàng),比如前面的分組授權(quán)也是常用的控制數(shù)據(jù)權(quán)限的方式。
表單保存和流程啟動流轉(zhuǎn)解耦
當(dāng)流程引擎獨(dú)立作為技術(shù)服務(wù)實(shí)現(xiàn)的時(shí)候,可以看到對于流程啟動,流程流轉(zhuǎn)等都是調(diào)用的API接口服務(wù)來完成,那么這個(gè)時(shí)候就形成了分布式事務(wù)場景。
比較好的做法仍然是表單存儲和流程API服務(wù)之間需要異步解耦,即對流程流轉(zhuǎn)觸發(fā)請求先寫入到消息中間件,然后在異步訂閱消息隊(duì)列數(shù)據(jù)來啟動流程或流轉(zhuǎn)節(jié)點(diǎn)。
流程規(guī)則實(shí)現(xiàn)
在整個(gè)流程的處理中,還涉及到規(guī)則的處理和實(shí)現(xiàn),而對于規(guī)則可以理解為兩種。
其一是簡單的判斷規(guī)則,比如報(bào)銷單金額超過1萬需要流轉(zhuǎn)到總經(jīng)理審核;還有一種是負(fù)責(zé)規(guī)則判斷,比如需要進(jìn)行詳細(xì)預(yù)算完整性檢查,通過和不通過需要流轉(zhuǎn)到不同分支。
結(jié)合傳統(tǒng)流程引擎實(shí)現(xiàn)方式,對于簡單規(guī)則可以走參數(shù)變量傳遞,而對于復(fù)雜規(guī)則,則可以考慮直接調(diào)用外部API接口服務(wù)來實(shí)現(xiàn)校驗(yàn)。
在這里只傳遞需要用作流程判斷的數(shù)據(jù)項(xiàng)目信息參數(shù)到流程執(zhí)行中,本身也減少資源負(fù)荷。對于Param信息的傳遞,一個(gè)思路是在流程實(shí)例啟動后進(jìn)行緩存,一個(gè)是在每一個(gè)流程活動節(jié)點(diǎn)執(zhí)行的時(shí)候都重新傳入。個(gè)人建議方式是在流程實(shí)例啟動的時(shí)候進(jìn)行緩存。
表單和組織權(quán)限模型集成
在前面已經(jīng)談到對象建模要和表單建模分離,即一個(gè)對象建模完成后,實(shí)際基于這個(gè)對象可以構(gòu)建多個(gè)不同的表單模型,還是拿供應(yīng)商舉例。
一個(gè)供應(yīng)商即使不掛接流程也可以拆分為供應(yīng)商完整信息維護(hù),供應(yīng)商銀行信息維護(hù),供應(yīng)商模糊查詢,供應(yīng)商資質(zhì)信息查詢,特定供應(yīng)商信息查詢等不同的表單功能,但是這些表單功能都對應(yīng)同一個(gè)對象模型。表單設(shè)計(jì)完成后形成的是表單功能。一個(gè)表單設(shè)計(jì)完成后,可以掛接到具體的功能菜單上,同時(shí)也可以和某個(gè)具體的操作按鈕或事件綁定。簡單來說就是表單本身可能是存在入口參數(shù)的。
一個(gè)供應(yīng)商查詢功能表單,查詢結(jié)果是列表,可以點(diǎn)列表里面的詳細(xì)信息鏈接,這個(gè)時(shí)候應(yīng)該調(diào)整到特定供應(yīng)商查看界面,那么供應(yīng)商ID就是重要的傳入?yún)?shù)。
可以看到整體權(quán)限控制思路仍然是基于角色+資源的訪問授權(quán)。
一個(gè)表單掛接到菜單資源,菜單可以授權(quán)給用戶組或角色。同樣,對應(yīng)表單設(shè)計(jì)中的數(shù)據(jù)項(xiàng)或數(shù)據(jù)分組也可以定義為需要細(xì)粒度控制的資源對象,在資源定義完成后講資源對象授權(quán)到具體的用戶組或角色,包括表單中的按鈕等都可以采用該思路進(jìn)行。
即在表單建模完成后,我們需要對建模完成的表單抽象資源對象,資源對象可以是一個(gè)獨(dú)立的數(shù)據(jù)項(xiàng),也可以是數(shù)據(jù)分組或者按鈕操作。同時(shí)再將資源對象和角色或用戶進(jìn)行綁定。
數(shù)據(jù)項(xiàng)權(quán)限默認(rèn)設(shè)置
一個(gè)數(shù)據(jù)項(xiàng)權(quán)限配置最好是既支持默認(rèn)可見,也支持默認(rèn)不可見。比如采購訂單金額只對采購總結(jié)可見,那么這個(gè)數(shù)據(jù)項(xiàng)目默認(rèn)值則是全不可見,同時(shí)將金額定義為資源,授權(quán)給采購總監(jiān)角色。
靜態(tài)權(quán)限和動態(tài)權(quán)限重疊
當(dāng)靜態(tài)權(quán)限和動態(tài)權(quán)限重疊時(shí)候如何處理?一般來說應(yīng)該是以動態(tài)權(quán)限為主,比如靜態(tài)權(quán)限設(shè)置是沒有權(quán)限,但是動態(tài)權(quán)限計(jì)算后可操作或可維護(hù),那么該用戶在動態(tài)流程執(zhí)行中對相關(guān)信息就具備動態(tài)權(quán)限控制。流程處理完后權(quán)限即消失。
表單和規(guī)則引擎
對于低代碼開發(fā)平臺來講,實(shí)際上我個(gè)人并不建議引入比較重的規(guī)則引擎,要明白如果真的業(yè)務(wù)規(guī)則很復(fù)雜,用規(guī)則引擎同樣需要寫大量的腳本代碼才能夠?qū)崿F(xiàn),而且這個(gè)腳本代碼本身后續(xù)更加難以維護(hù)。
規(guī)則引擎出來這么多年,實(shí)際現(xiàn)在很少看到很成熟的在企業(yè)信息化領(lǐng)域的應(yīng)用場景。
對于規(guī)則,我們可以分開來看。
一種是基于當(dāng)前前端已有的表單數(shù)據(jù)就能夠進(jìn)行計(jì)算和校驗(yàn)的規(guī)則,這類規(guī)則一般為參考完整性規(guī)則,比如當(dāng)我在電商平臺訂購商品的時(shí)候,選擇了10件商品,都有不同的折扣,但是有些折扣不能同時(shí)共享,那么這個(gè)時(shí)候前端就能夠完成規(guī)則計(jì)算給出一個(gè)最佳折扣和總費(fèi)用。對于這類規(guī)則,表單設(shè)計(jì)器是需要支持的,最好方式是能夠腳本化,可以自己寫簡單的規(guī)則定義腳本并進(jìn)行處理。
還有一類規(guī)則為需要調(diào)用后端數(shù)據(jù)才能夠完成計(jì)算的規(guī)則。比如在提交報(bào)賬單據(jù)申請的時(shí)候,需要在后臺校驗(yàn)當(dāng)前預(yù)算是否足夠和滿足,滿足的才能夠提交。
第二類規(guī)則實(shí)際才是規(guī)則引擎可能涉及的場景。
即在第二類場景下整體流程可以理解為
- 在規(guī)則模型中定義規(guī)則,規(guī)則接受輸入并產(chǎn)生輸出
- 表單傳入關(guān)鍵param參數(shù)到規(guī)則引擎
- 規(guī)則引起基于param參數(shù)從數(shù)據(jù)庫后臺獲取數(shù)據(jù)
- 基于提前定義的規(guī)則進(jìn)行規(guī)則計(jì)算
- 返回規(guī)則計(jì)算結(jié)果給表單前端
f如果規(guī)則復(fù)雜你會看到規(guī)則是不能通過簡單的配置就實(shí)現(xiàn)的,仍然需要寫大量的規(guī)則腳本代碼。那么在這種情況下更推薦的方式是自己來實(shí)現(xiàn)自定義的API接口。
表單設(shè)計(jì)過程中,對于關(guān)鍵事件點(diǎn)都可以調(diào)用自定義API接口。
當(dāng)前快速開發(fā)平臺叫低代碼開發(fā)是合適的一個(gè)叫法,即不要期望所有復(fù)雜地方都能夠配置出來,特別是復(fù)雜規(guī)則實(shí)現(xiàn)。最好的方式就是復(fù)雜規(guī)則仍然是自己寫代碼實(shí)現(xiàn)接口,然后在表單建模和流程建模的時(shí)候能夠調(diào)用自己寫好的API接口方法。
事件是一個(gè)軟件開發(fā)里面標(biāo)準(zhǔn)概念,點(diǎn)擊按鈕,下拉選擇框,焦點(diǎn)移出等都可以觸發(fā)事件。對于事件觸發(fā)后在無規(guī)則的情況下就會調(diào)用表單自己的處理邏輯。
比如保存按鈕,事件觸發(fā)后就調(diào)用表單保存操作對數(shù)據(jù)進(jìn)行保存。但是實(shí)際上你會看到在保存前你可能需要進(jìn)行業(yè)務(wù)規(guī)則和邏輯處理,在保存后你可能觸發(fā)其它關(guān)聯(lián)操作。
- //Form.SaveBefore();
- //Form.Save
- //Form.SaveAfter();
當(dāng)前在保存前你還可能調(diào)用多個(gè)API接口進(jìn)行多個(gè)校驗(yàn)。
這個(gè)時(shí)候就出現(xiàn)另外一個(gè)關(guān)鍵點(diǎn),即不僅僅是支持事件前后調(diào)用外部API接口,還需要支持對API接口進(jìn)行簡單的編排。
實(shí)際上你可以看到,對于一個(gè)完整的低代碼開發(fā)平臺,面對各種復(fù)雜業(yè)務(wù)場景的時(shí)候,這種開放的編排能力是必須的。這種編排思路實(shí)際和SOA上的服務(wù)組合或流程編排思路是一致的。
服務(wù)組合編排
還是以電商產(chǎn)品購買為例,在進(jìn)行訂單提交的時(shí)候,如果需要同時(shí)處理三個(gè)動作。即調(diào)用訂單對象的保存操作,調(diào)用庫存對象的庫存扣減,調(diào)用配送單對象的配送單自動創(chuàng)建。
在這種場景下你可以看到如果沒有服務(wù)組合和編排能力是很難實(shí)現(xiàn)的。
即將對象建模暴露的接口能力進(jìn)一步進(jìn)行可視化的組裝和編排,形成組合服務(wù)能力再暴露給表單設(shè)計(jì)中使用。
一個(gè)好的低代碼開發(fā)平臺參考SOA分層架構(gòu)思想和領(lǐng)域建模思想是必要的,即對象建模設(shè)計(jì)完成后暴露API接口服務(wù)能力,前臺的表單設(shè)計(jì)是和API接口服務(wù)層進(jìn)行交互。這種設(shè)計(jì)方式方便后續(xù)進(jìn)行服務(wù)能力編排的擴(kuò)展。
即使前期沒有可視化服務(wù)編排能,我們也可以自定義API接口服務(wù)能力進(jìn)行接入。