Summary of "If considered harmful: How to eradicate 95% of all your bugs in one simple step - Jules May"
Summary of "If considered harmful: How to eradicate 95% of all your bugs in one simple step" by Jules May
Main Ideas and Concepts
-
The Core Problem: Synchronized Conditions (Ifs) as the Major Source of Bugs
- Jules May claims that about 90% of bugs in large codebases stem from a single anti-pattern involving duplicated or synchronized conditional checks (i.e., repeated
ifstatements controlling different parts of code). - This anti-pattern causes "wormhole code," a form of "spooky action at a distance" where logically connected conditions are physically separated in code, leading to desynchronization and bugs.
- Secondary bugs (bugs caused by fixing other bugs) approach 99% and are also largely due to this pattern.
- Contrary to popular belief, the
gotostatement is not the main culprit; rather, it is the misuse ofifconditions that causes the majority of problems.
- Jules May claims that about 90% of bugs in large codebases stem from a single anti-pattern involving duplicated or synchronized conditional checks (i.e., repeated
-
Historical Context: Edsger Dijkstra’s Work on structured programming
- Dijkstra’s 1968 letter, "The Case Against the Go-To Statement," linked the presence of
gotos to bugs and introduced the concept of structured programming. - He introduced the concept of an execution coordinate, a way to link program code location (spatial/static) with the point in time during execution (dynamic), allowing better program understanding.
- structured programming replaces free-form
gotos with controlled flow constructs (loops, conditionals, function calls) that maintain a clear execution coordinate. - Modern programming has tamed
gotos through structured constructs, but the equivalent discipline forifconditions is lacking.
- Dijkstra’s 1968 letter, "The Case Against the Go-To Statement," linked the presence of
-
Execution Coordinates and structured programming
- Execution coordinates represent a program’s position both in code and in execution time, including call stack and loop iterations.
- Structured programs maintain a one-to-one mapping between code location and execution time/history.
- Unstructured code (e.g., excessive or unsynchronized
ifs andgotos) breaks this mapping, making debugging and reasoning difficult.
-
The Anti-Pattern: Repeated or Synchronized If Conditions
- Having the same condition tested in multiple places leads to bugs because these conditions can get out of sync.
- This is worsened by debugging practices that patch bugs by adding new
ifconditions scattered throughout the code, increasing technical debt. - These scattered conditions represent latent defects waiting to cause malfunctions.
-
Distinction Between Defects and Malfunctions
- A defect is a fault in the code; a malfunction is the observable failure caused by a defect.
- Not all defects cause malfunctions immediately; many sit dormant until triggered.
- Adding scattered conditionals as patches increases defects rather than eliminating them.
-
Proposed Solution: Decision Structure and Concentration of Conditions
- Instead of scattering conditions (
ifs) throughout the code, centralize the decision logic in one place. - Separate decisions (conditions/tests) from their consequences (actions).
- Use constructs that imply decisions from the shape of the code rather than explicit repeated conditionals.
- This mirrors how structured programming replaced
gotowith loops and function calls.
- Instead of scattering conditions (
-
Techniques and Methodologies to Implement the Solution
-
Assertions:
- Use assertions to enforce preconditions and invariants, stopping execution immediately when conditions fail rather than patching with
if. - Assertions can be runtime (throw exceptions, abort) or compile-time (type checks, contracts).
- Assertions document intent and improve reliability by catching defects early.
- Use assertions to enforce preconditions and invariants, stopping execution immediately when conditions fail rather than patching with
-
Polymorphism and Value Polymorphism:
- Use polymorphism to handle different cases instead of
if-based conditionals. - Value polymorphism (common in functional languages like Haskell or F#) allows dispatch based on values as well as types.
- Express decision logic at the function or class level, not scattered in multiple
ifs.
- Use polymorphism to handle different cases instead of
-
Factory Methods and Object-Oriented Design:
- Concentrate decision logic in factory methods that instantiate appropriate subclasses based on input conditions.
- Make constructors private and expose creation only through factory methods to control instantiation logic centrally.
- This reduces scattered conditional logic and keeps consequences grouped in related classes.
-
Null Object Pattern Instead of Null Pointers:
- Avoid null pointers as they cause many bugs requiring scattered null checks.
- Use null objects that implement the expected interface but represent "no operation" or default behavior.
- Null objects can be checked at compile time and reduce runtime defects.
-
Pre-compilers and Compiler Extensions:
- Use pre-compilers or compiler extensions (e.g., Roslyn for .NET) to enforce code hygiene, such as ensuring fields are initialized and conditions are centralized.
- Automate checks to prevent introduction of defects.
-
Assertions:
- Modern Language Support
Category
Educational
Share this summary
Is the summary off?
If you think the summary is inaccurate, you can reprocess it with the latest model.
Preparing reprocess...