Skip to content
fix-bad-practices logo

Fix Bad Practices Skill

fix-bad-practices

Fix bad coding practices identified by audit, following fail-fast principles

SKILL.md

Full skill instructions

Fix Bad Practices Skill

Systematically fix bad coding practices identified by audit, following fail-fast principles.

When to Use

Use this skill:

  • After running /​audit-code-quality
  • When fixing specific bad patterns
  • During refactoring for code quality
  • Autonomously as part of quality workflow

Philosophy: Fail Fast Fixes

When fixing bad practices:

  1. Make errors visible - Replace silent failures with loud ones
  2. Be specific - Catch only exceptions you can handle
  3. Always log - Enable debugging by humans and LLMs
  4. Preserve stack traces - Use raise from or raise
  5. Test after fixing - Ensure fixes don't break functionality

Fix Patterns

Fix 1: Bare except: pass → Specific Exception + Logging

Before (BAD):

try:
    do_something()
except:
    pass

After (GOOD):

try:
    do_something()
except SpecificError as e:
    logger.exception("Failed to do_something: %s", e)
    raise

Or if recovery is possible:

try:
    result = do_something()
except SpecificError as e:
    logger.warning("do_something failed, using fallback: %s", e)
    result = fallback_value  # Only if fallback is valid!

Fix 2: except Exception → Specific Exceptions

Before (BAD):

try:
    data = parse_json(text)
except Exception as e:
    logger.error(e)
    return None

After (GOOD):

try:
    data = parse_json(text)
except json.JSONDecodeError as e:
    logger.exception("Invalid JSON: %s", e)
    raise ValueError(f"Cannot parse JSON: {e}") from e
except FileNotFoundError as e:
    logger.exception("File not found: %s", e)
    raise

Fix 3: Silent continue → Explicit Error Handling

Before (BAD):

for item in items:
    if not item.is_valid():
        continue
    process(item)

After (GOOD) - Option A: Fail on first error:

for item in items:
    if not item.is_valid():
        raise ValueError(f"Invalid item: {item}")
    process(item)

After (GOOD) - Option B: Collect errors, report at end:

errors = []
for item in items:
    if not item.is_valid():
        errors.append(f"Invalid item: {item}")
        continue
    process(item)

if errors:
    raise ValueError(f"Processing failed with {len(errors)} invalid items:\n" +
                     "\n".join(errors))

After (GOOD) - Option C: Log warning if skip is intentional:

for item in items:
    if not item.is_valid():
        logger.warning("Skipping invalid item: %s (reason: %s)", item, item.validation_error)
        continue
    process(item)

Fix 4: return None on Error → Raise Exception

Before (BAD):

def load_config(path):
    if not os.path.exists(path):
        return None
    with open(path) as f:
        return json.load(f)

After (GOOD):

def load_config(path: Path) -> dict:
    """Load configuration from path.

    Raises:
        FileNotFoundError: If config file doesn't exist
        json.JSONDecodeError: If config is not valid JSON
    """
    if not path.exists():
        raise FileNotFoundError(f"Config file not found: {path}")

    with open(path) as f:
        return json.load(f)

Fix 5: Error Return Codes → Exceptions

Before (BAD):

def process_data(data):
    if not data:
        return -1, "No data provided"
    if not validate(data):
        return -2, "Invalid data"
    result = transform(data)
    return 0, result

After (GOOD):

def process_data(data):
    """Process the data.

    Raises:
        ValueError: If data is empty or invalid
    """
    if not data:
        raise ValueError("No data provided")
    if not validate(data):
        raise ValueError(f"Invalid data: {get_validation_errors(data)}")
    return transform(data)

Fix 6: Defensive None Checks → Fail Fast

Before (BAD):

def process(data):
    if data is None:
        return
    # ... rest of processing

After (GOOD) - If None is never valid:

def process(data):
    if data is None:
        raise ValueError("data cannot be None")
    # ... rest of processing

After (GOOD) - If function should handle None gracefully:

def process(data: Optional[Data]) -> Optional[Result]:
    """Process data if provided.

    Args:
        data: Data to process, or None to skip processing

    Returns:
        Result if data was processed, None if data was None
    """
    if data is None:
        logger.debug("process() called with None, returning None")
        return None
    # ... rest of processing

Fix 7: subprocess Without Error Checking → check=True

Before (BAD):

subprocess.run(["git", "commit", "-m", "message"])

After (GOOD):

try:
    subprocess.run(
        ["git", "commit", "-m", "message"],
        check=True,
        capture_output=True,
        text=True
    )
except subprocess.CalledProcessError as e:
    logger.exception("Git commit failed: %s\nstderr: %s", e, e.stderr)
    raise

Fix 8: Catch-Log-Reraise → Add Context or Remove

Before (BAD) - Adds noise:

try:
    do_something()
except SomeError as e:
    logger.error(f"Error: {e}")
    raise

After (GOOD) - Option A: Add context:

try:
    do_something()
except SomeError as e:
    logger.exception("Failed during do_something in context X")
    raise RuntimeError(f"Operation failed in context X") from e

After (GOOD) - Option B: Just let it propagate:

do_something()  # Let caller handle the exception

Adding Proper Logging

Logger Setup

Ensure each module has a logger:

import logging

logger = logging.getLogger(__name__)

Logging Levels Guide

LevelUse For
logger.debug()Detailed diagnostic info
logger.info()Normal operation milestones
logger.warning()Recoverable issues, degraded operation
logger.error()Errors that don't stop execution
logger.exception()Errors with stack trace (use in except blocks)
logger.critical()Fatal errors, application cannot continue

Logging Best Practices

# GOOD - Use exception() in except blocks (includes stack trace)
except SomeError as e:
    logger.exception("Operation failed: %s", e)

# GOOD - Use lazy formatting
logger.debug("Processing item %s of %s", i, total)

# BAD - Eager string formatting
logger.debug(f"Processing item {i} of {total}")  # Formats even if debug disabled

# GOOD - Include relevant context
logger.error("Failed to load preset '%s' from %s: %s", preset_id, path, e)

# BAD - Vague messages
logger.error("Error occurred")

Fix Workflow

Step 1: Run Audit

# Run audit first
/​audit-code-quality

# Or run grep patterns directly
grep -rn "except.*:$" --include="*.py" -A1 | grep -B1 "pass$"

Step 2: Categorize Issues

Priority order:

  1. except: pass or except Exception: pass (CRITICAL)
  2. Overly broad except Exception (HIGH)
  3. Silent continuation patterns (MEDIUM)
  4. Missing logging (MEDIUM)
  5. Return None on error (LOW)

Step 3: Fix Each Issue

For each issue:

  1. Understand the intent - Why was error suppressed?
  2. Determine correct handling:
    • Should it fail fast? → Raise exception
    • Is recovery possible? → Handle specifically with logging
    • Is it truly optional? → Document and log at DEBUG level
  3. Apply fix pattern from above
  4. Add/​update tests for error conditions
  5. Run tests to verify fix

Step 4: Verify Fixes

# Run tests
uv run pytest MouseMaster/​Testing/​Python/ -v

# Run linting
uv run ruff check .

# Re-run audit to confirm
/​audit-code-quality

Automated Fix Script

For simple patterns, use sed (review changes before committing!):

#!/​bin/​bash
# CAUTION: Review all changes manually!

# Find files with except:pass (for manual review)
echo "Files needing manual review:"
grep -rl "except.*:" --include="*.py" | while read f; do
    if grep -q "pass$" "$f"; then
        echo "  $f"
    fi
done

Note: Automated fixes are risky. Always review manually and run tests.


Exception Handling Decision Tree

Is this a programming error (bug)?
├─ Yes → Let it crash (don't catch)
└─ No → Can user/​system recover?
         ├─ Yes → Catch, log, handle gracefully
         └─ No → Catch, log with context, re-raise or wrap

When catching:
├─ Can you name the specific exception?
│   ├─ Yes → Catch that specific type
│   └─ No → Research what exceptions can occur
└─ Is logging added?
    ├─ Yes → Good
    └─ No → Add logger.exception() call

Valid Exception Handling Cases

Not all exception handling is bad. Valid cases include:

1. User Input Validation

try:
    value = int(user_input)
except ValueError:
    logger.warning("Invalid input '%s', prompting user", user_input)
    show_error_to_user("Please enter a valid number")

2. Optional Feature Degradation

try:
    import optional_dependency
    FEATURE_AVAILABLE = True
except ImportError:
    logger.info("Optional feature unavailable: optional_dependency not installed")
    FEATURE_AVAILABLE = False

3. Resource Cleanup

try:
    resource = acquire_resource()
    use_resource(resource)
finally:
    resource.cleanup()  # Always runs

4. Retry Logic

for attempt in range(max_retries):
    try:
        return do_operation()
    except TransientError as e:
        logger.warning("Attempt %d failed: %s", attempt + 1, e)
        if attempt == max_retries - 1:
            raise
        time.sleep(backoff)

5. Boundary/​API Error Translation

try:
    result = external_api.call()
except ExternalAPIError as e:
    logger.exception("External API failed")
    raise OurDomainError(f"Service unavailable: {e}") from e

Testing Error Paths

After fixing, add tests for error conditions:

def test_load_config_missing_file():
    """Test that missing config raises FileNotFoundError."""
    with pytest.raises(FileNotFoundError, match="Config file not found"):
        load_config(Path("/​nonexistent/​path"))

def test_process_invalid_data():
    """Test that invalid data raises ValueError with details."""
    with pytest.raises(ValueError, match="Invalid data"):
        process_data({"bad": "data"})

Commit Message Template

After fixes:

fix: replace exception swallowing with proper error handling

- Remove except:pass in module_name.py
- Add specific exception types with logging
- Add error path tests

Follows fail-fast principle: errors now surface immediately
with full context for debugging.

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View