I like the sentiment of the “Avoid Negations” section, especially in how negations can weasel their way into naming, but I agree with @mjk that renaming isInorganic()
to isOrganic()
is in fact a good cautionary tale of going too far and not considering the domain context. Also, I think the fact that the
Result.INORGANIC
constant exists and couldn’t be renamed is a big clue that the term “inorganic” is probably an important domain concept.
Regarding the three-line version of isValid()
, I think the book would be better served if it skipped the foreshadowing and presented it in the “Simplify Boolean Expressions” section instead of the preceding “Return Boolean Expressions Directly”, that way we can see the two approaches, i.e., introducing local vars versus extracting methods, closer together.
And perhaps this is covered later, but I also think the book misses an opportunity to suggest using libraries to simplify expressions. For example, using a string-utility library such as StringUtils in Commons Lang 3 would also simplify isValid()
in a clear and concise way:
boolean isValid() {
return missions >= 0 && StringUtils.isNotBlank(name);
}
I don’t propose adding a new dependency only for the sake of simplifying one single line of code, but in this specific example of string logic, a sizable project most likely already has such a library as a dependency.
And finally, I think the example in the “Avoid Negations” section could be carried forward into a discussion of the proper use of conditional expressions, i.e., ternaries, to get some really concise yet expressive code.
Here’s the example from the book:
class Laboratory {
Microscope microscope;
Result analyze(Sample sample) {
if (microscope.isInorganic(sample)) {
return Result.INORGANIC;
} else {
return analyzeOrganic(sample);
}
}
private Result analyzeOrganic(Sample sample) {
if (!microscope.isHumanoid(sample)) {
return Result.ALIEN;
} else {
return Result.HUMANOID;
}
}
}
And here’s how it looks after inlining the private analyzeOrganic()
, replacing if/else with a cascading ternary expression, flipping a negation, and applying some code formatting:
class Laboratory {
Microscope microscope;
Result analyze(Sample sample) {
return
microscope.isInorganic(sample) ? Result.INORGANIC :
microscope.isHumanoid(sample) ? Result.HUMANOID :
/* else */ Result.ALIEN;
}
}
The key is to keep ternaries simple and cleanly formatted, kinda like cond
in lisps such as Clojure. I love 'em!