Skip to content

obra/clank

https://skillcdn.ai/gh/obra/clank

Connect this address to your AI to use this skill. How to connect

  • Unverified
  • Default branchmain
  • Commit2db8793
  • LicenseNone declared
View on GitHub

Keeping Routines Focused

Each routine does one thing and does it well - extract when routines have multiple responsibilities

Path
skills/coding/keeping-routines-focused/SKILL.md
License
None declared

Warnings for the author

  • "name" should use lowercase letters, digits and single hyphens only
  • "name" should match the name of the directory that holds SKILL.md
  • Not listed through the skills extension: the directory must be named after the skill.

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 FocusExtraction Technique
Description has "and"Extract each responsibility
Routine > 200 linesExtract logical sections
Parameters > 7Group related params, extract
Hard to nameClarify purpose, split if multiple
Hard to testExtract testable pieces
Mixed abstraction levelsExtract low-level details
Deep nestingExtract nested logic
Long parameter listExtract to class or group params
Does A, B, C, DExtract 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)
  1. Coincidental - Unrelated things grouped together (avoid)
  2. Logical - Related things but different operations (weak)
  3. Temporal - Things done at same time (weak)
  4. Procedural - Things done in sequence (medium)
  5. Communicational - Work on same data (medium)
  6. Sequential - Output of one is input to next (good)
  7. 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:

NameFocus 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:
  1. Multiple responsibilities - Routine does A and B and C
  2. Mixed abstraction levels - High-level calls mixed with low-level details
  3. Complex section - One part is complex, rest is simple (extract complex part)
  4. Duplicate logic - Same code appears in multiple places
  5. Hard to test - Doing too much to test atomically
  6. Poor naming - Can't name it clearly (probably unfocused)
  7. Long routine - Natural extraction points exist
Don't Extract When:
  1. Simpler inline - Extraction adds more complexity than it removes
  2. Used once - No duplication, no complexity reduction
  3. 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, use
This skill’s instructions are not fully loaded. Continue to read all inherited rules and required context.

Files of this skill

This skill has no supporting files.

Browse all supporting files