Provisa 中的業務邏輯¶
問題所在¶
每個組織都有業務邏輯的標準,大多數團隊亦都遵守。然而多年下來,隨著系統不斷建設和替換、團隊不斷更替,邏輯分散到了 ETL 作業、儀表板、API 和預存程序之中。每一塊單獨看都說得通。常常沒有人規劃過整體,更常見的是沒有人跨越時間規劃過整體。結果大家都很熟悉:「淨收入」在三個地方有三種算法,沒有人說得清哪個是對的。
業界對其中的部分問題已有答案。指標層常以語義層的名義出售,它把「淨收入」定義一次,供每個工具讀取。Open Data Product Standard(ODPS,開放資料產品標準)描述資料產品,Open Data Contract Standard(ODCS,開放資料合約標準)描述資料合約。Provisa 兩者都能匯出。這些都是好主意,亦都越來越受歡迎,但每個只涵蓋一部分。更大的問題是,它們如何作為一個連貫、可組合的模型融入受控、受管治的資料。衍生或更改資料的邏輯需要與資料本身同樣的管治:誰可以使用它,它讀取和寫入甚麼,它的結果去往哪裡。
交付渠道令情況更差。邏輯被分別建構進每個渠道:BI 工具裡的計算欄位、API 處理程式裡的規則、應用程式解析器裡的篩選條件。每個渠道最終都有自己版本的真相,因此同一個問題透過其中兩個渠道提出,很少得到相同的答案。最終,人們放棄了:他們開始把這種混亂當作專業分工和服務眾多不同持份者的代價來接受。
甚麼是業務邏輯¶
業務邏輯是建立、更新、刪除或轉換數據的規則。
業務術語是另一回事。網域、表和欄的名稱與描述,以及本體中的術語,說明數據的含義。業務邏輯說明對數據做了甚麼。
三種角色¶
每條規則扮演三種角色之一,每種角色都可以用三種方式編寫:
| 角色 | SQL | 外部呼叫 | 程式碼 |
|---|---|---|---|
| 數據集 | 視圖、語句指令 | 返回行的 API 或預存程序 | 程式碼解析器 @table, @stream; python 或 script 命令 |
| 值 | 視圖運算式、指標 | — | python 或 script 命令 |
| 變更 | INSERT, UPDATE, DELETE, 語句指令 |
API 寫入、mutation、預存程序 | @command; python 或 script 命令 |
- 外部呼叫。 另一個系統的 GraphQL、REST 或 gRPC API,或數據庫的預存程序,登錄為指令。
- 以表作為參數。 命令可以接收表作為參數,因此一個資料集可以由其他資料集建構。
- 指標。 一個只定義一次的具名聚合,例如把
net_revenue定義為SUM(orders.amount) - SUM(orders.refunds)。每個查詢按自己要求的維度展開它,因此數據倉庫、儀表板和 API 讀到的是同一個數字。
隱藏的副作用¶
隱藏的副作用是從規則的定義中看不出來的副作用。
每條規則都有名稱和類型,並且已登錄、受稽核、受保護。 命令亦可以要求在執行前獲得審批。
| 可能的副作用 | 限制方式 | |
|---|---|---|
| SQL | 無 | — |
| 外部呼叫 | 另一個系統自身的工作流程、通知和連鎖操作 | 出站允許清單(HTTP、gRPC);以密鑰保存的憑證(預存程序、來源操作) |
| 程式碼解析器 | 對外部服務和網絡的呼叫;結果會變化;成本 | 固定的程式碼、固定的主機指紋、沙盒、計量 |
| 主機程式碼 | 能讀取伺服器能讀取的一切(記憶體、憑證、檔案、網絡);可能耗盡伺服器資源或令其停機 | commands.allow_host_code, 預設關閉 |
外部呼叫的類型來自該系統自身的結構描述,或你登錄指令時宣告的參數和返回欄。
程式碼解析器的程式碼按套件版本、Git 提交或封存檔雜湊固定,因此隨模型一起推廣。
主機程式碼是 python 或 script 命令。它在伺服器內部執行,擁有伺服器的全部存取權限,因此惡意、有缺陷或貪婪的程式碼能讀取伺服器能讀取的一切,耗盡其資源或令其停機。它很方便,在你信任這段程式碼時亦是安全的。模型只保存一個參照(module:attr 或一條命令列),因此程式碼不會隨推廣一起遷移。它只在 commands.allow_host_code 開啟的地方執行。
這些限制能約束副作用,但無法消除它們。外部系統或你自己的程式碼做甚麼,最終取決於它自己。
模型帶給你甚麼¶
- 邏輯存在於模型之中,而不是渠道之中。每個渠道(SQL、GraphQL、REST、Arrow Flight、MCP 等)都讀取相同的規則,因此同一個問題在任何地方都得到相同的答案。
- 每條規則都登錄在一個網域中,並有授權。
- 每條規則都以同樣的方式治理,無論它如何編寫。
- 每條規則都在血緣中可見。