Claude Skills Guide

Claude Code for SOLID Principles Refactoring Workflow

Writing clean, maintainable code is a goal every developer pursues, yet the path to achieving it often feels overwhelming. The SOLID principles—Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion—provide a proven framework for object-oriented design. But applying these principles to existing codebases, especially large ones, requires a systematic approach. This is where Claude Code becomes invaluable.

This guide presents a practical workflow for using Claude Code to refactor code toward SOLID principles, making the process faster, safer, and more methodical.

Understanding SOLID and Why It Matters

Before diving into the workflow, let’s briefly revisit what each SOLID principle means:

Violating these principles leads to code that is hard to test, maintain, and extend. But manually auditing and refactoring an entire codebase is time-consuming. Claude Code can accelerate this process significantly.

Setting Up the Refactoring Session

Start by creating a focused skill or prompt for the refactoring session. Create a new skill file for SOLID refactoring:

---
name: solid-refactor
description: Refactor code to follow SOLID principles
---

You are a code quality expert specializing in SOLID principles. When I provide code, analyze it for SOLID violations and propose refactored versions.

This skill establishes context and gives Claude Code a clear mandate. The explicit tool list ensures the session has necessary capabilities while maintaining focus.

Phase 1: Audit the Current State

Begin by understanding what you’re working with. Use Claude Code to scan your codebase and identify potential SOLID violations:

# Find files that might need attention
glob "**/*.ts"  # or .js, .py, etc.

Once you have a list of files, ask Claude Code to audit specific files:

Review the following code and identify any SOLID principle violations. For each violation, explain which principle is violated and why it could cause problems.

This initial audit serves as a baseline. Document the violations you find—this becomes your refactoring roadmap.

Phase 2: Prioritize and Plan

Not all violations carry equal weight. Use these criteria to prioritize:

  1. Impact: Does the violation cause actual bugs or maintenance issues?
  2. Stability: Is the code frequently changing or stable?
  3. Dependencies: How many other modules depend on this code?

A class with five responsibilities that’s used across fifty files should be addressed before a small utility used in one place. Claude Code can help assess these factors:

Based on the violations found, create a prioritized refactoring plan. List the top 5 files to refactor, with specific violations and suggested fixes.

This gives you an actionable plan rather than an overwhelming list.

Phase 3: Single Responsibility First

The Single Responsibility Principle (SRP) is often the easiest to identify and fix, and it frequently unlocks improvements in other areas. Look for these warning signs:

Here’s a refactoring example. Before:

class OrderProcessor:
    def __init__(self, db_connection):
        self.db = db_connection
    
    def process_order(self, order_data):
        # Validate order
        if not order_data.get('items'):
            raise ValueError("Empty order")
        
        # Calculate total
        total = sum(item['price'] * item['quantity'] for item in order_data['items'])
        
        # Save to database
        cursor = self.db.cursor()
        cursor.execute("INSERT INTO orders VALUES (?)", (order_data,))
        self.db.commit()
        
        # Send confirmation email
        self.send_email(order_data['customer_email'], "Order confirmed")
    
    def send_email(self, to, message):
        # Email sending logic
        pass

After refactoring for SRP:

class OrderValidator:
    def validate(self, order_data):
        if not order_data.get('items'):
            raise ValueError("Empty order")
        return True

class OrderCalculator:
    def calculate_total(self, items):
        return sum(item['price'] * item['quantity'] for item in items)

class OrderRepository:
    def __init__(self, db_connection):
        self.db = db_connection
    
    def save(self, order_data):
        cursor = self.db.cursor()
        cursor.execute("INSERT INTO orders VALUES (?)", (order_data,))
        self.db.commit()

class OrderNotifier:
    def send_confirmation(self, email, message):
        # Email sending logic
        pass

class OrderProcessor:
    def __init__(self, validator, calculator, repository, notifier):
        self.validator = validator
        self.calculator = calculator
        self.repository = repository
        self.notifier = notifier
    
    def process_order(self, order_data):
        self.validator.validate(order_data)
        total = self.calculator.calculate_total(order_data['items'])
        self.repository.save(order_data)
        self.notifier.send_confirmation(order_data['customer_email'], "Order confirmed")

Claude Code can suggest these refactorings while preserving functionality. Always ask for the “before” and “after” to verify the changes maintain behavior.

Phase 4: Address Dependency Inversion

Once you have smaller, focused classes, applying Dependency Inversion becomes natural. The goal is to depend on abstractions (protocols, interfaces, abstract classes) rather than concrete implementations.

In the refactored example above, notice how OrderProcessor depends on concrete classes. Refactor further:

from abc import ABC, abstractmethod

class OrderValidator(ABC):
    @abstractmethod
    def validate(self, order_data):
        pass

class OrderCalculator(ABC):
    @abstractmethod
    def calculate_total(self, items):
        pass

class OrderRepository(ABC):
    @abstractmethod
    def save(self, order_data):
        pass

class OrderNotifier(ABC):
    @abstractmethod
    def send_confirmation(self, email, message):
        pass

Now OrderProcessor depends on abstractions, making it easy to swap implementations for testing:

class MockOrderRepository(OrderRepository):
    def save(self, order_data):
        pass  # No-op for testing

Phase 5: Verify and Test

After each refactoring phase, verification is crucial. Claude Code can help by:

  1. Generating test cases: “Write unit tests for the refactored OrderProcessor”
  2. Running existing tests: Ensure nothing broke
  3. Checking for regressions: Compare behavior before and after

Always run your test suite after substantial refactoring. If tests pass, you have confidence the refactoring preserved behavior.

Tips for Effective AI-Assisted Refactoring

Conclusion

Refactoring toward SOLID principles doesn’t have to be a painful, months-long endeavor. With Claude Code as your assistant, you can systematically audit, plan, and refactor code while maintaining confidence through each step. The key is establishing a clear workflow: audit first, prioritize, refactor incrementally, and always verify with tests.

Start with a small, well-contained module to build confidence in the process. Once you see the benefits—easier testing, clearer code organization, simpler debugging—you’ll want to apply this workflow across your entire codebase.

Built by theluckystrike — More at zovo.one