Java Omnibus
OOAD & Architecture / Anti-patterns / God Class and Blob Anti-Pattern in Java
Anti-Patterns Java Order Management
Anti-Patterns

A God class forms when too many design questions are answered in one place.

The God class, sometimes called a Blob, is one of the easiest anti-patterns to recognize and one of the hardest to untangle once it has matured. It becomes the default home for new rules, integrations, validations, orchestration, and metrics because it already sits in the middle of everything. Over time, the system starts to revolve around it.

Why This Topic Matters

Why it matters in real Java systems

Order placement, cancellation, refunds, inventory handling, shipment coordination, and notifications can all end up trapped inside one Java service. When that happens, every change competes for the same file and the same mental model. The class becomes a bottleneck for understanding, testing, and team ownership.

Core Explanation

The failure shape behind this anti-pattern

The God class anti-pattern often begins with success. One service or manager class works well for the first few use cases, so new behavior gets added there by default. Eventually the class becomes the only place that knows how the system works, and that centrality starts to damage cohesion and changeability.

In Java systems, frameworks can accelerate this problem because service classes already feel like legitimate homes for orchestration. Without careful responsibility discipline, they slowly absorb domain logic, integration concerns, retries, validation, and notification side effects.

Refactoring a God class usually means rediscovering the missing design: use cases, domain objects, policies, and collaborator boundaries that should have existed earlier.

Concept Breakdown

Key signals to watch for

Signal

One class becomes the system

The class gradually absorbs policy, orchestration, validation, and infrastructure work until everything depends on it.

Signal

Change amplification follows

Every new business rule arrives in the same place, which multiplies regression risk and merge pressure.

Signal

Responsibility boundaries disappear

The code can still be organized into methods, but the underlying responsibilities are no longer coherent.

Java Example

Java example in the Order Management domain

Java example: a service turning into the system center
package org.javaomnibus.ecommerce.antipatterns;

public final class OrderManagerService {
    public OrderReceipt placeOrder(CheckoutRequest request) {
        validateCustomer(request.customerId());
        validateDiscountCode(request.discountCode());
        reserveInventory(request.items());
        authorizePayment(request.paymentMethod(), request.total());
        saveOrder(request);
        createShipment(request);
        sendOrderConfirmation(request.customerEmail());
        publishMetrics(request);
        return new OrderReceipt("ORD-5501");
    }

    public void cancelOrder(String orderId) {}
    public void refundOrder(String orderId) {}
    public void retryPayment(String orderId) {}
}
Code Walkthrough

Step by step

  1. The class is no longer focused on one use case or one policy area.
  2. The same type owns order placement, cancellation, refund, retries, notifications, and metrics.
  3. That centrality makes every future change more expensive.
  4. A refactoring path would split orchestration, policies, and domain state transitions into clearer homes.
Real-World Usage

Where this shows up in practice

  • Legacy Spring services that kept absorbing more flows over several years
  • Application managers or facades that became permanent instead of transitional
  • Shared orchestration classes that several teams now fear editing
Trade-Offs

How to respond proportionately

Not every central service is a Blob. Some coordination classes are valid. The anti-pattern appears when the class stops being a narrow coordinator and starts becoming the default home for unrelated responsibilities.

Common Mistakes

Frequent mistakes to watch for

  • Refactoring the class into many tiny helpers without clarifying who owns what
  • Splitting by technical operation instead of by responsibility
  • Keeping all decision logic in the same orchestration layer after extraction
  • Trying to rewrite everything at once instead of carving out one cohesive slice at a time
Related Pages

Related concepts


What To Read Next