Tuesday, July 12, 2011

Disentangling boolean logic: The problem

 One of the most difficult things i've had to do in my carreer as a refactorer is to trying to clean up entangled boolean logic. The program has many states represented by booleans and depending on their values or a combination of their values, various pieces of logic execute. All is fine and dandy, unfortunately not all that logic executes correctly, in other words we have a bug. Being new to a system i often find myself fixing one such a bug, only to introduce another, and then when i think i fixed them both, 2 others appear, and so on. Now it's time to bring in the big guns and get a proper grip on the problem. Where are all these booleans coming from? Who is using them and how? Do some of these variables produce a butterfly effect, affecting seemingly unrelated pieces of code or even the air conditioning in your building? So the first approach is to try to get an overview of the use cases. What at least some organized programmers do is create a matrix of possible inputs to expected outputs (or expected function calls). This can be quite a challenge, since if your input is represented by n booleans, your possible set of input states is 2^n, and that's just one of the dimensions.

Luckily, usually the real use cases can be encoded much more concisely (see my other post on this subject), by reducing the set of booleans by 1 enum. Suppose after an arduous journey through boolean land, we have come up with a matrix of inputs to outputs for test cases, which has a total number of cells between 15-50. Are we there yet? Unfortunately, we have only started. The matrix that we have created represents the ideal state. Now all that's left is to figure out how what we have corresponds to what we need. And as Murphy's Law would have it, we don't have a 1:1 correspondence between the variables in the current program and the entries in the matrix.

So, as a pragmatic reader, you may ask, what does this post actually advocate? Well, ahem... It advocates a heavy-handed refactoring process that attempt to arrive at a quite complex solution space (the ideal reduced matrix of inputs to outputs, which may not even be that small) from an even more complex space (in practice a less ideal matrix of much larger dimensions). I have to say I do not have a nice and clean approach to this, but I do have a few tips & tricks that have helped me in the past to reduce the complexity of boolean logic, which I'll describe in the next post. 

No comments:

Post a Comment