원클릭으로
solid
SOLID principles for object-oriented design. Trigger: When designing classes, refactoring code, or reviewing architecture.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
SOLID principles for object-oriented design. Trigger: When designing classes, refactoring code, or reviewing architecture.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Design or review REST APIs, define endpoints, request/response schemas, or evaluate API contracts. Use when the user is designing a new API, reviewing an existing one, or asking about HTTP conventions.
Perform a structured code review. Use when the user asks to review code, check a PR, audit a file, or validate an implementation against best practices.
Systematically investigate and fix bugs, errors, or unexpected behavior. Use when the user reports a bug, shares an error/stacktrace, or asks why something isn't working.
Write or improve technical documentation. Use when the user asks to document code, write a README, generate API docs, write a technical spec, or explain how something works for other engineers.
Improve the internal structure of code without changing its behavior. Use when the user asks to clean up, refactor, simplify, or reduce complexity in existing code.
Review code or configuration for security vulnerabilities. Use when the user asks to audit security, check for vulnerabilities, review auth logic, or validate input handling.
| name | solid |
| description | SOLID principles for object-oriented design. Trigger: When designing classes, refactoring code, or reviewing architecture. |
| license | Apache-2.0 |
| metadata | {"author":"mrp4sten","version":"1.0","scope":["root"],"auto_invoke":["Designing classes or interfaces","Refactoring object-oriented code","Reviewing class architecture"]} |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash |
Five principles for maintainable, scalable object-oriented design:
A class should have only one reason to change.
Each class should focus on a single responsibility or concern.
class UserManager {
saveUser(user: User) {
// Validate user
if (!user.email.includes('@')) throw new Error('Invalid email');
// Save to database
db.insert('users', user);
// Send email
emailService.send(user.email, 'Welcome!');
// Log activity
logger.info(`User ${user.id} created`);
}
}
Problems:
class UserValidator {
validate(user: User): void {
if (!user.email.includes('@')) {
throw new Error('Invalid email');
}
}
}
class UserRepository {
save(user: User): void {
db.insert('users', user);
}
}
class UserNotifier {
sendWelcomeEmail(user: User): void {
emailService.send(user.email, 'Welcome!');
}
}
class UserService {
constructor(
private validator: UserValidator,
private repository: UserRepository,
private notifier: UserNotifier,
private logger: Logger
) {}
createUser(user: User): void {
this.validator.validate(user);
this.repository.save(user);
this.notifier.sendWelcomeEmail(user);
this.logger.info(`User ${user.id} created`);
}
}
Benefits:
Software entities should be open for extension but closed for modification.
Extend behavior without modifying existing code.
class PaymentProcessor {
process(type: string, amount: number): void {
if (type === 'credit-card') {
// Credit card logic
} else if (type === 'paypal') {
// PayPal logic
} else if (type === 'crypto') {
// Crypto logic - REQUIRES MODIFYING THIS CLASS
}
}
}
Problems:
interface PaymentMethod {
process(amount: number): void;
}
class CreditCardPayment implements PaymentMethod {
process(amount: number): void {
// Credit card logic
}
}
class PayPalPayment implements PaymentMethod {
process(amount: number): void {
// PayPal logic
}
}
class CryptoPayment implements PaymentMethod {
process(amount: number): void {
// Crypto logic - NEW CLASS, NO MODIFICATION
}
}
class PaymentProcessor {
process(method: PaymentMethod, amount: number): void {
method.process(amount);
}
}
Benefits:
Subtypes must be substitutable for their base types without altering correctness.
Child classes should enhance, not break, parent class behavior.
class Bird {
fly(): void {
console.log('Flying...');
}
}
class Penguin extends Bird {
fly(): void {
throw new Error('Penguins cannot fly!'); // BREAKS CONTRACT
}
}
function makeBirdFly(bird: Bird): void {
bird.fly(); // Will throw error if bird is a Penguin
}
Problems:
interface Bird {
eat(): void;
}
interface FlyingBird extends Bird {
fly(): void;
}
class Sparrow implements FlyingBird {
eat(): void {
console.log('Eating seeds...');
}
fly(): void {
console.log('Flying...');
}
}
class Penguin implements Bird {
eat(): void {
console.log('Eating fish...');
}
}
function makeBirdFly(bird: FlyingBird): void {
bird.fly(); // Only accepts birds that can fly
}
Benefits:
Clients should not depend on interfaces they don't use.
Create focused interfaces instead of monolithic ones.
interface Worker {
work(): void;
eat(): void;
sleep(): void;
getPaid(): void;
}
class Robot implements Worker {
work(): void {
// Works
}
eat(): void {
throw new Error('Robots do not eat'); // FORCED TO IMPLEMENT
}
sleep(): void {
throw new Error('Robots do not sleep'); // FORCED TO IMPLEMENT
}
getPaid(): void {
throw new Error('Robots do not get paid'); // FORCED TO IMPLEMENT
}
}
Problems:
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
interface Payable {
getPaid(): void;
}
class Human implements Workable, Eatable, Sleepable, Payable {
work(): void { /* ... */ }
eat(): void { /* ... */ }
sleep(): void { /* ... */ }
getPaid(): void { /* ... */ }
}
class Robot implements Workable {
work(): void { /* ... */ }
// Only implements what it needs
}
Benefits:
Depend on abstractions, not concretions.
High-level modules should not depend on low-level modules. Both should depend on abstractions.
class MySQLDatabase {
save(data: string): void {
console.log('Saving to MySQL:', data);
}
}
class UserService {
private db = new MySQLDatabase(); // TIGHTLY COUPLED
saveUser(user: User): void {
this.db.save(JSON.stringify(user));
}
}
Problems:
interface Database {
save(data: string): void;
}
class MySQLDatabase implements Database {
save(data: string): void {
console.log('Saving to MySQL:', data);
}
}
class PostgreSQLDatabase implements Database {
save(data: string): void {
console.log('Saving to PostgreSQL:', data);
}
}
class UserService {
constructor(private db: Database) {} // DEPENDS ON ABSTRACTION
saveUser(user: User): void {
this.db.save(JSON.stringify(user));
}
}
// Usage (Dependency Injection)
const userService = new UserService(new MySQLDatabase());
// Or switch to PostgreSQL without changing UserService
const userService2 = new UserService(new PostgreSQLDatabase());
Benefits:
Before writing a class, ask:
| Smell | Violated Principle | Fix |
|---|---|---|
| God Class (too many responsibilities) | SRP | Extract classes |
| Long if/else or switch statements | OCP | Use polymorphism |
| instanceof checks | LSP | Fix inheritance hierarchy |
| Interfaces with unused methods | ISP | Split interfaces |
| new keyword scattered everywhere | DIP | Use dependency injection |
# Dependency Inversion with ABC
from abc import ABC, abstractmethod
class Database(ABC):
@abstractmethod
def save(self, data: str) -> None:
pass
class MySQLDatabase(Database):
def save(self, data: str) -> None:
print(f"Saving to MySQL: {data}")
class UserService:
def __init__(self, db: Database):
self.db = db
def save_user(self, user: dict) -> None:
self.db.save(str(user))
// Interface Segregation
public interface Workable {
void work();
}
public interface Payable {
void getPaid();
}
public class Employee implements Workable, Payable {
@Override
public void work() { /* ... */ }
@Override
public void getPaid() { /* ... */ }
}
public class Volunteer implements Workable {
@Override
public void work() { /* ... */ }
// No getPaid() - not forced to implement
}