Race Conditions

Unsafe shared mutable state in concurrent contexts.

“Program correctness depends on the relative timing of events.” – Brian Goetz

Signs of Use (Symptoms)

  • Random failures under load (“Works on my machine, fails in prod”).
  • “Heisenbugs” that disappear when you add logging.
  • Shared global variables modified without locks.

Why it is bad (Consequences)

  • Data Corruption: Two writers overwrite each other.
  • Unpredictability: Bugs are intermittent and hard to reproduce.

Why it happens (Root Cause)

Concurrency is hard. Developers often don’t think about threading.

When it might be okay (Exceptions)

  • Never okay if it causes corruption. Always guard shared state.

Explanation

Problem

Two threads read count = 10, both increment, both write 11. Count should be 12.

The Flaw

Read-Modify-Write is not atomic.

Real world analogy

Two cashiers selling the “last” ticket because they both checked inventory before either updated it.

Refactoring Solution

  • Atomic Operations: Use Atomics, AtomicInteger.
  • Locks/Mutexes: Synchronize access.
  • Immutability: Avoid shared mutable state.
  • Actor Model: Isolate state per actor.

Pros and Cons (of the Antipattern)

Pros (Why people do it) Cons (The price you pay)
  • Simple code (ignoring the problem)
  • Data corruption
  • Unpredictable bugs
  • Comparison

    • Related Antipatterns: None directly.
    • Related Principles: ACID Isolation.

    Code example

    Typescript

    Bad (The Antipattern)

    Good (The Fix)