This is somewhat subjective, but a good general rule of thumb is to remove as much complexity as possible. By complexity, I mean the number of operations you need to perform in order to obtain the desired result.
In this sense, !a && !b
is worse than !(a || b)
because in one case you're negating a and b, then performing the and
operator resulting in 3 operations whereas in the latter case, you're only performing 2. Of course this is vacuous when you're talking about two conditions, but when you're dealing with many, this can make a big difference.
Ideally, the form of your conditions would be either in the form a || b || c
or a && b && c
, adding parentheses as necessary. Try to avoid forms like !(a && b) || (b && (c || d || !a))
as it is very difficult to decifer the meaning without creating a truth table.
Also, it is generally a good idea to avoid "not" in variables holding conditions, even if it adds complexity.
In other words, it is better to see isWet = raining && !hasUmbrella && !isInside
than to have isNotWet = !raining || hasUmbrella || isInside
, because it's easier to rationalize the meaning of variable isWet
than isNotWet
. You can always negate isWet
to achieve the same value of isNotWet
.