Master Software Contracts
Learn why understanding pre-conditions, post-conditions, and invariants is the foundation of all good codeβand how it eliminates the need for defensive programming
Most Code Is Drowning in Defensive Checks
Null checks everywhere. Validation scattered across codebases. Business logic buried under 40 lines of defensive programming. The type system provides zero help.
57 lines: 42 validation, 15 business logic
Understand Contracts
When you understand pre-conditions, post-conditions, and invariants, defensive programming becomes unnecessary. Validation happens once. Types guarantee correctness. Business logic becomes clear.
8 lines: 0 validation, 8 business logic
The Three Pillars of Correctness
Pre-conditions
What must be true before an operation executes. Encode them in types, not runtime checks.
// Type enforces positivity
Post-conditions
What the operation guarantees after execution. Make them explicit in return types.
// No silent failures
Invariants
Properties that remain true. Maintain by construction, protect with encapsulation.
// Structurally impossible to violate
Types Encode Pre-conditions
Instead of checking if a quantity is positive in every method, create a PositiveInteger type that cannot represent non-positive values.
β if (quantity <= 0) throw
β
Quantity.of(value)
// validates once
Invariants By Construction
Maintain invariants through immutability and encapsulation, not scattered runtime checks. Make invalid states impossible to construct.
β if (balance < 0) fix
β
Money type prevents it
// structurally impossible
Explicit Post-conditions
Return types that explicitly represent success or failure. No null returns. No exceptions for control flow. Clear contracts in signatures.
β User findUser() // null?
β
Result<User, NotFound>
// explicit contract
Layered Type Systems
Build foundational types that enforce constraints once, then compose them into domain types without re-validation. Each layer builds on guarantees below.
NonEmptyString β ProductId
PositiveInt β Quantity
// compose without checks
But First, You Need to See What's Missing
Before you can encode contracts in types, you need to develop the fundamental skill most developers lack: recognizing missing contracts in code
That's what this training system does. Through 60 real-world examples, you'll train your eye to instantly spot missing pre-conditions, unclear post-conditions, and violated invariants.
Train Your Contract Recognition Skills
Learn to identify what's missing before bugs reach production
You'll Learn to Identify
Missing Pre-conditions
What must be true before this code can safely execute?
- β’ Is the parameter null?
- β’ Is the array empty?
- β’ Is the divisor zero?
Unclear Post-conditions
What does this code guarantee about its output?
- β’ Can it return null?
- β’ What type is the result?
- β’ What's the range of values?
Violated Invariants
What properties should always hold?
- β’ Balance never negative?
- β’ Array always sorted?
- β’ Size matches count?
Unhandled Edge Cases
What boundary conditions break this code?
- β’ Empty collections?
- β’ Overflow/underflow?
- β’ Race conditions?
Progressive Training System
Basic Checks
Null checks, empty arrays, division by zero
Type Safety
Type mismatches, property access
Collections
Array bounds, sorting, uniqueness
State Machines
Invalid transitions, ordering
Concurrency
Race conditions, atomicity
See a Real Question
Each question presents buggy code and asks you to identify what's missing
Array First Element
function getFirst(items) {
return items[0];
}What could go wrong with this code?
items might be null or undefined
Pre-condition violation - would crash when accessing [0]
items might be empty
Edge case - empty array returns undefined
items must be sorted
No sorting requirement - we just return first element
Real-world impact: E-commerce site crashed when cart items array was empty but code assumed there was always at least one item.
Develop Code Review Instincts
Learn to instantly spot missing contracts during code review. Your team will write fewer bugs because you'll catch them before merge.
Before: "Looks good to me" β
After: "What if user is null?" π―
Write Code With Proper Contracts
Understanding what's missing is the first step toward encoding contracts in types. Once you see the pattern, you'll design better from the start.
Pattern: Spot contract β Encode in type β Bug impossible
Debug Faster
When production breaks, you'll immediately know where to look: which pre-condition was violated? Which invariant doesn't hold?
NullPointerException
β Missing pre-condition check
Learn From Real World Cases
Every question includes a real-world example of how that missing checks caused production issuesβlearn from others' mistakes.
"Connection pool corruption when same connection returned to pool twice"
Practice in Multiple Languages
Contract principles are universal. See how pre-conditions, post-conditions, and invariants apply across: