mcpskills.net
SkillsMCPsAgentsPrompts
mcpskills.net — A curated directory of AI agent Skills and MCP servers
TermsPrivacy
← Back to Skills
Development

Code Simplification

Simplifies code for clarity. Use when refactoring code for clarity without changing behavior.

by Addy OsmaniRepository →Source →

Simplify code by reducing complexity while preserving exact behavior. The goal is code that is easier to read, understand, modify, and debug.

When to Use

  • After a feature is working and tests pass, but the implementation feels heavier than it needs to be
  • During code review when readability or complexity issues are flagged
  • When you encounter deeply nested logic, long functions, or unclear names
  • When refactoring code written under time pressure

The Five Principles

1. Preserve Behavior Exactly

Don't change what the code does — only how it expresses it.

ASK BEFORE EVERY CHANGE:
→ Does this produce the same output for every input?
→ Does this maintain the same error behavior?
→ Does this preserve the same side effects and ordering?
→ Do all existing tests still pass without modification?

2. Follow Project Conventions

Simplification means making code more consistent with the codebase, not imposing external preferences.

3. Prefer Clarity Over Cleverness

// UNCLEAR: Dense ternary chain
const label = isNew ? 'New' : isUpdated ? 'Updated' : isArchived ? 'Archived' : 'Active';

// CLEAR: Readable mapping
function getStatusLabel(item: Item): string {
  if (item.isNew) return 'New';
  if (item.isUpdated) return 'Updated';
  if (item.isArchived) return 'Archived';
  return 'Active';
}

4. Maintain Balance

Watch for over-simplification traps:

  • Inlining too aggressively
  • Combining unrelated logic
  • Removing "unnecessary" abstraction
  • Optimizing for line count

5. Scope to What Changed

Default to simplifying recently modified code. Avoid drive-by refactors of unrelated code.

The Simplification Process

Step 1: Understand Before Touching (Chesterton's Fence)

Before changing anything, understand why it exists:

BEFORE SIMPLIFYING, ANSWER:
- What is this code's responsibility?
- What calls it? What does it call?
- What are the edge cases and error paths?
- Are there tests that define the expected behavior?
- Why might it have been written this way?

Step 2: Identify Simplification Opportunities

Structural complexity:

Pattern Signal Simplification
Deep nesting (3+ levels) Hard to follow control flow Extract into guard clauses
Long functions (50+ lines) Multiple responsibilities Split into focused functions
Nested ternaries Requires mental stack Replace with if/else chains
Boolean parameter flags doThing(true, false, true) Replace with options objects
Repeated conditionals Same if check in multiple places Extract to predicate function

Naming and readability:

Pattern Signal Simplification
Generic names data, result, temp Rename to describe content
Misleading names Function named get that mutates Rename to reflect behavior
Comments explaining "what" // increment counter Delete the comment
Comments explaining "why" // Retry because API is flaky Keep these — they carry intent

Redundancy:

Pattern Signal Simplification
Duplicated logic Same 5+ lines in multiple places Extract to shared function
Dead code Unreachable branches, unused variables Remove
Unnecessary abstractions Wrapper that adds no value Inline the wrapper
Over-engineered patterns Factory-for-a-factory Replace with simple approach

Step 3: Apply Changes Incrementally

Make one simplification at a time. Run tests after each change.

Step 4: Verify the Result

COMPARE BEFORE AND AFTER:
- Is the simplified version genuinely easier to understand?
- Did you introduce any new patterns inconsistent with the codebase?
- Is the diff clean and reviewable?
- Would a teammate approve this change?

Language-Specific Guidance

TypeScript / JavaScript

// SIMPLIFY: Unnecessary async wrapper
// Before
async function getUser(id: string): Promise<User> {
  return await userService.findById(id);
}
// After
function getUser(id: string): Promise<User> {
  return userService.findById(id);
}

// SIMPLIFY: Verbose conditional assignment
// Before
let displayName: string;
if (user.nickname) {
  displayName = user.nickname;
} else {
  displayName = user.fullName;
}
// After
const displayName = user.nickname || user.fullName;

// SIMPLIFY: Manual array building
// Before
const activeUsers: User[] = [];
for (const user of users) {
  if (user.isActive) {
    activeUsers.push(user);
  }
}
// After
const activeUsers = users.filter((user) => user.isActive);

Verification

After completing a simplification pass:

  • All existing tests pass without modification
  • Build succeeds with no new warnings
  • Each simplification is a reviewable, incremental change
  • Simplified code follows project conventions
  • No error handling was removed or weakened
  • No dead code was left behind
  • A teammate would approve the change as a net improvement