Agent Skills Framework Extension
Software Design Patterns Skill
When to Use This Skill
Use this skill when implementing software design patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
C4 methodology for architecture documentation, system design principles, GoF design patterns, SOLID principles, and architectural patterns for robust software design.
Core Capabilities
- C4 Architecture - Context, Container, Component, Code diagrams
- Design Patterns - Creational, Structural, Behavioral patterns (GoF)
- SOLID Principles - Single Responsibility, Open/Closed, Liskov, Interface Segregation, Dependency Inversion
- Architectural Patterns - Layered, Microservices, Event-Driven, CQRS
- Pattern-Based Refactoring - Identify opportunities, apply patterns, validate improvements
C4 Model Implementation
# scripts/c4_model_generator.py
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum
class C4Level(Enum):
"""C4 diagram levels."""
CONTEXT = "context"
CONTAINER = "container"
COMPONENT = "component"
CODE = "code"
@dataclass
class C4Element:
"""Base C4 element."""
name: str
description: str
technology: Optional[str] = None
tags: List[str] = None
@dataclass
class C4Relationship:
"""Relationship between elements."""
source: str
target: str
description: str
technology: Optional[str] = None
class C4ModelGenerator:
"""Generate C4 architecture diagrams."""
def __init__(self, system_name: str):
self.system_name = system_name
self.people: List[C4Element] = []
self.systems: List[C4Element] = []
self.containers: List[C4Element] = []
self.components: List[C4Element] = []
self.relationships: List[C4Relationship] = []
def add_person(self, name: str, description: str) -> 'C4ModelGenerator':
"""Add person (user) to model."""
self.people.append(C4Element(name, description))
return self
def add_system(self, name: str, description: str, tags: List[str] = None) -> 'C4ModelGenerator':
"""Add software system to model."""
self.systems.append(C4Element(name, description, tags=tags or []))
return self
def add_container(
self,
name: str,
description: str,
technology: str,
tags: List[str] = None
) -> 'C4ModelGenerator':
"""Add container (application/data store) to model."""
self.containers.append(C4Element(name, description, technology, tags or []))
return self
def add_component(
self,
name: str,
description: str,
technology: str = None
) -> 'C4ModelGenerator':
"""Add component to model."""
self.components.append(C4Element(name, description, technology))
return self
def add_relationship(
self,
source: str,
target: str,
description: str,
technology: str = None
) -> 'C4ModelGenerator':
"""Add relationship between elements."""
self.relationships.append(C4Relationship(source, target, description, technology))
return self
def generate_context_diagram(self) -> str:
"""Generate Level 1: System Context diagram (PlantUML)."""
plantuml = "@startuml\n"
plantuml += "!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml\n\n"
plantuml += f"LAYOUT_WITH_LEGEND()\n\n"
plantuml += f"title System Context diagram for {self.system_name}\n\n"
# Add people
for person in self.people:
plantuml += f'Person({self._sanitize(person.name)}, "{person.name}", "{person.description}")\n'
# Add systems
for system in self.systems:
if system.name == self.system_name:
plantuml += f'System({self._sanitize(system.name)}, "{system.name}", "{system.description}")\n'
else:
plantuml += f'System_Ext({self._sanitize(system.name)}, "{system.name}", "{system.description}")\n'
plantuml += "\n"
# Add relationships
for rel in self.relationships:
plantuml += f'Rel({self._sanitize(rel.source)}, {self._sanitize(rel.target)}, "{rel.description}")\n'
plantuml += "@enduml\n"
return plantuml
def generate_container_diagram(self) -> str:
"""Generate Level 2: Container diagram."""
plantuml = "@startuml\n"
plantuml += "!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml\n\n"
plantuml += f"title Container diagram for {self.system_name}\n\n"
# Add people
for person in self.people:
plantuml += f'Person({self._sanitize(person.name)}, "{person.name}", "{person.description}")\n'
plantuml += "\n"
plantuml += f'System_Boundary(c1, "{self.system_name}") {{\n'
# Add containers
for container in self.containers:
tech = f', "{container.technology}"' if container.technology else ''
plantuml += f' Container({self._sanitize(container.name)}, "{container.name}", "{container.description}"{tech})\n'
plantuml += "}\n\n"
# Add external systems
for system in self.systems:
if system.name != self.system_name:
plantuml += f'System_Ext({self._sanitize(system.name)}, "{system.name}", "{system.description}")\n'
plantuml += "\n"
# Add relationships
for rel in self.relationships:
tech = f', "{rel.technology}"' if rel.technology else ''
plantuml += f'Rel({self._sanitize(rel.source)}, {self._sanitize(rel.target)}, "{rel.description}"{tech})\n'
plantuml += "@enduml\n"
return plantuml
def _sanitize(self, name: str) -> str:
"""Sanitize name for PlantUML."""
return name.replace(' ', '_').replace('-', '_').lower()
# Example usage
c4 = C4ModelGenerator("E-Commerce Platform")
# Context diagram
c4.add_person("Customer", "A customer of the e-commerce platform") \
.add_person("Admin", "Administrator managing the platform") \
.add_system("E-Commerce Platform", "Allows customers to browse and purchase products") \
.add_system("Payment Gateway", "External payment processing") \
.add_system("Email Service", "Sends emails to customers") \
.add_relationship("Customer", "E-Commerce Platform", "Browses products, places orders") \
.add_relationship("Admin", "E-Commerce Platform", "Manages products, views orders") \
.add_relationship("E-Commerce Platform", "Payment Gateway", "Processes payments") \
.add_relationship("E-Commerce Platform", "Email Service", "Sends order confirmations")
print(c4.generate_context_diagram())
# Container diagram
c4.add_container("Web Application", "Delivers the static content and the e-commerce SPA", "React") \
.add_container("API Application", "Provides e-commerce functionality via JSON/REST API", "Node.js/Express") \
.add_container("Database", "Stores product catalog, orders, user information", "PostgreSQL") \
.add_container("Cache", "Stores frequently accessed data", "Redis") \
.add_relationship("Customer", "Web Application", "Visits using", "HTTPS") \
.add_relationship("Web Application", "API Application", "Makes API calls to", "JSON/HTTPS") \
.add_relationship("API Application", "Database", "Reads from and writes to", "SQL/TCP") \
.add_relationship("API Application", "Cache", "Reads from and writes to", "Redis protocol")
print(c4.generate_container_diagram())
SOLID Principles Validator
// tools/solid-validator.ts
interface SolidViolation {
principle: 'SRP' | 'OCP' | 'LSP' | 'ISP' | 'DIP';
file: string;
class: string;
severity: 'high' | 'medium' | 'low';
message: string;
suggestion: string;
}
class SolidPrinciplesValidator {
validate(codebasePath: string): SolidViolation[] {
const violations: SolidViolation[] = [];
// Single Responsibility Principle
violations.push(...this.validateSRP(codebasePath));
// Open/Closed Principle
violations.push(...this.validateOCP(codebasePath));
// Liskov Substitution Principle
violations.push(...this.validateLSP(codebasePath));
// Interface Segregation Principle
violations.push(...this.validateISP(codebasePath));
// Dependency Inversion Principle
violations.push(...this.validateDIP(codebasePath));
return violations;
}
private validateSRP(path: string): SolidViolation[] {
// Check for classes with too many responsibilities
// Indicators:
// - Too many methods (> 20)
// - Too many dependencies
// - Methods operating on different subsets of fields
const violations: SolidViolation[] = [];
// Implementation would analyze AST to find violations
return violations;
}
private validateOCP(path: string): SolidViolation[] {
// Check for classes closed for modification, open for extension
// Indicators:
// - Switch statements on type
// - Conditional logic that changes when new types added
// - Missing abstraction (interfaces/abstract classes)
return [];
}
private validateLSP(path: string): SolidViolation[] {
// Check that derived classes can substitute base classes
// Indicators:
// - Overridden methods throwing NotImplementedError
// - Overridden methods with different preconditions
// - Overridden methods with different postconditions
return [];
}
private validateISP(path: string): SolidViolation[] {
// Check for interfaces that are too large
// Indicators:
// - Interfaces with many methods (> 10)
// - Classes implementing interface but not using all methods
// - Empty/stub method implementations
return [];
}
private validateDIP(path: string): SolidViolation[] {
// Check for dependency on abstractions, not concretions
// Indicators:
// - High-level modules depending on low-level modules
// - Direct instantiation of concrete classes in high-level code
// - Missing interfaces/abstractions
return [];
}
}
Design Pattern Catalog
# scripts/design_patterns.py
from typing import List, Dict
from dataclasses import dataclass
@dataclass
class DesignPattern:
"""Design pattern definition."""
name: str
category: str # Creational, Structural, Behavioral
intent: str
applicability: List[str]
implementation: str
example_code: str
# Creational Patterns
SINGLETON = DesignPattern(
name="Singleton",
category="Creational",
intent="Ensure a class has only one instance and provide global access to it",
applicability=[
"There must be exactly one instance of a class",
"The instance must be accessible from a well-known access point",
"The sole instance should be extensible by subclassing"
],
implementation="""
class Singleton:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not self._initialized:
# Initialize only once
self._initialized = True
self.value = None
# Usage
s1 = Singleton()
s2 = Singleton()
assert s1 is s2 # Same instance
""",
example_code="Database connection pool, Configuration manager, Logger"
)
FACTORY_METHOD = DesignPattern(
name="Factory Method",
category="Creational",
intent="Define an interface for creating objects, but let subclasses decide which class to instantiate",
applicability=[
"A class can't anticipate the class of objects it must create",
"A class wants its subclasses to specify the objects it creates",
"Classes delegate responsibility to one of several helper subclasses"
],
implementation="""
from abc import ABC, abstractmethod
class Product(ABC):
@abstractmethod
def operation(self) -> str:
pass
class ConcreteProductA(Product):
def operation(self) -> str:
return "Result of ConcreteProductA"
class ConcreteProductB(Product):
def operation(self) -> str:
return "Result of ConcreteProductB"
class Creator(ABC):
@abstractmethod
def factory_method(self) -> Product:
pass
def some_operation(self) -> str:
product = self.factory_method()
return f"Creator: Working with {product.operation()}"
class ConcreteCreatorA(Creator):
def factory_method(self) -> Product:
return ConcreteProductA()
class ConcreteCreatorB(Creator):
def factory_method(self) -> Product:
return ConcreteProductB()
""",
example_code="Document creator, UI toolkit, Database driver manager"
)
OBSERVER = DesignPattern(
name="Observer",
category="Behavioral",
intent="Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified",
applicability=[
"An abstraction has two aspects, one dependent on the other",
"A change to one object requires changing others, and you don't know how many",
"An object should be able to notify other objects without assumptions about who those objects are"
],
implementation="""
from abc import ABC, abstractmethod
from typing import List
class Observer(ABC):
@abstractmethod
def update(self, subject: 'Subject') -> None:
pass
class Subject:
def __init__(self):
self._observers: List[Observer] = []
self._state: int = 0
def attach(self, observer: Observer) -> None:
self._observers.append(observer)
def detach(self, observer: Observer) -> None:
self._observers.remove(observer)
def notify(self) -> None:
for observer in self._observers:
observer.update(self)
@property
def state(self) -> int:
return self._state
@state.setter
def state(self, value: int) -> None:
self._state = value
self.notify()
class ConcreteObserver(Observer):
def update(self, subject: Subject) -> None:
print(f"Observer: Reacted to state change to {subject.state}")
""",
example_code="Event handling systems, MVC frameworks, Pub/Sub systems"
)
Usage Examples
Generate C4 Diagrams
Apply software-design-patterns skill to create C4 Context and Container diagrams for the system
Validate SOLID Principles
Apply software-design-patterns skill to check codebase for SOLID principle violations
Identify Design Patterns
Apply software-design-patterns skill to detect Factory, Singleton, and Observer patterns in code
Pattern Selection Decision Tree
Use this tree to select the appropriate design pattern:
What problem are you solving?
│
├── Creating objects
│ ├── Single instance needed globally?
│ │ └── SINGLETON
│ ├── Create family of related objects?
│ │ └── ABSTRACT FACTORY
│ ├── Subclasses determine object type?
│ │ └── FACTORY METHOD
│ ├── Step-by-step construction?
│ │ └── BUILDER
│ └── Clone existing object?
│ └── PROTOTYPE
│
├── Structuring objects
│ ├── Adapt incompatible interface?
│ │ └── ADAPTER
│ ├── Add responsibilities dynamically?
│ │ └── DECORATOR
│ ├── Simplify complex subsystem?
│ │ └── FACADE
│ ├── Part-whole hierarchies?
│ │ └── COMPOSITE
│ └── Lazy initialization / access control?
│ └── PROXY
│
└── Managing behavior
├── Notify dependents of state change?
│ └── OBSERVER
├── Encapsulate algorithm variations?
│ └── STRATEGY
├── Queue/log/undo operations?
│ └── COMMAND
├── Sequential access without exposing structure?
│ └── ITERATOR
└── State-dependent behavior?
└── STATE
Quick Reference Table:
| Problem | Pattern | Example Use Case |
|---|---|---|
| One global instance | Singleton | Database connection pool |
| Object creation varies | Factory Method | Document parser (PDF, Word, etc.) |
| Complex object construction | Builder | SQL query builder, HTTP request |
| Interface mismatch | Adapter | Legacy API wrapper |
| Add features without subclassing | Decorator | Logging, caching wrappers |
| Notify on change | Observer | Event systems, MVC |
| Swap algorithms | Strategy | Sorting, payment methods |
| Undo/redo operations | Command | Text editor, transaction |
Integration Points
- codebase-analysis-patterns - Architecture analysis and pattern detection
- software-design-document-patterns - SDD generation with design patterns
- orchestrator-code-review-patterns - Architectural compliance validation
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: software-design-patterns
Completed:
- [x] Design patterns identified and documented
- [x] C4 diagrams generated (Context, Container, Component as needed)
- [x] SOLID principles validated
- [x] Pattern implementation code provided
- [x] Architectural compliance verified
Pattern Analysis:
- Design patterns detected: X patterns (Creational: Y, Structural: Z, Behavioral: W)
- SOLID violations found: N issues (P0: X, P1: Y, P2: Z)
- C4 diagrams created: X diagrams
- Code quality score: X% (based on pattern adherence)
Outputs:
- C4 PlantUML diagram files (if generated)
- SOLID validation report
- Pattern catalog with implementations
- Refactoring recommendations (if violations found)
Completion Checklist
Before marking this skill as complete, verify:
- All requested design patterns documented with intent and applicability
- Code examples provided for each pattern implementation
- C4 diagrams rendered successfully (test with PlantUML)
- SOLID principle violations identified with severity ratings
- Pattern-based refactoring suggestions provided
- Integration points with other skills documented
- All diagrams include proper annotations and descriptions
- Pattern catalog references GoF taxonomy correctly
- Code examples compile and follow language best practices
Failure Indicators
This skill has FAILED if:
- ❌ PlantUML syntax errors in generated C4 diagrams
- ❌ Design pattern misidentification (wrong pattern for problem)
- ❌ SOLID validation produces false positives/negatives
- ❌ Code examples contain syntax errors or don't compile
- ❌ Pattern implementations violate the patterns they implement
- ❌ C4 diagrams missing critical system components
- ❌ No integration strategy with existing codebase provided
- ❌ Pattern recommendations conflict with project architecture
- ❌ Missing applicability criteria for pattern selection
- ❌ Refactoring suggestions break existing functionality
When NOT to Use
Do NOT use this skill when:
- Simple procedural code sufficient (use basic-code-patterns instead)
- Rapid prototyping phase (patterns add unnecessary complexity)
- Code has no reuse or extensibility requirements
- Team unfamiliar with design patterns (training needed first)
- Performance-critical sections (some patterns add overhead)
- Microservices with single responsibility (patterns may over-engineer)
- Legacy code with no refactoring budget (use legacy-code-patterns)
- Domain-specific patterns needed (use domain-modeling-patterns)
Use alternatives:
- Simple implementations →
basic-code-patterns - Domain modeling →
domain-modeling-patterns - Legacy refactoring →
legacy-code-patterns - Performance optimization →
performance-patterns
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Pattern for every class | Over-engineering, unnecessary complexity | Apply patterns only when solving specific problems |
| Mismatched pattern selection | Wrong solution for the problem | Understand pattern intent and applicability first |
| Pattern without understanding | Cargo-cult programming | Study pattern thoroughly before implementation |
| Ignoring language idioms | Patterns don't fit language | Adapt patterns to language strengths (e.g., Python vs Java) |
| Premature abstraction | YAGNI violation, speculative generality | Wait for 3 use cases before abstracting |
| Mixing pattern responsibilities | Violates Single Responsibility | One pattern per responsibility |
| Incomplete C4 diagrams | Missing critical context | Include all system boundaries and dependencies |
| SOLID validation without context | False positives from AST analysis | Combine static analysis with architectural review |
| Copy-paste pattern code | Doesn't fit actual use case | Customize pattern to specific requirements |
| Not documenting pattern choice | Lost architectural rationale | Document why pattern chosen in ADR or comments |
Principles
This skill embodies:
- #1 Recycle → Extend → Re-Use → Create - Reuses proven Gang of Four and architectural patterns
- #2 First Principles - Understands WHY patterns exist before applying
- #3 Keep It Simple - Applies simplest pattern that solves the problem
- #4 Separation of Concerns - Each pattern addresses distinct design concern
- #5 Eliminate Ambiguity - Clear pattern documentation with applicability criteria
- #6 Clear, Understandable, Explainable - Patterns make code intent explicit
Full Standard: CODITECT-STANDARD-AUTOMATION.md