# Never Nesting

> Flatten deeply nested code using guard clauses, early return/continue, function extraction, and error-handling redesign - and recognize when nesting should stay (symmetric branches, RAII/defer cleanup idioms). Use when writing or refactoring code with deep indentation, pyramid-of-doom or arrow-shaped if/else, nested loops or try/catch blocks, a buried happy path, or when the user mentions nesting…

- **Type:** Skill
- **Install:** `agentstack add skill-morzecrew-agent-skills-never-nesting`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [morzecrew](https://agentstack.voostack.com/s/morzecrew)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [morzecrew](https://github.com/morzecrew)
- **Source:** https://github.com/morzecrew/agent-skills/tree/main/skills/never-nesting

## Install

```sh
agentstack add skill-morzecrew-agent-skills-never-nesting
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Never Nesting

Each level of indentation is one more condition the reader must hold as true to
understand the innermost line. SonarSource's cognitive-complexity metric
formalizes this: every control structure costs +1, **plus +1 for each level of
nesting it sits under**. Four sequential guard clauses cost 4; the same logic as
four nested `if`s costs 1+2+3+4 = 10. Nesting doesn't add difficulty linearly —
it compounds. The Linux kernel style guide puts it bluntly: "if you need more
than 3 levels of indentation, you're screwed anyway, and should fix your
program."

Treat **three levels as a soft ceiling** and a fourth as a refactoring signal,
not a formatting problem. The moves below flatten code; the last section covers
the cases where flattening makes code worse.

## Use this skill when

- Writing a function that is growing nested `if`/`for`/`try` blocks.
- Refactoring arrow code / pyramid-of-doom conditionals (`if { if { if { ... }}}`).
- The happy path sits several indents deep with error handling wrapped around it.
- Reviewing code for readability or a complexity-metric violation.
- The user mentions nesting, guard clauses, early returns, or flattening conditionals.

## Do not use this skill when

- The user explicitly wants the existing structure preserved.
- Both branches of a conditional are equally normal behavior (see "When not to flatten").
- Manual resource cleanup makes early returns leak (see "When not to flatten").

## The move-set

| Move | Use when | Effect |
| --- | --- | --- |
| Guard clause (invert + early return) | edge/error cases wrap the happy path | happy path drops to base indent |
| `continue` / `break` | per-item conditions nest a loop body | loop body flattens |
| Extract function | a nested block is a coherent, nameable unit | resets nesting to zero; names intent |
| Define errors out of existence | every caller must check or catch | the error branch disappears entirely |
| Aggregate error handling | `try`/`catch` wraps each individual call | one handler at one level |
| Dispatch table / pattern match | nested `if`/`else` selects among cases | branching becomes data |

## Guard clauses: invert, fail fast, return early

Fowler's "Replace Nested Conditional with Guard Clauses": handle each unusual
case first with an immediate `return`/`raise`, so the remaining code needs no
`else` and the real work sits at base indentation. The guards read as a
declaration of the function's preconditions.

```python
# Before: reader holds 3 conditions to understand the core 3 lines
def save(user, payload):
    if user is not None:
        if user.is_active:
            if payload.is_valid():
                record = build_record(payload)
                store(record)
                return record
            else:
                raise InvalidPayload()
        else:
            raise InactiveUser()
    else:
        raise MissingUser()

# After: each condition is discharged, then forgotten
def save(user, payload):
    if user is None:
        raise MissingUser()
    if not user.is_active:
        raise InactiveUser()
    if not payload.is_valid():
        raise InvalidPayload()

    record = build_record(payload)
    store(record)
    return record
```

Mechanics: (1) negate the outermost condition and exit early in that branch;
(2) the `else` is now dead — delete it and promote its body one level;
(3) repeat inward until the happy path is flat. Inside loops, the same inversion
uses `continue` (or `break`) instead of `return`:

```python
for item in items:
    if item.skip:
        continue
    process(item)
```

If several guards share the same failure response, one combined condition
(`if not (a and b and c): raise ...`) can beat three separate guards — choose
whichever states the requirement most directly.

## Extraction: name the block, reset the depth

When a nested block does one coherent thing, pull it into a function. This
removes indentation at the call site, gives the block a name that documents
intent, and — because complexity metrics assess each function separately —
resets the nesting count to zero inside the new function.

```python
# Before: the interesting logic starts 4 levels deep
def process_downloads(downloads):
    for d in downloads:
        if d.state == "in_progress":
            result = d.process()
            if result.is_error():
                if result.retriable and d.retries < 3:
                    d.retries += 1
                    d.state = "pending"
                else:
                    fail(d)

# After: the loop is a summary; the extracted function is guard-flat
def process_downloads(downloads):
    for d in downloads:
        if d.state == "in_progress":
            handle_result(d, d.process())

def handle_result(d, result):
    if not result.is_error():
        return
    if result.retriable and d.retries < 3:
        d.retries += 1
        d.state = "pending"
        return
    fail(d)
```

For a long function with distinct phases, extract each phase so the top level
reads as an outline. Real refactors alternate the moves: extract to drop a
level, then invert inside the extraction.

## Flatten error handling at the source

Nesting is often not a control-flow problem but an API-design problem. Two
moves from Ousterhout's *A Philosophy of Software Design*:

- **Define errors out of existence.** Redesign the operation so the "error"
  case is normal behavior and the branch vanishes for every caller. Deleting a
  missing key throws → make deletion idempotent (succeed if already absent).
  Out-of-range substring throws (Java) → clamp to the valid range (Python
  slicing). One API change deletes a `try`/`except` from every call site.
- **Aggregate exception handling.** Instead of wrapping each call in its own
  `try`/`catch` (pyramids of handlers), let exceptions propagate to a single
  handler at the level that can actually respond — a request-level error
  handler, a per-item `try` around the loop body, a top-level retry loop.

## Replace conditional trees with data or idioms

- A nested `if`/`else` chain that maps a value to behavior is a **dispatch
  table**: `handlers[kind](payload)` — branching becomes a data lookup.
- Prefer built-in flat forms where the language has them: pattern matching
  (`match`/`switch` with cases), comprehensions and `filter`/`map` for
  filter-inside-loop, `with`/`using` for acquire-release nesting.

## When not to flatten

- **Symmetric branches.** A guard clause signals "this branch is not what the
  function is about." Fowler's rule: use guards when one branch is the unusual
  case; when **both branches are normal behavior** (`days = 366 if leap else
  365`, buy vs sell), keep `if`/`else` (or a conditional expression) so both
  get equal emphasis — a guard would falsely mark one as an error path.
- **Manual cleanup languages.** Early return is safe only when cleanup runs
  automatically: RAII destructors (C++/Rust), `defer` (Go), context managers
  (`with`), `try`/`finally`, `using` (C#). In C-style code with manual
  `free`/`unlock`, extra returns leak resources; the flat idiom there is a
  single `goto err` cleanup chain (the Linux kernel's own pattern) — don't
  graft early returns onto it.
- **Trivial one-off extraction.** Don't extract a two-line block used once if
  the name adds nothing; a guard clause alone is often enough. Each extraction
  also adds a definition the reader may have to chase.
- **Single-exit codebases.** If the style guide bans early returns, flatten by
  extraction and dispatch tables instead of inversion.

The goal is fewer conditions held in the reader's head, not a zero-indent
contest.

## Quick checklist

- Any function past ~3 levels? It's a candidate.
- Can edge cases become guards so the happy path reaches base indent?
- Is a nested block a nameable unit? Extract it.
- Is the nesting caused by an API that throws where it could tolerate? Fix the API.
- Is any branch you're about to guard actually normal behavior? Keep `if`/`else`.
- Does an early return skip manual cleanup? Use the language's cleanup idiom first.

## Related skills

- `naming-things` — extraction only pays off if the new function's name informs; naming difficulty means the block isn't a coherent unit yet.
- `self-documenting-code` — guard clauses and extracted functions document intent that comments would otherwise carry.
- `less-code-same-behavior` — flattening often reveals duplicate branches that can be merged or deleted.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [morzecrew](https://github.com/morzecrew)
- **Source:** [morzecrew/agent-skills](https://github.com/morzecrew/agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-morzecrew-agent-skills-never-nesting
- Seller: https://agentstack.voostack.com/s/morzecrew
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
