Functions, invariants, recursion and error boundaries — DedSec Project
Functions, invariants, recursion and error boundaries Functions and contracts Design principle and reasoning A function contract specifies accepted inputs, outputs, errors and side effects…
Functions and contracts
Design principle and reasoning
A function contract specifies accepted inputs, outputs, errors and side effects. Type hints alone do not enforce numeric ranges or filesystem permissions; runtime checks are necessary for untrusted inputs.
Study a concrete case
def percent(part,total):
if total<=0 or not 0<=part<=total: raise ValueError('range')
return 100*part/total
assert percent(2,4)==50
Independent exercise
Test zero total and part>total and prove the caller observes clear exceptions. Decide if fractional inputs are allowed.
Evidence for review
For Functions and contracts, identify one failure mode beyond the happy path and specify a test or observation that would expose it. Write the expected result first, then validate the exact boundary without altering a production environment.
Iteration and invariants
Design principle and reasoning
A loop invariant is true before every iteration and remains true afterward. In an accumulator loop, total equals the sum of elements already processed; termination requires measurable progress.
Study a concrete case
def total(xs):
s=0
for x in xs:s+=x
return s
assert total([2,3,4])==9
Independent exercise
Instrument iterations and assert that the running sum matches a prefix. Test empty input and negative elements.
Evidence for review
For Iteration and invariants, identify one failure mode beyond the happy path and specify a test or observation that would expose it. Write the expected result first, then validate the exact boundary without altering a production environment.
Recursion and termination
Design principle and reasoning
Every recursive call must reduce a well-founded measure until a base case applies. An argument that never changes causes unbounded recursion, and increasing the interpreter stack limit does not correct logic.
Study a concrete case
def depth(n):
if n<0: raise ValueError()
if n==0:return 0
return 1+depth(n-1)
assert depth(4)==4
Independent exercise
Trace the call stack for n=3. Compare iterative implementation at n=20000 and explain recursion depth limits.
Evidence for review
For Recursion and termination, identify one failure mode beyond the happy path and specify a test or observation that would expose it. Write the expected result first, then validate the exact boundary without altering a production environment.
Error handling boundaries
Design principle and reasoning
Errors should be handled where a component can make a meaningful decision: a parser reports invalid data, while the CLI chooses whether to show a message or exit. Catching Exception around everything can hide defects.
Study a concrete case
def parse_port(s):
n=int(s)
if not 1<=n<=65535:raise ValueError('port')
return n
assert parse_port('443')==443
Independent exercise
Distinguish integer conversion failure, out-of-range values and missing files. Only translate errors at a boundary where you can add useful context.
Evidence for review
For Error handling boundaries, identify one failure mode beyond the happy path and specify a test or observation that would expose it. Write the expected result first, then validate the exact boundary without altering a production environment.