Know thy rules

time to read 5 min | 806 words

Most interesting applications have some sort of a business rules inside of them. This is the part where most sane programmers are left wondering: "You work like this and you make money?"

Of course, usually it's because the business works like that it manages to make money. I believe that the classical example is a software to manage the real estate business, where the various options that you can gives the client can make or break a deal.

One problem I run into with writing those rules is efficency. No, I'm not worried (much) about efficency yet (although I do consider revoking my statement about the post decrement operator, in the name of performance :-) ). I do keep certain things in the front of my mind, and in this case, the business scenario and application efficency are going hand in hand.

The issue is simple: I want to run a set of business rules on an object graph. In order to validate the object graph, the rules will need to access the database for further information. This is a point where I want to reduce to a minimum the number of request that are made to the database and the amount of data that would be transfered. The user wants to get a response as soon as he thinks about the problem, and we wants to make sure that the answer is relevant to the question asked.

Let's consider this example:

No employee in a department may earn more than 25% more than median of the salaries in the department.

Seems like a rule that should be very easy to implement, doesn't it? If we're smart, we can implement that as a single database query and be done with it. But for the purpose of the discussion we will assume that we can't do that (perhaps the backend is really stupid, or we expect to use this rule as a stepping stone for more rules, or we just feel like it :-) ).

So, what is the problem with this rule? The problem is the context in which you run it. The department manager may need to run this before a raise can be given. The HR HQ would need to run it for the whole company, and you need to support it running anywhere in between. Beyond the issue of performance and efficency (you don't want to validate the whole company just to figure out that your little piece of heaven is fine, right?) there is also the issue of security. I might not be allowed to access certain records. In certain environments, it would be impossible to execute such rules, since they would try to access information that you don't have rights to see and will be blocked.

Now it's not that simple.

You can re-create the rule for each level that you need it, perhaps by creating an abstract rule and inheriting from it for each level you need. The problem with that is that it's not really elegant, in my opinion. You need to create the correct object at every place, and you need to create a new object if you need to support a new level:

DivergenceOfSalaryInDepartment divergence = new DivergenceOfSalaryInDepartmentForWholeCorp(corp);
dviegence.Validate();

I was thinking about this all day and it finally hit me when I was driving (I sometimes do my best thinking away from computers). The issue is all about the context you're executing the rule in. And if it's all about the context, why not make the context an explicit part of our model? Instead of pulling the data directly from the database, the rule would have a context that would get it for it, filtering it so only the information for the current context will be returned.

The usage would look like this:

DivergenceOfSalaryInDepartment divergence = new DivergenceOfSalaryInDepartment( new CorporationRuleContext(corp));
dviegence.Validate();

Now you can reuse the context from rule to rule, and you've got only one rule to maintain. Sure, it's not a world shaking idea, but it a nice one, I think.