Clean code implementation
Six rules bind every line you write. They are one habit, not six checklists.
| Rule | Skill | Enforced by |
|---|---|---|
| A function name is a verb | function-names-are-verbs |
nothing — you |
| A function is short | oversized-function |
oversized_function.py |
| A name replaces a comment | self-documenting-names |
comment_smell.py |
| A helper sits below its caller | helper-functions-ordering |
helper_order.py |
| The code stays maintainable | maintainable-coding-principles |
nothing — you |
| The behavior is proven by a test | tdd |
nothing — you |
Load the skill itself when a rule bites. This page is the index, not the content.
Not optional
These are required rules. They are not style preferences.
Three of them block your turn. The verb rule and the maintainability rule do not, which makes them the ones you will drop first. They are not weaker.
They are the same rule
Each one pushes meaning into a name.
- The verb says what the function does.
- The line limit says it does only that.
- The absent comment says the name was enough.
- The position says which function it serves.
A failure in one shows up as a failure in the others. A function you cannot name with one verb is a function doing two things, and it is the function you were about to write a comment above.
The order to apply them
- Write the failing test first. Prove the behavior does not exist yet, or
prove the bug is real, before writing the fix — see
tdd. - Name it first. Write the verb before the body.
chargeOrder, notorderProcessing. If no single verb fits, you have two functions — stop and split before you write either. - Write the body. Watch the length. Passing 12 effective lines is a signal
to name the responsibilities, not a signal to extract
helperA. - Delete the comments. Every comment you wanted is a name you did not pick. Move the meaning, then remove the comment.
- Place it under its caller. A new helper goes directly below the line that calls it, never at the top or the bottom of the file.
- Check the wider habits. Guard clauses, meaningful names, contained
dependencies, unrepresentable invalid states, decisions separate from side
effects, useful errors, focused changes — see
maintainable-coding-principles. - Run the suite green. Refactor with tests passing throughout — see
tdd. - Commit the loop. One commit carries the test, the code that passes it,
and the refactor. Commit on green, never on red — see
tdd.
Before you finish
Read your diff and ask six questions.
- Does every new function name start with a verb that is true?
- Is any new function over the limit without a written reason?
- Does any new comment say what the code does?
- Is any new helper defined above the function that calls it?
- Does this design make the code easier for the next engineer to understand, safely change, test, and trust?
- Does every new behavior have a test that failed before the fix and passes now?
Six "no" answers and you are done.
The escape hatches
allow-long-function: <reason>, allow-comment: <reason> and
allow-helper-order: <reason> all need a written reason. A bare marker is
reported.
Reaching for a marker before you have tried the rename is a skipped step, not a judgement. "The rest of the file does it this way" is not a reason.
Legacy code you touch
The three name-and-length rules bind the lines you write. Old lines around them stay — a rename spreads across call sites, and that is a new task.
Ordering is the exception. It is pure movement, so when you open a file, put its helpers under their callers. Commit that move on its own.
What this does not cover
Scope. How much to change is a separate decision — see the increments-plan
skill. Generated and vendored files are outside all six rules; change the
generator, not the output.