Evaluate the efficiency and readability of programs with conditionals. Learn how to use code reviews to give and receive feedback.
We can structure our conditional code in many different ways to achieve the same functionality. Two programs may do the same thing, but the way they organize their code matters, too!
What is a code review?
Before a programmer submits their code changes, they often send their work to another person to review. The code review process lets programmers learn from each other, just like peer revisions on an essay.
Code reviewers help the author look for bugs, improve readability, and evaluate tradeoffs. They also make sure the code is maintainable, meaning others can easily modify it later.
Maintainable code avoids redundant logic. We call this the "don't repeat yourself" principle, or DRY code. Redundant code increases the risk of bugs, because future programmers may not recognize the relationship between certain lines of code. When they go to modify it, they may accidentally break the intended behavior!
Evaluating conditionals
Imagine you've been asked to review the code changes below. What redundancies do you see? Consider how you would the conditional to be more maintainable. Then, take a look at the provided code review and compare.
Each program demonstrates a common conditional anti-pattern. Once you learn how to fix them here, keep an eye out for them in the code you read and write!
Don't compare booleans
if age >= 18 == True: can_edit = Trueif can_edit == False: print("Unauthorized. You must be an editor.")
The expression age >= 18
already evaluates to a boolean value, so it's redundant to compare it to the value True
. We're asking: is age >= 18
equal to True
? when instead we could just ask: is age >= 18
?
Similarly, can_edit
contains a boolean value, so we can rewrite the condition can_edit == False
as: not can_edit
.
if age >= 18: can_edit = Trueif not can_edit: print("Unauthorized. You must be an editor.")
Up-level shared logic
if weight < 16: print("Package size: small") num_packages = num_packages + 1elif weight < 32: print("Package size: medium") num_packages = num_packages + 1else: print("Package size: large") num_packages = num_packages + 1
Each branch does almost the same thing, and we always execute exactly one of the branches. Instead of repeating the same line in each branch, we can increment num_packages
outside of the conditional. Then, we only have to write that line of code once.
With the print
statements, only the package size name changes based on the branch. The rest of the message stays the same. If we move the print
statement outside of the conditional, it makes it easier to modify the message later. We'd only need to change the one print
statement, instead of coordinating across all three.
if weight < 16: package_size = "small"elif weight < 32: package_size = "medium"else: package_size = "large"print("Package size: " + package_size)num_packages = num_packages + 1
Combine related branches
if city == "Newark": state = "New Jersey"elif city == "Allentown": state = "Pennsylvania"elif city == "Princeton": state = "New Jersey"else: state = "Pennsylvania"
It looks like some of these branches do the same thing. If the city
is equal to "Newark"
or "Princeton"
, we set state
to the value "New Jersey"
. In all other cases, the state
is "Pennsylvania"
.
We can shorten the conditional if we use a compound condition to combine multiple branches into one. This avoids the redundant assignment statements, which makes it easier to see the relationship between city
and state
.
It also means we only have to type out the state
name once, which reduces the chance that we misspell a tricky word like "Pennsylvania"
!
if city == "Newark" or city == "Princeton": state = "New Jersey"else: state = "Pennsylvania"
Chain exclusive conditions
if year > 1279 and year <= 1368: print("Yuan dynasty in China")if year > 1368 and year <= 1644: print("Ming dynasty in China")if year > 1644 and year <= 1912: print("Qing dynasty in China")if year > 1600 and year <= 1868: print("Edo period in Japan")
The first three conditions print the Chinese dynasty during that time period. The date ranges are all mutually exclusive, so we can chain them using elif
branches.
If we later find that we're off by a year, we've made the relationship to the other conditions more obvious. We'd know that we should adjust the ranges of the chained conditions to match.
This also improves efficiency. With the chain, the computer won't bother evaluating the remaining conditions if it's already found that the first condition evaluates to True
.
if year > 1279 and year <= 1368: print("Yuan dynasty in China")elif year > 1368 and year <= 1644: print("Ming dynasty in China")elif year > 1644 and year <= 1912: print("Qing dynasty in China")if year > 1600 and year <= 1868: print("Edo period in Japan")