Clean Code - Pragmatic AI Coding Standards
CRITICAL SKILL - Be concise, direct, and solution-focused.
Core Principles
SOLID Principles
| Principle |
Rule |
| SRP |
Single Responsibility Principle: A class/function should have only one reason to change |
| OCP |
Open/Closed Principle: Open for extension, but closed for modification. Use polymorphism instead of long switch/case blocks |
| LSP |
Liskov Substitution Principle: Subclasses must be substitutable for their base classes without breaking the application |
| ISP |
Interface Segregation Principle: Create small, specific interfaces. Clients should not be forced to depend on methods they do not use |
| DIP |
Dependency Inversion Principle: Depend on abstractions, not on concrete implementations. Use Dependency Injection (e.g., via constructor) |
Other Principles
| Principle |
Rule |
| DRY |
Don't Repeat Yourself: extract duplicates, reuse |
| KISS |
Keep It Simple: simplest solution that works |
| YAGNI |
You Aren't Gonna Need It: don't build unused features |
| Boy Scout |
Leave code cleaner than you found it |
Naming Rules
| Element |
Convention |
| Variables |
Reveal intent: userCount not n |
| Booleans |
Question form: isActive, hasPermission, canEdit |
| Collections |
Use plural or explicit suffix: users or userList |
| Functions |
Verb + noun: getUserById() not user() |
| Classes |
Noun or Noun Phrase: Customer, WikiPage |
| Constants |
SCREAMING_SNAKE: MAX_RETRY_COUNT |
Rule: If you need a comment to explain a name, rename it.
Function Rules
| Rule |
Description |
| Small |
Max 25 lines, ideally 5-10 |
| Line Width |
Max 150 characters per line |
| One Thing |
Does one thing, does it well |
| One Level |
One level of abstraction per function |
| Few Args |
Max 3 arguments, prefer 0-2 |
| No Side Effects |
Don't mutate inputs unexpectedly |
| CQS |
Command-Query Separation: A function changes state OR returns info. Never both. |
Error Handling
| Rule |
Description |
| Exceptions > Codes |
Use Exceptions instead of returning error codes (e.g., -1, false) |
| No Null |
NEVER pass null as an argument, NEVER return null. Use Optional or Null Object Pattern |
| Try-Catch Isolation |
If a function has a try-catch, it should contain nothing else (separate error processing from logic) |
| Unchecked Exceptions |
Prefer unchecked exceptions (standard runtime errors) over checked exceptions to avoid clutter |
Testing Standards
| Rule |
Description |
| F.I.R.S.T. |
Fast, Independent, Repeatable, Self-Validating, Timely |
| One Assert |
Minimize assertions per test. Test one concept per test function |
| Readable |
Test code must be as clean as production code |
| Coverage |
Do not consider task complete without verifying happy path AND edge cases |
| Behavior |
Test behavior, not implementation details |
Class & Object Design
| Principle |
Rule |
| Step-Down Rule |
Public methods at the top, private methods below them. Code should read like a newspaper article |
| Law of Demeter |
Don't talk to strangers. a.getB().getC().do() is bad. Only talk to immediate friends |
| Cohesion |
Classes should have a small number of instance variables. Methods should use those variables |
| Boundaries |
Wrap 3rd-party code/generics (e.g., Map) in your own classes. Don't leak external APIs. |
| Data vs Obj |
Objects expose behavior/hide data. Data Structures expose data/have no behavior. Don't mix them (Hybrids) |
Code Structure
| Pattern |
Apply |
| Guard Clauses |
Early returns for edge cases |
| Flat > Nested |
Avoid deep nesting (max 2 levels) |
| Composition |
Small functions composed together |
| Colocation |
Keep related code close |
Anti-Patterns (DON'T)
| Pattern |
Fix |
| Comment every line |
Delete obvious comments |
| Helper for one-liner |
Inline the code |
| Factory for 2 objects |
Direct instantiation |
| utils.ts with 1 function |
Put code where used |
| "First we import..." |
Just write code |
| Deep nesting |
Guard clauses |
| Magic Numbers |
Named constants: if (status == 2)? Replace 2 with STATUS.READY |
| Selector Args |
render(true)? Stop. Make renderPage() and renderSnippet() |
| God functions |
Split by responsibility |
| Feature Envy |
Method relies too much on another class? Move it there |
| Dead Code |
Commented-out code? Delete it immediately (Git handles history) |
| Inconsistent Level |
Don't mix high-level logic with low-level I/O in the same function |
AI Coding Style
| Situation |
Action |
| User asks for feature |
Write it directly |
| User reports bug |
Fix it, don't explain |
| No clear requirement |
Ask, don't assume |
Before Editing ANY File (THINK FIRST!)
Before changing a file, ask yourself:
| Question |
Why |
| What imports this file? |
They might break |
| What does this file import? |
Interface changes |
| What tests cover this? |
Tests might fail |
| Is this a shared component? |
Multiple places affected |
Quick Check:
File to edit: UserService.ts (or .cs/.py)
└── Who imports this? → UserController, AuthController
└── Do they need changes too? → Check function signatures
Rule: Edit the file + all dependent files in the SAME task.
Never leave broken imports or missing updates.
Summary
| Do |
Don't |
| Write code directly |
Write tutorials |
| Let code self-document |
Add obvious comments |
| Fix bugs immediately |
Explain the fix first |
| Inline small things |
Create unnecessary files |
| Name things clearly |
Use abbreviations |
| Keep functions small |
Write 100+ line functions |
Remember: The user wants working code, not a programming lesson.
Self-Check Before Completing (MANDATORY)
Before saying "task complete", verify:
| Check |
Question |
| Goal met? |
Did I do exactly what user asked? |
| Files edited? |
Did I modify all necessary files? |
| Code works? |
Did I test/verify the change? |
| No errors? |
Build/Compile succeeds? No syntax or linter errors? |
| Nothing forgotten? |
Any edge cases missed? |
Rule: Always READ output → If ANY check fails, fix it before completing.
1---2name: clean-code3description: Pragmatic coding standards - Clean Code + SOLID - concise, direct, no over-engineering, no unnecessary comments4---56# Clean Code - Pragmatic AI Coding Standards78> **CRITICAL SKILL** - Be **concise, direct, and solution-focused**.910---1112## Core Principles1314### SOLID Principles15| Principle | Rule |16|-----------|------|17| **SRP** | Single Responsibility Principle: A class/function should have only one reason to change |18| **OCP** | Open/Closed Principle: Open for extension, but closed for modification. Use polymorphism instead of long switch/case blocks |19| **LSP** | Liskov Substitution Principle: Subclasses must be substitutable for their base classes without breaking the application |20| **ISP** | Interface Segregation Principle: Create small, specific interfaces. Clients should not be forced to depend on methods they do not use |21| **DIP** | Dependency Inversion Principle: Depend on abstractions, not on concrete implementations. Use Dependency Injection (e.g., via constructor) |2223### Other Principles24| Principle | Rule |25|-----------|------|26| **DRY** | Don't Repeat Yourself: extract duplicates, reuse |27| **KISS** | Keep It Simple: simplest solution that works |28| **YAGNI** | You Aren't Gonna Need It: don't build unused features |29| **Boy Scout** | Leave code cleaner than you found it |3031---3233## Naming Rules3435| Element | Convention |36|---------|------------|37| **Variables** | Reveal intent: `userCount` not `n` |38| **Booleans** | Question form: `isActive`, `hasPermission`, `canEdit` |39| **Collections** | Use plural or explicit suffix: `users` or `userList` |40| **Functions** | Verb + noun: `getUserById()` not `user()` |41| **Classes** | Noun or Noun Phrase: `Customer`, `WikiPage` |42| **Constants** | SCREAMING_SNAKE: `MAX_RETRY_COUNT` |4344> **Rule:** If you need a comment to explain a name, rename it.4546---4748## Function Rules4950| Rule | Description |51|------|-------------|52| **Small** | Max 25 lines, ideally 5-10 |53| **Line Width** | Max 150 characters per line |54| **One Thing** | Does one thing, does it well |55| **One Level** | One level of abstraction per function |56| **Few Args** | Max 3 arguments, prefer 0-2 | 57| **No Side Effects** | Don't mutate inputs unexpectedly |58| **CQS** | Command-Query Separation: A function changes state OR returns info. Never both. |5960---6162## Error Handling6364| Rule | Description |65|------|-------------|66| **Exceptions > Codes** | Use Exceptions instead of returning error codes (e.g., `-1`, `false`) |67| **No Null** | NEVER pass `null` as an argument, NEVER return `null`. Use `Optional` or Null Object Pattern |68| **Try-Catch Isolation** | If a function has a try-catch, it should contain nothing else (separate error processing from logic) |69| **Unchecked Exceptions** | Prefer unchecked exceptions (standard runtime errors) over checked exceptions to avoid clutter |7071---7273## Testing Standards7475| Rule | Description |76|------|-------------|77| **F.I.R.S.T.** | Fast, Independent, Repeatable, Self-Validating, Timely |78| **One Assert** | Minimize assertions per test. Test one concept per test function |79| **Readable** | Test code must be as clean as production code |80| **Coverage** | Do not consider task complete without verifying happy path AND edge cases |81| **Behavior** | Test behavior, not implementation details |8283---8485## Class & Object Design8687| Principle | Rule |88|-----------|------|89| **Step-Down Rule** | Public methods at the top, private methods below them. Code should read like a newspaper article |90| **Law of Demeter** | Don't talk to strangers. `a.getB().getC().do()` is bad. Only talk to immediate friends |91| **Cohesion** | Classes should have a small number of instance variables. Methods should use those variables |92| **Boundaries** | Wrap 3rd-party code/generics (e.g., Map) in your own classes. Don't leak external APIs. |93| **Data vs Obj** | Objects expose behavior/hide data. Data Structures expose data/have no behavior. Don't mix them (Hybrids) |9495---9697## Code Structure9899| Pattern | Apply |100|---------|-------|101| **Guard Clauses** | Early returns for edge cases |102| **Flat > Nested** | Avoid deep nesting (max 2 levels) |103| **Composition** | Small functions composed together |104| **Colocation** | Keep related code close |105106---107108## Anti-Patterns (DON'T)109110| Pattern | Fix |111|-------- |-----|112| Comment every line | Delete obvious comments |113| Helper for one-liner | Inline the code |114| Factory for 2 objects | Direct instantiation |115| utils.ts with 1 function | Put code where used |116| "First we import..." | Just write code |117| Deep nesting | Guard clauses |118| Magic Numbers | Named constants: if (status == 2)? Replace 2 with STATUS.READY |119| Selector Args | render(true)? Stop. Make renderPage() and renderSnippet() |120| God functions | Split by responsibility |121| Feature Envy | Method relies too much on another class? Move it there |122| Dead Code | Commented-out code? Delete it immediately (Git handles history) |123| Inconsistent Level | Don't mix high-level logic with low-level I/O in the same function |124125---126127## AI Coding Style128129| Situation | Action |130|-----------|--------|131| User asks for feature | Write it directly |132| User reports bug | Fix it, don't explain |133| No clear requirement | Ask, don't assume |134135---136137## Before Editing ANY File (THINK FIRST!)138139**Before changing a file, ask yourself:**140141| Question | Why |142|----------|-----|143| **What imports this file?** | They might break |144| **What does this file import?** | Interface changes |145| **What tests cover this?** | Tests might fail |146| **Is this a shared component?** | Multiple places affected |147148**Quick Check:**149```150File to edit: UserService.ts (or .cs/.py)151└── Who imports this? → UserController, AuthController152└── Do they need changes too? → Check function signatures153```154155> **Rule:** Edit the file + all dependent files in the SAME task.156> **Never leave broken imports or missing updates.**157158---159160## Summary161162| Do | Don't |163|----|-------|164| Write code directly | Write tutorials |165| Let code self-document | Add obvious comments |166| Fix bugs immediately | Explain the fix first |167| Inline small things | Create unnecessary files |168| Name things clearly | Use abbreviations |169| Keep functions small | Write 100+ line functions |170171> **Remember: The user wants working code, not a programming lesson.**172173---174175## Self-Check Before Completing (MANDATORY)176177**Before saying "task complete", verify:**178179| Check | Question |180|-------|----------|181| **Goal met?** | Did I do exactly what user asked? |182| **Files edited?** | Did I modify all necessary files? |183| **Code works?** | Did I test/verify the change? |184| **No errors?** | Build/Compile succeeds? No syntax or linter errors? |185| **Nothing forgotten?** | Any edge cases missed? |186187> **Rule:** Always READ output → If ANY check fails, fix it before completing.