The Problem
You built a user authentication module. It works great. Three months later, you start a new project and want to reuse it. You copy the file... and it breaks. It references config.APP_SECRET. It imports from database.models. It calls logger.log_auth_event(). What you thought was a reusable component is tightly coupled to your specific project.
If you can't extract it cleanly, it's not fractal.
The challenge: building components that are self-contained, portable, and work anywhere with minimal adaptation.
The Core Insight
The fractal test: Copy a component to a new file. If it works with just dependency injection changes, it passes. If it needs deep rewrites, it fails.
Fractal components are like Lego bricks: they have standard interfaces and work anywhere. Non-fractal components are like jigsaw pieces: they only fit in one specific spot.
When AI generates code for fractal components, it's portable. AI learns patterns that transfer across projects, not one-off hacks.
The Walkthrough
Non-Fractal Component (Fails Test)
# auth.py - tightly coupled
import config
from database.models import User
from utils.logger import log_auth_event
def authenticate_user(username, password):
# References global config
secret = config.APP_SECRET
# Tightly coupled to specific database model
user = User.query.filter_by(username=username).first()
if not user:
# Tightly coupled to specific logger
log_auth_event("failed_login", username)
return None
# Uses hardcoded hashing (can't swap algorithm)
if bcrypt.verify(password, user.password_hash):
log_auth_event("successful_login", username)
return generate_jwt(user, secret)
return None
Try to extract this to a new project:
- Need to recreate
config.APP_SECRET - Need a
Usermodel with exact same fields - Need
log_auth_event()function - Can't change hashing algorithm
- Can't change JWT implementation
Fractal Test Result: FAIL. Requires deep integration with host project.
Fractal Component (Passes Test)
# auth.py - fractal design
from typing import Protocol, Optional
from dataclasses import dataclass
# Define interfaces, not implementations
class UserRepository(Protocol):
def find_by_username(self, username: str) -> Optional['UserData']:
...
class Logger(Protocol):
def log(self, event: str, data: dict):
...
class PasswordHasher(Protocol):
def verify(self, password: str, hash: str) -> bool:
...
class TokenGenerator(Protocol):
def generate(self, user_data: dict, secret: str) -> str:
...
@dataclass
class UserData:
username: str
password_hash: str
class AuthService:
"""Portable authentication service."""
def __init__(
self,
user_repo: UserRepository,
logger: Logger,
hasher: PasswordHasher,
token_gen: TokenGenerator,
secret: str
):
self.user_repo = user_repo
self.logger = logger
self.hasher = hasher
self.token_gen = token_gen
self.secret = secret
def authenticate(self, username: str, password: str) -> Optional[str]:
"""Authenticate user and return token."""
user = self.user_repo.find_by_username(username)
if not user:
self.logger.log("failed_login", {"username": username})
return None
if self.hasher.verify(password, user.password_hash):
self.logger.log("successful_login", {"username": username})
return self.token_gen.generate(
{"username": username},
self.secret
)
return None
Extract to new project:
- Copy
auth.py - Implement the 4 protocols with your project's infrastructure
- Inject dependencies
- Done!
Fractal Test Result: PASS. Component is self-contained, dependencies are explicit, implementation is swappable.
Why This Matters for AI
When AI sees the fractal version, it understands: "This is a service that takes dependencies." It can suggest similar patterns elsewhere. The non-fractal version looks like project-specific code that can't be generalized.
The Fractal Test Checklist
For any component, ask:
| Question | Fractal Answer | Non-Fractal Answer |
|---|---|---|
| Can I copy this file to a new project? | Yes, with DI changes only | No, needs deep rewrites |
| Are dependencies explicit? | All in constructor/params | Hidden imports, globals |
| Can I swap implementations? | Yes, via interfaces | No, hardcoded |
| Does it reference globals? | No globals | Uses config.*, app.*, etc |
| Can I test it in isolation? | Yes, with mocks | Needs full app setup |
Test It: The 5-Minute Extract
Literally try to extract your component:
# Create a new empty project
mkdir /tmp/test-extract
cd /tmp/test-extract
# Copy just the component file
cp /path/to/your/component.py .
# Try to use it
# How long does it take to make it work?
# How many files do you need to bring with it?
# How much code do you need to rewrite?
If you can make it work in 5 minutes with just dependency injection, it's fractal.
Patterns for Fractal Components
Pattern 1: Dependency Injection Everywhere
# Non-fractal: Hidden dependencies
class EmailService:
def send(self, to, subject, body):
# Where does smtp_config come from?
smtp = smtplib.SMTP(smtp_config.host, smtp_config.port)
smtp.send_message(...)
# Fractal: Explicit dependencies
class EmailService:
def __init__(self, smtp_client: SMTPClient):
self.smtp = smtp_client
def send(self, to, subject, body):
self.smtp.send_message(...)
Pattern 2: Interface Segregation
# Non-fractal: Depends on entire database
class OrderService:
def __init__(self, database: Database):
self.db = database
def create_order(self, order_data):
self.db.orders.insert(order_data)
# Now coupled to full database API
# Fractal: Depends on minimal interface
class OrderRepository(Protocol):
def create(self, order: Order) -> Order:
...
class OrderService:
def __init__(self, orders: OrderRepository):
self.orders = orders
def create_order(self, order_data):
return self.orders.create(Order(**order_data))
Pattern 3: Configuration as Dependency
# Non-fractal: Reads config directly
import os
class CacheService:
def __init__(self):
# Coupled to environment variables
self.ttl = int(os.getenv('CACHE_TTL', '3600'))
self.redis_url = os.getenv('REDIS_URL')
# Fractal: Config injected
@dataclass
class CacheConfig:
ttl: int
redis_url: str
class CacheService:
def __init__(self, config: CacheConfig):
self.ttl = config.ttl
self.redis_url = config.redis_url
Pattern 4: Pure Functions Where Possible
# Non-fractal: Stateful, side-effectful
class PriceCalculator:
def __init__(self):
self.tax_rate = load_tax_rate_from_database()
def calculate_total(self, items):
# Mixes calculation with data access
subtotal = sum(item.price for item in items)
return subtotal * (1 + self.tax_rate)
# Fractal: Pure function, easy to extract
def calculate_total(items: List[Item], tax_rate: float) -> float:
"""Pure function - no side effects, no hidden state."""
subtotal = sum(item.price for item in items)
return subtotal * (1 + tax_rate)
Failure Patterns
1. The Singleton Trap
Symptom: Component uses singleton instances, can't be extracted.
# Non-fractal: Singleton dependency
class UserService:
def get_user(self, user_id):
# Coupled to global singleton
return Database.instance().get_user(user_id)
# Fractal: Injected dependency
class UserService:
def __init__(self, db: Database):
self.db = db
def get_user(self, user_id):
return self.db.get_user(user_id)
2. The Circular Dependency
Symptom: Can't extract A without B, can't extract B without A.
Fix: Introduce interfaces to break cycles.
3. The God Object
Symptom: Component does too much, has 20 dependencies.
Fix: Split into smaller, single-purpose components.
4. The Hidden State
Symptom: Component behavior depends on module-level state.
# Non-fractal: Module state
_cache = {}
def get_user(user_id):
if user_id in _cache:
return _cache[user_id]
# ...
# Fractal: Explicit state
class UserCache:
def __init__(self):
self._cache = {}
def get_user(self, user_id):
if user_id in self._cache:
return self._cache[user_id]
# ...
When Extraction Doesn't Matter
Some code is genuinely project-specific and doesn't need to be fractal:
- Main application entry point
- Project-specific configuration
- Integration glue code
Focus fractal design on reusable business logic and utilities.
AI Assistance with Fractal Components
Prompt: Make This Fractal
Prompt to AI:
"Refactor this component to be fractal - extractable to a new project with just DI changes.
Current code:
[paste code]
Requirements:
1. All dependencies explicit via constructor
2. Use protocols/interfaces for dependencies
3. No globals or hidden imports
4. Configuration injected, not read directly
5. Should be testable in isolation"
AI will apply dependency inversion, extract interfaces, and make dependencies explicit.
Prompt: Test Extractability
Prompt to AI:
"Analyze this component. Could I copy this file to a new project and use it with minimal changes? List what would need to be adapted.
Code:
[paste code]"
AI will identify coupling points and suggest fixes.
Quick Reference
The Fractal Test:
- Copy component to empty project
- Implement required interfaces
- Inject dependencies
- Does it work? If yes → fractal. If no → coupled.
Fractal Component Checklist:
- ✓ Dependencies injected via constructor
- ✓ Uses interfaces/protocols, not concrete types
- ✓ No global state or singletons
- ✓ Configuration injected, not read directly
- ✓ Testable in isolation with mocks
- ✓ No hardcoded references to other modules
- ✓ Clear single responsibility
Refactoring to Fractal:
# 1. Find hidden dependencies
grep -r "import config\|os.getenv\|global " component.py
# 2. Extract interfaces
# Create Protocol classes for all external dependencies
# 3. Add DI constructor
# Move all dependencies to __init__
# 4. Test extraction
# Try copying to new project
# 5. Verify
# Can it work with just interface implementations?
Quick Conversion Template:
# Before: Coupled
class MyService:
def do_thing(self):
result = global_db.query(...)
send_email(result)
# After: Fractal
class MyService:
def __init__(self, db: Database, email: EmailService):
self.db = db
self.email = email
def do_thing(self):
result = self.db.query(...)
self.email.send(result)