Skill: wpank/reducing-entropy (version 0.1.0)

--- name: reducing-entropy model: reasoning category: testing description: Minimize total codebase size through ruthless simplification. Measure success by final code amount, not effort. Bias toward deletion. version: 1.0 keywords: [simplification, deletion, refactoring, complexity, entropy, YAGNI, less code, minimalism] activation: manual # Only activate when explicitly requested --- # Reducing Entropy > More code begets more code. Entropy accumulates. This skill biases toward the smallest possible codebase. --- ## WHAT This Skill Does Provides a mindset and checklist for: - Evaluating whether changes reduce or increase total code - Finding opportunities to delete code - Resisting premature abstraction - Choosing the simplest solution that solves the problem **Core question:** "What does the codebase look like *after*?" ## WHEN To Use Activate this skill when: - **Refactoring code** and considering options - **Adding a new feature** and choosing implementation approach - **Reviewing PRs** to challenge unnecessary complexity - **Paying down tech debt** and prioritizing what to simplify - **User explicitly asks** for code reduction or simplification --- ## The Goal The goal is **less total code in the final codebase** — not less code to write right now. | Scenario | Verdict | |----------|---------| | Writing 50 lines that delete 200 lines | **Net win** ✓ | | Keeping 14 functions to avoid writing 2 | **Net loss** ✗ | | "Better organized" but more code | **More entropy** ✗ | | "More flexible" but more code | **More entropy** ✗ | | "Cleaner separation" but more code | **More entropy** ✗ | **Measure the end state, not the effort.** --- ## Before You Begin **Load a mindset from `references/`:** 1. List files in `references/` 2. Read frontmatter descriptions 3. Pick at least one that applies 4. State which you loaded and its core principle Available mindsets: - `simplicity-vs-easy.md` — Simple is objective; easy is subjective. Choose simple. - `design-is-taking-apart.md` — Good design separates concerns, removes dependencies. - `data-over-abstractions.md` — 100 functions on one structure beats 10 on 10. - `expensive-to-add-later.md` — When YAGNI doesn't apply (PAGNI exceptions). --- ## Three Questions ### 1. What's the smallest codebase that solves this? Not "what's the smallest change" — what's the smallest *result*. - Could this be 2 functions instead of 14? - Could this be 0 functions (delete the feature)? - What would we delete if we did this? ### 2. Does the proposed change result in less total code? Count lines before and after. If after > before, challenge it. ``` Before: 847 lines across 12 files After: 623 lines across 8 files Verdict: ✓ Net reduction of 224 lines ``` ### 3. What can we delete? Every change is an opportunity to delete. Ask: - What does this make obsolete? - What was only needed because of what we're replacing? - What's the maximum we could remove? --- ## Red Flags | Phrase | What It Hides | Challenge | |--------|---------------|-----------| | "Keep what exists" | Status quo bias | "Total code is the metric, not churn" | | "This adds flexibility" | Speculative generality | "Flexibility for what? Is it needed now?" | | "Better separation of concerns" | More files = more code | "Separation isn't free. Worth how many lines?" | | "Type safety" | Sometimes bloats code | "Worth how many lines? Could runtime checks work?" | | "Easier to understand" | More things ≠ easier | "14 things are not easier than 2 things" | | "This is the pattern" | Pattern worship | "Does the pattern fit, or are we forcing it?" | | "We might need this later" | YAGNI violation | "Delete it. Git remembers." | --- ## Deletion Checklist Before completing any refactor, ask: - [ ] Did I count lines before and after? - [ ] Did I delete everything this change makes obsolete? - [ ] Did I remove any now-unnecessary abstractions? - [ ] Did I consolidate files that are too small to stand alone? - [ ] Did I delete tests for deleted code? - [ ] Did I update imports to remove dead dependencies? --- ## When This Doesn't Apply - The codebase is already minimal for what it does - You're in a framework with strong conventions (don't fight it) - Regulatory/compliance requirements mandate certain structures - The "simpler" version would be genuinely unmaintainable (rare) --- ## NEVER Do 1. **NEVER keep code "in case we need it"** — delete it; git has history 2. **NEVER add abstractions for fewer than 3 use cases** — wait for the pattern to emerge 3. **NEVER create new files for single functions** — colocate with usage 4. **NEVER preserve code just because someone wrote it** — evaluate on merit 5. **NEVER accept "more organized" as justification for more code** — organization should reduce, not increase 6. **NEVER skip the line count** — measure before and after; feelings lie 7. **NEVER add "flexibility" without immediate need** — YAGNI applies 8. **NEVER refactor without deleting something** — if nothing becomes obsolete, question the value --- ## Quick Wins | Pattern | Action | |---------|--------| | Wrapper that just forwards calls | Inline the wrapped code | | Config file with 2 settings | Move to environment variables | | Utils file with 1 function | Move function to where it's used | | Interface with 1 implementation | Delete the interface | | Abstract class with 1 subclass | Merge into concrete class | | Module that re-exports everything | Delete; import from source | | Comments explaining obvious code | Delete comments; code is clear | --- ## The Grug Perspective > "complexity very very bad. say again: complexity very bad. you think you not, but you are." Grug brain developer knows: - Complexity demon hides in abstraction - More code = more bugs = more complexity - Best code is no code - Second best code is simple code - If you can't understand it in your head, it's too complex --- ## References Philosophical foundations for simplicity thinking: | Reference | Core Principle | |-----------|----------------| | [simplicity-vs-easy.md](references/simplicity-vs-easy.md) | Simple (objective) vs easy (subjective) — choose simple | | [design-is-taking-apart.md](references/design-is-taking-apart.md) | Good design separates; composition beats construction | | [data-over-abstractions.md](references/data-over-abstractions.md) | Generic data + many functions beats many custom types | | [expensive-to-add-later.md](references/expensive-to-add-later.md) | PAGNI exceptions — what you probably are gonna need | External resources: - [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy/) — Rich Hickey - [The Grug Brained Developer](https://grugbrain.dev/) - [Out of the Tar Pit](https://curtclifton.net/papers/MosesleyMarks06a.pdf) — Moseley & Marks

path: README.md
content: # Reducing Entropy

Minimize total codebase size through ruthless simplification. Measure success by the final code amount, not effort. Bias toward deletion — more code begets more code, and entropy accumulates.

## What's Inside

- The goal: less total code in the final codebase
- Three guiding questions (smallest codebase, less total code, what to delete)
- Red flags and challenge phrases ("adds flexibility", "better separation", "we might need this later")
- Deletion checklist for every refactor
- Quick wins table (inline wrappers, delete single-implementation interfaces, merge abstract classes)
- Reference mindsets (simplicity vs easy, design is taking apart, data over abstractions, expensive to add later)
- The Grug perspective on complexity

## When to Use

- Refactoring code and considering options
- Adding a new feature and choosing implementation approach
- Reviewing PRs to challenge unnecessary complexity
- Paying down tech debt and prioritizing what to simplify
- Explicitly asked for code reduction or simplification

## Installation

```bash
npx add https://github.com/wpank/ai/tree/main/skills/testing/reducing-entropy
```

### Manual Installation

#### Cursor (per-project)

From your project root:

```bash
mkdir -p .cursor/skills
cp -r ~/.ai-skills/skills/testing/reducing-entropy .cursor/skills/reducing-entropy
```

#### Cursor (global)

```bash
mkdir -p ~/.cursor/skills
cp -r ~/.ai-skills/skills/testing/reducing-entropy ~/.cursor/skills/reducing-entropy
```

#### Claude Code (per-project)

From your project root:

```bash
mkdir -p .claude/skills
cp -r ~/.ai-skills/skills/testing/reducing-entropy .claude/skills/reducing-entropy
```

#### Claude Code (global)

```bash
mkdir -p ~/.claude/skills
cp -r ~/.ai-skills/skills/testing/reducing-entropy ~/.claude/skills/reducing-entropy
```

## Related Skills

- [clean-code](../clean-code/) — Coding standards with YAGNI and KISS principles
- [code-review](../code-review/) — Review PRs with a simplification lens

---

Part of the [Testing](..) skill category.


path: references/data-over-abstractions.md
content: ---
description: 100 functions on one data structure beats 10 functions on 10 structures. Generic data and operations enable composition.
---

# Data-Oriented Design

## The Core Principle

> "It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures."

Generic operations on generic data structures beat specialized operations on specialized structures.

## Why Custom Abstractions Hurt

Every custom type, wrapper class, or specialized structure:
- Adds a concept to understand
- Requires its own operations
- Limits composition with other code
- Creates maintenance burden

A `Map<String, Value>` can be processed by hundreds of existing functions. A `SettingsManager` class can only be processed by the methods you write for it.

## Information Over Objects

Model the information domain, not the behavior.

- What data exists?
- What are the essential relationships?
- What transformations do you need?

Then use generic structures (maps, vectors, sets) to represent that information. The behavior comes from functions that operate on data - not from methods bound to custom objects.

## Practical Application

Before creating a new class/type, ask:
- Could this be a map/dict with well-known keys?
- Could this be a simple tuple/record?
- Do I need custom behavior, or just data?

If you just need data, use data structures. Save custom types for when you genuinely need custom behavior that can't be a function.

**The power is in the combinations, not the custom constructs.**

## External References

- [The Value of Values](https://www.infoq.com/presentations/Value-Values/) - Rich Hickey on data vs objects
- [Data-Oriented Design](https://www.dataorienteddesign.com/dodbook/) - Richard Fabian's book on DOD
- [CppCon 2014: Mike Acton "Data-Oriented Design"](https://www.youtube.com/watch?v=rX0ItVEVjHc) - Practical DOD in game engines


path: references/design-is-taking-apart.md
content: ---
description: Design is taking things apart, not adding features. Separate concerns, remove dependencies, compose simple pieces.
---

# Composition Over Construction

## The Core Insight

> "Design is about taking things apart."

Good design is not about adding features. It's about removing dependencies. It's about separating concerns so cleanly that each piece can be understood, tested, and changed independently.

## Taking Things Apart

When you see a complex system, the instinct is to understand how the pieces fit together. But the real skill is seeing how to *pull them apart*.

- What different concerns are mixed here?
- Which responsibilities could be separate?
- Where are we conflating different concepts?

Each separation reduces complexity. Each coupling increases it.

## Building from Simple Parts

Once you have simple, independent pieces:
- They compose freely
- They test trivially
- They change safely

Inheritance complects. Composition liberates.

A system built from small, focused functions that transform data is:
- Easier to understand (each piece does one thing)
- Easier to test (pure functions, clear inputs/outputs)
- Easier to change (modify one piece without touching others)

## The Anti-Pattern

The opposite of composition is the "god object" or "kitchen sink" - one thing that knows about everything, does everything, and can't be changed without breaking everything else.

Every helper method you add to a class is a small step toward the kitchen sink. Every layer of abstraction is a coupling waiting to cause pain.

## Practical Application

Before adding a method, wrapper, or abstraction:
- Does this *separate* concerns, or *combine* them?
- Am I making pieces more independent, or more coupled?
- Could I solve this with a function that takes data and returns data?

**Separate, don't combine. Compose, don't construct.**

## External References

- [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy/) - Rich Hickey on complecting vs composing
- [Out of the Tar Pit](https://curtclifton.net/papers/MosesleyMarks06a.pdf) - Moseley & Marks on essential vs accidental complexity
- [A Philosophy of Software Design](https://www.amazon.com/dp/173210221X) - John Ousterhout on deep vs shallow modules


path: references/expensive-to-add-later.md
content: ---
description: Some things you Probably Are Gonna Need - know when YAGNI doesn't apply because retrofitting is dramatically more expensive than building it in from the start.
---

# PAGNI: Probably Are Gonna Need It

## The Core Insight

> "When should you override YAGNI? When the cost of adding something later is so dramatically expensive compared with the cost of adding it early on that it's worth taking the risk."

YAGNI is a good default. But some things are genuinely cheaper to build in from the start than to retrofit later. Know the difference.

## Why This Matters

Ruthless YAGNI application can backfire when:
- Adding it later requires touching everything (logging, timestamps, audit trails)
- You can't add it retroactively at all (API versioning, mobile app kill switches)
- The cost of not having it is catastrophic (security fundamentals, data you threw away)

The avoiding-complexity skill pushes toward less. This mindset identifies the exceptions where "add it now" beats "add it later."

## Common PAGNIs

**Data you can't get back:**
- `created_at` / `updated_at` timestamps on every table
- Audit logs (who did what when)
- Many-to-many from the start if there's any hint you'll need more than one

**Infrastructure that's painful to retrofit:**
- API versioning (even if v1 is the only version)
- API pagination (even if lists are small now)
- Automated deploys and CI from day one
- Logging infrastructure

**Security fundamentals:**
- Vulnerability disclosure policy and security@ email
- Session/password invalidation mechanisms
- Safe ways to move redacted data out of production

## The Test

Before invoking PAGNI, ask:
1. **Is retrofitting dramatically more expensive?** (10x+, not 2x)
2. **Is this a known pattern from experience?** (not speculative)
3. **Is the cost of adding it now actually low?** (minutes/hours, not days)

If yes to all three, it's a PAGNI. Otherwise, YAGNI still applies.

## The Balance

PAGNI is not an escape hatch for over-engineering. It's a small, specific list of exceptions learned from painful experience. When in doubt, YAGNI wins.

**Most features: YAGNI. Infrastructure and data collection: probably PAGNI.**

## External References

- [PAGNIs: Probably Are Gonna Need Its](https://simonwillison.net/2021/Jul/1/pagnis/) - Simon Willison
- [YAGNI Exceptions](https://lukeplant.me.uk/blog/posts/yagni-exceptions/) - Luke Plant
- [Application Security PAGNIs](https://jacobian.org/2021/jul/8/appsec-pagnis/) - Jacob Kaplan-Moss


path: references/simplicity-vs-easy.md
content: ---
description: Simple is objective (not intertwined), easy is subjective (familiar). Choose simple over easy for long-term maintainability.
---

# Simplicity vs Easy

## The Core Distinction

**Simple** and **easy** are not the same thing. We conflate them constantly, and it costs us.

- **Simple**: One concept, not intertwined with others. Objective measure.
- **Easy**: Near at hand, familiar, relative to our capabilities. Subjective.

Easy changes over time as you learn. Simple is absolute.

## Why This Matters

When we reach for the "easy" solution - the familiar pattern, the framework we know, the abstraction we've used before - we often add complexity. The easy path introduces concepts that intertwine with others.

The simple solution might be unfamiliar. It might require thinking. But it doesn't braid together concerns that should be separate.

## Complecting

"Complect" means to intertwine or braid together.

Complexity comes from braiding together concepts that should be separate. Every time we couple things, we create complexity. Every coupling is a future debugging session.

Simple means:
- One role
- One task  
- One concept

If you can't explain it simply, it's too complex.

## The Choice

When designing, ask: "Am I choosing this because it's simple, or because it's familiar?"

Familiar feels productive. Simple *is* productive - over the lifetime of the code.

**Choose simple over easy. Always.**

## External References

- [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy/) - Rich Hickey's canonical talk on this distinction
- [The Value of Values](https://www.infoq.com/presentations/Value-Values/) - Related talk on immutability and simplicity


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)