Docs‎ > ‎API Creator‎ > ‎Specify your Business Rules‎ > ‎

Learning Rules

Rules offer the promise of accelerating backend delivery by an order of magnitude. That's a very big promise. But it's a new paradigm, so there are sensible questions:
  • Complexity. How are complex problems addressed?
  • 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.

Rule Operation


Prerequisites: You have read Rule Operation, or watched the Rules video, which visualizes rule operation.

Other resources:

The Promise of Rules

The Check Credit example shown at the top of this page is a representative transaction, where a insert/update/delete affects multiple related objects.

Correctness

The challenges of building correct code are well 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 programming logic much easier to maintain. Just add/change rules: you can be assured they will execute, and 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

We compared the rules (Reactive Programming) approach with conventional event handlers. Here are 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, the same logic is programmed using conventional approaches. The result was 200-500 lines of code. We further observe that the rules look like a requirements document that Business Users can read. This promotes communication, which can reduce requirements risk.

These observations are not proofs, but we hope they warrant time to investigate. Let's begin by looking into common concerns.

Complexity

API Creator provides support to address complex examples, as described in the sub-sections below.

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

Moreover, you can enable and load your own JavaScript libraries and jars, and call these from your JavaScript, like this:

if (row.placed_date === null) return new Date(); // moment();
else
return row.placed_date;

Events

An integrated event model enables you to provide logic not addressed by rules, such as

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.

Rules reduce complexity

Aspects we'll discuss below regarding ordering, Dependency Management and Automatic Invocation inherently reduce complexity. The result is that a few simple rules can solve problems of surprising complexity, in the same way that a few spreadsheet formulas can solve highly complex numerical problems.

Examples: Bill of Materials, Payment Allocation, etc

The Logic Tutorial covers a series of Use Cases, ranging from simple examples to well-known complex examples. All are addressed with just a few rules.

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 not select sum queries, but rather much more efficient single row updates. This is particularly significant when aggregates nest (are based on other aggregates)
  • Caching: reads and write are automatically buffered in a Transaction Cache, so, for example, inserting an Order with 5 OrderDetails results in only 1 Orders and Customer adjustment.

To learn more about performance, see performance here.

Debugging

API Creator provides a detailed log of all rule and SQL activity, including complete row state for each stage. A debugger is also provided for JavaScript code.

Learning Rules

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

Key Differences

We can now make some key observation 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. They are instantiated on updates by API Creator, and they 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.

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 logic shown above is fully 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.

Here's 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 our Object Model foreign key relationships:

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

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 - that is all addressed with system RESTful Update Processing.

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. 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.
      • Department must have employees.

Scaling to Complexity

Basing rule definition on JavaScript enables you to identify and automate your own patterns. API Creator includes several, useful both directly and extensibility examples:

  • Copy - invoke copy, including deep copy, for patterns like auditing, or cloning. It even automates a Bill of Materials explosion.
  • Allocation - allocate an amount to a set of recipient - a bonus to department employees, a payment to outstanding orders, etc.

Explore these examples, which range for simple to quite complex - all handled with a few rules.