Anti-Patterns and How to Choose the Right Pattern

Site Admin · 11 Sep 2026 · 15 views

Anti-Patterns and How to Choose the Right Pattern

Knowing design patterns is only half the battle. Knowing when NOT to use them is equally important. An anti-pattern is a practice that seems like a good idea but in practice leads to problems like rigidity, fragility, or unnecessary complexity. Recognising anti-patterns helps you avoid common traps and make better design decisions.

Common Anti-Patterns

The most dangerous anti-patterns tend to appear when developers apply patterns too eagerly or when they avoid refactoring.

+-----------------------------------------+
|           God Object Anti-Pattern       |
|                                         |
|  +-----------------------------------+  |
|  |    OrderManager                   |  |
|  |  - database                       |  |
|  |  - email                          |  |
|  |  - inventory                      |  |
|  |  - payment                        |  |
|  |  - logging                        |  |
|  |  + validate()                     |  |
|  |  + processPayment()               |  |
|  |  + sendEmail()                    |  |
|  |  + updateInventory()              |  |
|  |  + auditLog()                     |  |
|  +-----------------------------------+  |
|  does EVERYTHING in one class           |
+-----------------------------------------+

The God Object takes on every responsibility. Changing email logic risks breaking payment processing. Testing is nearly impossible because everything is coupled together. The solution is to apply the Single Responsibility Principle and extract each concern into its own class.

Spaghetti Code

Spaghetti code is unstructured, deeply nested code with no clear separation of concerns. Methods call each other randomly, and there is no layering or abstraction.

public void processOrder(String orderId) {
    // 200 lines of database access
    // mixed with validation
    // mixed with email sending
    // mixed with payment processing
    // nested 8 levels deep
    if (order != null) {
        if (order.getStatus().equals("NEW")) {
            // even more nesting
        }
    }
}

The fix is refactoring into smaller methods and applying patterns like Strategy for payment logic, Observer for notifications, and Template Method for the processing pipeline. Each pattern separates one tangled concern into its own clean module.

Premature Optimisation

Writing a Flyweight factory before you have proven you have a memory problem, or building a complex caching Proxy before measuring response times, adds complexity that may never pay for itself. The right approach is to follow YAGNI - You Ain't Gonna Need It - and apply a pattern only when a concrete problem demands it.

How to Choose the Right Pattern

Choosing a pattern starts with the problem, not the solution. Ask yourself what is actually hard about the current code. Is it that adding new types requires modifying existing classes? That points to Factory or Strategy. Is it that objects are tightly coupled? That points to Mediator or Observer. Is it that state transitions are tangled? That points to State.

Problem Diagnosis Flowchart:

  Too many conditionals on state?      --> State pattern
  Request passes through many steps?   --> Chain of Responsibility
  Objects know too much about each other? --> Mediator
  Creating too many similar objects?    --> Flyweight
  Need undo/restore capability?         --> Memento
  Algorithm skeleton with hook steps?   --> Template Method
  Need to vary behaviour at runtime?    --> Strategy

The key is that a pattern solves a specific kind of problem. Applying the wrong pattern creates more complexity than it removes.

Real-World Scenario

A team once wrapped every service call in a Proxy, every DTO in a Builder, and every collection access in a custom Iterator - all before writing a single business rule. The codebase became a labyrinth of indirection with no actual domain logic. The takeaway: start simple, identify pain points, and then refactor toward a pattern that directly addresses that pain. Patterns are tools, not goals.

Key Points

  • An anti-pattern is a common practice that causes more harm than good, such as God Object or Spaghetti Code.
  • The God Object violates the Single Responsibility Principle by handling too many concerns in one class.
  • Spaghetti Code results from no separation of concerns and can be fixed by extracting logic into pattern-based modules.
  • Always apply the YAGNI principle - do not introduce a pattern until a concrete problem justifies it.
  • Choose patterns based on the specific problem you face, not on which pattern seems most impressive.
Share this post:

Comments (0)

Please login or register to comment.