| name | engineering-code-quality |
| description | Code quality metrics, maintainability principles, SOLID design, code smells detection, and quality measurement |
Code Quality & Maintainability
Scope: Comprehensive guide to code quality principles, SOLID design, code smells, metrics, and long-term maintainability
Lines: ~400
Last Updated: 2025-10-27
Format Version: 1.0 (Atomic)
When to Use This Skill
Activate this skill when:
- Evaluating code quality in reviews or audits
- Establishing quality standards for a team
- Refactoring legacy code to improve maintainability
- Setting up code quality metrics and monitoring
- Training engineers on clean code principles
- Defining "done" criteria for features
- Improving codebase health over time
- Reducing bug rates and technical debt
Core Concepts
Concept 1: The SOLID Principles
S - Single Responsibility Principle
A class/function should have one reason to change
class User:
def save_to_database(self): ...
def send_email(self): ...
def generate_pdf_report(self): ...
def validate_password(self): ...
class User:
def validate_password(self): ...
class UserRepository:
def save(self, user: User): ...
class EmailService:
def send_welcome_email(self, user: User): ...
class ReportGenerator:
def generate_user_report(self, user: User): ...
O - Open/Closed Principle
Open for extension, closed for modification
class PaymentProcessor:
def process(self, method: str, amount: float):
if method == "credit_card":
elif method == "paypal":
elif method == "bitcoin":
class PaymentMethod:
def process(self, amount: float): ...
class CreditCardPayment(PaymentMethod):
def process(self, amount: float): ...
class PayPalPayment(PaymentMethod):
def process(self, amount: float): ...
class PaymentProcessor:
def process(self, method: PaymentMethod, amount: float):
method.process(amount)
L - Liskov Substitution Principle
Subtypes must be substitutable for their base types
class Rectangle {
width: number;
height: number;
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
area(): number { return this.width * this.height; }
}
class Square extends Rectangle {
setWidth(w: number) {
this.width = w;
this.height = w;
}
}
interface Shape {
area(): number;
}
class Rectangle implements Shape {
constructor(private width: number, : ) {}
(): { . * .; }
}
{
() {}
(): { . * .; }
}
I - Interface Segregation Principle
Clients shouldn't depend on interfaces they don't use
type Worker interface {
Work()
Eat()
Sleep()
}
type Robot struct{}
func (r Robot) Work() { }
func (r Robot) Eat() { }
func (r Robot) Sleep() { }
type Worker interface {
Work()
}
type LivingWorker interface {
Worker
Eat()
Sleep()
}
type Robot struct{}
func (r Robot) Work() { }
type Human struct{}
func (h Human) Work() { }
func (h Human) Eat() { }
func (h Human) Sleep() { }
D - Dependency Inversion Principle
Depend on abstractions, not concretions
class MySQLDatabase {
save(data: string) { }
}
class UserService {
private db = new MySQLDatabase();
saveUser(user: User) {
this.db.save(JSON.stringify(user));
}
}
interface Database {
save(data: string): void;
}
class MySQLDatabase implements Database {
save(data: string) { }
}
class PostgresDatabase implements Database {
save(data: string) { }
}
class UserService {
constructor( : ) {}
() {
..(.(user));
}
}
Concept 2: Code Smells
Common Code Smells:
| Smell | Description | Fix |
|---|
| Long Method | Method > 30 lines | Extract smaller methods |
| Large Class | Class > 500 lines | Split into multiple classes |
| Long Parameter List | > 3-4 parameters | Use object/struct |
| Duplicated Code | Same logic in multiple places | Extract to function |
| Dead Code | Unused code | Delete it |
| Magic Numbers | Hardcoded constants | Use named constants |
| Nested Conditionals | If/else > 3 levels deep | Extract guard clauses |
| Primitive Obsession | Over-reliance on primitives | Create value objects |
| Feature Envy | Method uses another class's data more than its own | Move method |
| Data Clumps | Same group of data everywhere | Create a class |
Examples:
def calculate_price(quantity):
return quantity * 19.99 * 1.08
PRICE_PER_ITEM = 19.99
TAX_RATE = 1.08
def calculate_price(quantity):
return quantity * PRICE_PER_ITEM * TAX_RATE
function createUser(
name: string,
email: string,
age: number,
address: string,
phone: string,
company: string
) { }
interface UserData {
name: string;
email: string;
age: number;
address: string;
phone: string;
company: string;
}
function createUser(data: UserData) { }
func processOrder(order Order) error {
if order.IsValid() {
if order.HasInventory() {
if order.PaymentSucceeded() {
if order.ShippingAvailable() {
}
}
}
}
}
func processOrder(order Order) error {
if !order.IsValid() {
return ErrInvalidOrder
}
if !order.HasInventory() {
return ErrOutOfStock
}
if !order.PaymentSucceeded() {
return ErrPaymentFailed
}
if !order.ShippingAvailable() {
return ErrShippingUnavailable
}
return nil
}
Concept 3: Code Quality Metrics
Cyclomatic Complexity
Measure of code complexity based on number of independent paths
def add(a, b):
return a + b
def get_discount(user_type, purchase_amount):
if user_type == "premium":
if purchase_amount > 100:
return 0.20
return 0.10
elif user_type == "regular":
if purchase_amount > 100:
return 0.10
return 0
Code Coverage
Percentage of code executed by tests
pytest --cov=myapp --cov-report=html
Maintainability Index
Composite metric: 171 - 5.2 * ln(V) - 0.23 * G - 16.2 * ln(L)
- V: Halstead Volume (complexity)
- G: Cyclomatic Complexity
- L: Lines of Code
| Score | Maintainability |
|---|
| 85-100 | Highly maintainable |
| 65-85 | Moderately maintainable |
| < 65 | Difficult to maintain |
Code Churn
How often files change
git log --format=format: --name-only | sort | uniq -c | sort -rn | head -10
Patterns
Pattern 1: Readable Code Structure
Function Length:
def process_order(order):
def process_order(order):
validate_order(order)
charge_payment(order)
update_inventory(order)
send_confirmation(order)
Variable Naming:
let d: number;
let tmp: string;
let data: any[];
let daysUntilExpiration: number;
let userEmail: string;
let activeOrders: Order[];
Comments:
i++
taxRate := 0.08
time.Sleep(time.Duration(math.Pow(2, retries)) * time.Second)
Pattern 2: Error Handling
Python:
try:
user = get_user(user_id)
except:
pass
try:
user = get_user(user_id)
except UserNotFoundError as e:
logger.error(f"User {user_id} not found: {e}")
raise
except DatabaseError as e:
logger.error(f"Database error: {e}")
user = get_user_from_cache(user_id)
Go:
user, _ := getUser(userID)
user, err := getUser(userID)
if err != nil {
return fmt.Errorf("failed to get user %d: %w", userID, err)
}
Rust:
let user = get_user(user_id).unwrap();
let user = get_user(user_id)?;
match get_user(user_id) {
Ok(user) => process_user(user),
Err(e) => log::error!("Failed to get user: {}", e),
}
Pattern 3: Testable Code Design
Bad: Hard to Test:
class UserService {
async createUser(email: string): Promise<User> {
const db = new MySQLDatabase();
const emailService = new SendGridEmailService();
const logger = new FileLogger();
const user = await db.save({ email });
await emailService.send(user.email, "Welcome!");
logger.info(`Created user ${user.id}`);
return user;
}
}
Good: Easy to Test:
interface Database {
save(data: any): Promise<User>;
}
interface EmailService {
send(to: string, subject: string): Promise<void>;
}
interface Logger {
info(message: string): void;
}
class UserService {
constructor(
private db: Database,
private emailService: EmailService,
private logger: Logger
) {}
async createUser(email: string): Promise<User> {
const user = await this.db.save({ email });
await this.emailService.send(user.email, "Welcome!");
this..();
user;
}
}
mockDb = { : jest.() };
mockEmail = { : jest.() };
mockLogger = { : jest.() };
service = (mockDb, mockEmail, mockLogger);
Pattern 4: Code Organization
Package Structure:
# Bad: Organized by type
src/
controllers/
user_controller.py
order_controller.py
product_controller.py
models/
user.py
order.py
product.py
services/
user_service.py
order_service.py
product_service.py
# Good: Organized by feature/domain
src/
users/
controller.py
model.py
service.py
repository.py
orders/
controller.py
model.py
service.py
repository.py
products/
controller.py
model.py
service.py
repository.py
Module Cohesion:
def calculate_tax(amount): ...
def send_email(to, subject): ...
def hash_password(password): ...
def calculate_sales_tax(amount, state): ...
def calculate_income_tax(income, bracket): ...
def get_tax_rate(state): ...
def send_email(to, subject, body): ...
def send_bulk_email(recipients, subject, body): ...
def validate_email(email): ...
def hash_password(password): ...
def verify_password(password, hash): ...
def generate_token(user_id): ...
Best Practices
Code Quality Checklist
Before Committing:
During Review:
Anti-Patterns
Common Mistakes
❌ Over-engineering: Premature abstraction
→ Start simple, refactor when needed
❌ God objects: Classes that do everything
→ Follow Single Responsibility Principle
❌ Premature optimization: Optimizing before profiling
→ Make it work, make it right, make it fast
❌ Copy-paste coding: Duplicating logic
→ Extract to shared functions
❌ Commenting obvious code: // Set x to 5
→ Only comment complex/non-obvious logic
❌ Inconsistent naming: getUserData() vs fetchUser()
→ Pick conventions and stick to them
❌ Deep nesting: If/else 5+ levels deep
→ Use guard clauses, early returns
❌ Ignoring errors: try { } catch { }
→ Handle errors explicitly
Tools & Automation
Static Analysis Tools
Python:
flake8 src/
pylint src/
mypy src/
radon cc src/ -a
radon mi src/
bandit -r src/
JavaScript/TypeScript:
eslint src/
tsc --noEmit
npx complexity-report src/
Go:
golangci-lint run
gocyclo -over 10 .
gosec ./...
Quality Gates in CI
name: Code Quality
on: [pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run linters
run: |
flake8 src/ --max-complexity=10
pylint src/ --fail-under=8.0
- name: Check test coverage
run: |
pytest --cov=src --cov-fail-under=80
- name: Security scan
run: |
bandit -r src/ -ll
- name: Check complexity
run: |
radon cc src/ -a -nb --total-average-threshold=B
Related Skills
- engineering-code-review: Reviewing code for quality issues
- engineering-refactoring-patterns: Improving code quality through refactoring
- engineering-test-driven-development: Writing quality code via TDD
- engineering-technical-debt: Managing quality trade-offs
- engineering-design-patterns: Applying proven design solutions
References