Home / Programming Languages / Code Quality and Refactoring: SOLID Principles and Clean
Programming Languages

Code Quality and Refactoring: SOLID Principles and Clean

Elevate your code quality with SOLID principles, identify and eliminate code smells, master refactoring techniques, and leverage static analysis tools across...

What you will learn

Practical execution with concise explanations, real implementation patterns, and production-ready recommendations.

!Architecture Overview

Code Quality and Refactoring: SOLID Principles and Clean Code

Introduction

Prerequisites

Requirement Details
Basic setup and tooling Basic setup and tooling

Figure: Code pattern examples for code quality and refactoring—syntax comparison, idiomatic approaches, performance characteristics, and common pitfalls.

Figure: Best practices implementation for code quality and refactoring—error handling, testing strategies, maintainability patterns, and documentation standards.

Figure: Production readiness checklist for code quality and refactoring—logging, monitoring, performance tuning, and security hardening.

High-quality code is maintainable, testable, and extensible. This guide covers SOLID principles for object-oriented design, common code smells and their remedies, practical refactoring techniques, and static analysis tools for JavaScript, Python, and C# that help maintain code quality.

SOLID Principles

Single Responsibility Principle (SRP)

Definition: A class should have only one reason to change.

❌ Violation:

// User class has too many responsibilities
class User {
```javascript
constructor(
    public name: string,
    public email: string
) {}

// Database responsibility
save(): void {
    const db = new Database();
    db.execute(`INSERT INTO users VALUES ('${this.name}', '${this.email}')`);
}

// Email responsibility
sendWelcomeEmail(): void {
    const smtp = new SMTPClient();
    smtp.send(this.email, 'Welcome!', 'Thanks for joining...');
}

// Validation responsibility
validate(): boolean {
    return this.email.includes('@') && this.name.length > 0;
}```
}

✅ Following SRP:

// Each class has single responsibility
class User {
```text
constructor(
    public name: string,
    public email: string
) {}```
}

class UserValidator {
```text
validate(user: User): boolean {
    return user.email.includes('@') && user.name.length > 0;
}```
}

class UserRepository {
```sql
async save(user: User): Promise<void> {
    await this.db.execute(
        'INSERT INTO users (name, email) VALUES (?, ?)',
        [user.name, user.email]
    );
}```
}

class EmailService {
```text
async sendWelcomeEmail(user: User): Promise<void> {
    await this.smtp.send({
        to: user.email,
        subject: 'Welcome!',
        body: 'Thanks for joining...'
    });
}```
}

Open/Closed Principle (OCP)

Definition: Software entities should be open for extension but closed for modification.

❌ Violation:

class PaymentProcessor:
```python
def process_payment(self, payment_type, amount):
    if payment_type == "credit_card":
        print(f"Processing credit card payment: ${amount}")
    elif payment_type == "paypal":
        print(f"Processing PayPal payment: ${amount}")
    elif payment_type == "bitcoin":  # Adding new type requires modifying class
        print(f"Processing Bitcoin payment: ${amount}")

**✅ Following OCP:**

```python
from abc import ABC, abstractmethod

# Open for extension
class PaymentMethod(ABC):
```python
@abstractmethod
def process(self, amount: float) -> None:
    pass

class CreditCardPayment(PaymentMethod):

def process(self, amount: float) -> None:
    print(f"Processing credit card: ${amount}")

class PayPalPayment(PaymentMethod):

def process(self, amount: float) -> None:
    print(f"Processing PayPal: ${amount}")

class BitcoinPayment(PaymentMethod): # Extension doesn't modify existing code

def process(self, amount: float) -> None:
    print(f"Processing Bitcoin: ${amount}")

class PaymentProcessor:

def process_payment(self, method: PaymentMethod, amount: float) -> None:
    method.process(amount)

Usage

processor = PaymentProcessor() processor.process_payment(CreditCardPayment(), 99.99) processor.process_payment(BitcoinPayment(), 0.002)


## Liskov Substitution Principle (LSP)

**Definition:** Derived classes must be substitutable for their base classes.





**❌ Violation:**

```csharp
public class Rectangle
{
```javascript
public virtual int Width { get; set; }
public virtual int Height { get; set; }

public int GetArea() => Width * Height;```
}

public class Square : Rectangle
{
```javascript
// Violates LSP - changes behavior of base class
public override int Width
{
    get => base.Width;
    set
    {
        base.Width = value;
        base.Height = value;  // Side effect!
    }
}

public override int Height
{
    get => base.Height;
    set
    {
        base.Width = value;   // Side effect!
        base.Height = value;
    }
}```
}

// This breaks when using Square
void ResizeRectangle(Rectangle rect)
{
```text
rect.Width = 5;
rect.Height = 10;
// Expects area to be 50, but Square gives 100!
Console.WriteLine(rect.GetArea());```
}

✅ Following LSP:

public interface IShape
{
```text
int GetArea();```
}

public class Rectangle : IShape
{
```javascript
public int Width { get; set; }
public int Height { get; set; }

public int GetArea() => Width * Height;```
}

public class Square : IShape
{
```javascript
public int Side { get; set; }

public int GetArea() => Side * Side;```
}

// Now works correctly with both shapes
void PrintArea(IShape shape)
{
```text
Console.WriteLine($"Area: {shape.GetArea()}");```
}

Interface Segregation Principle (ISP)

Definition: Clients shouldn't be forced to depend on interfaces they don't use.

❌ Violation:

// Fat interface
interface Worker {
```text
work(): void;
eat(): void;
sleep(): void;```
}

// Robot forced to implement eat() and sleep()
class RobotWorker implements Worker {
```javascript
work(): void {
    console.log("Working...");
}

eat(): void {
    throw new Error("Robots don't eat!");
}

sleep(): void {
    throw new Error("Robots don't sleep!");
}```
}

✅ Following ISP:

// Segregated interfaces
interface Workable {
```text
work(): void;```
}

interface Eatable {
```text
eat(): void;```
}

interface Sleepable {
```text
sleep(): void;```
}

class HumanWorker implements Workable, Eatable, Sleepable {
```javascript
work(): void {
    console.log("Working...");
}

eat(): void {
    console.log("Eating lunch...");
}

sleep(): void {
    console.log("Sleeping...");
}```
}

class RobotWorker implements Workable {
```javascript
work(): void {
    console.log("Working 24/7...");
}```
}

Dependency Inversion Principle (DIP)

Definition: High-level modules shouldn't depend on low-level modules. Both should depend on abstractions.

❌ Violation:

## High-level module depends on low-level implementation


class MySQLDatabase:
```python
def save(self, data):
    print(f"Saving to MySQL: {data}")

class UserService:

def __init__(self):
    self.db = MySQLDatabase()  # Tight coupling!





def create_user(self, name):
    self.db.save(name)

**✅ Following DIP:**

```python
from abc import ABC, abstractmethod

## Abstraction
class Database(ABC):
```python
@abstractmethod
def save(self, data: str) -> None:
    pass

Low-level implementations

class MySQLDatabase(Database):

def save(self, data: str) -> None:
    print(f"Saving to MySQL: {data}")

class MongoDatabase(Database):

def save(self, data: str) -> None:
    print(f"Saving to MongoDB: {data}")

High-level module depends on abstraction

High-level module depends on abstraction

Figure: Connector browser – actions with dynamic content picker.

class UserService:

def __init__(self, db: Database):
    self.db = db





def create_user(self, name: str) -> None:
    self.db.save(name)

Dependency injection

mysql_db = MySQLDatabase() user_service = UserService(mysql_db) # Easy to swap implementations


## Common Code Smells

### Long Method





**Smell:**

```csharp
public void ProcessOrder(Order order)
{
```text
// 150 lines of code doing everything...
// Validation
if (order.Items.Count == 0) throw new Exception("Empty order");
if (!order.Customer.IsActive) throw new Exception("Inactive customer");

// Calculate totals
decimal subtotal = 0;
foreach (var item in order.Items)
{
    subtotal += item.Price * item.Quantity;
}
decimal tax = subtotal * 0.08m;
decimal shipping = CalculateShipping(order);
decimal total = subtotal + tax + shipping;

// Apply discounts
if (order.Customer.IsPremium && total > 100)
{
    total *= 0.9m;
}

// Process payment
// ...

// Send notifications
// ...```
}

Refactored:

public void ProcessOrder(Order order)
{
```text
ValidateOrder(order);
var totals = CalculateOrderTotals(order);
ApplyDiscounts(order, totals);
ProcessPayment(order, totals.Final);
SendNotifications(order);```
}

private void ValidateOrder(Order order)
{
```text
if (order.Items.Count == 0)
    throw new ValidationException("Empty order");
if (!order.Customer.IsActive)
    throw new ValidationException("Inactive customer");```
}

private OrderTotals CalculateOrderTotals(Order order)
{
```javascript
var subtotal = order.Items.Sum(i => i.Price * i.Quantity);
var tax = subtotal * 0.08m;
var shipping = CalculateShipping(order);
return new OrderTotals(subtotal, tax, shipping);```
}

Large Class (God Object)

Smell:

// 2000-line class doing everything
class OrderManager {
```text
// Order creation
createOrder(items: Item[]): Order { }

// Payment processing
processPayment(order: Order): void { }

// Inventory management
updateInventory(items: Item[]): void { }

// Email notifications
sendOrderConfirmation(order: Order): void { }

// Reporting
generateInvoice(order: Order): void { }
generateReport(): Report { }

// Shipping
calculateShipping(order: Order): number { }
scheduleShipment(order: Order): void { }```
}

Refactored:

class OrderService {
```javascript
constructor(
    private orderRepository: OrderRepository,
    private paymentService: PaymentService,
    private inventoryService: InventoryService,
    private notificationService: NotificationService
) {}

async createOrder(items: Item[]): Promise<Order> {
    const order = await this.orderRepository.create(items);
    await this.inventoryService.reserve(items);
    await this.notificationService.sendOrderConfirmation(order);
    return order;
}```
}

class PaymentService {
```text
processPayment(order: Order): Promise<PaymentResult> { }```
}

class InventoryService {
```text
reserve(items: Item[]): Promise<void> { }
release(items: Item[]): Promise<void> { }```
}

class NotificationService {
```text
sendOrderConfirmation(order: Order): Promise<void> { }```
}

Duplicate Code

Smell:

def calculate_employee_salary(employee):
```text
base = employee.base_salary
bonus = base * 0.1
tax = (base + bonus) * 0.2
return base + bonus - tax

def calculate_contractor_payment(contractor):

base = contractor.hourly_rate * contractor.hours
bonus = base * 0.05
tax = (base + bonus) * 0.3
return base + bonus - tax

**Refactored:**

```python
from dataclasses import dataclass

@dataclass
class CompensationRules:
```yaml
bonus_rate: float
tax_rate: float

def calculate_compensation(base_amount: float, rules: CompensationRules) -> float:

bonus = base_amount * rules.bonus_rate
gross = base_amount + bonus
tax = gross * rules.tax_rate
return gross - tax

Usage

Usage

Figure: Configuration and management dashboard with status overview.

employee_rules = CompensationRules(bonus_rate=0.1, tax_rate=0.2) contractor_rules = CompensationRules(bonus_rate=0.05, tax_rate=0.3)

employee_salary = calculate_compensation(

employee.base_salary,
employee_rules```
)

contractor_payment = calculate_compensation(
```text
contractor.hourly_rate * contractor.hours,
contractor_rules```
)

Feature Envy

Smell:

// OrderProcessor is too interested in Order internals
public class OrderProcessor
{
```text
public decimal CalculateTotal(Order order)
{
    decimal total = 0;
    foreach (var item in order.Items)
    {
        total += item.Price * item.Quantity;
    }
    
    if (order.DiscountCode != null)
    {
        total *= (1 - order.DiscountRate);
    }
    
    return total;
}```
}

Refactored:

// Move logic to where data lives
public class Order
{
```javascript
public List<OrderItem> Items { get; set; }
public string DiscountCode { get; set; }
public decimal DiscountRate { get; set; }

public decimal CalculateTotal()
{
    var subtotal = Items.Sum(i => i.Price * i.Quantity);
    return ApplyDiscount(subtotal);
}

private decimal ApplyDiscount(decimal amount)
{
    return DiscountCode != null
        ? amount * (1 - DiscountRate)
        : amount;
}```
}

public class OrderProcessor
{
```text
public void ProcessOrder(Order order)
{
    var total = order.CalculateTotal();  // Delegate to Order
    // Process payment...
}```
}

Refactoring Techniques

Extract Method

// Before
function printOwing(invoice: Invoice): void {
```javascript
console.log("***********************");
console.log("**** Customer Owes ****");
console.log("***********************");

let outstanding = 0;
for (const order of invoice.orders) {
    outstanding += order.amount;
}

console.log(`Name: ${invoice.customer}`);
console.log(`Amount: ${outstanding}`);```
}

// After
function printOwing(invoice: Invoice): void {
```javascript
printBanner();
const outstanding = calculateOutstanding(invoice);
printDetails(invoice, outstanding);```
}

function printBanner(): void {
```javascript
console.log("***********************");
console.log("**** Customer Owes ****");
console.log("***********************");```
}

function calculateOutstanding(invoice: Invoice): number {
```javascript
return invoice.orders.reduce((sum, order) => sum + order.amount, 0);```
}

function printDetails(invoice: Invoice, outstanding: number): void {
```javascript
console.log(`Name: ${invoice.customer}`);
console.log(`Amount: ${outstanding}`);```
}

Replace Conditional with Polymorphism

## Before
class Bird:
```python
def __init__(self, bird_type):
    self.type = bird_type





def fly(self):
    if self.type == "eagle":
        print("Soaring high")
    elif self.type == "penguin":
        print("Can't fly")
    elif self.type == "parrot":
        print("Flying in circles")

After

from abc import ABC, abstractmethod

class Bird(ABC):

@abstractmethod
def fly(self):
    pass

class Eagle(Bird):

def fly(self):
    print("Soaring high")

class Penguin(Bird):

def fly(self):
    print("Can't fly")

class Parrot(Bird):

def fly(self):
    print("Flying in circles")

## Static Analysis Tools

### ESLint (JavaScript/TypeScript)





```json
// .eslintrc.json
{
  "extends": [
```text
"eslint:recommended",
"plugin:@typescript-eslint/recommended"```
  ],
  "rules": {
```text
"no-console": "warn",
"no-unused-vars": "error",
"complexity": ["warn", 10],
"max-lines-per-function": ["warn", 50],
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/explicit-function-return-type": "warn"```
  }
}

Pylint (Python)

## .pylintrc
[MASTER]
max-line-length=100





[MESSAGES CONTROL]
disable=
```text
missing-docstring,
too-few-public-methods

[DESIGN] max-args=5 max-locals=15 max-returns=6 max-branches=12 max-statements=50

[SIMILARITIES] min-similarity-lines=4


## Roslyn Analyzers (C#)

```xml
<!-- .editorconfig -->
[*.cs]
dotnet_diagnostic.CA1062.severity = warning  # Validate arguments
dotnet_diagnostic.CA1031.severity = error    # Don't catch generic Exception
dotnet_diagnostic.CA1303.severity = none     # String literals (localization)





## Code style
csharp_prefer_braces = true:warning
csharp_style_var_elsewhere = true:suggestion
csharp_style_expression_bodied_methods = true:suggestion





Best Practices

  1. Keep methods small - Aim for 20 lines or less
  2. Limit class responsibilities - Single Responsibility Principle
  3. Use meaningful names - Avoid abbreviations and single letters
  4. Write tests first - TDD helps design better APIs
  5. Refactor continuously - Boy Scout Rule: leave code cleaner than you found it
  6. Use static analysis - Catch issues before code review
  7. Code reviews - Multiple eyes catch more issues
  8. Measure complexity - Track cyclomatic complexity metrics

Architecture Decision and Tradeoffs

When designing software development solutions with Programming Languages, consider these key architectural trade-offs:

Approach Best For Tradeoff
Managed / platform service Rapid delivery, reduced ops burden Less customisation, potential vendor lock-in
Custom / self-hosted Full control, advanced tuning Higher operational overhead and cost

Recommendation: Start with the managed approach for most workloads and move to custom only when specific requirements demand it.

Validation and Versioning

  • Last validated: April 2026
  • Validate examples against your tenant, region, and SKU constraints before production rollout.
  • Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.

Security and Governance Considerations

  • Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
  • Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
  • Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.

Cost and Performance Notes

  • Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
  • Baseline performance with synthetic and real-user checks before and after major changes.
  • Scale resources with measured thresholds and revisit sizing after usage pattern changes.

Official Microsoft References

  • https://learn.microsoft.com/
  • https://learn.microsoft.com/azure/
  • https://learn.microsoft.com/power-platform/
  • https://learn.microsoft.com/microsoft-365/

Public Examples from Official Sources

  • These examples are sourced from official public Microsoft documentation and sample repositories.
  • Documentation examples: https://learn.microsoft.com/training/
  • Sample repositories: https://github.com/microsoft
  • Prefer adapting these examples to your tenant, subscriptions, and governance requirements before production use.

Key Takeaways

  • SOLID principles guide maintainable object-oriented design
  • Code smells indicate areas needing refactoring
  • Small, focused methods and classes improve readability
  • Static analysis tools enforce consistency and catch bugs
  • Continuous refactoring prevents technical debt accumulation

Next Steps

  • Learn Test-Driven Development for better design
  • Explore Domain-Driven Design patterns
  • Study Clean Architecture principles
  • Practice code katas for refactoring skills

Additional Resources


Quality is not an act, it's a habit.

Discussion