Blog‎ > ‎

How does Declarative Business Logic work?


We need to stop working so hard and let the machine do what it does best.

The problem

When you write a business system, say an order processing application, you have to specify a lot of logic. It's so blindingly obvious that it feels silly to even say it.
  • A customer's balance is the sum of the unpaid orders. 
  • An order's total is the sum of its line items, plus shipping and taxes. 
  • An order for liquor cannot be shipped across state lines. 
  • Customers without a credit line must pay cash.
There's hundreds, thousands of these. They typically get written down in the specifications, and then translated into code.

And that's where trouble begins, because as soon as they're translated into code, three things happen:
  • they become atomized -- mixed up with all the other code, and therefore difficult (if not impossible) to identify
  • they become difficult (if not impossible) to trace back to their original intent
  • they start interacting with each other in unforeseen ways. They become interdependent. They step on each other's toes.

Anyone who's worked on a real software system knows this. The bigger the system, the worse it gets. And it's not linear. Growing a system ten-fold does not make it ten times more complicated, it makes it fifty times more complicated, because the total possible number of interactions and dependencies grows exponentially.

A hint at the solution

There is one type of system where we can have a lot of logic, with a lot less complexity: spreadsheets. If you've ever done your taxes in a spreadsheet, or financial modeling, or anything non-trivial, you know that you can quickly create a very complex system, without having to worry (too much) about these problems. If you change one cell, or one formula, somehow, the spreadsheet figures out how to recompute the whole thing. You never have to tell it how to do that: it just knows.

The spreadsheet knows because it looks at the formulas and understands (to some extent) what they do. It can therefore analyze the dependencies, order them, and recompute the spreadsheet efficiently (by recomputing only those cells that need to be), and correctly (by guaranteeing that all cells that need to be recomputed are).

It's not that you can't get into trouble with a spreadsheet -- we've all seen spreadsheets from hell that are beyond comprehension -- it's that you can do in minutes what would take you days to program by hand in Java or Python. It takes you farther, quicker. It lets you focus on what the numbers should be, rather than how they should be computed.

The solution

Declarative business logic uses the same principle, but in a transactional setting. It lets you declare the logic that governs your persistent data, and leaves it up to the system to figure out when and how to execute that logic.

For this to work, each bit of logic must be understandable by the system. It must be expressed in a way that can be analyzed, so that the consequences can be derived. This of course puts limitations on the type of logic it can handle. But don't be put off by that: even though it won't replace all your business logic, it will still replace a very considerable portion of it.

So we take all these bits of logic and throw them into the logic engine (just like you declare all your formulas in a spreadsheet without any regard for ordering or dependencies). How does the engine then know when to invoke them, and how to invoke them?

We're talking about a transactional setting here, so there are clear units of work. All changes happen within well-defined boundaries. And commit time is the perfect time for the engine to work its magic. By commit time, we know everything the users want to do. We have a complete picture of their intention (for that one transaction, anyway).

So the engine looks at all the changes that have been made in the transaction, and it figures out (based on its analysis of the dependencies in all your bits of logic) what logic needs to be applied. Of course, that may very well cause some changes in the data, which means that we're going to keep doing this until all the logic has been satisfied.

Once again, this is not rocket science: this is exactly how a spreadsheet works.

Let's take a look at a few examples.


Let's start with the most basic, the most intuitive of rules: the constraint. It's simply a condition that should be true. A typical example might be: a customer's balance cannot exceed their credit limit.

When you put that bit of logic into the system, it will be analyzed, and the logic engine will figure out that this constraint depends on two things: customer's balance and customer's credit limit. Based on that, it will then know that this constraint should be checked any time one of these two things change.

At this point, you're done. You are now relieved of the responsibility for this condition. You have given it to the business logic engine, it is now its job to ensure that it is never violated.


A formula is just like in a spreadsheet: you specify that the value of an attribute is equal to the result of a formula. A trivial example might be: an order's total is equal to the sum of its line items, plus shipping, plus tax. Note that each of these three quantities can, in turn, be specified by a formula, or some other type of logic, such as...

Sums are calculated by adding up one attribute for a number of rows. But the trick here is to turn that into a concept, just like you would have a sum in an Excel spreadsheet. By making it into a formal