Everything about Grule Engine

Trong hầu hết các hệ thống enterprise, business logic luôn là phần thay đổi nhiều nhất. Hôm nay Marketing muốn giảm giá 20% cho VIP, ngày mai đổi thành 15%. Tháng sau lại bổ sung Flash Sale, Voucher, Member Day, Birthday và hàng chục campaign mới.
Nếu toàn bộ logic đều được hardcode bằng if-else hoặc switch-case, codebase sẽ nhanh chóng trở thành một "mê cung" khó bảo trì.
Đó là lúc Grule Engine phát huy giá trị.
Grule là một Business Rule Engine (BRE) dành cho Golang, cho phép tách business logic khỏi source code bằng cách định nghĩa các rule dưới dạng DSL (Domain Specific Language). Ứng dụng chỉ cần cung cấp dữ liệu, còn Grule sẽ quyết định rule nào được áp dụng và thực thi theo đúng thứ tự.

1. Business Context

Hãy lấy một bài toán quen thuộc: Promotion Engine.
Một hệ thống thương mại điện tử có thể phải xử lý hàng trăm quy tắc như:
  • VIP Discount
  • Voucher
  • Flash Sale
  • Brand Promotion
  • Category Promotion
  • Birthday Reward
  • New User
  • Payment Method
  • Campaign
  • Supplier
  • Shipping Promotion
Ban đầu, code có thể rất đơn giản.
ifuser.IsVIP&&order.Amount>1_000_000 {discount=20 }elseiforder.Amount>500_000 {discount=10 }ifcampaign=="SUMMER" {discount+=5 }ifuser.NewUser {discount+=10 }ifpayment=="VISA" {discount+=5 }
Sau vài tháng phát triển, số lượng điều kiện tăng lên hàng trăm.
if ... else if ... else if ... ...
Mỗi lần business thay đổi, developer phải:
  • sửa source code
  • review
  • test
  • build
  • deploy
Trong khi đó, điều duy nhất thay đổi chỉ là một con số:
VIP giảm từ 20% xuống 15%
Đây là dấu hiệu điển hình cho thấy business logic đang bị gắn chặt với application logic.

Grule giải quyết vấn đề như thế nào?

Thay vì viết logic trong Go, ta định nghĩa rule riêng.
rule VIPDiscount "VIP Discount" salience 100 { when User.IsVIP == true && Order.Amount > 1000000 then Discount.Value = 20; Retract("VIPDiscount"); }
Rule cho khách hàng mới
rule NewUser { when User.NewUser == true then Discount.Value += 10; }
Rule thanh toán bằng VISA
rule VisaPayment { when Payment.Method == "VISA" then Discount.Value += 5; }
Ứng dụng chỉ cần thực hiện:
engine.Execute(dataContext)
Toàn bộ việc đánh giá điều kiện, xác định thứ tự và thực thi rule sẽ do Grule đảm nhiệm.

Vì sao Rule Engine phù hợp với các hệ thống lớn?

Tách business logic khỏi application

Application chỉ tập trung vào:
  • API
  • Database
  • Kafka
  • Redis
  • Logging
  • Monitoring
Business rule được lưu riêng:
promotion.grl voucher.grl shipping.grl member.grl
Điều này giúp business có thể thay đổi mà không ảnh hưởng tới core application.

Business thay đổi liên tục

Hôm nay:
Order > 500k
Ngày mai:
Order > 700k
Nếu hardcode:
Code change → Build → Deploy
Nếu dùng Grule:
Edit .grl → Reload

Hàng trăm rule vẫn dễ quản lý

Một Promotion Engine thực tế có thể có hơn 500 rule.
Ví dụ:
  • Flash Sale
  • Voucher
  • Brand
  • Category
  • Birthday
  • Payment
  • Member Level
  • Campaign
  • Supplier
  • Shipping
Nếu tất cả được viết bằng if-else, việc maintain gần như là cơn ác mộng.

Rule độc lập

Rule VIP không ảnh hưởng Rule VISA.
Nếu Marketing muốn thêm:
ShopeePay Promotion
Chỉ cần thêm:
ShopeePay.grl
Không cần sửa bất kỳ rule cũ nào.

Hỗ trợ Priority

Grule sử dụng salience để xác định mức ưu tiên.
rule VIP salience 100
rule Voucher salience 50
VIP luôn được thực thi trước Voucher.

Conflict Resolution

Nếu nhiều rule cùng thỏa mãn điều kiện, engine sẽ tự quyết định thứ tự thực thi dựa trên:
  • Salience
  • Rule order
  • Insertion order

Forward Chaining

Một rule có thể kích hoạt các rule khác.
Ví dụ:
VIP ↓ Discount = 20% ↓ Voucher Available ↓ Free Shipping ↓ Gift
Không cần developer gọi từng bước.
Engine sẽ tự suy luận.

2. Grule Engine

Nếu chỉ xem Grule là một thư viện để viết rule, bạn sẽ bỏ lỡ giá trị lớn nhất của nó.
Thực chất, Grule là một Inference Engine được xây dựng dựa trên Rete Algorithm — cùng nền tảng với các Rule Engine nổi tiếng như Drools, nhưng được thiết kế dành riêng cho Golang.
Kiến trúc tổng quan của Grule như sau:
.grl Rule Files │ ▼ RuleBuilder.Parse() │ ▼ KnowledgeBase │ ▼ Engine.Execute() ┌────────┴────────┐ ▼ ▼ DataContext Working Memory └────────┬────────┘ ▼ Rete Network ▼ Pattern Matching ▼ Fire Rules
Toàn bộ hệ thống gồm 5 thành phần chính:
  • Rule DSL
  • RuleBuilder
  • KnowledgeBase
  • DataContext
  • Engine

Rule DSL

Một rule trong Grule gồm ba phần:
rule VIPDiscount "VIP Discount" salience 100 { when User.IsVIP && Order.Total > 1000000 then Discount.Value += 20; Retract("VIPDiscount"); }
Cấu trúc này khá giống SQL:
rule when then
Điểm quan trọng là DSL không phải Go code.
Grule sẽ parse DSL thành AST trước khi thực thi.

RuleBuilder

RuleBuilder đóng vai trò giống compiler.
.grl ↓ Lexer ↓ Parser ↓ AST ↓ KnowledgeBase
Khi application khởi động, toàn bộ rule sẽ được parse và lưu trong KnowledgeBase.

KnowledgeBase

KnowledgeBase lưu toàn bộ business rule.
Promotion ├── VIP ├── Voucher ├── Birthday ├── FlashSale ├── Brand └── Payment
KnowledgeBase không chứa dữ liệu, chỉ chứa logic.

DataContext

DataContext là cầu nối giữa Go object và Rule DSL.
dataCtx.Add("User",user)dataCtx.Add("Order",order)dataCtx.Add("Discount",discount)
Khi rule viết:
User.IsVIP
Engine sẽ truy cập:
user.IsVIP
Thông qua DataContext.

Working Memory

Toàn bộ dữ liệu sẽ được đưa vào Working Memory.
User Order Voucher Discount
Rule chỉ đọc dữ liệu từ Working Memory.
Không truy vấn Database.
Không gọi API.
Điều này giúp việc đánh giá rule diễn ra rất nhanh.

3. Deep Dive: How Grule Works

Rule Matching

Engine sẽ kiểm tra từng fact có khớp với điều kiện của rule hay không.
Ví dụ:
User VIP Order > 1M Payment VISA
Những rule thỏa điều kiện sẽ được đưa vào Agenda.

Agenda

Agenda là hàng đợi chứa các rule đã match.
VIP Birthday Voucher Visa
Engine không thực thi ngay khi match.
Thay vào đó, Agenda sẽ sắp xếp và chọn rule phù hợp để chạy.

Salience

Salience là độ ưu tiên của rule.
VIP 100 Voucher 50
Engine luôn ưu tiên rule có salience cao hơn.

Retract

Sau khi rule được thực thi, nếu điều kiện vẫn còn đúng thì rule có thể tiếp tục được kích hoạt.
Điều này dễ dẫn tới vòng lặp vô hạn.
Vì vậy Grule cung cấp:
Retract("VIPDiscount")
để loại bỏ rule khỏi Agenda sau khi hoàn thành.

Forward Chaining

Đây là khả năng mạnh nhất của Rule Engine.
Ví dụ:
Rule A ↓ Discount = 20 ↓ Rule B ↓ Free Shipping ↓ Rule C ↓ Gift
Việc thay đổi dữ liệu trong Working Memory sẽ khiến các rule khác được đánh giá lại.
Developer không cần gọi từng rule bằng tay.

Rete Algorithm

Đây là trái tim của Grule.
Nếu có:
  • 1.000 rules
  • 1.000 facts
Cách tiếp cận thông thường sẽ phải thực hiện khoảng:
1.000 × 1.000
lần so sánh.
Rete Algorithm giải quyết vấn đề bằng cách xây dựng một mạng lưới (graph) các điều kiện.
User │ ┌──────┴──────┐ │ │ VIP Birthday │ ▼ Discount
Nếu chỉ có thông tin User thay đổi, engine sẽ không cần đánh giá lại các rule liên quan đến Order hoặc Payment.
Nhờ đó hiệu năng tăng lên đáng kể khi số lượng rule lớn.

Alpha Node

Alpha Node xử lý điều kiện trên một fact duy nhất.
Ví dụ:
Age > 18 VIP == true Gender == Male

Beta Node

Beta Node kết hợp nhiều fact.
Ví dụ:
User.ID == Order.UserID
Nó dùng để xây dựng các điều kiện liên quan giữa nhiều object.

Terminal Node

Khi toàn bộ điều kiện đều được thỏa mãn, engine sẽ đi đến Terminal Node và thực thi action của rule.

Conflict Resolution

Nếu nhiều rule cùng đúng tại một thời điểm, engine sẽ lựa chọn dựa trên:
  1. Salience
  1. Rule order
  1. Insertion order
Nhờ vậy việc thực thi luôn nhất quán.

Engine Execution Loop

Về bản chất, engine hoạt động theo vòng lặp:
for {matchedRules:=Match()iflen(matchedRules)==0 {break }highest:=Agenda.Pop()Execute(highest)UpdateWorkingMemory() }
Chu trình này lặp lại cho đến khi không còn rule nào được kích hoạt.

Ứng dụng trong Promotion Engine

Đây là mô hình thường thấy trong các hệ thống thương mại điện tử lớn.
Cart ↓ Facts ↓ Grule Engine ↓ Brand Rule ↓ Voucher Rule ↓ Birthday Rule ↓ Flash Sale Rule ↓ Shipping Rule ↓ Final Promotion Result
Điểm quan trọng là service không cần biết business rule cụ thể.
Nó chỉ cung cấp dữ liệu và nhận kết quả.

4. Insights: Pros & Cons

Ưu điểm

Tách biệt business logic khỏi source code, giúp hệ thống sạch và dễ bảo trì.
Marketing hoặc Business Analyst có thể thay đổi rule mà không cần chỉnh sửa application.
Mở rộng dễ dàng, chỉ cần thêm file .grl thay vì sửa các khối if-else khổng lồ.
Hỗ trợ priority, conflict resolution và forward chaining ngay từ đầu.
Hiệu năng tốt với số lượng rule lớn nhờ Rete Algorithm.
Rule độc lập, giảm rủi ro ảnh hưởng lẫn nhau khi bổ sung tính năng mới.

Nhược điểm

Learning curve cao. Các khái niệm như Working Memory, Agenda hay Rete Algorithm không dễ tiếp cận với developer mới.
Debug khó hơn so với việc đọc trực tiếp source code, đặc biệt khi nhiều rule cùng tác động lên một fact.
Không phù hợp với business logic đơn giản. Nếu hệ thống chỉ có vài điều kiện cố định, if-else sẽ dễ đọc và dễ bảo trì hơn.
Cần thiết kế rule cẩn thận. Thiếu Retract hoặc quản lý salience không tốt có thể dẫn đến vòng lặp hoặc kết quả ngoài mong đợi.
Khó kiểm soát khi số lượng rule quá lớn nếu không có quy ước đặt tên, phân nhóm và quy trình review rõ ràng.

Kết luận

Grule Engine không đơn thuần là một thư viện viết rule cho Golang. Nó là một Inference Engine giúp tách biệt business logic khỏi application, cho phép hệ thống xử lý hàng trăm đến hàng nghìn quy tắc một cách linh hoạt và có tổ chức.
Đối với các bài toán mà business thay đổi liên tục như Promotion Engine, Pricing, Fraud Detection, Eligibility, Approval Workflow hay Policy Management, Grule mang lại lợi ích rõ rệt về khả năng mở rộng và bảo trì.
Ngược lại, nếu hệ thống chỉ có một vài điều kiện đơn giản và hiếm khi thay đổi, việc sử dụng Rule Engine có thể là không cần thiết. Khi đó, những câu lệnh if-else rõ ràng, dễ đọc sẽ là lựa chọn phù hợp hơn.
Chọn đúng công cụ cho đúng bài toán luôn quan trọng hơn việc áp dụng một công nghệ chỉ vì nó "mạnh". Với Grule, giá trị lớn nhất không nằm ở cú pháp DSL, mà ở khả năng biến business rule thành một thành phần độc lập, linh hoạt và dễ phát triển theo thời gian.

Loading Comments...

Follow me @kevinbkdev

Donate to me
Bank QR

Bank QR Code

Buy me a coffee
Buy Me A Coffee

@source-blog by @thanhledev

Thứ 7 (24-12) lúc 9 giờ sáng mình có buổi workshop nhỏ chia sẻ cách viết Smart Contract dùng Solidity, target là chỉ cần biết code là làm được.
Nếu bạn hứng thú hãy tham gia nhé!