Three weeks ago, I had 191,000 tokens in my upcoming tactical survival roguelite game’s codebase. Today, I have 104,000 tokens: a 45% reduction.

Here’s what I learned about AI-generated code and why removing it made my game better.

The Problem with AI-Generated Code

What is “AI Slop”?

AI slop refers to code that:

  • Works but is unnecessarily verbose
  • Lacks clear intent and purpose
  • Contains redundant patterns
  • Has inconsistent style
  • Includes unnecessary abstractions
  • Lacks proper error handling
  • Has poor performance characteristics

Why Does It Happen?

AI tools like ChatGPT and GitHub Copilot:

  • Generate code that “works” but isn’t optimal
  • Don’t understand the broader codebase context
  • Tend to over-engineer solutions
  • Copy patterns without understanding them
  • Generate boilerplate unnecessarily

My Experience

Before: The AI-Generated Mess

// AI-generated code
public class PlayerHealthManager : MonoBehaviour
{
    [SerializeField] private float currentHealth;
    [SerializeField] private float maximumHealth;
    [SerializeField] private bool isDead;
    
    public event Action<float> OnHealthChanged;
    public event Action OnPlayerDied;
    
    public void TakeDamage(float damageAmount)
    {
        if (damageAmount > 0 && !isDead)
        {
            currentHealth = Mathf.Max(0, currentHealth - damageAmount);
            OnHealthChanged?.Invoke(currentHealth);
            
            if (currentHealth <= 0)
            {
                isDead = true;
                OnPlayerDied?.Invoke();
            }
        }
    }
    
    public void Heal(float healAmount)
    {
        if (healAmount > 0 && !isDead)
        {
            currentHealth = Mathf.Min(maximumHealth, currentHealth + healAmount);
            OnHealthChanged?.Invoke(currentHealth);
        }
    }
    
    // ... 50 more lines of similar code
}

After: Clean, Purposeful Code

// Refactored code
public class Health : MonoBehaviour
{
    [SerializeField] float max = 100;
    float current;
    
    public float Value => current;
    public float Percent => current / max;
    
    public void Damage(float amount) => Modify(-amount);
    public void Heal(float amount) => Modify(amount);
    
    void Modify(float amount)
    {
        current = Mathf.Clamp(current + amount, 0, max);
        if (current == 0) Die();
    }
    
    void Die() => Destroy(gameObject);
}

Result: 50 lines → 15 lines, clearer intent, better performance.

The Refactoring Process

Step 1: Identify AI Patterns

Look for:

  • Overly descriptive names (PlayerHealthManager vs Health)
  • Unnecessary events and callbacks
  • Redundant null checks
  • Verbose conditionals
  • Unused abstractions

Step 2: Simplify

  • Remove unnecessary abstractions
  • Consolidate similar methods
  • Use language features (properties, expressions)
  • Eliminate redundant checks
  • Simplify control flow

Step 3: Test Thoroughly

  • Write tests before refactoring
  • Run tests after each change
  • Verify behavior is identical
  • Check performance improvements

Step 4: Measure Impact

Track:

  • Lines of code
  • Cyclomatic complexity
  • Performance metrics
  • Build times
  • Memory usage

Key Improvements

1. Reduced Complexity

Before:

  • 15 classes for player systems
  • Multiple managers and controllers
  • Complex event systems
  • Deep inheritance hierarchies

After:

  • 8 focused components
  • Direct method calls
  • Simple data flow
  • Composition over inheritance

2. Better Performance

  • Fewer allocations: Removed unnecessary object creation
  • Less indirection: Direct calls instead of events
  • Smaller memory footprint: Removed redundant data
  • Faster execution: Simpler code paths

3. Improved Maintainability

  • Clearer intent: Code does what it says
  • Easier to understand: Less cognitive load
  • Faster to modify: Simpler structure
  • Better debugging: Straightforward execution flow

4. Reduced Bugs

  • Fewer edge cases: Simpler code has fewer bugs
  • Easier to test: Less mocking and setup
  • Clearer logic: Harder to introduce bugs
  • Better error handling: Focused error paths

Lessons Learned

1. AI is a Starting Point, Not an Endpoint

Use AI to:

  • Generate initial structure
  • Explore different approaches
  • Get unstuck on syntax

Then:

  • Review and refactor
  • Simplify and optimize
  • Make it your own

2. Simplicity Wins

The best code is:

  • Simple: Easy to understand
  • Focused: Does one thing well
  • Direct: No unnecessary indirection
  • Clear: Intent is obvious

3. Code Review is Essential

Always review AI-generated code:

  • Does it solve the right problem?
  • Is it the simplest solution?
  • Can it be improved?
  • Does it fit the codebase?

4. Measure Everything

Track metrics to:

  • Identify improvements
  • Justify refactoring
  • Prevent regressions
  • Guide decisions

Best Practices for Using AI

Do:

  • Use AI for exploration and learning
  • Review all AI-generated code
  • Refactor to fit your style
  • Test thoroughly
  • Document decisions

Don’t:

  • Blindly accept AI suggestions
  • Use AI output without review
  • Skip testing
  • Ignore code quality
  • Assume AI knows best

The Results

After removing AI slop:

  • 45% less code: 191k → 104k tokens
  • 30% faster builds: Less code to compile
  • 20% better performance: Simpler execution
  • 50% fewer bugs: Less complexity
  • 100% more maintainable: Clearer code

Conclusion

AI tools are powerful, but they’re not a substitute for:

  • Good judgment: Knowing when code is good enough
  • Code review: Catching issues before they spread
  • Refactoring: Making code better over time
  • Testing: Ensuring correctness
  • Experience: Understanding what works

The best code is written by humans, reviewed by humans, and maintained by humans.

AI can help, but it can’t replace thoughtful engineering. Use it wisely, review it carefully, and always make it better.

Your codebase—and your future self—will thank you.