Anti-Patterns: What NOT to Do
5 min read
Lesson slides
1 / 15
Anti-patterns are common responses to recurring problems that are usually ineffective and counterproductive. Understanding anti-patterns is as important as knowing design patterns.
Design Pattern Anti-Patterns
graph TD
A[Anti-Patterns] --> B[Misuse of Patterns]
A --> C[Architectural Anti-Patterns]
A --> D[Code-Level Anti-Patterns]
B --> B1[Golden Hammer]
B --> B2[Pattern Obsession]
B --> B3[Copy-Paste Programming]
C --> C1[Big Ball of Mud]
C --> C2[Spaghetti Code]
C --> C3[God Object]
D --> D1[Magic Numbers]
D --> D2[Dead Code]
D --> D3[Duplicate Code]1. Pattern-Specific Anti-Patterns
Singleton Anti-Patterns
# ❌ ANTI-PATTERN: Singleton Abuse
class ConfigManager: # Everything becomes singleton
_instance = None
# ... singleton implementation
class DatabaseManager: # Another singleton
_instance = None
# ... singleton implementation
class LogManager: # Yet another singleton
_instance = None
# ... singleton implementation
# Problems: Global state, testing difficulties, tight coupling# ✅ BETTER APPROACH: Dependency Injection
class OrderService:
def __init__(self, config, db, logger):
self.config = config
self.db = db
self.logger = logger
def process_order(self, order):
# Use injected dependencies
passFactory Anti-Patterns
# ❌ ANTI-PATTERN: God Factory
class EverythingFactory:
def create_object(self, type, subtype, variant, options):
if type == "user":
if subtype == "admin":
if variant == "super":
# 50 lines of creation logic
elif variant == "regular":
# 30 lines of creation logic
elif subtype == "regular":
# ... more nested conditions
elif type == "product":
# ... another 100 lines
# This factory does too much!# ✅ BETTER APPROACH: Specialized Factories
class UserFactory:
def create_admin(self, level): pass
def create_regular_user(self): pass
class ProductFactory:
def create_physical_product(self): pass
def create_digital_product(self): pass2. Architectural Anti-Patterns
The God Object
classDiagram
class GodObject {
+processUser()
+handlePayment()
+sendEmail()
+validateData()
+generateReport()
+manageInventory()
+calculateTax()
+logActivity()
+... 50 more methods
}
note for GodObject "Violates Single Responsibility Principle"Big Ball of Mud
The "Big Ball of Mud" anti-pattern refers to a software architecture or system design characterized by a lack of structure, organization, and clear separation of concerns. In a Big Ball of Mud architecture, the codebase typically evolves over time without a coherent architectural vision or efficient design decisions. As a result, the system becomes increasingly complex, tangled, difficult to understand, maintain, and extend.
graph LR
A[Module A] -.-> B[Module B]
B -.-> C[Module C]
C -.-> A
A -.-> D[Module D]
D -.-> E[Module E]
E -.-> B
C -.-> F[Module F]
F -.-> A
E -.-> F
style A fill:#ff9999
style B fill:#ff9999
style C fill:#ff9999
style D fill:#ff9999
style E fill:#ff9999
style F fill:#ff99993. Common Design Anti-Patterns
Magic Numbers and Strings
# ❌ ANTI-PATTERN: Magic Numbers
def calculate_discount(price):
if price > 1000:
return price * 0.15 # What does 0.15 mean?
elif price > 500:
return price * 0.10 # What does 0.10 mean?
return 0
def get_user_type(code):
if code == 1: # What does 1 mean?
return "admin"
elif code == 2: # What does 2 mean?
return "user"# ✅ BETTER APPROACH: Named Constants
class DiscountRates:
PREMIUM_THRESHOLD = 1000
PREMIUM_RATE = 0.15
STANDARD_THRESHOLD = 500
STANDARD_RATE = 0.10
class UserTypes:
ADMIN = 1
REGULAR_USER = 2
def calculate_discount(price):
if price > DiscountRates.PREMIUM_THRESHOLD:
return price * DiscountRates.PREMIUM_RATE
elif price > DiscountRates.STANDARD_THRESHOLD:
return price * DiscountRates.STANDARD_RATE
return 0Copy-Paste Programming
# ❌ ANTI-PATTERN: Duplicate Code
def process_order_email(order):
subject = f"Order {order.id} Confirmation"
body = f"Dear {order.customer.name}, your order has been processed"
send_email(order.customer.email, subject, body)
def process_shipment_email(order):
subject = f"Order {order.id} Shipped" # Similar code
body = f"Dear {order.customer.name}, your order has been shipped" # Similar code
send_email(order.customer.email, subject, body) # Duplicate
def process_delivery_email(order):
subject = f"Order {order.id} Delivered" # Similar code again
body = f"Dear {order.customer.name}, your order has been delivered" # Similar code again
send_email(order.customer.email, subject, body) # More duplication# ✅ BETTER APPROACH: Template Method Pattern
class EmailNotification:
def send_order_notification(self, order, event_type):
subject = self._create_subject(order, event_type)
body = self._create_body(order, event_type)
send_email(order.customer.email, subject, body)
def _create_subject(self, order, event_type):
return f"Order {order.id} {event_type.title()}"
def _create_body(self, order, event_type):
messages = {
'confirmation': 'has been processed',
'shipped': 'has been shipped',
'delivered': 'has been delivered'
}
return f"Dear {order.customer.name}, your order {messages[event_type]}"4. Anti-Pattern Detection Checklist
flowchart TD
A[Code Review] --> B{Class > 500 lines?}
B -->|Yes| C[Possible God Object]
B -->|No| D{Method > 50 lines?}
D -->|Yes| E[Extract Methods]
D -->|No| F{Duplicate Code?}
F -->|Yes| G[Apply DRY Principle]
F -->|No| H{Magic Numbers?}
H -->|Yes| I[Extract Constants]
H -->|No| J{Tight Coupling?}
J -->|Yes| K[Apply SOLID Principles]
J -->|No| L[Code Looks Good!]5. Refactoring Anti-Patterns
Before: Anti-Pattern Example
class OrderProcessor: # God Object Anti-Pattern
def process_order(self, order_data):
# Validation (should be separate)
if not order_data.get('email'):
raise ValueError("Email required")
# Payment processing (should be separate)
if order_data['payment_method'] == 'credit_card':
# 20 lines of credit card logic
pass
elif order_data['payment_method'] == 'paypal':
# 15 lines of PayPal logic
pass
# Inventory management (should be separate)
for item in order_data['items']:
# 10 lines of inventory logic
pass
# Email notification (should be separate)
# 15 lines of email logic
# Logging (should be separate)
# 5 lines of logging logicAfter: Proper Pattern Application
class OrderProcessor:
def __init__(self, validator, payment_processor, inventory, notifier, logger):
self.validator = validator
self.payment_processor = payment_processor
self.inventory = inventory
self.notifier = notifier
self.logger = logger
def process_order(self, order_data):
self.validator.validate(order_data)
payment_result = self.payment_processor.process(order_data)
self.inventory.reserve_items(order_data['items'])
self.notifier.send_confirmation(order_data)
self.logger.log_order_processed(order_data)
return payment_resultAnti-Pattern Prevention Guidelines
- Single Responsibility: Each class should have one reason to change
- Avoid Global State: Minimize singletons and global variables
- Favor Composition: Use dependency injection over inheritance
- Keep It Simple: Don't over-engineer solutions
- Regular Refactoring: Continuously improve code structure
- Code Reviews: Have others review your pattern usage
- Test-Driven Development: Write tests to catch design issues early