Skip to main content

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

  1. Review the patterns and examples below
  2. Apply the relevant patterns to your implementation
  3. 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

  1. C4 Architecture - Context, Container, Component, Code diagrams
  2. Design Patterns - Creational, Structural, Behavioral patterns (GoF)
  3. SOLID Principles - Single Responsibility, Open/Closed, Liskov, Interface Segregation, Dependency Inversion
  4. Architectural Patterns - Layered, Microservices, Event-Driven, CQRS
  5. 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:

ProblemPatternExample Use Case
One global instanceSingletonDatabase connection pool
Object creation variesFactory MethodDocument parser (PDF, Word, etc.)
Complex object constructionBuilderSQL query builder, HTTP request
Interface mismatchAdapterLegacy API wrapper
Add features without subclassingDecoratorLogging, caching wrappers
Notify on changeObserverEvent systems, MVC
Swap algorithmsStrategySorting, payment methods
Undo/redo operationsCommandText 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-PatternProblemSolution
Pattern for every classOver-engineering, unnecessary complexityApply patterns only when solving specific problems
Mismatched pattern selectionWrong solution for the problemUnderstand pattern intent and applicability first
Pattern without understandingCargo-cult programmingStudy pattern thoroughly before implementation
Ignoring language idiomsPatterns don't fit languageAdapt patterns to language strengths (e.g., Python vs Java)
Premature abstractionYAGNI violation, speculative generalityWait for 3 use cases before abstracting
Mixing pattern responsibilitiesViolates Single ResponsibilityOne pattern per responsibility
Incomplete C4 diagramsMissing critical contextInclude all system boundaries and dependencies
SOLID validation without contextFalse positives from AST analysisCombine static analysis with architectural review
Copy-paste pattern codeDoesn't fit actual use caseCustomize pattern to specific requirements
Not documenting pattern choiceLost architectural rationaleDocument 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