Friday, April 13, 2007

Business rules: hard-coding or soft-coding

Couple of days ago “Worse Than Failure” published (instead of a usual daily IT horror story) a very interesting article dedicated to “Soft Coding”. The article discussed a problem known to anyone who ever did some business-related software design: dealing with business rules.

The problem with business rules is that they are almost impossible to generalize, often follow some odd logic and are subject to frequent and unpredictable changes. Usually business rules involve some arbitrary values, which programmers are reluctant to hard-code. The article gives quite a good example of the situation, but let me give here one of my own.

Let’s suppose that one of the business rules is:

“If a user account is inactive for more than 180 days it should be deleted, except for the cases when the user is located in New York or New Jersey, or when the user is an employee of XYZ Corp.”

The most straightforward way to implement the rule is just to write a couple lines of a code:


if (account.getInactiveTime() > 180 ) {
if ( account.getUser().getState()!=”NY”
&& account.getUser().getState()!=”NJ”
&& account.getUser().getCompany()!=”XYZ”) {

account.delete();
}
}

The classic approach tells us that this code is bad: it has hard-coded values, which means that changing one of those values will require code change. The obvious solution is to move the values somewhere outside the source code, for example to a configuration file. But the logic of the rule itself is also subject to unexpected changes; so it will seem natural that the logic should be somehow generalized and the concrete details should also be moved out. Unfortunately, this almost always leads to creation of some monstrous home-brew scripting languages, which turn the maintenance of such projects into a nightmare.

The article suggests that it’s much better to just leave the logic in the code: this way it’s easy to read and it’s implemented in a well-known programming language.

In my opinion, both approaches are equally good – or equally bad, depending upon the circumstances.

Having business logic in the code has some very serious disadvantages. Yes, the build process is no longer as expensive as it used to be some time ago; however, the necessity to change code when a business rule changes is still unpleasant:

  • Builds themselves are cheap now; however, the deployment might be quite expensive. If you need to re-deploy application to one or two servers – it’s easy; however, if the application runs in a complex environment with multiple server groups and clusters, that might be quite a different story. And if the application is actually deployed on the users’ desktops…

  • Changing code might cause ripple effects, and requires regression testing – which also might be expensive.

  • Frequent minor code changes under time pressure usually cause a code quality to deteriorate.

  • The last, but not least: with this approach, the developers become forever responsible for implementing rule changes.



In my experience, the right solution for the problem lies (as usual) somewhere between those two approaches. There is no silver bullet, and each group of business rules (and, sometimes, even each rule) has to be addressed separately. Here are the principles I try to follow when dealing with applications with business rules.


  1. Try to identify as many business rules as possible in the project you are working on. The purpose is to understand, which part of the requirements (or implementation) deals with core business logic, and which with some arbitrary business rules.

  2. Estimate which elements of business rules are going to change and how often? It’s never possible to get an absolutely precise answer to this question; however, surprisingly often one can get a good estimate just by asking for it: “The states in this rule change constantly – last year we had 4 states, then two months ago we added two more, and a week ago a new regulation came out…” or “XYZ was always a special case – it’s our largest partner”.

  3. Frequently changing values should go into an external location (file, database…)

  4. Rarely changing values might also go there, or can be implemented as constants, whichever will make the code easier to maintain. Just do not leave them as “magic numbers”!

  5. The business rules logic should be moved to separate classes, and, possibly, to separate modules. There are quite many ways to achieve it. Observer pattern can be used when the rules are to be triggered by some events. Decorator and Strategy patterns are also helpful here. Another possible approach would be using aspect-oriented programming and moving some business rules to aspects. It might also be a good idea to implement certain groups of business rules as plugins, and to make the core system automatically discover them. (I did something similar to this in one of my projects, and it worked pretty well). The basic idea behind all of this is to minimize ripple effect and make required change as small as possible.

  6. If the business rules logic is subject to frequent changes, the situation becomes more serious. The design approaches suggested above will, definitely, somewhat alleviate the pain, but in general this type of situation calls for more drastic measures. Usually this involves adding some sort of scripting support and giving the users ability to write some simple scripts and script snippets. One advice for those who will go down this path: do not invent new scripting languages – first try to use an existing one. It’s also a good idea to provide some UI which will help with writing snippets and putting them in a right place. Adding scripting support and providing is, definitely, quite an effort. So, before doing this, it always makes sense to look outside of the project: sometimes frequent business rules logic changes might be prevented by fixing some business processes, or by working with users and stakeholders. It may sound unrealistic, but there are occasions when just explaining the fact that the requested changes are not as minor as the requestor thinks and do not come free of charge helps significantly reduce the frequency of change requests.

  7. While following those principles, try to keep the system from turning into chaos of different techniques applied. Group similar or related business rules together, and use for each group the technique needed for the rules with maximal volatility. For example, if you have 10 similar rules, and two of them are changing frequently enough to validate usage of external configuration file for them – use it for all 10 rules. Just make sure your grouping is fine-grained enough.



Technorati tags: ,

14 comments:

Bad Wombat said...

Well, nowadays, popular scripting languages such as perl, ruby or python can be easily embedded into the code. This way you can have business rule logic outside of the compiled code, but still written in a known language.

Aleksey Linetskiy said...

Yes, and there are also Groovy, Lua and others... That's what I had in mind when I wrote about adding scripting support. It's just important to understand that this path is dangerous and expensive.

Jerry said...

If your main application is written in a C-like language, then JavaScript might be a good choice for scripting business rules. Your if statements are going to be syntactically identical, at least, which will help your programmers. If you are doing more than a few ifs, to the point where the syntax differences between JS and whatever really start to matter, you should move some of the rules into the main application.

I would suggest that most of these hooks could use an event-style programming model, like in a browser, where named script handlers are called just before certain things happen (e.g. customer delete) and simply return a value indicating what action should be taken. This helps enforce the rule that actual behaviors get coded into the main application and "business rules" merely get to choose from among the various actions; they don't get to invent new actions of their own.

Peter Eddy said...

When rules get complex, I've had good results using Jess with Java: http://herzberg.ca.sandia.gov/jess/

thought-bytes said...

I would think in cases like these, a rules engine would be the cleanest way to go

Rajgo said...

Hi,

Don't you think that the people who are involved in the change process as it affects business rules would/could be different?

Tax Calculations, Loan Pricing Rules and the like, it would be very difficult for a Developer to be good at these kinds of rules.

These kinds of rules also change much more often, and it would be desirable to have the business guys get a handle into these kinds of rules.

The definition of these business rules would also come from the business and not IT. Check this writeup where I differentiate between software Requirements & Business Rules.

Doing this with code would require very powerful frameworks and tooling for complicated and numerous rules.

For simple rules, a good externalization abstraction, and parameterization technique will suffice.

For more complicated scenarios, you will need better tools like a BRMS.

My 2 cents!

Kit said...

One other tip that is important IME is to isolate rules in their own methods. So in your case, the if-statement would go into its own method called something like accountCanExpire() returning boolean. Apart from making the code more readable IMO, it allows you to play around with how the rules are executed (in code, via script, etc) with the minimum amount of impact.

setusol said...

It sounds like you are describing a very common behaviour.
Rulesharp does all this using a database. I like the way they are handling it.

James Taylor said...

Why not just use a business rules management system to manage them? You use a database to manage data and a content management system to manage content, why not a business rules management system to manage business rules?
I ranted at length about this here. Sigh
JT
www.edmblog.com

Dushan Hanuska said...

Having rules hard-coded is usually the simplest solution that does not involve any rules engine overhead. It is very well suited for simple or complex sets of rules that do not change often.

If you rule set becomes too complex (usually indicated by a high amount of comments in the code) consider taking them out to an external location (file, database, etc.) and putting a rule engine in.

It's also very important to keep the rules in a central place. This is more important that the way these rules are implemented (hard-coded or soft-coded). A good candidate for these rules is a business object (in terms of EJBs: session bean).

BTW: The rules implementation in your example (and same goes for original article) use String reference comparison - a very common mistake Java programmers make. Change != to !equals(). It should be:

...
!"NY".equals(account.getUser().getState())
...

Hardy said...

I totally agree with the author.

I made a rule engine for a bank nearly 15 years ago using just the same principles. Rules coded in C++ as the rest of the application, but in seperate classes, activated by some event mechanism and parameters in the database.
And it was and is still a success. Do not understimate the value of using the same language. In big projects programmers come and go, and you don't want to learn a new language for just adding one simple rule.
It is a very common mistake among programmers to use smart tools THEY know about, without caring too much about what comes after.

Adrian said...

Hi! Thank you for that post. I found your blog while I was doing research on live help and live support software.
I see you are enjoying your google blogger :) Well, I think it's great that Google are making such good products like Blogger here, but also Picasa and other Google Apps. They have a great impact on what happens in the internet. I also wanted to tell you that it would be awesome if you would find a little time to visit my web site, it would be greatly appreciated. Maybe you are looking for live chat solution for your web site? If yes, please try LIVECHAT Contact Center. Using this application will help you maximizing online conversion, increase sales and customer satisfaction. My company's offer contains also LIVECHAT Communicator - multiprotocol instant messenger for business use. You can contact all of your friends (who use different applications like MSN, ICQ, etc) with it, but also organize instant messenging network in company. 14-day trial versions of both applications are free and you can download them directly from the web site.

Michael Bonner said...

Please Check out www.rulesworld.com for the best way to model Business Rules by far

Free Nifty Future Tips said...

What’s up, I read your blogs daily. Your story-telling style is awesome, keep doing what you’re doing for trading !