The Problem
Businesses and organizations live or die on the efficiency and effectiveness of their processes, and none is more important than procedures to control of expenditures. Improperly authorized spending can bankrupt an organization, but controls that are too burdensome can result in lost opportunities. It's one of the more difficult balancing acts faced by modern organizations in the face of sophisticated fraud schemes and a fast changing world. As a result, expenditure controls are often complex and often need to be updated on a regular basis to meet new threats while also responding to changing needs. For these reasons, expenditure approval procedures present a good case for the use of techniques I'm promoting via Blockly for Business Logic (BBL).
USAF/CAP Example
For my example, I found an online description of expenditure controls used the the United States Air Force Auxiliary Civil Air Patrol in
this PDF and implemented the procedure in BBL. The main output is a boolean calculation I've called "expenditure approved" which is true if the expenditure is approved and false if it's not, which looks like this:
Blockly has a built-in feature for adding comments, which look like this:
In Blockly, you add comments by right clicking on a block, which creates a question mark in a blue button on the block. Clicking on the button opens a box for entering the comment. You can hide or show the comment by clicking on the button.
As this example, shows, there are two ways to approve an expenditure. Non-recurring expenditures have a complex approval process, while recurring expenditures are more or less automatic.
The following screen shot looks more closely at the non-recurring approval process:
The green blocks are inputs to this calculation. The first three are boolean inputs that indicate whether the request is documented, whether it's within guidelines, and whether documents have been reviewed. These inputs are generated outside of this logic and may be as simple as having the requester click on check boxes indicating they have been done, or they may involve more complex validations.
The word "is" in parenthesis is the "type" of the input, and "is" indicates boolean. This is intended to be read by non-programmers, so the use of technical terms like "boolean" is avoided.
There are two forms of approval allowed: written, or online signature using Sertifi.
Calculated Inputs
Next we look at some inputs that are calculated using sub-modules.
These three inputs are actually outputs from sub-modules. Within this module, though, they appear simply as inputs. BBL is able to figure out which module definitions depend on which other module definitions and perform the source calculations before running the higher-level dependent calculations. Recursion is not allowed. You can't call a module from itself or from any of its sub-modules. It could be implemented, of course, but the whole point is to create a simple way of expressing logic that works for perhaps 80% of business logic and is usable by non-programmers. More complex logic would be implemented outside of this context, either during generation of inputs to this process (preferable, I think) or by implementing custom-designed operations as blocks.
Unlike most programming languages, sub-modules are called without the use of parameters. Again, the point is to reduce complexity for use by non-programmers. All inputs to all modules are global. Because the process is "functional", there are never any local variables, so name conflicts between global inputs and local variables are never a problem.
Here is the definition of the "approver approved" sub-module:
It checks for individual approver limits. In this simplified example, there is only one approver. If there were a small number of approvers, they might be handled as shown here, though for a large number of approvers it would be handled in a database outside the BBL mechanism and the approver limit would be passed as an input instead of the identity of the approver.
This is the definition of the "level approved" sub-module:
And this is the definition of the "sertifi approved" sub-module:
Unit Tests
When a module is defined, a template for creating unit test cases is automatically generated. In the case of the main module, it looks like this:
Test cases are set up by filling out the controls for a test and saving them. When the tests are run, the output is shown, and if it matches the "expect" value, a green check mark shows, otherwise a red circled X.
These are unit tests, not integration tests, so the inputs that come from sub-modules are not calculated, just entered. Likewise, the inputs used by sub-modules but not used by the main module are not included in these tests. Integration testing will also be required, but that is a separate process.
Generated Code
The immediate result of creating a valid definition is an XML representation of the calculation, for example:
<output name="expenditure_approved" type="is">
<conjunction operator="any">
<conjunction operator="all">
<input type="is">documented</input>
<input type="is">within_guidelines</input>
</conjunction>
<conjunction operator="all">
<selection name="form_of_approval">recurring_approval</selection>
<input type="is">recurring_approved</input>
<input type="is">documents_reviewed</input>
<conjunction operator="any">
<selection name="form_of_approval">written_approval</selection>
<selection name="form_of_approval">sertifi_approval</selection>
</conjunction>
<input type="is">approver_approved</input>
<input type="is">level_approved</input>
<input type="is">sertifi_approved</input>
</conjunction>
<conjunction operator="all">
<selection name="form_of_approval">recurring_approval</selection>
<input type="is">recurring_approved</input>
</conjunction>
</conjunction>
</output>
This XML can automatically be translated into any programming language. For purposes of running the unit tests, it's translated into JavaScript, which looks like the following. This code is somewhat difficult to understand because it's generated in a "functional" style, as one long expression. As I said in a previous post, the functional style has great advantages in terms of being able to validate correctness and for other reasons, but is difficult to work with if you're not using something like Blockly.
expenditure_approved:function(inputs)
{
return
(
(
(
(
validate(
"is",
inputs.documented
)
) &&
(
validate(
"is",
inputs.within_guidelines
)
)
)
) ||
(
(
(
(
validate(
"form_of_approval",
inputs.form_of_approval
) === "recurring_approval"
)
) &&
(
validate(
"is",
inputs.recurring_approved
)
) &&
(
validate(
"is",
inputs.documents_reviewed
)
) &&
(
(
(
(
validate(
"form_of_approval",
inputs.form_of_approval
) === "written_approval"
)
) ||
(
(
validate(
"form_of_approval",
inputs.form_of_approval
) === "sertifi_approval"
)
)
)
) &&
(
validate(
"is",
inputs.approver_approved
)
) &&
(
validate(
"is",
inputs.level_approved
)
) &&
(
validate(
"is",
inputs.sertifi_approved
)
)
)
) ||
(
(
(
(
validate(
"form_of_approval",
inputs.form_of_approval
) === "recurring_approval"
)
) &&
(
validate(
"is",
inputs.recurring_approved
)
)
)
)
)
}
How It's Used
The ultimate question is, how is this used? It may be used in a variety of different ways. It can be used to generate the validations for a web form input, for example, or it can be used to validate a batch file containing expenditure records. It can be used to create a server application that validates via a server protocol. It can be used in multiple ways at the same time. If it's used to generate code for one platform, you can more easily switch to using a different platform, without having to pick the business logic out of the old code and rewrite it in new code.
The biggest advantage, though, is that the logic can be written by someone who is not a programmer, or at least by someone who has only "light" programming skills. Even more important, the logic can be READ by someone who is not a programmer. This allows the code to be "self documenting" and is important for software auditing.
The Bottom Line
All organizations do battle with the two-headed monster of control versus responsiveness. Yes, an organization needs to maintain tight controls and yes, the organization needs to be flexible and responsive. Doing both things at once requires getting more control over the expression of business logic within the organization, and something like the BBL approach seems to offer a way forward.