Agent skill

maintainability

Maintainability assessment criteria for code review. Apply when evaluating code for readability, change tolerance, hidden assumptions, and debuggability.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/maintainability

SKILL.md

Maintainability Assessment

Evaluate whether code will be easy to understand, modify, extend, and debug over time.

Quick Reference

Factor Key Question Severity
Readability Understandable in 6 months? Critical if high cognitive load
Change tolerance Changes localized? Improvement
Extensibility Add without modifying? Improvement
Hidden assumptions Constraints explicit? Critical if causes bugs
Debuggability Failures traceable? Critical if silent
Intent documentation "Why" captured? Improvement

Anti-Patterns

Anti-Pattern Problem Instead
Clever one-liners Requires mental parsing Named intermediate steps
Scattered logic Changes touch many files Centralize related behavior
Hardcoded values Configuration changes require code changes Use config objects
Growing if/elif chains Every new type modifies existing code Registry or protocol pattern
Bare except: Swallows all errors including KeyboardInterrupt Catch specific exceptions
Silent failures No trace when things go wrong Log errors with context
Comments saying "what" Restates code Explain "why"

Readability

Check: Can someone understand this in 6 months?

python
# HIGH COGNITIVE LOAD: Too much at once
def process(data):
    return {k: sum(x['value'] for x in v if x.get('active', True))
            for k, v in groupby(sorted(filter(lambda x: x['status'] != 'deleted',
            data), key=lambda x: x['category']), key=lambda x: x['category'])}

# READABLE: Named intermediate steps
def process(data):
    active_items = [x for x in data if x['status'] != 'deleted']
    sorted_items = sorted(active_items, key=lambda x: x['category'])

    result = {}
    for category, items in groupby(sorted_items, key=lambda x: x['category']):
        result[category] = sum(x['value'] for x in items if x.get('active', True))
    return result

Heuristics

  • Can you explain what a function does in one sentence?
  • Would a new team member understand this without asking questions?
  • Are variable names descriptive enough to skip comments?

Severity

  • Critical: Understanding requires significant mental effort
  • Improvement: Some parts require careful reading
  • Nitpick: Minor clarity improvements possible

Change Tolerance

Check: How many places need modification for typical changes?

python
# BRITTLE: User display logic scattered
# views.py
def user_profile(user):
    return f"{user.first_name} {user.last_name}"

# emails.py
def format_recipient(user):
    return f"{user.first_name} {user.last_name} <{user.email}>"

# Adding middle name requires 2+ file changes

# RESILIENT: Centralized
class User:
    @property
    def display_name(self) -> str:
        return f"{self.first_name} {self.last_name}"

    @property
    def email_display(self) -> str:
        return f"{self.display_name} <{self.email}>"

Severity

  • Critical: Typical changes require 5+ file modifications
  • Improvement: 2-4 files need coordinated changes
  • Nitpick: Changes generally localized but could be cleaner

Extensibility

Check: Can new behavior be added without modifying existing code?

python
# CLOSED: Adding new type requires modifying existing code
def process_payment(payment):
    if payment.type == "credit_card":
        process_credit_card(payment)
    elif payment.type == "paypal":
        process_paypal(payment)
    elif payment.type == "crypto":  # had to add this
        process_crypto(payment)

# OPEN: New types don't touch existing code
class PaymentProcessor(Protocol):
    def process(self, payment: Payment) -> Result: ...

PROCESSORS: dict[str, PaymentProcessor] = {
    "credit_card": CreditCardProcessor(),
    "paypal": PayPalProcessor(),
}

def process_payment(payment):
    return PROCESSORS[payment.type].process(payment)

Severity

  • Improvement: Extending requires modifying existing functions/classes
  • Nitpick: Extension points exist but could be cleaner

Hidden Assumptions

Check: Are constraints and expectations explicit?

python
# HIDDEN: items is never empty
def get_average(items):
    return sum(items) / len(items)  # ZeroDivisionError

# EXPLICIT: Documented and enforced
def get_average(items: list[float]) -> float:
    """Calculate average. Raises ValueError if items is empty."""
    if not items:
        raise ValueError("Cannot calculate average of empty list")
    return sum(items) / len(items)

Severity

  • Critical: Hidden assumptions will cause production bugs
  • Improvement: Assumptions reasonable but not documented
  • Nitpick: Assumptions obvious from context

Debuggability

Check: When things fail, is it clear why?

python
# BAD: Silent failure
def update_user(user_id, data):
    user = get_user(user_id)
    if user:
        user.update(data)
    # if user doesn't exist... nothing happens

# BAD: Exception swallowing
try:
    result = complex_operation()
except Exception:
    pass

# GOOD: Specific error with context
def update_user(user_id, data):
    user = get_user(user_id)
    if user is None:
        raise UserNotFoundError(f"No user with id {user_id}")
    user.update(data)

# GOOD: Logged with structured context
def process_batch(items):
    for item in items:
        try:
            process(item)
        except Exception as e:
            logger.error(f"Failed to process item {item.id}: {e}",
                        extra={"item_id": item.id, "item_type": item.type})

Severity

  • Critical: Failures are silent or swallowed
  • Improvement: Errors lack context for debugging
  • Nitpick: Errors could be slightly more informative

Intent Documentation

Check: Is the "why" captured, not just the "what"?

python
# USELESS: Restates the code
x = x + 1  # increment x

# USEFUL: Explains why
x = x + 1  # account for 0-indexing in the API response

# WITHOUT CONTEXT: What is this magic?
if (n & (n - 1)) == 0 and n != 0:
    ...

# WITH CONTEXT: Clear purpose
# Check if n is a power of 2 (only one bit set)
if (n & (n - 1)) == 0 and n != 0:
    ...

Severity

  • Improvement: Complex logic lacks explanation
  • Nitpick: Documentation could be clearer but code is understandable

Quick Smell Test

Answer these for any significant code change:

  1. New developer test: Could someone unfamiliar fix a bug in this?
  2. 2am test: Could you debug this at 2am with incomplete logs?
  3. Feature request test: Could you add a related feature without rewriting?
  4. Handoff test: Could you explain this to a colleague in 5 minutes?

If any answer is "no", the code likely has maintainability issues worth flagging.

Convention Reference

When flagging maintainability issues in reviews, reference this skill:

markdown
**Convention**: See `maintainability` skill: Debuggability

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results