Agent skill
Keeping Routines Focused
Each routine does one thing and does it well - extract when routines have multiple responsibilities
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/keeping-routines-focused-barrydobson-dotfiles-extra
SKILL.md
Keeping Routines Focused
Overview
A routine should do ONE thing and do it well. This is called functional cohesion - the strongest, best kind of cohesion.
Core principle: If a routine's description contains "and", it's doing too many things. Extract into focused routines.
Goal: Improve intellectual manageability. The more focused a routine, the easier to understand, test, modify, and reuse.
When to Use
Proactively (writing new code):
- Designing new functions/methods
- Writing routine specifications
- Naming routines (if name is vague or has "and", too many responsibilities)
Reactively (improving existing code):
- Reviewing code with long routines
- Refactoring when routine does multiple things
- When routine is hard to understand or test
- When routine keeps growing with each modification
Warning signs routine needs focus:
- Description has "and" in it
- Routine name is vague or long
- Routine is hard to name clearly
- Routine is > 200 lines (strong signal)
- Parameter list > 7 parameters
- Many local variables (> 10)
- Multiple levels of abstraction mixed
- Does validation AND calculation AND side-effects
- Hard to write test (does too much to test atomically)
What is "One Thing"?
One thing means one level of abstraction:
✅ Does one thing:
def calculate_total_price(items, tax_rate):
"""Calculate total price of items including tax."""
subtotal = sum(item.price * item.quantity for item in items)
tax = subtotal * tax_rate
return subtotal + tax
Single purpose: price calculation. All statements at same abstraction level (arithmetic).
❌ Does multiple things:
def handle_order(order_data, user_id):
"""
Process order:
- Validate order data
- Calculate total with tax
- Apply discount codes
- Check inventory
- Create order record
- Send confirmation email
- Update user history
- Return confirmation
"""
validated = validate_order_data(order_data, user_id) # Thing 1
subtotal = calculate_subtotal(validated["items"]) # Thing 2
discount = apply_discount(subtotal, validated.get("discount_code")) # Thing 3
tax = calculate_tax(subtotal - discount, validated["tax_rate"]) # Thing 4
total = subtotal - discount + tax # Thing 5
check_inventory(validated["items"]) # Thing 6
order_record = create_order_record(...) # Thing 7
send_confirmation_email(...) # Thing 8
update_user_history(user_id, order_record["order_id"]) # Thing 9
return {...} # Thing 10
Description has 8 "and"s. Does 10 different things. Violates single responsibility.
How to Extract Routines
Technique 1: Extract by Responsibility
Group related statements, extract into focused routine:
Before (orchestrator does everything):
def handle_order(order_data, user_id):
# Validation (lines 1-10)
validated = validate_order_data(order_data, user_id)
# Pricing (lines 11-15)
subtotal = calculate_subtotal(validated["items"])
discount = apply_discount(subtotal, validated.get("discount_code"))
tax = calculate_tax(subtotal - discount, validated["tax_rate"])
total = subtotal - discount + tax
# Inventory (lines 16-20)
check_inventory(validated["items"])
# Persistence (lines 21-30)
order_record = create_order_record(...)
# Notifications (lines 31-35)
send_confirmation_email(...)
update_user_history(user_id, order_record["order_id"])
return {...}
After (each phase is focused routine):
def handle_order(order_data, user_id):
"""Single responsibility: Orchestrate order processing."""
validated_order = validate_order_request(order_data, user_id)
pricing = calculate_order_pricing(validated_order)
verify_inventory_available(validated_order)
order = create_and_save_order(validated_order, pricing, user_id)
send_order_notifications(order)
return create_confirmation_response(order, pricing)
def validate_order_request(order_data, user_id):
"""Single responsibility: Validate order data."""
# Just validation
def calculate_order_pricing(validated_order):
"""Single responsibility: Calculate prices."""
# Just pricing math
def verify_inventory_available(validated_order):
"""Single responsibility: Check inventory."""
# Just inventory check
def create_and_save_order(validated_order, pricing, user_id):
"""Single responsibility: Persist order."""
# Just database operations
def send_order_notifications(order):
"""Single responsibility: Send notifications."""
# Just email/notifications
Each routine now has single, clear purpose.
Technique 2: Extract Levels of Abstraction
If routine mixes high and low-level operations, extract low-level:
❌ Mixed abstraction levels:
def process_report():
# High level
data = fetch_data()
# LOW level detail
for i in range(len(data)):
if data[i] is not None and data[i] > 0:
normalized = (data[i] - min_val) / (max_val - min_val)
data[i] = normalized
# High level
generate_output(data)
✅ Consistent abstraction:
def process_report():
# All high level
data = fetch_data()
normalized_data = normalize_values(data) # Low-level extracted
generate_output(normalized_data)
def normalize_values(data):
# Low-level details isolated here
result = []
for value in data:
if value is not None and value > 0:
normalized = (value - min_val) / (max_val - min_val)
result.append(normalized)
return result
Technique 3: Extract Complex Conditions
If conditional logic is complex, extract to well-named boolean function:
❌ Complex inline condition:
if (user.age >= 18 and user.has_account and
user.account_balance > minimum and not user.is_suspended and
user.verified_email):
allow_purchase()
✅ Extracted condition:
if is_eligible_for_purchase(user):
allow_purchase()
def is_eligible_for_purchase(user):
"""Single responsibility: Determine purchase eligibility."""
return (user.age >= 18 and
user.has_account and
user.account_balance > minimum and
not user.is_suspended and
user.verified_email)
Benefits: Name explains WHAT checking, function explains HOW.
Quick Reference
| Sign Routine Needs Focus | Extraction Technique |
|---|---|
| Description has "and" | Extract each responsibility |
| Routine > 200 lines | Extract logical sections |
| Parameters > 7 | Group related params, extract |
| Hard to name | Clarify purpose, split if multiple |
| Hard to test | Extract testable pieces |
| Mixed abstraction levels | Extract low-level details |
| Deep nesting | Extract nested logic |
| Long parameter list | Extract to class or group params |
| Does A, B, C, D | Extract B, C, D into focused routines |
Functional Cohesion
The gold standard: Routine does one thing and only that thing.
Levels of Cohesion (Worst to Best)
- Coincidental - Unrelated things grouped together (avoid)
- Logical - Related things but different operations (weak)
- Temporal - Things done at same time (weak)
- Procedural - Things done in sequence (medium)
- Communicational - Work on same data (medium)
- Sequential - Output of one is input to next (good)
- Functional - Do ONE thing completely (best)
Always aim for functional cohesion.
Examples of Cohesion Types
❌ Coincidental (worst):
def miscellaneous_functions():
initialize_printer()
calculate_payroll()
sort_personnel_records()
# Unrelated things in one routine - terrible
⚠️ Temporal (weak):
def startup():
initialize_database()
initialize_ui()
initialize_logging()
# Related by WHEN (startup), not by WHAT
✅ Functional (best):
def calculate_employee_pay(employee, hours_worked):
# Does ONE thing: calculate pay
hourly_rate = employee.rate
gross_pay = hourly_rate * hours_worked
deductions = calculate_deductions(gross_pay)
return gross_pay - deductions
Naming as a Diagnostic
Routine name reveals focus:
| Name | Focus Assessment |
|---|---|
calculateTotal() |
✅ Focused - one clear purpose |
processData() |
❌ Vague - what processing? |
getUserAndValidate() |
❌ Two things ("and" in name) |
initializeSystemData() |
⚠️ Might be multiple things |
handleUserRegistrationAndWelcomeEmail() |
❌ Obviously two things |
If you struggle to name a routine clearly, it probably does too many things.
Extract until naming is easy.
Parameter Count Guideline
Research shows: Routines with > 7 parameters correlate with higher error rates.
Why? Many parameters suggest routine is doing too much.
❌ Too many parameters:
def create_order(user_id, items, shipping_addr, billing_addr,
discount_code, tax_rate, payment_method, notes):
# 8 parameters - probably doing too much
✅ Group related parameters:
def create_order(user_id, order_details):
# 2 parameters - order_details is an object containing the data
✅ Or extract responsibilities:
def create_order(validated_order, calculated_pricing):
# Validation and pricing are separate responsibilities
# This routine just creates the order record
Length Guidelines
No hard limit, but:
- Most routines: < 50 lines
- Review if > 100 lines
- Strong signal to extract if > 200 lines
Exception: Generated code, complex state machines, extensive error handling
Question to ask: Can I extract logical sections without making code worse?
When to Extract
Extract When:
- Multiple responsibilities - Routine does A and B and C
- Mixed abstraction levels - High-level calls mixed with low-level details
- Complex section - One part is complex, rest is simple (extract complex part)
- Duplicate logic - Same code appears in multiple places
- Hard to test - Doing too much to test atomically
- Poor naming - Can't name it clearly (probably unfocused)
- Long routine - Natural extraction points exist
Don't Extract When:
- Simpler inline - Extraction adds more complexity than it removes
- Used once - No duplication, no complexity reduction
- No natural boundary - Arbitrary split would make code harder to understand
Default: When in doubt, extract. Extraction rarely makes code worse.
Extraction Patterns
Pattern 1: Extract Complex Calculation
# ✅ Extract complex logic
def calculate_mortgage_payment(principal, annual_rate, years):
monthly_rate = convert_to_monthly_rate(annual_rate)
num_payments = years * 12
return calculate_monthly_payment(principal, monthly_rate, num_payments)
def convert_to_monthly_rate(annual_rate):
return annual_rate / 12 / 100
def calculate_monthly_payment(principal, monthly_rate, num_payments):
return principal * (monthly_rate * (1 + monthly_rate)**num_payments) / \
((1 + monthly_rate)**num_payments - 1)
Pattern 2: Extract Validation
# ✅ Extract validation to focused routine
def process_payment(payment_data):
validate_payment_data(payment_data) # Extracted
return execute_payment_transaction(payment_data)
def validate_payment_data(data):
"""Single responsibility: validation."""
# All validation logic here
Pattern 3: Extract by Abstraction Level
# ✅ High-level routine calls lower-level focused routines
def generate_report():
# High-level orchestration
data = collect_report_data()
analysis = analyze_data(data)
formatted_report = format_report_output(analysis)
save_report(formatted_report)
return formatted_report
Common Mistakes
❌ God function (does everything):
def handle_user_request():
# Validation
# Authentication
# Authorization
# Business logic
# Database operations
# Logging
# Email sending
# Response formatting
# 300 lines doing 8 different things
✅ Focused orchestrator:
def handle_user_request(request):
"""Single responsibility: Orchestrate request handling."""
user = authenticate_user(request)
authorize_action(user, request.action)
result = execute_business_logic(request, user)
save_to_database(result)
send_notifications(user, result)
return format_response(result)
❌ Mixed abstraction levels:
def process_order(order):
validate_order(order) # High level
# Low level details mixed in
for item in order.items:
db.execute("UPDATE inventory SET quantity = quantity - ? WHERE id = ?",
(item.quantity, item.product_id))
send_confirmation(order) # High level
✅ Consistent abstraction:
def process_order(order):
"""High-level orchestration."""
validate_order(order)
update_inventory(order.items) # Low-level extracted
send_confirmation(order)
def update_inventory(items):
"""Low-level: Update database."""
for item in items:
db.execute("UPDATE inventory SET quantity = quantity - ? WHERE id = ?",
(item.quantity, item.product_id))
❌ "Utility" routine (does miscellaneous things):
def utils():
# Initializes printer
# Calculates payroll
# Sorts records
# Unrelated things - coincidental cohesion (worst)
✅ Focused routines:
def initialize_printer(): ...
def calculate_payroll(): ...
def sort_personnel_records(): ...
The "And" Test
Listen to your description of the routine:
❌ "This routine validates the input AND calculates the result AND sends email" → Three responsibilities. Extract 2 of them.
❌ "This gets user data AND formats it for display" → Two responsibilities (retrieval and formatting). Extract formatting.
✅ "This calculates the shipping cost based on weight and destination" → One responsibility (calculation). The "and" lists parameters, not responsibilities.
If description has "and" connecting actions → routine does too many things.
Quick Decision Tree
Need to write/review a routine
↓
Does it do ONE thing?
├─ YES → Good, keep it focused
└─ NO → Does description have "and"?
├─ YES → Extract responsibilities
└─ Mixed abstraction levels?
├─ YES → Extract low-level details
└─ > 200 lines?
├─ YES → Find natural boundaries, extract
└─ > 7 parameters?
├─ YES → Group params or extract
└─ Hard to name?
├─ YES → Clarify purpose, maybe split
└─ Keep as-is, it's focused
Extraction Example
Original (unfocused):
def handle_order(order_data, user_id):
# Validate (responsibility 1)
if not order_data.get("items"):
raise ValueError("No items")
if not user_id:
raise ValueError("No user")
# Calculate pricing (responsibility 2)
subtotal = sum(item["price"] * item["qty"] for item in order_data["items"])
tax = subtotal * 0.08
total = subtotal + tax
# Check inventory (responsibility 3)
for item in order_data["items"]:
if inventory[item["id"]] < item["qty"]:
raise InventoryError()
# Create record (responsibility 4)
order_id = f"ORD-{datetime.now().isoformat()}"
order = {"id": order_id, "user_id": user_id, "total": total}
save_order(order)
# Send email (responsibility 5)
send_email(user_id, f"Order {order_id} confirmed")
return order
Extracted (focused routines):
def handle_order(order_data, user_id):
"""Single responsibility: Orchestrate order flow."""
validate_order_request(order_data, user_id)
pricing = calculate_pricing(order_data)
verify_inventory(order_data)
order = create_order(order_data, pricing, user_id)
notify_user(order, user_id)
return order
def validate_order_request(order_data, user_id):
"""Single responsibility: Validation."""
if not order_data.get("items"):
raise ValueError("No items")
if not user_id:
raise ValueError("No user")
def calculate_pricing(order_data):
"""Single responsibility: Pricing."""
subtotal = sum(item["price"] * item["qty"] for item in order_data["items"])
tax = subtotal * 0.08
return {"subtotal": subtotal, "tax": tax, "total": subtotal + tax}
def verify_inventory(order_data):
"""Single responsibility: Inventory check."""
for item in order_data["items"]:
if inventory[item["id"]] < item["qty"]:
raise InventoryError(f"Insufficient inventory for {item['id']}")
def create_order(order_data, pricing, user_id):
"""Single responsibility: Order creation."""
order_id = f"ORD-{datetime.now().isoformat()}"
order = {"id": order_id, "user_id": user_id, "total": pricing["total"]}
save_order(order)
return order
def notify_user(order, user_id):
"""Single responsibility: Notification."""
send_email(user_id, f"Order {order['id']} confirmed")
Benefits:
- Each routine has single, testable responsibility
- Can modify pricing without touching validation
- Can reuse validate_order_request elsewhere
- Easy to understand each piece in isolation
- Clear names describe exactly what each does
Benefits of Focused Routines
1. Easier to Understand
Small, focused routines are easier to comprehend:
- Can understand without seeing rest of system
- Name tells you what it does
- Implementation is short enough to hold in mind
2. Easier to Test
# ✅ Easy to test focused routine
def calculate_tax(amount, rate):
return amount * rate
# Test with various inputs, done
# ❌ Hard to test unfocused routine
def handle_order(...):
# Does 8 things - need to test all 8 in combination
# Need mocks for email, database, inventory, etc.
3. Easier to Modify
Focused routines have clear boundaries:
- Change pricing logic → modify calculate_pricing only
- Change validation → modify validate_order_request only
- Changes don't ripple unexpectedly
4. Easier to Reuse
# ✅ Can reuse focused routines
def handle_order(...):
validate_order_request(...) # Reusable
def handle_return(...):
validate_order_request(...) # Same validation, different context
5. Reduces Complexity
Breaking into focused pieces makes each piece simpler:
- One routine: 200 lines, complex
- Four routines: 50 lines each, simple
Mental load: Understand 50 lines vs understand 200 lines.
When Routine is Appropriately Long
Some routines are naturally longer:
- Extensive but straightforward validation - Many simple checks in sequence
- State machines - Many states and transitions
- Generated code - Auto-generated switch statements
- Linear algorithms - Many sequential steps with no natural boundaries
Question: Are there natural extraction points that would improve clarity?
If no → keep as-is. If yes → extract.
Verification Checklist
For each routine, check:
- Does ONE thing (functional cohesion)?
- Description has no "and" connecting different actions?
- Name clearly describes the one thing it does?
- All statements at consistent abstraction level?
- Parameters < 7 (or grouped into object)?
- Length natural for its purpose (not artificially inflated)?
- Easy to write test case?
- Can understand without seeing rest of system?
If any "no" → consider extracting.
Real-World Impact
From Code Complete:
- Functional cohesion is strongest, most maintainable
- Routines doing one thing are easiest to understand
- Most routines should be simple enough to name clearly
- Parameter count > 7 correlates with higher error rates
From baseline testing:
- Agent extracted helper functions (good instinct!)
- BUT orchestrator still did 8-10 things
- Each helper was focused, but main routine wasn't
- Grade: C (good instinct, incomplete application)
With this skill: Both helpers AND orchestrators stay focused.
Integration with Other Skills
For extracting during refactoring: See skills/designing-before-coding - sometimes one pseudocode line explodes to many code lines, indicating need to extract
For complexity reduction: See skills/architecture/reducing-complexity - focused routines reduce mental juggling required
Didn't find tool you were looking for?