Skip to content

Instantly share code, notes, and snippets.

@huw
Created November 17, 2025 03:19
Show Gist options
  • Select an option

  • Save huw/79c80c4653c2136ab4fc43ec832834a5 to your computer and use it in GitHub Desktop.

Select an option

Save huw/79c80c4653c2136ab4fc43ec832834a5 to your computer and use it in GitHub Desktop.
The Grug Brained Claude
name description
grug-brain
Use when designing features, writing code, reviewing implementations, considering refactoring, evaluating libraries, or applying DRY/SOLID principles - helps resist over-abstraction, premature generalization, unnecessary frameworks, and complexity through systematic questioning about actual needs vs theoretical benefits

Grug Brain Developer

Overview

Core principle: Complexity is the enemy. Simple, obvious code beats clever abstractions. Question everything that adds indirection.

This skill helps you recognize and resist common complexity traps throughout the development lifecycle.

When to Use

Use this skill during:

  • Design/brainstorming - Before committing to approach
  • Implementation - While writing code
  • Code review - Evaluating existing code
  • Refactoring decisions - Before restructuring

The Grug Questions

Before adding abstraction, creating patterns, or introducing dependencies, ask:

1. What is the actual problem?

  • "Feels messy" is not a problem
  • "Could be cleaner" is not a problem
  • "Might need X later" is not a problem
  • Real problems: "I had to change 5 files for one feature" or "this function is 400 lines and I can't understand it"

2. What do I actually need?

  • Not what I might need
  • Not what would be elegant
  • Not what's theoretically scalable
  • What I need right now for this concrete use case

3. How many real uses exist?

  • 1 use = no abstraction (copy-paste is fine)
  • 2 uses = probably no abstraction (duplication okay)
  • 3+ uses = maybe abstract (if pattern is obvious)

4. Is the abstraction simpler than the "problem"?

  • 15 lines of if/else vs 40 lines of lookup table pattern
  • 3 inline validations vs framework with config
  • Direct function calls vs strategy pattern with interfaces

5. What's the 80/20 solution?

  • What's the simplest thing that gets 80% of the value?
  • Can I accept imperfection instead of generalization?

Common Complexity Traps

Trap: Elegance Seeking

Symptom: "This code could be cleaner/more elegant"

Ask:

  • Cleaner how? What specific problem does "messy" code cause?
  • Is the code hard to understand, or just repetitive-looking?
  • Will the abstraction make changes easier or harder?

Example:

// "Feels repetitive"
if (type === 'A') { doA(); logA(); }
if (type === 'B') { doB(); logB(); }
if (type === 'C') { doC(); logC(); }

// Grug: This is fine. Each type does different things.
// Lookup table would scatter code and add indirection.
// Refactor when you have 10 types and it annoys you, not at 3.

Trap: Premature Abstraction

Symptom: "Let's make this extensible/pluggable/configurable"

Ask:

  • Extensible for what? Do I have concrete second use case?
  • Is this speculation about future needs?
  • What happens if I just write the simple version now?

Grug says: Write code for the use case you have. When second use case appears, then consider abstraction. Most "future needs" never happen.

Trap: DRY Absolutism

Symptom: "These 3 places have similar code - violates DRY"

Ask:

  • Is this duplication of knowledge or duplication of coincidence?
  • If requirements diverge, do I want them coupled?
  • Is locality (code near its use) more valuable than DRY?

Grug says: Some duplication is good. Simple repeated code beats elaborate DRY abstraction. Prefer obvious code over clever code.

Example:

// Three forms with same validation
const emailError = !email.includes('@') ? 'Invalid' : null;

// Grug: Keep it. They're independent requirements that
// happen to match today. Tomorrow they might diverge.
// Don't create coupling for 1 line of code.

Trap: Framework/Library Reflex

Symptom: "Should I use library X? This seems like reinventing the wheel"

Ask:

  • How many cases do I actually handle? (not how many exist)
  • Is my code working? Is it 50 lines or 500?
  • What's the library size/complexity vs my simple code?

Grug says: 20 lines of code you understand beats 100KB library that handles Swahili dates. Use library when simple code stops working, not because library exists.

Example:

// Parsing 2-3 date patterns
if (msg.includes('next Tuesday')) { /* calc */ }
if (msg.match(/\w+ \d+/)) { /* parse */ }

// Grug: If this handles your actual use cases, keep it.
// Add chrono-node when you need 20 patterns, not at 2.

Trap: Architecture Astronaut

Symptom: "We need clean architecture/layers/hexagonal/DDD"

Ask:

  • What specific problem am I solving?
  • Is my business logic actually complex or just API orchestration?
  • Will layers make changes easier or add ceremony?

Grug says: Route-level organization is fine for most apps. Introduce layers only when you have concrete need (like swapping implementations). Most apps never need swappable implementations.

Trap: Principle Invocation

Symptom: "This violates [Open/Closed|SOLID|DRY|etc] principle"

Ask:

  • What concrete harm results from this "violation"?
  • Am I naming principles to sound smart, or solving real problems?
  • Would following the principle actually improve this code?

Grug says: Principles are guidelines, not laws. "Violates X principle" is not a problem unless you can point to concrete harm. Simple working code that "violates" principles beats complex correct code.

Positive Patterns

Locality of Behavior

Keep related code together, even if it creates some duplication.

// GOOD: All booking logic in one place
function processBooking(booking) {
  if (booking.type === 'rafting') {
    sendRaftingEmail();
    notifyRaftingGuide();
  }
  if (booking.type === 'camping') {
    sendCampingEmail();
    notifyCampingHost();
  }
}

// BAD: Scattered across handlers/strategies
const handlers = { rafting: RaftingHandler, camping: CampingHandler };
// Now need to jump between files to understand one booking type

Inline Until Painful

Start with inline code. Extract when duplication becomes genuinely annoying (5+ places, not 2).

Named Intermediate Variables

Break complex expressions into named steps.

// GOOD: Debuggable, readable
const isValidUser = user.active && user.verified;
const hasAccess = isValidUser && user.role === 'admin';
if (hasAccess) { ... }

// BAD: Clever one-liner
if (user.active && user.verified && user.role === 'admin') { ... }

Simple Concurrency

Prefer stateless handlers and independent jobs over complex shared state.

// GOOD: Simple parallel calls
await Promise.all([
  sendEmail(booking),
  notifyGuide(booking),
  logAnalytics(booking)
]);

// BAD: Complex state machine with locks

Decision Framework

When someone (including you) suggests complexity:

1. Question: "What problem does this solve?"
   - If answer is vague ("better architecture", "more maintainable"), reject
   - If answer is concrete ("changing X requires editing 8 files"), consider

2. Question: "What's the simplest solution?"
   - Often: just copy-paste the code
   - Or: extract one focused function
   - Not: create extensibility framework

3. Question: "Can I do 80/20?"
   - Full solution: support all date formats with NLP library
   - 80/20: handle the 3 formats users actually send
   - Choose 80/20 until it stops working

4. If still adding abstraction: "Will I regret this?"
   - Small focused function: probably fine
   - New abstraction layer/pattern: probably regret

Integration with Other Skills

With test-driven-development:

  • Write test first (TDD)
  • Make test pass with simplest code (grug)
  • Don't refactor to patterns until 3+ uses (grug)

With systematic-debugging:

  • Add logging for observability (both agree)
  • Prefer simple code that's easy to debug (grug)
  • Named intermediate variables for breakpoint debugging (grug)

With brainstorming:

  • Explore options (brainstorming)
  • Pick simplest that works (grug)
  • Delay abstraction decisions (grug)

Common Rationalizations

Excuse Reality
"Violates DRY/SOLID/Clean principles" Naming principles doesn't make abstraction necessary
"Makes code more maintainable" Abstraction without clear need reduces maintainability
"What if we need X later?" Most future needs never happen. Add when needed.
"This will be more scalable" Scalable to what? Current code handles current scale.
"Best practice is to..." Best practice depends on context. Simple is best.
"The pattern is cleaner" Cleaner how? Is it actually simpler?
"Industry standard approach" Industry writes complex code. Don't copy bad habits.
"More testable this way" Simple code is easiest to test
"This is how senior devs do it" Senior devs write simple code, juniors write clever code
"What seems simple quickly becomes complex" Ask about actual needs first, don't assume future complexity
"This is exactly where [pattern/library] pays off" Asserting benefit without measuring actual need
"You'll spend weeks building what libraries solved" Assumes you need everything the library solves
"Tech lead/code review requires it" Push back with concrete questions about actual problems

Red Flags - Check Yourself

Stop and reconsider if you're saying:

  • "Let's make this more abstract"
  • "What if we need to support X in the future?"
  • "This violates [principle]"
  • "Industry best practice is..."
  • "More maintainable/scalable/testable"
  • "Let me create a framework for this"
  • "We should use [library] instead of writing code"

All of these trigger grug alarm. Ask the questions above first.

The Bottom Line

Complexity is the enemy. Simple working code is the goal.

Question everything that adds indirection, abstraction, or dependencies. Most complexity comes from solving problems you don't have yet.

When in doubt: write the obvious code, make it work, resist the urge to make it "better."

Future you will thank you for simple code they can understand, not clever abstractions they have to decode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment