Creating APIs‎ > ‎Logic‎ > ‎

Learning Rules

Rules offer the promise of accelerating backend delivery by an order of magnitude. That is a big promise. But rules are a new paradigm, so there are sensible questions:

  • Complexity. How do rules address complex problems?
  • Performance. Nothing matters if the system is slow.
  • Debugging. Is it a black box, or are problems easy to address?
  • Learning. Is the paradigm reasonable to learn?

This page addresses these questions.

Prerequisites:

The following video introduces rule operation:

Rule Operation

The Promise of Rules

The Check Credit example is a representative transaction, where a insert/update/delete affects multiple related objects.

  • Correctness. The challenges of building correct code are known. Reactive programming addresses several of the inherent challenges of quality by automating control flow:
    • Automatic Invocation. After you declare a rule, it is executed for any use case. This eliminates an entire class of corner-case bugs (the Customer Balance was not adjusted when the Order was re-assigned to a different account)
    • Ordering. Execution is ordered by system-discovered dependencies.
  • Maintainability. The same elements that promote correctness make reactive logic easier to maintain. Add/change rules and they execute in the proper order.
  • Clarity. Removing the boilerplate Change Detection/Propagation and SQL reveals the intent of the logic. Moreover, it is revealed in terms clear to Business Users. The result: Business Users and IT, speaking the same language. This can reduce the risk of requirements misunderstandings.
  • Conciseness. The following code snippet shows the rules:
Validation: return row.CreditLimit >= row.Balance
Derive Customer.Balance as Sum(Orders.AmountTotal where ShippedDate === null)
Derive Orders.AmountTotal as Sum(OrderDetails.Amount)
Derive OrderDetails.Amount as row.Price * row.Quantity // JavaScript Expression
Derive OrderDetails.Price as copy(Product.Price)

To provide contrast between the rules (reactive programming) approach and conventional event handlers, the same logic is programmed using conventional approaches. The result was 200-500 lines of code. You can further observe that the rules look like a requirements document that business users can read. This promotes communication, which can reduce requirements risk.

Address Complex Examples

You can address complex examples using API Creator:

  • Rules can Use JavaScript. Formula and Validation rules are expressed in (server-side) JavaScript. This enables conditional logic, such as this formula to compute an OrderDetails amount:
var amount =
row.Quantity * row.UnitPrice; // row is the OrderDetails row
if (row.Quantity !== 0) {
amount = amount * (100 - 100*row.Discount) / 100;
}
return amount;
  • Extensible libraries. You can enable and load your own JavaScript libraries and JARs and call these from your JavaScript, for example:
if (row.placed_date === null) return new Date(); // moment();
  else
return row.placed_date;

For more information about loading JavaScript libraries and JARs, see Manage your API Project.

  • Events. You can provide logic not addressed by rules using the integrated event model. For example:
if ("INSERT" != logicContext.initialVerb && row.amount_total != oldRow.amount_total)
SysLogic.insertChildFrom("purchaseorder_audit", logicContext);

Live API Creator includes the SysLogic library. You can also introduce your own libraries.

For more information about the SysLogic object, see The SysLogic Object.

  • Rules reduce complexity. Ordering, dependency management, and automatic invocation inherently reduce complexity. A few simple rules can solve complex problems, in the same way that a few spreadsheet formulas can solve highly complex numerical problems.

For more information about viewing a series of use cases, ranging from simple examples to well-known complex examples, addressed with a few rules, see the Reactive Logic Tutorial.

Performance

The API Server automates best practices for performance:
  • Pruning. Rules, and associated SQL, are not executed if a specific transaction does not alter their dependent data. For example, changing an Orders' DueDate has no effect on the Customer's Balance
  • SQL optimizations. Parent adjustments for aggregates are single row updates. This is particularly significant when aggregates nest, that is, they are based on other aggregates.
  • Caching. API Server automatically buffers reads and write in a transaction cache. For example, inserting an Order with five OrderDetails results in an order and a customer adjustment.
For more information about performance, see Performance.

Debugging

API Creator provides a detailed log of all rule and SQL activity, including complete row state for each stage. You can also use the debugger for JavaScript code.

For more information about the log, see Debugging.

Learning Rules

Use the following approach to address problems with rules. It's easy, but it's different.

Differences between Reactive Programming and Conventional Procedural Programming

You can make some observations about some fundamental characteristics that distinguish reactive programming from conventional procedural (Imperative) programming:

No Object Model coding - Object Model from Schema

In a conventional approach, you typically need to create Domain Classes (JPA Objects, Entity Framework Objects, etc) that provide access to attributes, related objects, and persistence services to read/write data. And, you need to keep these consistent with your schema.

API Creator creates these automatically. They stay in sync with your schema.

Logic Aware Object Model

Most importantly, your objects are logic-aware. API Creator instantiates your objects on updates. The objects encapsulate:

    • The events. Row events are "about" a domain class.
    • Rules. The rules you state are attached to Objects and Attributes, and are expressed in terms of the Object Model. In other words, your schema expresses the operands for rule expressions.

The following image shows how API Creator instantiates your objects on updates:

No Control Flow

In normal code, you must explicitly invoke object methods for them to execute.

Invoked per changes in referenced attributes

Reactive programming rules are more similar to event handlers or triggers. But they are much more granular. They react not to an update, but to a change in the referenced attributes.

Ordered by Dependencies

In conventional programming, logic within a method or event handler is ordered. This is tedious, and difficult to maintain. Reactive programming rules are ordered by their dependencies. When you alter the rules (maintenance, iterative development), the logic flow automatically adjusts per the new dependencies.

Elimination of Boiler Plate code

In a conventional approach, the bulk of your code is change detection, change propagation, and persistence handling (SQL commands). Reactive programming automates all of this, so the previous logic is executable.

A Simple Validation Example

The declarative rules are expressions for deriving / validating data. The expression operands are derived from the schema: tables, columns and foreign key relationships. The rule expressions are entered with a combination of Forms and server-side JavaScript functions (providing if/else logic, access to libraries, etc). You can see the details in the Tour.

The following code snippet shows a simple example:

Customer Validation: return row.CreditLimit >= row.Balance

This validation rule ensures that the balance does not exceed the credit limit (else the transaction is rolled back). Such rules can also reference related object data, per the object model foreign key relationships:

Orders Validation: return row.AmountTotal < row.Customer.MaxAmount

For more information about validation rules, see Validation Rule Type.

A simple SUM example

Ok, but the balance is derived. How do we deal with that? We add another rule, a Sum:

Customer Validation: return row.CreditLimit >= row.Balance
Derive Customer.Balance as Sum(OrdersList.AmountTotal where ShippedDate === null)

The rule operands, again, are based on the schema; OrdersList is a defaulted name, derived from to a foreign key relationship. Again, these rules are fully executable. After you have entered them, you do not need to worry with the details of calling them, ordering them, reading/writing data. This is all addressed with system RESTful Update Processing.

For more information:

Rules automate Logic Patterns

This simple example illustrates one of the keys to using rules: they work in combination to achieve a desired behavior.

Validate a Sum

This simple "Balance < CreditLimit" example illustrates one of the most common logic patterns: validating a rollup/constrain derived result. Other examples of the pattern:

  • Rollup employee salaries to department, constrain to budget.
  • Rollup departments, constrain to budget.
  • Rollup Student Course Credit, constrain to max for student, max for course.
  • Compute Product Price from the sum of the Component Parts (nested).
  • Compute Event GiftsAmount from sum of EventGifts.

A similar pattern is described in the following section.

Existence Checks: validations on [qualified] counts

Such as Order must have items and Department must have employees.

Scaling to Complexity

You can identify and automate your own patterns by basing rule definitions on JavaScript. API Creator includes several examples:

  • Copy. Invoke copy, including deep copy, for patterns like auditing or cloning. The copy pattern automates a Bill of Materials explosion.
  • Allocation. Allocate an amount to a set of recipient, such as a bonus to department employees or a payment to outstanding orders.

For more information:

  • About exploring examples that range from simple to quite complex, all handled with a few rules, see the Reactive Logic Tutorial.
  • About logic patterns, including the allocation and see Logic Patterns.

More Information