8000 Draft: the ruby prompts that would remain by devill · Pull Request #152 · habit-hooks/habit-hooks · GitHub
[go: up one dir, main page]

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Deeply nested blocks — `if` inside `for` inside `try` inside `if` — force the reader to hold every enclosing condition in their head at once. The smell is not the indentation; it is that the function is doing too much branching in one place.
Deeply nested blocks — `if` inside `for` inside `try` inside `if` — force the reader to hold every enclosing condition in their head at once. The smell is not the indentation; it is that the function/method is doing too much branching in one place.

Read the nesting from the inside out and ask what the innermost block actually needs. Usually most of the enclosing conditions are *guards* — preconditions that should be checked and bailed on early, not wrapped around the real work.

Prefer, in order:

1. **Guard clauses / early returns.** Invert a condition and `return` (or `continue`/`throw`) early so the happy path stays at the top indentation level. Each guard you lift removes one level of nesting from everything below it.
2. **Extract a helper.** When an inner block is a coherent sub-step, pull it into a named function. The name documents the intent and the nesting moves into a flat, separately-readable unit.
2. **Extract a helper.** When an inner block is a coherent sub-step, pull it into a named function/method. The name documents the intent and the nesting moves into a flat, separately-readable unit.
3. **Replace the structure.** A deep `if/else` ladder is often a lookup table or a polymorphic dispatch in disguise; a nested loop is often a `filter`/`map`/`flatMap` pipeline.

Avoid the mechanical fix of merging conditions with `&&` just to drop a level — that trades vertical nesting for an unreadable horizontal condition. The goal is a function whose shape you can take in at a glance, not one that merely passes the depth threshold.
Avoid the mechanical fix of merging conditions with `&&` just to drop a level — that trades vertical nesting for an unreadable horizontal condition. The goal is a function/method whose shape you can take in at a glance, not one that merely passes the depth threshold.

If the nesting is genuinely irreducible (a real algorithm with interacting conditions), extracting the inner loops into well-named helpers is still the move: keep each function shallow even when the algorithm as a whole is deep.
If the nesting is genuinely irreducible (a real algorithm with interacting conditions), extracting the inner loops into well-named helpers is still the move: keep each function/method shallow even when the algorithm as a whole is deep.

{% include "includes/line_level_issues.md" %}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Duplicated blocks are the cheapest visible sign of a missing abstraction. The ri

Read both occurrences side by side and ask: (1) Are these two copies of the same idea, or two different ideas that happen to look alike? (2) If they are the same idea, what is its name? (3) Does the duplicated block belong to a domain concept that does not exist yet — a value object, a strategy, a small class?

Avoid mechanical extraction. Pulling the matching lines into a function with five parameters and a couple of conditionals leaves the real shape untouched and adds a worse name on top. If extracting feels awkward, the underlying abstraction is wrong — step back and find the right one.
Avoid mechanical extraction. Pulling the matching lines into a function/method with five parameters and a couple of conditionals leaves the real shape untouched and adds a worse name on top. If extracting feels awkward, the underlying abstraction is wrong — step back and find the right one.

A concrete technique: try to write one sentence that names what both copies do. If the sentence reads naturally, that sentence is the name of the abstraction you are missing. If you can only describe the block as "the code that does X, Y, and Z", the duplication is hiding two or three smaller abstractions, not one.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
High cyclomatic complexity means one function makes too many decisions at once. The count is the symptom; tangled responsibilities are the cause.
High complexity means one function/method makes too many decisions at once. The count is the symptom; tangled responsibilities are the cause.

**Untangle the decisions:**
1. Lift guards out first — turn precondition checks into early returns so the happy path stays flat. Much of the count is preconditions wrapped around the real work.
2. Change the shape of what remains: an `if`/`else` chain switching on one value is often a lookup table or polymorphism in disguise; a nested loop is often a filter/map pipeline.
3. If the branches are genuinely separate jobs, extract one function per branch, each named for the responsibility it handles.
3. If the branches are genuinely separate jobs, extract one function/method per branch, each named for the responsibility it handles.

Useful tip: describe each branch in one sentence. Two branches with the same sentence belong together; a branch you cannot name cleanly wants its own function.
Useful tip: describe each branch in one sentence. Two branches with the same sentence belong together; a branch you cannot name cleanly wants its own function/method.

**AVOID**: merging conditions with and/or, or rewriting branches as ternaries, just to lower the score — the decisions remain, only the counter moves. You are done when a first-time reader can hold the whole function in their head.
**AVOID**: merging conditions with and/or, or rewriting branches as ternaries, just to lower the score — the decisions remain, only the counter moves. You are done when a first-time reader can hold the whole function/method in their head.

{% include "includes/line_level_issues.md" %}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Comments indicate code that is not self-documenting. The smell is the *need* for the comment — the reader could not work out what the code does from the names and structure alone.

Extract complex logic into well-named functions instead of explaining with a comment. A function called `applyDiscountForLoyalCustomers` does not need a header explaining what it does.
Extract complex logic into well-named functions/methods instead of explaining with a comment. A function/method called `applyDiscountForLoyalCustomers` does not need a header explaining what it does.

Remove comments unless they impact functionality (executable annotations) or explain *why* something non-obvious was chosen (a workaround for a sp 10BC8 ecific library bug, a reference to a spec). Comments that explain *what* the code does are almost always redundant — or worse, drift out of sync with the code and start lying.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Functions over 12 lines almost always carry more than one responsibility, and that is the smell to chase — not the line count itself.
Functions/methods over 12 lines almost always carry more than one responsibility, and that is the smell to chase — not the line count itself.

Analyse responsibilities first: what distinct concerns does this function handle? Ask: (1) Are these separate responsibilities that belong in different methods? (2) Should this become a class with multiple methods? (3) Can you group cohesive data into objects to reduce local variables?
Analyse responsibilities first: what distinct concerns does this function/method handle? Ask: (1) Are these separate responsibilities that belong in different functions/methods? (2) Should this become a class with multiple methods? (3) Can you group cohesive data into objects to reduce local variables?

Avoid mechanical extraction. Pulling out a `helperA` / `helperB` purely to satisfy the threshold often hides the smell behind worse names and leaves the real shape untouched. Find true responsibility boundaries.

If responsibilities are tangled you may need to first *inline* methods to see the whole picture before redistributing. Think of this when reducing line count seems particularly hard — stepping backwards often opens up better possibilities.
If responsibilities are tangled you may need to first *inline* functions/methods to see the whole picture before redistributing. Think of this when reducing line count seems particularly hard — stepping backwards often opens up better possibilities.

A concrete technique: write what the method does in one short sentence. Refactor until the code reads as close to that sentence as possible. If you cannot say what it does in one sentence, it almost certainly has more than one responsibility.
A concrete technique: write what the function/method does in one short sentence. Refactor until the code reads as close to that sentence as possible. If you cannot say what it does in one sentence, it almost certainly has more than one responsibility.

{% include "includes/line_level_issues.md" %}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ High parameter count is a sign of coupling.
Parameters that travel together across several calls are a missing abstraction.

**Find the missing abstraction:**
1. Look at the call sites and nearby functions — is there an existing class a group of these parameters belongs to? Search wider than the file that fired: values that keep appearing side by side are the entity, and it is usually one of the domain's own nouns — where that name already exists, it is the answer.
1. Look at the call sites and nearby functions/methods — is there an existing class a group of these parameters belongs to? Search wider than the file that fired: values that keep appearing side by side are the entity, and it is usually one of the domain's own nouns — where that name already exists, it is the answer.
2. If not, create it — then move behaviour that uses those fields onto it.
3. If one object owns most of the parameters, it may be the natural home for this function.
3. If one object owns most of the parameters, it may be the natural home for this function/method.
4. Use it at every site it fits, not only the one that fired — a call passing three of its fields is the same concept sitting under the threshold.

Useful tip: rewrite each call site with the signature that feels natural there, and let that shape the final method.
Useful tip: rewrite each call site with the signature that feels natural there, and let that shape the final function/method.

**AVOID**: A `{ ...everything }` bag that merely renames the list hides the coupling instead of removing it. A `FooProps` or options object named after the function that takes it is the same bag: organised by method rather than by abstraction, so the next function invents another one and the concept stays unnamed. You are done when the entity carries a domain name and no call site still passes its fields loose.
**AVOID**: A `{ ...everything }` bag that merely renames the list hides the coupling instead of removing it. A `FooProps` or options object named after the function/method that takes it is the same bag: organised by function/method rather than by abstraction, so the next function/method invents another one and the concept stays unnamed. You are done when the entity carries a domain name and no call site still passes its fields loose.

{% include "includes/line_level_issues.md" %}
15 changes: 0 additions & 15 deletions plugins/ruby/src/habit_hooks_ruby/guides/deep-nesting.md

This file was deleted.

12 changes: 0 additions & 12 deletions plugins/ruby/src/habit_hooks_ruby/guides/high-complexity.md

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Find true responsibility boundaries rather than splitting at the threshold: `app

A concrete technique: write what the block does in one short sentence and refactor until the code reads as close to it as possible. If you cannot say what it does in one sentence, it almost certainly does more than one thing.

{% include "includes/rubocop_line_level_issues.md" %}
{% include "includes/line_level_issues.md" %}
11 changes: 0 additions & 11 deletions plugins/ruby/src/habit_hooks_ruby/guides/oversized-function.md

This file was deleted.

11 changes: 0 additions & 11 deletions plugins/ruby/src/habit_hooks_ruby/guides/swallowed-exception.md

This file was deleted.

13 changes: 0 additions & 13 deletions plugins/ruby/src/habit_hooks_ruby/guides/too-many-parameters.md

This file was deleted.

5 changes: 0 additions & 5 deletions plugins/ruby/src/habit_hooks_ruby/guides/uncoached.md

This file was deleted.

8 changes: 0 additions & 8 deletions plugins/ruby/src/habit_hooks_ruby/guides/unused-variable.md

This file was deleted.

0