These are the design anti-patterns most frequently encountered in production codebases. For each, we cover the symptoms, root causes, consequences, and refactoring remedies using proper design patterns from this catalog.

1. God Object (The Blob)

Description: A single class that knows too much and does too much, controlling a disproportionate share of the application’s logic.

Symptoms:

  • One class with thousands of lines and dozens of methods
  • Modified in nearly every pull request
  • Name is vague: Manager, Handler, Utils, Application
  • Many unrelated imports and dependencies

Root Causes: Feature additions without refactoring; “just add it to the existing class” culture; lack of architectural boundaries.

Consequences: Untestable monoliths, merge conflicts, fear of change, onboarding takes weeks.

Remedy:

Step Action Pattern
1 Identify responsibility clusters Single Responsibility Principle
2 Extract each cluster into its own class Facade for the simplified API
3 Replace conditionals with polymorphism Strategy, State
4 Coordinate extracted classes Mediator or event bus
  // Before: God Object
class ApplicationManager {
    void handleLogin() { /* ... */ }
    void processPayment() { /* ... */ }
    void sendEmail() { /* ... */ }
    void generateReport() { /* ... */ }
    void manageDatabase() { /* ... */ }
}

// After: Decomposed with Facade
class AuthService { void login() { /* ... */ } }
class PaymentService { void process() { /* ... */ } }
class NotificationService { void sendEmail() { /* ... */ } }
class ReportService { void generate() { /* ... */ } }

class ApplicationFacade {
    private final AuthService auth;
    private final PaymentService payment;
    // coordinates services for common workflows
}
  

2. Spaghetti Code

Description: Control flow is tangled and unstructured, with GOTO-like jumps via exceptions, flags, and deeply nested conditionals.

Symptoms:

  • Methods with cyclomatic complexity above 15
  • Boolean flags that change behavior unpredictably (isProcessing, isRetry, isAdmin)
  • goto-like patterns using labeled breaks or recursive side effects
  • No clear entry or exit points

Root Causes: Incremental patches without restructuring; absence of state modeling; fear of rewriting working code.

Consequences: Impossible to test all paths; bugs hide in untested branches; every change risks regression.

Remedy:

Step Action Pattern
1 Map states and transitions State pattern
2 Replace conditionals with strategy objects Strategy
3 Chain processing steps Chain of Responsibility
4 Define algorithm skeleton Template Method

3. Golden Hammer

Description: Every problem is treated as a nail because the team has one favorite solution — often a specific design pattern, framework, or architecture style.

Symptoms:

  • Singleton used for everything (even stateless utilities)
  • Every class gets an interface “for flexibility” that is never needed
  • Microservices proposed for a 3-person team with 5 endpoints
  • “We are a Kafka shop” — message queues for synchronous CRUD

Root Causes: Recent training or success with one approach; resume-driven development; vendor advocacy.

Consequences: Unnecessary complexity, performance overhead, team frustration, solutions that do not fit the problem.

Remedy:

  • Evaluate each problem independently before choosing a pattern
  • Use the simplest solution that satisfies requirements
  • Apply the YAGNI principle (You Aren’t Gonna Need It)
  • Review architecture decisions with ADRs documenting alternatives considered

4. Lava Flow

Description: Dead code, obsolete features, and deprecated modules remain in the codebase because nobody knows if they are still needed.

Symptoms:

  • Commented-out blocks spanning hundreds of lines
  • Classes with zero references but “might be needed later”
  • Feature flags that have been true for three years
  • Dependencies on libraries no longer used

Root Causes: Fear of breaking unknown dependencies; no ownership of cleanup; lack of deletion culture.

Consequences: Cognitive load, slower builds, security vulnerabilities in unused dependencies, misleading documentation.

Remedy:

  • Use static analysis tools to find unreachable code
  • Delete with confidence — version control preserves history
  • Establish a “cleanup Friday” or allocate 10% of sprint capacity to removal
  • Require justification for keeping deprecated code beyond one release cycle

5. Copy-Paste Programming

Description: Code is duplicated across the codebase with minor modifications instead of extracting shared abstractions.

Symptoms:

  • Identical logic in 3+ places with slightly different variable names
  • Bug fixes that must be applied in multiple locations
  • “Find and replace” as a refactoring strategy

Root Causes: Deadline pressure; lack of refactoring skills; not recognizing duplication as a problem.

Consequences: Inconsistent behavior, multiplied maintenance cost, bugs fixed in one copy but not others.

Remedy:

Duplication Type Pattern Remedy
Algorithm varies by type Strategy
Steps are same, details differ Template Method
Object creation duplicated Factory Method
Similar objects with variations Prototype or Builder

6. Poltergeist

Description: Classes that exist but serve no meaningful purpose — they delegate everything, hold no state, and add indirection without value.

Symptoms:

  • Classes with only one method that calls another class’s method
  • “Wrapper” or “Helper” classes that pass through every call unchanged
  • Layers of abstraction with no logic at any layer

Root Causes: Over-application of layering rules; premature abstraction; copy-paste of architectural templates.

Consequences: Navigation overhead, confused new developers, stack traces with 10 frames of pass-through.

Remedy:

  • Delete the class and call the target directly
  • If indirection is needed, ensure the class adds value: validation, caching, logging (Decorator, Proxy)
  • Apply the rule of three: abstract only after the third duplication

7. Boat Anchor

Description: Code written for a future requirement that never materialized, sitting unused but maintained.

Symptoms:

  • Interfaces with no implementations
  • Configuration for features not in the roadmap
  • Abstract classes with one concrete child that is the only implementation ever

Root Causes: Over-engineering for hypothetical futures; architects designing without delivery feedback.

Consequences: Wasted development time, misleading code that suggests capabilities that do not exist.

Remedy:

  • Apply YAGNI — build for today’s requirements
  • If preparing for extension, use simple extension points (interfaces) without full implementations
  • Revisit speculative code quarterly — delete if still unused

8. Analysis Paralysis

Description: Excessive time spent on design and pattern selection without delivering working code.

Symptoms:

  • Weeks of architecture diagrams before the first line of code
  • Debates about whether a problem needs Strategy or State
  • UML diagrams that do not match the eventual implementation

Root Causes: Fear of making wrong decisions; perfectionism; lack of iterative delivery culture.

Consequences: Missed deadlines, outdated designs by the time coding starts, team frustration.

Remedy:

  • Start with the simplest design; refactor toward patterns when pain points emerge
  • Use spikes and prototypes to validate design decisions quickly
  • Time-box architecture discussions (e.g., 2-hour decision window)

Quick Reference: Detection and Fix

Anti-Pattern Quick Detection Primary Fix
God Object One class in every PR Extract + Facade
Spaghetti Code Complexity > 15 State / Strategy
Golden Hammer Same pattern everywhere Fit pattern to problem
Lava Flow Dead code > 15% Delete with VCS safety net
Copy-Paste 3+ similar blocks Extract + Template Method
Poltergeist Pass-through classes Delete or add real behavior
Boat Anchor Unused interfaces YAGNI / delete
Analysis Paralysis No code after weeks of design Spike / iterate

Prevention Checklist

Use this during code review:

  • Does each class have a single, clearly stated responsibility?
  • Are methods shorter than 30 lines with complexity below 10?
  • Is the chosen pattern the simplest one that solves the problem?
  • Has dead code been removed in this change?
  • Is duplicated logic extracted into a shared abstraction?
  • Does every class and layer add value beyond indirection?
  • Was speculative code justified by an approved roadmap item?

Key Takeaways

  • God Object and Spaghetti Code are the most destructive design anti-patterns in production systems.
  • Golden Hammer and Analysis Paralysis represent opposite failures: over-applying patterns vs over-planning.
  • Lava Flow and Copy-Paste Programming accumulate silently until they dominate maintenance cost.
  • Every anti-pattern has a concrete refactoring path using the design patterns in this catalog.
  • Prevention is cheaper than cure: pattern literacy, code review discipline, and dedicated refactoring time.

Return to Introduction to Anti-Patterns for the full taxonomy and detection methodology.