規則引擎

2009 年 1 月 7 日

我應該使用規則引擎嗎?

規則引擎的重點在於提供一種替代的運算模型。規則引擎並非採用常見的命令式模型(由帶有條件和迴圈的順序命令組成),而是基於產生式規則系統。這是一組產生式規則,每條規則都有一個條件和一個動作,簡單來說,你可以將其視為一堆 if-then 敘述。

微妙之處在於,規則可以按任何順序撰寫,引擎會決定在什麼時候評估規則,並使用對其有意義的順序。一個很好的思考方式是,系統會執行所有規則,挑選條件為真的一組規則,然後評估對應的動作。這樣做的好處是,許多問題自然符合此模型

  if car.owner.hasCellPhone then premium += 100;
  if car.model.theftRating > 4 then premium += 200;
  if car.owner.livesInDodgyArea && car.model.theftRating > 2 
     then premium += 300;

規則引擎是一種工具,讓你可以更輕鬆地使用此運算模型進行程式設計。它可以是一個完整的開發環境,或是一個可以與傳統平台搭配運作的架構。近年來我所見過的大多數工具都是設計成可以與現有平台配合使用的。曾經有一段時間,人們認為可以使用此類工具建構整個系統,但現在人們(明智地)傾向於只將規則引擎用於系統的某些部分。產生式規則運算模型最適合用於運算問題的子集,因此規則引擎最好嵌入到較大的系統中。

你可以自己建構一個簡單的規則引擎。你所需要做的,就是建立一堆具有條件和動作的物件,將它們儲存在一個集合中,然後執行這些物件以評估條件並執行動作。但大多數時候,當人們提到「規則引擎」時,他們指的是專門建構來協助你建構和執行規則引擎的產品。指定規則的技術可能有所不同,從供人們將規則描述為 Java 物件的 API,到用於表達規則的 DSL,再到允許人們輸入規則的 GUI。更有效率的執行引擎有助於使用特殊演算法(例如 Rete 演算法)快速評估數百條規則的條件。

規則引擎的一個重要特性是串接,其中一條規則的動作部分會以一種方式變更系統狀態,進而改變其他規則條件部分的值。串接聽起來很有吸引力,因為它支援更複雜的行為,但很容易最後變得非常難以推理和除錯。

我遇到過一些案例,人們使用規則引擎產品,每次事情似乎都沒有順利進行(免責聲明:我不是一個統計學上有效的樣本)。規則引擎的核心宣傳通常是它允許業務人員自行指定規則,以便他們可以在不涉及程式設計師的情況下建立規則。這聽起來很合理,但實際上很少奏效。

儘管如此,BusinessReadableDSL 仍然有價值,事實上,這是這個計算模型中我看到價值的領域。但這裡也有陷阱。最大的陷阱是,雖然逐條查看規則清單並確認每條規則都有道理是合理的,但規則之間的交互作用通常會很複雜,特別是鏈接。因此,我經常聽說建立規則系統很容易,但維護起來非常困難,因為沒有人能理解這種隱含的程式流程。這是放棄命令式計算模型的黑暗面。儘管命令式程式碼有各種缺點,但理解其工作原理相對容易。對於生產規則系統,似乎很容易達到這樣一個地步:一個地方的簡單變更會導致許多意想不到的後果,而這些後果很少會產生好的結果。

我沒有花足夠的時間使用這些系統來了解我們應該遵循哪些啟發法,以控制這種隱含行為。

  • 確實,限制規則數量似乎很重要,事實上,任何需要複雜演算法才能獲得良好效能的規則系統,可能規則太多而無法理解。
  • 非常小心地使用鏈接,通常最好組織規則以限制甚至消除鏈接
  • 在許多地方,測試通常被低估,但隱含行為使得測試變得更加重要,並且需要使用生產資料進行測試。
  • 在建立規則系統時,我希望能做一些會導致修改規則庫時產生早期痛苦 的事情。

所有這些都讓我認為,避免使用規則引擎產品有很多好處。生產規則的基本概念非常簡單。為了控制隱含行為,您還需要通過將規則保持在狹窄的範圍內來限制規則數量。這主張採用更特定於領域的方法來制定規則,其中團隊建立一個有限的規則引擎,該引擎僅設計用於在該狹窄的範圍內工作。如果您正在考慮使用規則引擎,我建議使用產品和手工編寫的特定於領域的方法進行原型製作,以便您可以很好地了解它們的比較方式。

有關建立您自己的簡單規則引擎的更多資訊,包括幾個玩具範例,請參閱 生產規則系統 一章,這是 我的 DSL 書籍 的一部分。