Question

One of my personal programming demons has always been complex logic that needs to be controlled by if statements (or similiar). Not always necessarily that complex either, sometimes just a few states that needs to be accounted for.

Are there any tools or steps a developer can perform during design time to help see the 'states' and take measures to refactor the code down to simplify the resulting code? I'm thinking drawing up a matrix or something along those lines...?

Was it helpful?

Solution

I'd recommend a basic course in propositional logic for every aspiring programmer. At first, the notation and Greek letters may seem off-putting to the math-averse, but it is really one of the most powerful (and oft-neglected) tools in your skillset, and rather simple, at the core.

The basic operators, de Morgan's and other basic laws, truth tables, and existence of e.g. disjunctive and conjunctive normal forms were an eye-opener to me. Before I learned about them, conditional expressions felt like dangerous beasts. Ever since, I know that I can whip them into submission whenever necessary by breaking out the heavy artillery!

OTHER TIPS

Truth tables are basically the exhaustive approach and will (hopefully) highlight all the possibilities.

You might like to take a look at Microsoft Pex, which can be helpful for spotting the fringe cases you hadn't thought of.

I think that the developer is asking how to make his life easier when dealing with complex if code.

The way that I handle complex if code is to code as flat as possible and weed out all negations first. If you can get rid of compound if by placing a portion of it above, then do that.

The beauty of simplicity is that it doesn't take a book or a class to learn it. If you can break it up, do so. If you can remove any part of it, do so. If you don't understand it, do it differently. And flat is almost always better than nested (thanks python!).

It's simpler to read:

if(broken){
  return false;
}
if (simple){
  doit();
  return true;
}
if(complicated){
  divide();
  conquor();
}
if(extra){
  extra();
}

than it is to read:

if(!broken && (simple || complicated)){
 ....
}
return false;

Truth tables and unit tests - draw up the tables (n dimensional for n variables), and then use these as inputs to your unit test, which can test each combination of variables and verify the results.

The biggest problem I've seen through the years with complex IFs is that people don't test all the branches. Make sure to write a test for each possible branch no matter how unlikely it seems that you will hit it.

You might also want to try Karnaugh maps, which are good for up to 4 variables.

If you haven't already, I'd highly suggest reading Code Complete. It has a lot of advice on topics such as this. I don't have my copy handy at the moment, otherwise I'd post a summary of this section in the book.

Split the logic down into discrete units (a && b, etc.), each with their own variable. Then build these up using the logic you need. Name each variable with something appropriate, so that your complex statement is fairly readable (although it may take up several extra lines and a fair few temporary variables).

Any reason you cannot just handle the logic with guard statements?

Karnaugh maps can be nice ways of taking information from a truth table (suggested by Visage) and turning them into compact and/or/not expressions. These are typically taught in an EE digital logic course.

Have you tried a design pattern? You might look into what is known as the Strategy pattern: http://en.wikipedia.org/wiki/Strategy_pattern

Check out the nuclear option: Drools. There's quite a lot to it-- took me a day or two of perusing the literature just to get a handle on its capabilities. But if you have applications where your complex if-then logic is an evolving part of the project (for example, an application with modular algorithms) it might be just the thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top