From SoMi AI
Use when naming things, structuring functions, deciding whether to add a comment, or cleaning up code mid-implementation. Pragmatic clean-code rules with explicit anti-patterns and when-not-to-apply guidance.
How this skill is triggered — by the user, by Claude, or both
Slash command
/somi-ai:clean-codeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The principles are in [`rules/20-clean-code.md`](../../rules/20-clean-code.md) — that's the
The principles are in rules/20-clean-code.md — that's the
always-on floor. This skill adds operational depth: decision tables (parameter counts,
function length), before/after example pairs (early returns, boolean naming), and
when-not-to-apply guidance. When a section restates the rule verbatim, replace with a pointer
and only keep the operational expansion.
eligibleUserIds beats arr.fetch/get/retrieve/load/pull for the same operation.strName, bIsValid).Manager, Helper, Util, Processor, Handler, Service. They usually
hide an SRP violation.isActive, hasPermission, canEdit, shouldRetry.isNotInvalid is unreadable.flag is meaningless. accountFrozen is clear.user.name is state; user.deactivate() is action.validateOrder better not also charge the card. Name truthfully.Aim for under ~20 lines. Length is a smell, not a hard limit. A 40-line function that reads top-to-bottom without nesting is fine. A 15-line function with five nested ifs is not.
| Count | Verdict |
|---|---|
| 0 | Suspect — what state is it pulling from? |
| 1 | Great. |
| 2 | Great. |
| 3 | Borderline. Consider a parameter object if related. |
| 4+ | Almost always wants a struct/record/object. |
Banned.
// bad
processOrder(order, true); // what does `true` mean?
// good
processOrderAndCharge(order);
processOrderAsDraft(order);
# bad — pyramid of doom
def process(req):
if req.is_valid():
if req.user.has_quota():
if not req.is_duplicate():
# actual work, four levels deep
...
# good — guard clauses, work at the surface level
def process(req):
if not req.is_valid(): return Err("invalid")
if not req.user.has_quota(): return Err("quota")
if req.is_duplicate(): return Err("duplicate")
# actual work
...
Default: no comment. The bar to add one is high. A comment is justified only when the WHY is non-obvious:
// must run before the lock is acquired — see issue #2412).// keep aligned with the schema in migrations/0042).// libfoo 1.4 returns null for empty results).// pre-allocate; the hot path runs ~1e6 times/sec).Banned:
// increment i).// added for TICKET-1234) — that rots; PR history is the
right place.Canonical rules: rules/20-clean-code.md §Errors. Operational
expansion specific to this skill:
raise ProcessingError("step 3") from e (Python),
fmt.Errorf("step 3: %w", err) (Go), throw new ProcessingError("step 3", { cause: e })
(JS). Don't throw new Error(e.message) — the stack and chain are lost.Canonical rules: rules/20-clean-code.md §Structure. Operational
addition specific to this skill:
utils.py / helpers.ts / common.go grab-bag modules. They become SRP graveyards.
When you reach for one, the actual concept already wants a name — give it one.See rules/20-clean-code.md §Diff hygiene for the canonical
list. Operational note: hooks (hooks/pre-tool/guard-protected-paths.sh) enforce some of these
mechanically (e.g., no lockfile hand-edits, no writes inside .git/). When a hook fires, the
rule is being enforced — don't work around the hook.
test-strategist first.Write code as if explaining the problem to a smart colleague who knows the language but not this codebase. Names, structure, and tests should let them follow along without questions. When a reviewer asks "what does this do?", the code lost.
npx claudepluginhub skathio/somi-ai --plugin somi-aiGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.