Valid reasoning & common fallacies
Validity versus soundness, the proof patterns that actually establish things, and the argument forms that only look like they do.
14 cards · 8 quiz questions · 10 min read
Every debugging session is an argument. You have premises — what the logs say, what the test asserts, what you believe the code does — and a conclusion about where the bug lives. Most wasted hours come from one of two failures: reasoning correctly from a premise that was false, or reasoning badly from premises that were fine. Logic gives those two failures separate names, and keeping them apart is most of the skill.
Arguments, validity, soundness
An argument is a set of premises offered in support of a conclusion. Assessing one means asking two independent questions.
Is it valid? Validity is purely about form: if the premises were true, would the conclusion have to be true? Nothing about whether they actually are.
Is it sound? A sound argument is valid and has all true premises. Only soundness guarantees a true conclusion.
The gap between them is where most bad reasoning lives:
- All services in this system are stateless.
- The billing service is in this system.
- Therefore the billing service is stateless.
Impeccably valid. If billing keeps an in-memory session cache, the conclusion is false anyway — because the first premise was. The reasoning was never the problem, and staring harder at the reasoning will not find the bug.
Turn this around and you get a useful tool. If a valid argument reaches a false conclusion, at least one premise must be false. That is how you narrow down a bug: the program’s behaviour contradicts your model, so one of your assumptions is wrong. Find it.
Two valid forms worth knowing by name
Write P → Q for “if P then Q”. Two inference patterns do most of the work.
Modus ponens: from P → Q and P, conclude Q. Affirm the antecedent, get the consequent. This is every conditional branch you have ever written — the condition holds, so the body runs.
Modus tollens: from P → Q and ¬Q, conclude ¬P. The consequence is absent, so the antecedent must fail. This is what a failing test does. “If the code is correct, this assertion passes. The assertion did not pass. Therefore the code is not correct.” Testing cannot prove code right; it can only, by modus tollens, prove it wrong — which is why a green suite is evidence and not a guarantee.
Contrapositive yes, converse no
From P → Q you can form three related statements, and only one of them is equivalent.
- Contrapositive:
¬Q → ¬P. Equivalent. Always the same truth value. - Converse:
Q → P. Not equivalent. - Inverse:
¬P → ¬Q. Not equivalent.
“If it is raining, the ground is wet” is true. Its converse — “if the ground is wet, it is raining” — is false, because a sprinkler will do. Its contrapositive — “if the ground is not wet, it is not raining” — is just as true as the original.
Because the contrapositive is equivalent, you may prove it instead whenever it is easier. That is proof by contraposition, and it is often the shortest route: to show that n² even implies n even, prove instead that n odd implies n² odd, which is a one-line calculation.
The converse trap has a practical edge. A guard clause encodes P → Q, and it is startlingly easy to read a validation rule backwards: “invalid input causes an error” does not mean “an error implies invalid input”.
The two formal fallacies
Confuse the converse or the inverse with the contrapositive and you have committed a formal fallacy — invalid regardless of subject matter.
Affirming the consequent: from P → Q and Q, conclude P. Invalid, because Q may have other causes. This is the debugging fallacy: “if the cache is stale the page is wrong; the page is wrong; therefore the cache is stale.” A broken template produces the same symptom. The dangerous version is the fix that appears to work — the symptom disappeared, so my change must have been the cause — when a restart, a cache expiry, or a timing shift did the real work.
Denying the antecedent: from P → Q and ¬P, conclude ¬Q. Invalid, because Q can arise for other reasons. “We didn’t deploy, so it can’t be broken” ignores expiring certificates, data growth and upstream changes.
Both are worth recognising instantly, because both feel persuasive.
Proof by contradiction
To prove a claim by contradiction, assume its negation and derive an impossibility. Since a contradiction cannot stand, the assumption must be false, and the claim survives.
Euclid’s proof that the primes are infinite runs this way. Suppose only finitely many primes exist. Multiply them all together and add one. The result leaves remainder 1 on division by every prime in the list, so either it is prime itself or it has a prime factor outside the list. Either way there is a prime you did not have, contradicting the assumption. Therefore there are infinitely many.
The engineering version is a reductio: “suppose two threads could both hold the lock — then this counter would exceed its bound, which we know never happens.” You reason from the impossibility backwards.
Induction, base case included
Mathematical induction proves a statement for every natural number using two pieces:
- Base case — the statement holds at the starting value.
- Inductive step — if it holds for an arbitrary
n, then it holds forn + 1.
Together they cover everything from the base upwards: the base lights the first rung, the step carries you up each one after.
Skipping the base case is fatal, and the reason is worth internalising. The inductive step only propagates truth; it never creates it. A perfectly correct chain of implications can carry a false statement forever if it was false at the start. That is the same structure as a recursive function with a correct recursive case and no terminating condition: locally right, globally useless.
This is not merely analogous to programming — it is how you argue that a loop is correct. A loop invariant is established before the first iteration (base case) and preserved by each iteration (inductive step), so it still holds when the loop exits. Induction is the tool that lets you say something true about all inputs, not just the ones you tested.
Informal fallacies, and a caution about them
Two informal ones show up constantly in technical discussion.
A straw man replaces someone’s position with a weaker, distorted version and refutes that. “You want stricter review” becomes “you want to block every merge”, which is easy to demolish and nobody argued for. The refutation can be perfectly valid and still miss.
A false dilemma presents two options as exhaustive when they aren’t: “either we rewrite it or we live with the bugs.” Arguing from a genuine either/or is valid; the fallacy is the smuggled premise that the list is complete. Ask what the third option is.
A fair caveat to end on. Everyday argument is mostly inductive and probabilistic, not deductive, and forcing it into P → Q form often distorts it. Reasoning that is invalid as proof can be perfectly good evidence: “the page is wrong, and the cache is usually the culprit” is a sensible place to start looking, even though it affirms the consequent. Douglas Walton spent a career arguing that many textbook fallacies are context-dependent — reasonable defaults that fail only under particular conditions.
Fallacy-spotting can itself become a rhetorical trick: naming a fallacy is quicker than engaging with an argument, and a label can end a conversation without settling anything. The forms are tools for checking your own reasoning first. Use them on other people’s sparingly, and on your own hypotheses relentlessly.
An argument is valid but its conclusion is false. What must be true?
Sources
- Kenneth H. Rosen — Discrete Mathematics and Its Applications book Rules of inference, proof methods and mathematical induction.
- Daniel J. Velleman — How to Prove It: A Structured Approach book Systematic treatment of contradiction, contraposition and induction as proof strategies.
- Irving M. Copi — Introduction to Logic book Standard reference on validity, soundness and the catalogue of formal and informal fallacies.
- Douglas Walton — Douglas Walton author Argumentation theorist; argued that many so-called fallacies are context-dependent rather than always wrong.