# How the Karpathy Guidelines Prevent Over-Abstraction of Single-Use Code

> Learn how Karpathy guidelines prevent over-abstraction of single-use code by enforcing inline implementation until duplication is necessary. Read more!

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

---

**The Karpathy guidelines explicitly prohibit creating abstractions for code that will only be used once, mandating inline implementations until actual duplication emerges.**

The `forrestchang/andrej-karpathy-skills` repository encodes Andrej Karpathy's coding philosophy into concrete rules for LLM-assisted development. Among these principles, the stance against over-abstraction of single-use code represents a deliberate architectural decision to prioritize readability and simplicity over premature generalization.

## The Rule Against Over-Abstraction of Single-Use Code

The prohibition appears in the **"Simplicity First"** section of both primary documentation files. In **[`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md)** at line 22, the rule *"No abstractions for single-use code"* appears directly after the admonition to avoid unnecessary features. This file serves as the central behavioral guide for LLM-assisted coding within the repository.

The same guidance is echoed in **[`skills/karpathy-guidelines/SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/skills/karpathy-guidelines/SKILL.md)** at line 28, where the bullet point *"No abstractions for single-use code"* is listed among the simplicity rules. This skill definition file allows the guidelines to be reused across different contexts while maintaining the same strict stance on abstraction.

## Three Core Principles Behind the Guideline

This architectural stance operates through three specific mandates that govern when to abstract:

**Write only what is required.** If functionality will be invoked a single time, implement it inline rather than extracting it into a generic helper. This eliminates the cognitive overhead of navigating unnecessary indirection.

**Avoid premature generalization.** Introducing abstractions before concrete needs appear adds cognitive load, maintenance burden, and hidden coupling. The guidelines treat speculative reuse as a form of over-engineering.

**Encourage refactoring only after duplication emerges.** When the same logic truly repeats across different contexts, extraction into a shared component becomes permissible—but only after the duplication is evident and the abstraction is justified by actual usage patterns.

## Code Examples: Over-Abstraction vs. Inline Implementation

Consider a scenario where you need to normalize text within a single processing function.

The discouraged approach creates a generic utility that serves only one call site:

```python
def normalize_text(text: str) -> str:
    # Generic utility that could be reused elsewhere

    return text.strip().lower()

def process_user_input(raw: str) -> str:
    # Uses the generic normalizer even though it's only needed here

    cleaned = normalize_text(raw)
    return f"Processed: {cleaned}"

```

The recommended approach keeps the logic inline, eliminating the unnecessary abstraction layer:

```python
def process_user_input(raw: str) -> str:
    # Inline, single-use normalization

    cleaned = raw.strip().lower()
    return f"Processed: {cleaned}"

```

If the normalization logic later needs to be shared across multiple modules, you can refactor it into a dedicated function at that point—fulfilling the "only after duplication" guideline.

## Summary

- **Explicit prohibition**: Both [`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) (line 22) and [`SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/SKILL.md) (line 28) contain the rule "No abstractions for single-use code" within their simplicity sections.
- **Inline first**: Single-use functionality should be implemented directly at the call site without extraction into helper functions.
- **Wait for duplication**: Only create shared abstractions after the same logic appears in multiple places.
- **Repository context**: These guidelines live in the `forrestchang/andrej-karpathy-skills` repository, designed to govern LLM-assisted coding workflows according to Karpathy's philosophy.

## Frequently Asked Questions

### When should I extract code into a reusable function?

You should only extract code into a shared abstraction after the same logic appears in multiple locations and the duplication becomes evident. According to the guidelines in [`CLAUDE.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md) and [`SKILL.md`](https://github.com/forrestchang/andrej-karpathy-skills/blob/main/SKILL.md), premature extraction creates unnecessary cognitive load and coupling that outweighs the benefits of reuse.

### Does this guideline mean I should never write utility functions?

No, utility functions are appropriate when they serve multiple call sites. The rule specifically targets **single-use** code—functionality invoked only once within the entire codebase. If a helper function genuinely eliminates duplication across modules, it aligns with the guidelines' intent to reduce repetition.

### How do I distinguish between single-use code and potentially reusable code?

Ask whether the logic is needed in exactly one context or if it's genuinely domain-agnostic. If the code contains business logic specific to a single workflow, keep it inline. If it represents a general pattern that has already appeared twice, consider extraction according to the principle of refactoring only after duplication emerges.

### What if I anticipate the code will be reused in future features?

The guidelines explicitly reject speculative abstraction. Future reuse is not justification for early extraction; you should refactor only when the second usage actually materializes. This prevents the maintenance burden of unused generic interfaces and keeps the codebase minimal.