# What Anti-Patterns Does the Simplicity First Principle Target?

> Discover the six anti-patterns Simplicity First targets: over-engineering premature optimization excessive configurability unnecessary error handling duplicated logic and nested control flow. Learn to code cleaner.

- Repository: [Jiayuan Zhang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills)
- Tags: best-practices
- Published: 2026-04-08

---

**The Simplicity First principle explicitly guards against six destructive coding anti-patterns: over-engineering, premature optimization, excessive configurability, unnecessary error-handling, duplicated logic, and deeply nested control flow.** These guidelines, documented in the [[`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) file of the [forrestchang/andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills) repository, establish concrete constraints to prevent architectural and implementation complexity from obscuring business logic.

## Core Anti-Patterns Eliminated by Simplicity First

The following six patterns represent the primary targets of the Simplicity First constraint. Each pattern adds cognitive load or maintenance burden without delivering proportional value to the current problem scope.

### Over-Engineering and Unused Abstractions

**Over-engineering** manifests as elaborate class hierarchies, generic frameworks, or "flexible" plumbing designed for hypothetical future requirements. According to the [`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) specification, this anti-pattern adds layers of indirection that inflate the code surface and hide the real intent. The principle mandates writing the **minimum code** that solves the problem today, avoiding abstractions unless they are strictly required for the current implementation.

### Premature Optimization

This anti-pattern involves micro-optimizing through complex caching, lazy-loading, or concurrency mechanisms before profiling identifies a concrete bottleneck. As noted in the repository guidelines, premature optimization leads to tangled logic and wasted development time. Simplicity First requires a **clear, correct implementation** first, with optimization applied only after measurements prove a specific bottleneck exists.

### Excessive Configurability

Exposing numerous knobs, environment variables, or optional behaviors that are never exercised increases cognitive load for readers and complicates testing. The principle insists on keeping the **API surface small and opinionated**, exposing configuration only when it adds immediate, demonstrable value to the use case.

### Unnecessary Error-Handling

Defensive coding that guards against "impossible" states—such as wrapping every call in try/catch blocks or validating inputs already guaranteed by the call-site—clutters code and obscures the happy path. Simplicity First dictates handling errors **where they are likely**, avoiding defensive checks for scenarios that cannot occur under normal usage patterns.

### Duplicated Logic and Copy-Paste

Re-implementing identical functionality across multiple locations rather than extracting a single, well-named helper causes divergence and maintenance overhead. The principle favors **single-source truth**, extracting reusable logic only when the extraction genuinely simplifies the overall flow rather than creating unnecessary indirection.

### Deeply Nested Control Flow

Long chains of `if/else` statements, multiple levels of loops, or callback pyramids reduce readability and make edge-case reasoning difficult. The guideline requires keeping functions **short and flat**, using early returns or guard clauses to flatten nesting and improve scannability.

## Code Examples: Complexity Versus Simplicity

The [[`SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/SKILL.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/skills/karpathy-guidelines/SKILL.md) file provides concrete before-and-after comparisons that illustrate these anti-patterns in practice.

### Example: Over-Engineered Strategy Pattern

**Anti-pattern (unnecessary abstraction):**

```python

# Unnecessary abstraction for a single use case

class DataProcessor:
    def __init__(self, strategy):
        self.strategy = strategy
    def run(self, data):
        return self.strategy.process(data)

class SumStrategy:
    def process(self, data):
        return sum(data)

# Caller builds the whole abstraction

processor = DataProcessor(SumStrategy())
result = processor.run([1, 2, 3])

```

**Simplicity First approach:**

```python

# Direct, minimal implementation – no extra class hierarchy

def sum_data(data):
    return sum(data)

# Caller uses the function directly

result = sum_data([1, 2, 3])

```

### Example: Premature Memoization

**Anti-pattern (optimization before measurement):**

```javascript
// Complex memoisation for a trivial calculation
const memo = new Map();
function expensiveFib(n) {
  if (memo.has(n)) return memo.get(n);
  if (n <= 1) return n;
  const val = expensiveFib(n-1) + expensiveFib(n-2);
  memo.set(n, val);
  return val;
}

```

**Simplicity First approach:**

```javascript
// Straight-forward recursive implementation – clarity first
function fib(n) {
  if (n <= 1) return n;
  return fib(n-1) + fib(n-2);
}

```

The first version adds caching logic before it is known whether the function will be a bottleneck. The second version remains concise, easier to test, and can be optimized later if profiling identifies a performance issue.

## Document Implementation

These constraints are codified across three key files in the repository:

- **[[`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md)** – Contains the full textual description of the Simplicity First principle and its guardrails against the six anti-patterns.
- **[[`SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/SKILL.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/skills/karpathy-guidelines/SKILL.md)** – Provides executable skill definitions and concrete code examples demonstrating the application of simplicity constraints.
- **[[`README.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/README.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/README.md)** – Offers overarching context for the repository's behavioral guidelines, referencing Simplicity First within the broader coding philosophy.

## Summary

The Simplicity First principle targets specific complexity vectors that degrade code maintainability:

- **Over-engineering** – Avoid abstractions for hypothetical future requirements.
- **Premature optimization** – Profile first, optimize second.
- **Excessive configurability** – Keep APIs opinionated and minimal.
- **Unnecessary error-handling** – Skip defensive checks for impossible states.
- **Duplicated logic** – Extract helpers only when they simplify the flow.
- **Deep nesting** – Prefer flat control flow with early returns.

By enforcing these boundaries, developers produce code that is readable, testable, and maintainable, focusing effort on solving actual problems rather than maintaining scaffolding that never sees use.

## Frequently Asked Questions

### What are the main anti-patterns targeted by Simplicity First?

The principle explicitly identifies six anti-patterns: over-engineering (elaborate unused abstractions), premature optimization (micro-optimizing before profiling), excessive configurability (unused knobs and options), unnecessary error-handling (defensive checks for impossible states), duplicated logic (copy-paste instead of single-source truth), and deeply nested control flow (complex conditional hierarchies).

### How does Simplicity First handle performance optimization?

The guideline does not forbid optimization; it forbids *premature* optimization. According to the [`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) specification, developers should first implement a clear, correct solution, then profile to identify concrete bottlenecks. Only after measurements prove a performance issue should complex caching or concurrency mechanisms be introduced.

### Where are these guidelines documented in the repository?

The complete guidelines reside in [[`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) at the repository root, with practical code examples in [[`skills/karpathy-guidelines/SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/skills/karpathy-guidelines/SKILL.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/skills/karpathy-guidelines/SKILL.md). The [[`README.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/README.md)](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/README.md) provides high-level context linking Simplicity First to the repository's overall philosophy.

### Does Simplicity First discourage all code reuse and abstraction?

No. The principle distinguishes between necessary simplification and harmful indirection. It encourages extracting reusable logic **when it simplifies the overall flow**, but discourages creating generic frameworks or class hierarchies that serve only hypothetical future use cases. The goal is single-source truth without speculative flexibility.