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 RuleParams during 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:

JSON
{
  "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 condition and action factory methods as the Strategy boundary between JSON tokens and compiled Java functions.
  • Compiled snapshot. Build an immutable RuleEngine once, then fire it many times. Use RuleEngineRef when the rule file needs hot reload.
  • Draft toggle. Use enabled: false for 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.SIMPLE for raw rule arrays
  • use RuleDocumentFormat.SPECIAL for metadata documents with requires and rules
  • keep triggers specific enough to avoid evaluating unrelated rules
  • use enabled: false to 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:

JAVA
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.