Java Omnibus
OOAD & Architecture / Anti-patterns / Feature Envy and Data Clumps in Java
Anti-Patterns Java Order Management
Anti-Patterns

When methods keep reaching into other objects for data, the design is usually telling you that behavior lives in the wrong place.

Feature envy and data clumps often appear together. Feature envy happens when a method seems more interested in another object's data than in its own. Data clumps happen when the same small group of fields travels together repeatedly. Both suggest weak object boundaries and missed modeling opportunities.

Why This Topic Matters

Why it matters in real Java systems

In an e-commerce domain, shipping address fields, money-related values, or customer contact details often travel together across methods and layers. When behavior keeps pulling those values apart from the outside, the codebase becomes harder to model and easier to duplicate incorrectly.

Core Explanation

The failure shape behind this anti-pattern

Feature envy is often a responsibility placement problem. A method repeatedly pulls data out of another object because the current object does not naturally own the behavior. Data clumps are often a modeling problem. The system keeps passing related fields separately because no one promoted them into a meaningful concept.

For Java developers, both problems are useful because they point toward better object boundaries. A method can often move closer to the data it envies. A repeated field group can often become a value object, request model, or domain concept.

The real payoff is not elegance for its own sake. It is fewer duplicated rules and clearer ownership of business meaning.

Concept Breakdown

Key signals to watch for

Signal

Behavior is reaching outward

Feature envy usually means the method is better placed on the object whose data it keeps interrogating.

Signal

Repeated field bundles are clues

Data clumps often indicate a missing value object or missing domain concept.

Signal

Weak models create duplication

Without stronger concepts, the same validation and derivation logic starts appearing in many places.

Java Example

Java example in the Order Management domain

Java example: repeated address fields and outward-reaching behavior
package org.javaomnibus.ecommerce.antipatterns;

public final class ShipmentLabelService {
    public String buildLabel(Order order) {
        return order.getStreet() + ", " + order.getCity() + ", " + order.getPostalCode() + ", " + order.getCountry();
    }
}

public final class TaxService {
    public TaxCategory resolve(String street, String city, String postalCode, String country) {
        return TaxCategory.DOMESTIC;
    }
}
Code Walkthrough

Step by step

  1. ShipmentLabelService is reaching deeply into Order data, which suggests misplaced behavior or a missing Address abstraction.
  2. TaxService is receiving a recurring field cluster that should likely be a value object.
  3. Together these patterns point toward stronger domain concepts and better responsibility placement.
  4. A refactoring might introduce ShippingAddress and move address-specific behavior closer to it.
Real-World Usage

Where this shows up in practice

  • Domain modeling improvements in service-heavy Java applications
  • Refactoring repeated field groups into value objects
  • Cleaning up DTO-to-domain boundaries where raw fields spread too far
Trade-Offs

How to respond proportionately

Not every repeated pair of fields deserves a new type. Promote a cluster into a real concept when it carries shared meaning, validation, or behavior.

Common Mistakes

Frequent mistakes to watch for

  • Creating value objects that are still just pass-through wrappers
  • Moving envious methods without checking whether orchestration context is still needed
  • Ignoring repeated validation logic around the same field groups
  • Accepting raw primitives and strings because introducing a concept feels inconvenient
Related Pages

Related concepts


What To Read Next