Simplifying Complex If statement
Where ever I go, what ever project I end up, no matter how simple the problem. I almost always end up having to deal with complex nested if statement. These statements seem logical at the time, but if left unchecked, grow into this special kind of monster which no one can decipher.... not even the guy who wrote it!
A project I worked on recently was revolved around a booking engine. This engine contained the business logic which dictated how the a booking was processed, which state it would move to, what validation had to fire when, etc etc.
It was split into several pages, all working on the same object (a booking) but a slightly different aspect of the booking. (pricing, accounts etc)
I decided that it would be a good idea to run all the different aspects of the booking through the same method, thus encapsulating the logic of a booking, and hence having 1 place to maintain this logic. It sounded nice at the time, however, over the cource of the 6 - 12 months of developement with 5-6 different developers, this method (group of methods) got extramly large, with a complex set of conditions and loops. What was ever worse was the fact that there were 5-6 developers working on this method using svn for version control. now, if you have used svn for version control, you'll know that if someone makes a major update to a file (ie moves anything to a different place) the merge tools have a bit of a spac attack, and merging your changes to the code base can be a bigger challenge then the code itself. So this section of the code was left unchecked for a very long time.
As a programmer who prides himself on finding a better way, I decided to search for and test the best way of handling this complex array of posibilities. After some searching and playing, I found a few techniques from Stack Overflow which help de-scramble nested if statement. An Interesting rule of thumb.
"3 is a magic number. If I needed more that 3 if's then I should probably use a case statement instead. If you're nesting if statements more than 3 deep then you should probably take that as a sign that there is a better way"
Words to live by really. I guess??
First off, I tried a Specification pattern. This tidies up your if-then-else logic complexity into a neat object structure in which you build your conditions into custom object which holds a smaller subset of that logic and apply IsSatisfiedBy method to return a partial truth. You then string together all the partial truths into an object which is you ISpecification. and then you ask it is my object IsSatisfiedBy this specification. This method will then traverse your string of partial truths evaluating each one and returning a boolean specifying if your object has satisfied the conditions.
Quite a neat way of simplifying the if then else, although it does mean alot of extra work creating new classes and scattering your logic into a million tiny pieces so you end up with an almost sensical string which is your condition. Something like the code below.
ISpecification tuple = new IsTuple().And(new HasContextName()).And(new HasContextValue().Not()).And(new HasTrefId().Not()).And(new HasTrefMemberId().Not());
ISpecification dimension = new IsDimension().And(new HasContextName()).And(new HasContextValue()).And(new HasTrefId()) .And(new HasTrefMemberId().Or(new HasValidDimensionSourceAttribute()));
ISpecification typedDimension = new IsTypedDimension().And(new HasContextName()).And(new HasContextValue()).And(new HasTrefId()).And(new HasValidDimensionSourceAttribute()).And(new HasTrefMemberId().Not());
Here are three Specification which I have created by stringing together my logical blocks. For example HasContextName() will check that the context name has a value, and that is all. Simple really.
Now I can string any combination of any of these logical blocks of code together to make a human readable complex nested if combination. and to check if my specification has been met, I can use just 1 if statement
if (tuple.IsSatisfiedBy(candidate)){
//do something
}
now all that complexity has been hidden away and is re-usable, in true OO style.
A project I worked on recently was revolved around a booking engine. This engine contained the business logic which dictated how the a booking was processed, which state it would move to, what validation had to fire when, etc etc.
It was split into several pages, all working on the same object (a booking) but a slightly different aspect of the booking. (pricing, accounts etc)
I decided that it would be a good idea to run all the different aspects of the booking through the same method, thus encapsulating the logic of a booking, and hence having 1 place to maintain this logic. It sounded nice at the time, however, over the cource of the 6 - 12 months of developement with 5-6 different developers, this method (group of methods) got extramly large, with a complex set of conditions and loops. What was ever worse was the fact that there were 5-6 developers working on this method using svn for version control. now, if you have used svn for version control, you'll know that if someone makes a major update to a file (ie moves anything to a different place) the merge tools have a bit of a spac attack, and merging your changes to the code base can be a bigger challenge then the code itself. So this section of the code was left unchecked for a very long time.
As a programmer who prides himself on finding a better way, I decided to search for and test the best way of handling this complex array of posibilities. After some searching and playing, I found a few techniques from Stack Overflow which help de-scramble nested if statement. An Interesting rule of thumb.
"3 is a magic number. If I needed more that 3 if's then I should probably use a case statement instead. If you're nesting if statements more than 3 deep then you should probably take that as a sign that there is a better way"
Words to live by really. I guess??
First off, I tried a Specification pattern. This tidies up your if-then-else logic complexity into a neat object structure in which you build your conditions into custom object which holds a smaller subset of that logic and apply IsSatisfiedBy method to return a partial truth. You then string together all the partial truths into an object which is you ISpecification. and then you ask it is my object IsSatisfiedBy this specification. This method will then traverse your string of partial truths evaluating each one and returning a boolean specifying if your object has satisfied the conditions.
Quite a neat way of simplifying the if then else, although it does mean alot of extra work creating new classes and scattering your logic into a million tiny pieces so you end up with an almost sensical string which is your condition. Something like the code below.
ISpecification tuple = new IsTuple().And(new HasContextName()).And(new HasContextValue().Not()).And(new HasTrefId().Not()).And(new HasTrefMemberId().Not());
ISpecification dimension = new IsDimension().And(new HasContextName()).And(new HasContextValue()).And(new HasTrefId()) .And(new HasTrefMemberId().Or(new HasValidDimensionSourceAttribute()));
ISpecification typedDimension = new IsTypedDimension().And(new HasContextName()).And(new HasContextValue()).And(new HasTrefId()).And(new HasValidDimensionSourceAttribute()).And(new HasTrefMemberId().Not());
Here are three Specification which I have created by stringing together my logical blocks. For example HasContextName() will check that the context name has a value, and that is all. Simple really.
Now I can string any combination of any of these logical blocks of code together to make a human readable complex nested if combination. and to check if my specification has been met, I can use just 1 if statement
if (tuple.IsSatisfiedBy(candidate)){
//do something
}
now all that complexity has been hidden away and is re-usable, in true OO style.
Comments
Post a Comment