9 月 29 日,掘金開發者 miss 發布了一篇約八千字的長文,完整記錄從零打造可視化規則編輯器的過程。場景很具體:在電網、金融、IoT 這些行業,業務規則一變就要找開發改程式碼、重新發版,每天都在發生。這個專案想解決的問題只有一句話,把規則的編寫權從開發手裡交還給業務人員。
成品左側是條件樹編排介面,右側即時顯示產生的 JSON 與執行結果,規則改完立刻能驗證。技術棧是 Vue 3、TypeScript、Vite、Pinia 與 Element Plus。這條路和先前介紹過的釘釘同款審批流設計器開源走的是同一個方向:企業內部系統的複雜邏輯,正一步步從程式碼搬進看得見的畫面。
最關鍵的決策:前端到底輸出什麼
文章作者把這一步稱為整個專案最關鍵的決策,做錯了後面全是返工。後端用的是老牌規則引擎 Drools,最直覺的做法是前端直接拼 DRL 規則字串丟給後端。作者想了兩天放棄,理由有兩個:DRL 語法會隨 Drools 版本演進,等於前後端要一起維護同一套語法;更麻煩的是前端無法本地執行 DRL,寫完規則只能盲發。
最終方案是前端只產標準 JSON,而且必須是引擎原生結構,不是自創的中間格式。這份 JSON 可以零轉換載入前端選用的 json-rules-engine-upgraded 做本地即時預覽,後端未來轉 DRL 也只需要認這一套結構。
用個比喻:與其讓客人直接寫廚房才懂的食譜,不如讓客人勾菜單,廚房自己翻譯。菜單改版容易,食譜寫錯卻會火災。
作者還給了一個務實的建議:選方案前,先拿真實資料把兩條路各寫一遍。他們用一條「220kV 主變過載保護」規則分別用 JSON 和 DRL 描述,DRL 版本要處理包宣告、import、salience、規則名唯一性,JSON 版本一個 all 欄位就完成,對比之下決策毫無懸念。
條件樹與遞迴:難在更新,不在結構
規則條件的本質是一棵可以無限嵌套的樹,葉子是條件,枝幹是 AND、OR、NOT 分組。資料結構直接照最終 JSON 設計,省掉一層轉換。真正卡住作者的課題是遞迴樹的不可變更新,改動深處某個節點時不能弄壞整棵樹的參照。
幾個實作細節值得做類似系統的團隊注意。NOT 節點在語意上只能有一個子節點,但使用者不會乖乖聽話,介面得主動引導或限制。除錯期最痛的是看不到每個條件各自的求值結果,作者為此做了逐條件的結果呈現。
三態語意與 fail-closed:工程判斷的核心
文章裡最有工程味道的一段,是 missing 與 error 必須分開處理。欄位不存在和欄位求值出錯是兩種不同的狀態,混在一起會讓規則結果無法解釋。搭配的原則是 fail-closed:錯誤絕不允許被翻譯成「命中」。對告警升級、保護跳閘這類規則來說,這條鐵律直接決定系統能不能被信任。
編輯即預覽用 300ms 防抖加手動對比實現,而雙引擎並排對比的設計更值得留意:本地 JSON 引擎的結果與後端 Drools 的結果放在一起,語意差異在開發期就能被發現,而不是等到上線後才收到事故報告。
對團隊的實際意義
這篇文章對兩種讀者有用。做企業內部系統的開發者,可以直接參考它的資料結構與取捨理由,尤其是「前端只產標準 JSON」與「fail-closed」兩個決策。管理流程系統的人,則可以看到規則維護成本下降的路徑:業務人員改完規則當場驗證,開發不再被零散的規則修改綁住發版週期。
規則引擎不是新東西,Drools 已經存在多年。新的變化在於前端框架與本地求值能力成熟之後,「誰有資格改規則」這個組織問題,開始有了技術上的答案。
主題