TinyRuleKit
Best Practices
These recommendations keep the basic static-rule path simple, flexible, and predictable as the rule set grows.
Keep The Java Boundary Strong
- define trigger, condition, and action enums as the public rule vocabulary
- keep resolver factories small and explicit
- parse and validate
RuleParamsduring engine construction - keep side effects inside actions
- prefer domain-specific resolver errors over generic failures
Design Rules For Review
Rules are easier to review when each one describes one business case:
{
"id": "vip_join_reward",
"trigger": "PLAYER_JOINED",
"conditions": [
{
"type": "LEVEL_AT_LEAST",
"params": {
"level": 5
}
}
],
"actions": [
{
"type": "GIVE_COINS",
"params": {
"amount": 25
}
}
]
}
Prefer descriptive id values for diagnostics. Keep when for action-specific
guards in JSON Authoring; keep basic rules focused on one trigger, clear
static conditions, and clear static actions.
Useful Design Patterns
- Enum vocabulary. Keep triggers, conditions, and actions in small enum collections so JSON can only ask for known rule concepts.
- Static factory resolvers. Use
conditionandactionfactory methods as the Strategy boundary between JSON tokens and compiled Java functions. - Compiled snapshot. Build an immutable
RuleEngineonce, then fire it many times. UseRuleEngineRefwhen the rule file needs hot reload. - Draft toggle. Use
enabled: falsefor rules that should not be compiled, indexed, or resolved yet.
Performance
- build engines once and reuse them
- avoid rebuilding an engine for every event
- omit the document format while learning or when both JSON shapes are accepted
- use
RuleDocumentFormat.SIMPLEfor raw rule arrays - use
RuleDocumentFormat.SPECIALfor metadata documents withrequiresandrules - keep triggers specific enough to avoid evaluating unrelated rules
- use
enabled: falseto skip draft rules before resolver compilation
Security
- keep JSON rule files under the same review process as other configuration
- keep condition and action factories explicit; do not resolve arbitrary class names
- avoid putting infrastructure access behind rule parameters
Testing
Test resolver factories independently from JSON loading when possible:
CompiledCondition<GameContext> condition = GameRules.condition(
"LEVEL_AT_LEAST",
RuleParams.of(Map.of("level", 5))
);
Then add integration tests that compile representative rule JSON and fire the engine with realistic contexts.
Continue with Expressions if static rules are not enough. Use JSON Authoring later when rule files need composition, expressions, or action guards.