Fundamentals 21 min read

Improving Code Quality with SOLID Principles, Architecture Patterns, and Refactoring Techniques

This article explains how applying the five SOLID principles, choosing appropriate system architectures, using clear naming, drawing diagrams, and refactoring code—including guard clauses, responsibility‑chain patterns, and composition over inheritance—can dramatically improve Python program design and maintainability.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Improving Code Quality with SOLID Principles, Architecture Patterns, and Refactoring Techniques

Why Good Code Matters

Writing maintainable, high‑quality code is essential for long‑term project health. The article outlines several key knowledge points that help improve program design.

Key Knowledge Points

Five basic SOLID principles of object‑oriented design

Three common architectural styles (monolithic, distributed, micro‑services)

Use of diagrams to clarify relationships

Choosing meaningful names for identifiers

Optimising nested if‑else structures

1. SOLID Principles

The five SOLID principles are:

Single Responsibility Principle

Open‑Closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Composite Reuse (Composition) Principle

Single Responsibility Principle (SRP)

Example of a poorly structured function that reads a file, extracts data, and makes a network request:

import re
import requests

FILE = "./information.fet"

def extract(file):
    fil = open(file, "r")
    content = fil.read()
    fil.close()
    find_object = re.search(r"url=\d+", content)
    find = find_object.group(1)
    text = requests.get(find)
    return text

if __name__ == "__main__":
    text = extract(FILE)
    print(text)

Problems: no error handling, tightly coupled steps, and a single function does many things.

Refactored version splits responsibilities into small functions:

def get_source():
    """Get data source"""
    return

def extract_(val):
    """Match key data"""
    return

def fetch(val):
    """Send network request"""
    return

def trim(val):
    """Trim data"""
    return

def extract(file):
    """Extract target data"""
    source = get_source()
    content = extract_(source)
    text = trim(fetch(content))
    return text

if __name__ == "__main__":
    text = extract(FILE)
    print(text)

Each function now does one thing, making the code easier to modify when requirements change.

Open‑Closed & Dependency Inversion

Typical storage class tightly couples business logic to a concrete MySQLSave implementation:

class MySQLSave:
    def __init__(self):
        pass
    def insert(self):
        pass
    def update(self):
        pass

class Business:
    def __init__(self):
        pass
    def save(self):
        saver = MySQLSave()
        saver.insert()

Using an abstract base class and dependency injection decouples the business layer from the storage implementation:

import abc

class Save(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def insert(self):
        pass
    @abc.abstractmethod
    def update(self):
        pass

class MySQLSave(Save):
    def __init__(self):
        self.classify = "mysql"
    def insert(self):
        pass
    def update(self):
        pass

class Excel(Save):
    def __init__(self):
        self.classify = "excel"
    def insert(self):
        pass
    def update(self):
        pass

class Business:
    def __init__(self, saver):
        self.saver = saver
    def insert(self):
        self.saver.insert()
    def update(self):
        self.saver.update()

if __name__ == "__main__":
    mysql_saver = MySQLSave()
    excel_saver = Excel()
    business = Business(mysql_saver)

The business code now depends on the stable abstraction Save, not on concrete storage classes.

Interface Segregation Principle (ISP)

Instead of a single large interface, split responsibilities. Example with a Book abstraction that separates purchase/borrow from shelving operations, allowing different client types to implement only the methods they need.

import abc

class Book(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def buy(self):
        pass
    @abc.abstractmethod
    def borrow(self):
        pass
    @abc.abstractmethod
    def shelf_off(self):
        pass
    @abc.abstractmethod
    def shelf_on(self):
        pass

Composite Reuse Principle (Composition over Inheritance)

Prefer object composition to inheritance to reduce coupling. The article shows a Car class and two derived classes, then refactors them to use a separate Color component that each car composes.

class Color:
    pass

class KateCar:
    color = Color()
    def move(self):
        pass
    def engine(self):
        pass

class FluentCar:
    color = Color()
    def move(self):
        pass
    def engine(self):
        pass

2. Common Architectural Styles

Three typical architectures are described:

Monolithic : all functionality in a single application; simple to deploy but suffers from high complexity, low deployment frequency, performance bottlenecks, and reliability issues.

Distributed : splits the system into multiple services to improve performance and reliability; still retains many monolithic drawbacks such as deployment complexity.

Micro‑services : many small, independently deployable services; offers better scalability, independent releases, and technology‑agnostic implementation, but introduces operational overhead, network latency, and coordination challenges.

The choice of architecture should be driven by concrete business needs and system complexity.

3. Supporting Practices

Diagramming : Use use‑case, collaboration, class, and state diagrams to visualise requirements, module relationships, and interactions.

Naming : Choose clear, consistent identifiers (e.g., avoid vague names like reversalList).

Optimising Nested if‑else : Apply guard clauses ("early return") to reduce nesting depth.

Example of guard‑clause optimisation:

if "http" not in url:
    return
if "www" not in url:
    return

Responsibility Chain Pattern

When many if‑else branches become unwieldy, replace them with a chain of handler objects. The article provides a Python implementation of a chain that decides which sales role can grant a discount based on price.

class Manager:
    def __init__(self):
        self.obj = None
    def next_handler(self, obj):
        self.obj = obj
    def handler(self, price):
        pass

class General(Manager):
    def handler(self, price):
        if price < 300000:
            print(f"{price} 普通销售")
        else:
            self.obj.handler(price)

class Elite(Manager):
    def handler(self, price):
        if 300000 <= price < 800000:
            print(f"{price} 精英销售")
        else:
            self.obj.handler(price)

class BOSS(Manager):
    def handler(self, price):
        if price >= 800000:
            print(f"{price} 店长")

# Build the chain
general = General()
elite = Elite()
boss = BOSS()
general.next_handler(elite)
elite.next_handler(boss)

prices = [550000, 220000, 1500000, 200000, 330000]
for price in prices:
    general.handler(price)

This pattern decouples request senders from concrete handlers and makes the logic extensible.

Source: NightTeam – Wei Shidong
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

architecturePythonsoftware designrefactoringSOLID
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.