A minimal, runnable example showing how structural constraints compound to reduce total system complexity as requirements grow.
This repository is intentionally not presented as an architectural pattern, framework, or best practice.
The structure-based implementation shown here is not reachable through incremental refactoring of the control-based version.
Why:
- Each individual change (introducing roles as types, isolating constraints, delegating checks, composing permissions) increases complexity if done alone.
- The reduction only appears when all responsibilities are reassigned simultaneously.
- Partial transformations are strictly worse than the original design.
This creates a structural barrier: a skilled developer working locally, even with full code ownership, cannot arrive at this form through stepwise improvement. The transformation requires recognizing and executing a non-trivial reallocation of responsibility across the entire system.
The process that produces this result is the core of what we teach.
This repository demonstrates a permission system that evolves through three stages of increasing complexity. At each stage, new requirements are added.
The repository contains two implementations of the same requirements:
Control-based: Each new requirement adds validation logic throughout the codebase. The reasoning burden grows with every addition. By Stage 3, the check function contains ~40 lines of nested conditionals that must be understood together.
Structure-based: Each new requirement is encoded as a structural constraint. These constraints compose mechanically. By Stage 3, the check function contains ~10 lines of pure delegation with zero rule knowledge.
This example demonstrates two specific properties:
-
Structural compounding: The structure-based implementation achieves a degree of reduction (in reasoning burden, not line count) that significantly exceeds the error-handling-by-structure example. The core checking logic remains invariant as rules scale, while expressiveness increases.
-
Transformation requirement: The reduction is not achievable through incremental human-only refactoring. The transformation requires simultaneous reorganization of multiple responsibilities—creating constraint types, inverting responsibility, establishing composition mechanisms, and eliminating dispatch logic. Each change is regressive without the others; there are no stable intermediate states.
The repository exists to make these properties observable and falsifiable through code, not rhetoric.
This is not:
- A permissions library or framework
- A claim about performance optimization
- An argument for eliminating all runtime checks
- A demonstration of a novel technique
- A claim that humans cannot understand structured code
- A claim that all refactoring must be simultaneous
- A suggestion that control-based code is "wrong"
This is a teaching artifact showing:
- How responsibility allocation affects reasoning burden at scale
- Why certain structural transformations cannot be achieved incrementally
- What compounding reduction looks like in code (not in theory)
The claims are falsifiable: you can attempt the incremental refactorings and observe whether they reduce reasoning burden.
We need to build a permission system that controls access to resources. The system must grow to handle:
- Basic role-based access - users have roles, resources require roles
- Role hierarchies - some roles grant capabilities of lower roles
- Contextual constraints - access depends on time, ownership, resource state, and role level
Each stage adds requirements that interact with all previous requirements.
Requirements:
- Users have a single role
- Resources require a specific role for access
- Check: does user have the required role?
Complexity:
- Control-based: Simple role comparison
- Structure-based: Permission type with role constraint
New requirements:
- Roles form a hierarchy (Admin > Editor > Viewer)
- Higher roles grant all capabilities of lower roles
- Check must consider role hierarchy
Complexity:
- Control-based: Add hierarchy lookup to every check
- Structure-based: Encode hierarchy in role types, checks remain simple
New requirements:
- Time constraints: some resources only accessible during business hours
- Ownership: users can always access their own content, need higher roles for others' content
- State constraints: published resources require higher role than drafts
- All constraints must compose correctly
Complexity:
- Control-based: Explosion of conditional logic checking all combinations
- Structure-based: Constraints encode as types, composition eliminates branching
As requirements grow:
- Each check site must validate all applicable rules
- New rules require updating every check location
- Conditional complexity grows multiplicatively
- Reasoning requires tracking all possible rule combinations
- Code volume and branching both increase monotonically
By Stage 3, the control-based implementation contains complex nested conditionals that must be reasoned about together. A single change can break multiple locations.
As requirements grow:
- New rules become new constraint types
- Constraint types compose automatically
- Permission checking code stays stable or simplifies
- Reasoning focuses on local constraint definitions
- Code volume may grow, but branching decreases
By Stage 3, the structure-based implementation has more types but simpler logic. Each constraint is defined once and composes with others mechanically.
In the control-based version, each new requirement creates N new validation sites where N is the number of existing check locations.
In the structure-based version, each new requirement creates one new constraint type. Existing code continues to work because constraints compose.
The structural approach frontloads investment: defining constraint types requires more initial code. But this investment compounds: each new constraint reduces the need for explicit validation elsewhere.
The effect is systemic, not local. You cannot achieve it by "being more careful" with control flow.
A skilled developer looking at the Stage 3 control-based implementation might attempt to refactor it incrementally. Common approaches:
def check_ownership(user_id, resource_owner_id):
return user_id == resource_owner_id
def check_time_restriction():
return is_business_hours()
def check_access_stage3(...):
if check_ownership(...) and resource_state == 'draft':
if resource_time_restricted and not check_time_restriction():
return False
return True
# ... rest of conditional logicWhy this fails: The conditionals remain. The function still branches on ownership, state, time, and their interactions. Reasoning burden is unchanged. You've added code without reducing complexity.
class OwnershipRule:
def applies(self, context): ...
def check(self, context): ...
def check_access_stage3(...):
rules = [OwnershipRule(), TimeRule(), StateRule()]
for rule in rules:
if rule.applies(context):
if not rule.check(context):
return False
# ... but how do rules interact? Need more conditionalsWhy this fails: You've created objects, but you still need conditional logic to determine which rules apply and how they compose. The central function still contains interaction logic. You haven't relocated responsibility, just wrapped it.
class Constraint:
def check(self, context): ...
class OwnershipConstraint(Constraint):
def check(self, context):
return context['user_id'] == context['owner_id']
class TimeConstraint(Constraint):
def check(self, context):
return is_business_hours()
def check_access_stage3(...):
constraints = []
# But which constraints apply? Need conditionals to decide
if resource_state == 'draft' and is_owner:
constraints = [OwnershipConstraint()]
elif resource_state == 'published':
constraints = [RoleConstraint(editor_level)]
# And how do time restrictions interact? More conditionals
if resource_time_restricted:
if user_role != 'admin': # Admin override - conditional!
constraints.append(TimeConstraint())
# Check all constraints
return all(c.check(context) for c in constraints)Why this fails: You've created constraint objects, but you still need conditional logic to determine which constraints apply and how they compose. The central function still contains interaction logic. You've added abstraction without reducing complexity.
This is the closest incremental approach can get, and it's regressive: more code, same reasoning burden, unclear responsibility allocation.
The structure-based implementation requires simultaneous changes that cannot be achieved incrementally:
- Ontological shift: Rules must become first-class composable types, not conditionals
- Responsibility inversion: Constraints must check themselves, not be checked by central logic
- Composition mechanism: A uniform way for constraints to combine (ConditionalPermission)
- Elimination of dispatch: The check function must delegate completely, with zero rule knowledge
Each of these changes is regressive without the others:
- Types without composition → more code, same complexity
- Composition without responsibility inversion → just wrapper objects
- Inversion without types → unclear responsibilities
- Partial elimination of dispatch → inconsistent abstraction
Concrete example of why intermediate states fail:
Imagine attempting to transform the control-based code by adding constraint objects while keeping the central check function:
# Step 1: Extract ownership check to object
class OwnershipConstraint:
def check(self, context):
return context['user_id'] == context['owner_id']
# Step 2: But the check function still needs conditionals
def check_access(...):
if resource_state == 'draft':
if OwnershipConstraint().check(context):
# Still need to handle time restrictions conditionally
if resource_time_restricted and not is_business_hours():
# And admin override - another conditional
if user_role != 'admin':
return False
return TrueAt this intermediate state, you have:
- More code (the constraint class + the conditionals)
- Same reasoning burden (still tracking interactions)
- Unclear responsibility (who decides when ownership matters?)
- No benefit yet (expressiveness unchanged, complexity increased)
The benefit only appears when ALL of these simultaneously exist:
- All rules as constraint objects (not just some)
- ConditionalPermission composing them (not central dispatch)
- AccessPolicy trying permission alternatives (not conditional branching)
- check_resource_access delegating completely (no rule knowledge)
This is not about developer skill. It requires seeing the complete structural pattern and implementing it as a coherent whole. Incremental steps are regressive because the pattern has no stable intermediate states.
By Stage 3, the control-based implementation requires tracking:
- Which role is higher in the hierarchy
- Whether the current time is during business hours
- Whether the user owns the resource
- What state the resource is in
- How all of these interact
A human can reason about this for small examples. But as the system grows:
- New engineers cannot see all the rules at once
- Changes in one rule affect validation logic everywhere
- Testing requires reasoning about combinatorial rule interactions
- Refactoring is risky because logic is distributed
The structure-based version localizes each rule in a type. The composition mechanism is mechanical and does not require human reasoning about how rules interact. Adding a new constraint type does not increase the reasoning burden on existing code.
What makes this exceed human-only reasoning:
This is not a claim that humans cannot understand the structure-based code. Rather, it demonstrates that:
-
The transformation itself cannot be achieved incrementally: Attempting to refactor from control-based to structure-based by making one change at a time creates regressive intermediate states (more code, same complexity, unclear responsibility). The pattern must be recognized and implemented as a coherent whole.
-
The structural pattern is not discoverable from conditionals: The control-based code provides no hints that rules should be constraint objects that compose via ConditionalPermission and AccessPolicy. These abstractions require recognizing an alternative ontology for rules—not improving the existing one.
-
The compounding effect requires the complete transformation: The benefit (invariant check complexity as rules scale) only appears when all components exist simultaneously. Partial transformation provides no intermediate benefit to guide the process.
This is not about human capability—it is about the nature of this particular transformation. It requires simultaneous reorganization that cannot be validated or guided by incremental improvement.
The repository makes this falsifiable: you can attempt the incremental refactorings shown in the README and observe that they do not reduce reasoning burden. You can examine the structure-based code and verify that its key abstractions (Constraint interface, ConditionalPermission composition, AccessPolicy alternatives) are not incrementally derivable from control-based conditionals.
This demonstrates a limit not of human reasoning about systems, but of human-only incremental transformation between different structural paradigms.
python run.pyThis runs both implementations through all three stages, showing:
- How control-based code grows in complexity
- How structure-based code grows in capability while simplifying checks
- Identical outputs for identical inputs
The value of this example is not that it can be directly applied to your codebase, but that it demonstrates a compounding effect that is difficult to see without concrete implementation.
Specifically, it shows:
- What compounding reduction looks like: Check complexity stays constant while rule expressiveness scales
- Why incremental refactoring fails: Each partial step is regressive without the complete pattern
- What simultaneous transformation requires: All four components (constraint types, responsibility inversion, composition mechanism, dispatch elimination) must exist together
The repository makes this observable and falsifiable through code. You can:
- Count the conditionals in each version at each stage
- Attempt the incremental refactorings and observe they don't reduce complexity
- Trace how adding a new constraint affects each implementation differently
- Verify that the structure-based abstractions are not incrementally derivable
It often prompts the question: "How would I even think to design systems this way?"
The answer this repository suggests: You wouldn't arrive here through incremental improvement of conditionals. You'd need to recognize the complete structural pattern and implement it as a coherent transformation.