CodeMash 2026

Java
Anti-Patterns

From God Objects to Graceful Code

Vitaliy Matiyash

Raise your hand if...

๐Ÿ“œ

You've seen a single class with > 3,000 lines of code?

๐Ÿ›

You fixed one bug only to immediately break two others?

๐Ÿ”ฎ

You've had to debug "Magic Numbers" (e.g., status == 7)?

๐Ÿ™ˆ

You've seen an empty catch (Exception e) {} block?

Anti-Pattern

"An antipattern is just like a pattern, except that instead of a solution, it gives something that looks superficially like a solution but isnโ€™t one."

- Andrew Koenig

Phase 1 The "Quick Fix"
Phase 2 Copy-Paste Propagation
Phase 3 Refactoring Nightmare

The Usual Suspects

Common Java Anti-Patterns

God Object

Spaghetti Code

Magic Numbers

Hard Coding

Lava Flow

Copy & Paste

Accidental Complexity

Reinventing the Wheel

Premature Optimization

The Ostrich Effect

THE GOD OBJECT

God Object

Definition & Symptoms

"Happens when a single object or class tries to do too much, resulting in tight coupling and decreased maintainability."

  • Low Cohesion: Methods are unrelated to each other.
  • Fragility: Changing one line breaks five unrelated features.
  • Naming Smells: Look for "Manager," "Utils," or "System."
  • Complexity: Hard to unit test because it requires 100 mocks.

AppManager.java

"A 3,000+ line class violating the Single Responsibility Principle by handling every concern in the system."


      public class AppManager {
          public void createUser(User u) {
              if (u.getName() == null) { ... } // Validation
              db.execute("INSERT...");         // SQL Persistence
              email.sendWelcome(u);            // Notification
              analytics.track("NEW_USER");     // Monitoring
              if (isHoliday()) { ... }         // Business Rules
          }
          // ... 200 unrelated methods follow ...
      }
                

Spaghetti Code

"Code where flow is tangled, logic is nested, and everything happens in one place."

The Arrowhead


public void processOrder(Order order) {
  if (order != null) {
    if (order.getItems() != null) {
      if (order.getItems().size() > 0) {
          // Deeply nested logic
          for (Item item : order.getItems()) {
             if (check(item)) { ... }
          }
      }
    }
  }
}
                

The Monolith Main


public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    System.out.println("User:");
    String u = s.nextLine();
    // Logic mixed with I/O
    if (u.equals("admin")) {
        System.out.println("Pass:");
        String p = s.nextLine();
        // Hardcoded auth
        if (p.equals("1234")) {
            System.out.println("New User:");
            String nu = s.nextLine();
            // Nested update logic
            if (!nu.isEmpty()) { 
                System.out.println("Updated"); 
            }
        }
    }
}
                
Refactoring Strategy
  • 1. Extract I/O: Move `System.out.println` to `print()` helper.
  • 2. Isolate Logic: `isValidUser()` instead of hardcoded `if (u.equals("admin"))`.
  • 3. Flatten: Use Guard Clauses (`if (order == null) return;`) to remove nesting.

Lava Flow

Definition

"The lava flow anti-pattern occurs when code that is no longer needed is left in the codebase."

Like hardened lava, it solidifies because developers are afraid to delete it.

OldUtils.java


// @Deprecated
// public static void doOldThing() {
//    // Is this used? Who knows.
//    // Don't touch it, it might break prod.
//    legacySystem.connect(); 
// }

public void activeMethod() {
   // int temp = 0; // Leftover debug code
   process();
}
                 

Magic Numbers & Hard Coding

Magic Numbers

"Bad programming practice in which numerical values are used in the source code without being properly named."


if (status == 7) { 
   // What is 7?
   run();
}
                

Hard Code

"Embedding values or configuration into the programโ€™s source code rather than storing it in a separate configuration file or database."


String dbUrl = 
  "jdbc:mysql://localhost:3306/db";
// Requires recompilation to change
                

Copy & Paste Programming

"Occurs when source code is copied and pasted from one location to another instead of reused through abstraction."

Class A

public void exportPdf() {
  connect();
  formatData(); // IDENTICAL
  saveFile();   // IDENTICAL
}
                    
Class B

public void exportCsv() {
  connect();
  formatData(); // IDENTICAL
  saveFile();   // IDENTICAL
}
                    

Update bug in one, forget the other.

Reinventing the Wheel

Definition

"Occurs when a solution to a problem is unnecessarily reinvented rather than using an existing solution or building on existing work."

The Custom Parser


// Why write 50 lines to parse JSON?
public class MyJsonParser {
    public Object parse(String s) {
        // Buggy, slow implementation
    }
}
                  

Just use Jackson or Gson.

Premature Optimization

"Optimizing before you have a profile is just guessing."

1. The "Maybe" Cache


// Caching a list of 5 items
// "Just in case it grows"
if (complexCache.has(id)) { 
    return complexCache.get(id); 
}
                

Cost of maintenance > Cost of re-fetching.

2. The "Fast" Stream


List<String> menu = List.of("Burger", "Fries");

// Thread fork/join overhead 
// is 100x slower than the operation
menu.parallelStream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
                

"Using a Ferrari to cross the street."

"Premature optimization is the root of all evil."

โ€” Donald Knuth

Accidental Complexity

"Occurs when a solution to a problem is unnecessarily complex."

Using Microservices + Kubernetes + Kafka...

โฌ‡๏ธ

...to build a To-Do List app for 1 user.

The Ostrich Effect

Swallowing Exceptions


try {
    dangerousOperation();
} catch (Exception e) {
    // TODO: Fix this later
    // e.printStackTrace(); // Commented out so logs are clean
}
            

The result? Silent failures in production that are impossible to debug.

CLEAN CODE

The Antidote to Anti-Patterns

Meaningful Names

"The name of a variable should answer all the big questions."

The Search Problem


// Good luck grepping for 't'
// in a million lines of code.
double t = 500.00;

// What is 7?
if (account.status == 7) ...
                

"Single-letter names and numeric constants are hard to locate across a body of text."

Searchable & Intentional


// Unique, searchable name
double transactionAmount = 500.00;

// Named constants are easy to find
int MAX_BLOCK_SIZE = 7;
if (account.status == MAX_BLOCK_SIZE)...
                

Clean Naming Standards

"Say what you mean. Mean what you say."

The Grammar of Code

  • Classes (Nouns): Should be nouns (`Customer`, `Account`). Avoid vague terms like `Manager` or `Processor` if possible. Never verbs.
  • Methods (Verbs): Should be verbs (`postPayment`, `deletePage`). Use `get`, `set`, and `is` for accessors.
  • Interfaces: Avoid the `I` prefix. `ShapeFactory` is better than `IShapeFactory`. The user shouldn't need to know it's an interface.

Don't Be Cute


// Cultural Reference / Slang
public void whack() { ... }
public void eatMyShorts() { ... }

// "Member" Encodings (Unnecessary)
private String m_name; 
                

Professional Clarity


// Clarity over Humor
public void save() { ... }
public void abort() { ... }

// Clean State
private String name; 
                    

The Rules of Functions

"The first rule of functions is that they should be small."

"The second rule of functions is that they should be smaller than that."

- Robert C. Martin

CLEAN CODE

Functions should do One Thing. They should do it well.

Visual Refactoring

Extracting Abstractions

The Monolith


public static String testableHtml(
  PageData pageData, 
  boolean includeSuiteSetup) throws Exception {
    
  WikiPage wikiPage = pageData.getWikiPage();
  StringBuffer buffer = new StringBuffer();
  
  if (pageData.hasAttribute("Test")) {
    if (includeSuiteSetup) {
      WikiPage suiteSetup = 
        PageCrawlerImpl.getInheritedPage(
          SuiteResponder.SUITE_SETUP_NAME, wikiPage);
      if (suiteSetup != null) {
        WikiPagePath pagePath = 
          suiteSetup.getPageCrawler().getFullPath(suiteSetup);
        String pagePathName = PathParser.render(pagePath);
        buffer.append("!include -setup .")
              .append(pagePathName).append("\n");
      }
    }
    // ... 50 more lines of append logic ...
  }
  return buffer.toString();
}
                

The Clean Version


public static String renderPage(
  PageData pageData, 
  boolean isSuite) throws Exception {

  if (isTestPage(pageData)) {
    includeSetupAndTeardownPages(pageData, isSuite);
  }
  
  return pageData.getHtml();
}
                

Why is this better?
1. Fits on one screen.
2. Describes what it does, not how.
3. One level of abstraction.

Descriptive Names

"A long descriptive name is better than a short enigmatic name."

includeSetup()
โžก๏ธ
includeSetupAndTeardownPages()
check()
โžก๏ธ
checkPasswordAndInitializeSession()

"Don't be afraid to make a name long... A long descriptive name is better than a long descriptive comment."

Arguments

"The ideal number of arguments for a function is zero (niladic)."

Good

  • includeSetupPage()
  • fileExists("MyFile")

Avoid (Polyadic)

  • makeCircle(double x, double y, double radius)
  • Better: makeCircle(Point center, double radius)

Side Effects

"Side effects are lies. Your function promises to do one thing, but it also does other hidden things."

The Lie


public boolean checkPassword(String userName, String password) {
    User user = UserGateway.findByName(userName);
    if (user != User.NULL) {
        if (cypher.verify(password, user)) {
            // SIDE EFFECT!
            // Function name says "Check", code says "Initialize"
            Session.initialize(); 
            return true;
        }
    }
    return false;
}
            

Temporal Coupling: This function can only be called when it is safe to initialize the session. If called elsewhere, you lose data.

Extract Try/Catch Blocks

"Error handling is 'One Thing'."

Mixed Concerns


public void delete(Page page) {
  try {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name);
  } catch (Exception e) {
    logger.log(e.getMessage());
  }
}
                

Separated Logic


public void delete(Page page) {
  try {
    deletePageAndAllReferences(page);
  } catch (Exception e) {
    logError(e);
  }
}

private void deletePageAndAllReferences(Page p) {
  deletePage(p);
  registry.deleteReference(p.name);
  configKeys.deleteKey(p.name);
}
                

Comments vs. Code

"Code is the only source of truth. Don't explain it, express it."

The "Explanation"


// Check if we should proceed with deployment
// (No deploys on Friday after 4 PM)
if (date.getDay() == 5 && 
    time.getHour() > 16) {
    throw new DeploymentException();
}
                

The Expression


if (!isDeploymentAllowed()) {
    abortDeployment();
}
                

The "Bad Comment" Stack

"Don't use a comment when you can use a function or a variable."

1. Journal Comments


/*
 * Changes:
 * 11-Oct-2021: Fixed bug (Jim)
 * 05-Nov-2021: Added feature (Pam)
 */
                

VERDICT: DELETE

"Source control (Git) does this better. These just clutter the file."

2. Noise & TMI


/** The Default Constructor */
public Account() {}

/** The day of the month */
private int dayOfMonth;

// See RFC-2045 Section 4.2.1...
                

VERDICT: DELETE

"Restating the obvious or dumping historical encyclopedias into code is just noise."

3. Position Markers


    } // end while
  } // end if
} // end method

// Added by Rick
                

VERDICT: REFACTOR

"If you need to mark the end of a function, your function is too big. Shorten it."

4. Ghost Code


// InputStreamResponse response = 
//      new InputStreamResponse();
// response = (InputStreamResponse) 
//      ...
                

VERDICT: DELETE IMMEDIATELY

"Others will be afraid to delete it because they think it's important. It rots. Kill it."

5. TODOs


// TODO: Fix this efficiency issue
// by 2018...
                

VERDICT: TOLERATE (BUT SCAN)

"TODOs are not an excuse to leave bad code. Scan them regularly or they become invisible."

Formatting

Vertical Formatting & Density

  • The Newspaper Metaphor: We would like a source file to be like a newspaper article.
  • Vertical Openness: Separate concepts with blank lines.
  • Vertical Distance: Concepts that are closely related should be kept vertically close to each other.

Unit Tests

The F.I.R.S.T. Rule

Fast: Tests should run quickly.

Independent: Should not depend on each other.

Repeatable: Run in any environment (QA, Prod, Laptop).

Self-Validating: Boolean output (Pass/Fail).

Timely: Written just before the production code (TDD).

The "Dirty" Test

Violating the abstraction barrier


public void testGetPageHierarchyAsXml() throws Exception {
  // 1. Details of PathParser and Crawler exposed
  crawler.addPage(root, PathParser.parse("PageOne"));
  crawler.addPage(root, PathParser.parse("PageOne.ChildOne"));

  // 2. Hard to see the "Act" step amidst the setup
  request.setResource("root");
  request.addInput("type", "xml");
  Responder responder = new SerializedPageResponder();
  SimpleResponse response =
    (SimpleResponse) responder.makeResponse(new FitNesseContext(root), request);
  String xml = response.getContent();

  // 3. Assertions mixed with low-level logic
  assertEquals("text/xml", response.getContentType());
  assertSubString("<name>PageOne</name>", xml);
  assertSubString("<name>ChildOne</name>", xml);
}
            

Refactoring to Clean Tests

Build-Operate-Check Pattern


public void testGetPageHierarchyAsXml() throws Exception {
  // BUILD: Create the test data using a helper
  makePages("PageOne", "PageOne.ChildOne");

  // OPERATE: Perform the action
  submitRequest("root", "type:xml");

  // CHECK: Assert using Domain Specific Language
  assertResponseIsXML();
  assertResponseContains(
    "<name>PageOne</name>", 
    "<name>ChildOne</name>"
  );
}
            
โœ“ Domain Specific Language
โœ“ One Concept
โœ“ Readable

The Ultimate Code Review Checklist

The Prevention Checklist

๐Ÿค– Automated Defense

SonarQube / SonarLint
  • In the IDE: Catch smells while you type (Instant Feedback).
  • In the CI/CD Pipeline: Enforce "Quality Gates" (e.g., Block merge if coverage < 80%).
Key Benefits
  • Detects Cyclomatic Complexity (> 10).
  • Finds Security Hotspots & Vulnerabilities.
  • Tracks Technical Debt ratio over time.

๐Ÿ‘€ Code Review Rules

  • 1.
    The "Explanation" Test

    If you have to explain "why" in a comment or chat, refactor the code instead.

  • 2.
    Single Responsibility Check

    Does this class have only one reason to change? If not, split it.

  • 3.
    The Boy Scout Rule

    Always leave the file cleaner than you found it (rename one variable, fix one magic number).

๐Ÿง 
The Ultimate Goal: Write code for Humans first, Compilers second.

The Action Plan

Anti-patterns at quick glance

  • ๐Ÿ›ก๏ธ Avoid them in new code
  • ๐Ÿ”ฅ Eliminate them from existing code
  • ๐Ÿ‘€ Resolve them during code reviews

Graceful Code

"Elegant code isn't just about adhering to patterns.
It's about empathy for the next developer who has to read it.
(Even if that developer is you, six months from now)."

Thank You

Let's build better software.

CodeMash 2026 | Vitaliy Matiyash

Feedback & Resources

Scan to connect or use the links below.

๐Ÿ—ฃ๏ธ

Session Feedback

Please take 30 seconds to rate this session.

Feedback QR
๐Ÿ’พ

Get the Slides

Grab the deck and code examples.

Slides QR