Last Revision — April 19, 2022
2 Min Read
---
Obfuscators
Conditional Logic
Within a Class
- Complicated Regex Expression (family)
- Obscured Intent (causes)
- Flag Argument (caused)
- "What" Comments (causes)
William C. Wake in book (2004): "Refactoring Workbook"
One should keep in mind that Boolean Expressions can be troublesome for some people (in other words, not as quick to comprehend as if it were an adequately named method instead). Wake reminds the reader of De Morgan Laws that could be applied to simplify the expression.
Wake also reminds us about guard checks, which could "peel off" complexity layers from the expression. [1] Interestingly, Robert Martin gives a minimum example in his Encapsulate Conditionals refactoring explanation [2], which could be a bit controversial but is yet another good perspective to look at the problem. Instead of simplifying the expression, he paid attention to the readable intention. As I have just mentioned, the example provided might be a bit controversial because it contains just one AND
operation, which is not a Discrete Mathematics 2 type problem. Nevertheless, the point is valid: An appropriately named function or method is more comprehensible at a glance than whatever the boolean
expression it is.
I have linked the smell to Obscured Intent as causes just because of all the cases of any if not thing.notDone()
double negated by token and name expressions, wherever they are. An unnecessary Flag Argument Code Smell might imperceptibly impact the complexity of an expression.
Similar to Conditional Complexity - developers introduced new features, and instead of doing it cleanly, developers used a dirty method conditional method instead.
It's easier to read declarative words than to computate logic statements.
if (timer.has_expired() and not timer.is_recurrent()):
...
if (should_be_deleted(timer)):
...
def cook(ready: bool, bag: list):
if (ready):
if (['raspberry', 'apple', 'tomato'] in bag and ['carrot', 'spinach', 'garlic'] not in bag):
...
# "ready" extracted out of the function scope
def cook(bag: list):
def hasFruit(container: list) -> bool:
return ['raspberry', 'apple', 'tomato'] in container
def hasVeggie(container: list) -> bool:
return ['carrot', 'spinach', 'garlic'] in container
if not hasFruit(bag):
return
if hasVeggie(bag):
return
...