Code Standards: Don't Let Your Code Become a Mess
Code is written for humans to read, and only incidentally for machines to execute. — Harold Abelson
Why Do Code Standards Matter?
You might think: "As long as the code works, who cares about formatting?"
Wrong. There are two reasons:
1. You'll Be Collaborating with Others
Imagine you and a friend are cooking together. You measure in centimeters, they measure in inches. You add salt by the spoonful, they add "a pinch." No wonder the dish turns out terrible.
Code standards are the agreed-upon "measurement system" — ensuring everyone's code looks like it was written by one person.
2. AI Needs Clean Code Too
AI tools (Cursor, Copilot) reference your existing code style when generating code. If your code is messy, the AI-generated code will be messy too.
Consistent code style = AI understands your intent better = generates more accurate code
Naming Conventions
Naming is the foundation of code readability. Three most common naming styles:
camelCase
First letter lowercase, first letter of each subsequent word capitalized:
const userName = "John";
const isLoggedIn = true;
function getUserInfo() { }
function handleSubmitForm() { }
Used for: JavaScript/TypeScript variables and functions
PascalCase
First letter of every word capitalized:
const UserProfile = () => { };
class ShoppingCart { }
interface ButtonProps { }
type UserType = { };
Used for: React components, class names, interfaces, types
snake_case
Words separated by underscores:
user_name = "John"
is_logged_in = True
def get_user_info(): pass
Used for: Python, database field names, environment variables
Naming Quick Reference
| Language/Scenario | Style | Example |
|---|---|---|
| JS/TS variables | camelCase | userName |
| JS/TS functions | camelCase | getUserInfo() |
| React components | PascalCase | UserProfile |
| Constants | UPPER_SNAKE | API_BASE_URL |
| CSS class names | kebab-case | user-card |
| Database fields | snake_case | created_at |
| Environment variables | UPPER_SNAKE | DATABASE_URL |
Good Names vs Bad Names
// ❌ Bad naming
const d = new Date();
const x = users.filter(u => u.a > 18);
function calc(a, b) { return a * b * 0.1; }
// ✅ Good naming
const currentDate = new Date();
const adultUsers = users.filter(user => user.age > 18);
function calculateTax(price, quantity) { return price * quantity * 0.1; }
Naming principles:
- Names should express intent — don't be afraid of long names
- Booleans should start with
is,has, orcan - Function names should start with verbs:
get,set,handle,create,delete
ESLint + Prettier Setup
ESLint checks code quality, Prettier enforces code formatting. Together, they keep your code consistent automatically.
Installation
npm install -D eslint prettier eslint-config-prettier eslint-plugin-prettier
ESLint Configuration (Next.js)
Create .eslintrc.json:
{
"extends": [
"next/core-web-vitals",
"prettier"
],
"rules": {
"no-unused-vars": "warn",
"no-console": "warn",
"prefer-const": "error",
"no-var": "error"
}
}
Prettier Configuration
Create .prettierrc:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "always"
}
Auto-Format on Save
Add the following to VS Code's settings.json:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
Now every time you press Ctrl+S, your code is auto-formatted and lint issues are automatically fixed.
.editorconfig
.editorconfig ensures different editors use the same formatting settings:
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
Place this file in your project root and commit it to Git. Team members using different editors will stay consistent.
Next.js Project Folder Structure
A good folder structure makes the project easy to understand at a glance:
my-app/
├── src/
│ ├── app/ # Next.js App Router pages
│ │ ├── layout.tsx # Global layout
│ │ ├── page.tsx # Homepage
│ │ ├── login/
│ │ │ └── page.tsx # Login page
│ │ └── api/ # API routes
│ │ └── users/
│ │ └── route.ts
│ ├── components/ # Reusable components
│ │ ├── ui/ # Base UI components
│ │ │ ├── Button.tsx
│ │ │ └── Input.tsx
│ │ └── layout/ # Layout components
│ │ ├── Header.tsx
│ │ └── Footer.tsx
│ ├── lib/ # Utility functions and config
│ │ ├── db.ts # Database connection
│ │ ├── auth.ts # Authentication logic
│ │ └── utils.ts # General utility functions
│ ├── hooks/ # Custom Hooks
│ │ └── useUser.ts
│ ├── types/ # TypeScript type definitions
│ │ └── index.ts
│ └── styles/ # Style files
│ └── globals.css
├── public/ # Static assets
│ └── images/
├── .env.local # Environment variables
├── .gitignore
├── next.config.js
├── package.json
├── tsconfig.json
└── README.md
File Naming Conventions
- Component files: PascalCase —
Button.tsx,UserProfile.tsx - Utility files: camelCase —
useUser.ts,formatDate.ts - Page files: Always
page.tsx(Next.js convention) - Style files: camelCase or kebab-case
The Art of Commenting
When to Write Comments
// ✅ Explain "why" not "what"
// Need to delay 300ms because Stripe's SDK takes time to load
await new Promise(resolve => setTimeout(resolve, 300));
// ✅ Explain complex business logic
// Discount rules: ¥30 off for orders over ¥200, ¥100 off for orders over ¥500, VIP gets an extra 10% off
function calculateDiscount(amount, isVip) { }
// ✅ Mark to-do items
// TODO: Add SMS verification later
// ✅ Warning messages
// WARNING: Do not modify this value — it affects all existing user passwords
const SALT_ROUNDS = 10;
When NOT to Write Comments
// ❌ Comment states the obvious
// Get the user name
const userName = getUser().name;
// ❌ Comment is longer than the code
// This function iterates through the array, checks each item's type property,
// and if the type equals 'active', adds it to the result array
const activeItems = items.filter(item => item.type === 'active');
// ❌ Commented-out code (just delete it — Git remembers everything)
// oldFunction();
// const temp = doSomething();
Principle: Good code speaks for itself. If you need lots of comments, the code isn't clear enough.
Using .cursorrules to Standardize AI-Generated Code
The .cursorrules file goes in your project root and tells Cursor AI your code style preferences:
# Project Standards
## Tech Stack
- Next.js 14+ (App Router)
- TypeScript (strict mode)
- Tailwind CSS
- Supabase
## Code Style
- Use functional components, not class components
- Use const, not let or var
- Components use PascalCase, variables use camelCase
- Prefer Server Components; use Client Components only when interactivity is needed
- Each file exports only one component
## Naming Conventions
- Page files: page.tsx
- Layout files: layout.tsx
- Component files: PascalCase.tsx
- Hook files: useXxx.ts
- Utility files: camelCase.ts
## Error Handling
- Use try/catch for async operations
- Show user-friendly error messages — don't expose technical details
- Use toast notifications for operation results
## Comments
- Complex logic must have comments
- Use JSDoc at the top of components for descriptions
- Don't write obvious comments
With this file, AI-generated code will be much more aligned with your project's style.
Code Review Checklist
Even if you're working solo, use this checklist to review your own code:
Basic Checks
- Does the code run correctly?
- Any leftover console.log statements?
- Any unused variables or imports?
- Are the names clear and meaningful?
Code Quality
- Any duplicated code? Can it be extracted into a function/component?
- Are functions too long? (Consider splitting if over 50 lines)
- Is error handling comprehensive?
- Any hardcoded values? (Should use constants or environment variables)
Security Checks
- Any exposed sensitive information? (API keys, passwords)
- Is user input validated?
- Any SQL injection or XSS risks?
Performance Checks
- Any unnecessary re-renders? (React)
- Are large lists paginated or virtualized?
- Are images optimized? (Compressed, lazy-loaded)
Commit Checks
- Is the commit message following conventions?
- Are there unnecessary files being committed? (.env, node_modules)
- Does the code pass ESLint checks?
Commit Message Conventions
Good commit messages make Git history clear at a glance:
# Format: type: short description
# ✅ Good commit messages
feat: add user login functionality
fix: fix homepage loading slowly
docs: update README installation instructions
style: unify code formatting
refactor: refactor authentication module
chore: upgrade Next.js to 14.1
# ❌ Bad commit messages
update
fix bug
modified
asdfgh
| Type | Purpose |
|---|---|
feat | New feature |
fix | Bug fix |
docs | Documentation |
style | Formatting (doesn't affect functionality) |
refactor | Refactoring |
chore | Housekeeping |
test | Testing |
Summary
- Name things clearly — code is written for humans
- Set up ESLint + Prettier — auto-format on save
- Keep folder structure consistent — easy to find, easy to maintain
- Comments should explain "why" — not "what"
- Use .cursorrules to guide AI — generate more consistent code
- Use the checklist before committing — build good habits
Code standards aren't a constraint — they're a tool that helps you write better code. Once standards become habit, you won't need to think about them anymore.