Skip to content
Back to skills

Code Conventions

ASecurity

Universal coding principles: DRY, security by default, null guards, and YAGNI. Trigger: When writing or reviewing code in any language or technology.

  • 4 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 12, 2026
developmentjavascripttypescriptgojavashellsqlreactvuegitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 12, 2026

npx -y skills add aibot88/sec_skill_store --skill code-conventions --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Code Conventions?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Code Conventions
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/aibot88-code-conventions/badge)](https://www.skillsdirectory.com/skills/aibot88-code-conventions)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: code-conventions
description: "Universal coding principles: DRY, security by default, null guards, and YAGNI. Trigger: When writing or reviewing code in any language or technology."
license: "Apache 2.0"
metadata:
  version: "3.0"
  type: universal
  allowed-tools:
    - file-reader
---

# Code Conventions

Universal coding principles and meta-conventions: how to write clean, secure, and robust code regardless of language or framework. Covers naming, file structure, organization, and active quality principles. Tech-specific conventions live in their respective skills.

## When to Use

- Writing new functions, classes, or modules in any language
- Applying quality principles during code generation
- Naming variables, functions, classes, files across any technology
- Organizing code structure and project layout
- Reviewing code for general best practices
- Establishing cross-project standards

Don't use for:

- TypeScript-specific patterns (import type, no any) → use typescript skill
- Framework-specific patterns (hooks, JSX) → use react/vue/etc skill
- Accessibility → a11y skill
- Architecture decisions → architecture-patterns skill
- Linting/formatting tools → code-quality skill

---

## Critical Patterns

> Universal rules only. TypeScript/JS-specific patterns (import type, no any, static imports) → see **typescript** skill.

### ✅ REQUIRED: Consistent Naming

Apply across any language:

```
Variables/functions: camelCase  → userId, getUserData
Classes/components:  PascalCase → UserService, LoginForm
Constants:           UPPER_SNAKE_CASE → MAX_RETRY_COUNT
Files (non-component): kebab-case → user-service.ts, api-client.ts
Files (components):  PascalCase → UserCard.tsx, LoginForm.vue
```

**Booleans:** `is`, `has`, `should` prefixes (`isActive`, `hasPermission`).

**Callbacks:** `handle` or `on` prefix (`handleClick`, `onSubmit`).

**Abbreviations:** Well-known OK (HTTP, API, URL, ID). Avoid custom (`userId` OK, `usrId` not).

**Acronyms:** Treat as words (`HttpService` not `HTTPService`, `apiKey` not `aPIKey`).

### ✅ REQUIRED: Single Responsibility per File

```
✅ UserService.ts   → handles user CRUD operations only
✅ UserValidator.ts → validates user data only
✅ UserTypes.ts     → defines user types only

❌ utils.ts         → validation + API calls + formatting + types (too many responsibilities)
```

**Rule:** File name = single, clear responsibility. If you can't name it clearly, it does too much.

### ✅ REQUIRED: No Dead Code

```
❌ Unused import → delete it
❌ Unused variable → delete it
❌ Commented-out code → delete it (use git history instead)
❌ Unreachable code after return → delete it

✅ Every import, variable, and function has an active caller
```

### ✅ REQUIRED: Avoid Variable Shadowing

```javascript
// ❌ WRONG: inner variable shadows outer
const items = [...];
const result = items.find(items => items.id === id); // 'items' shadows outer

// ✅ CORRECT: distinct names
const items = [...];
const result = items.find(item => item.id === id);
```

**Rule:** Inner scope names must not shadow outer scope names.

### DELEGATE: Import Organization (TypeScript/JS)

For `import type`, named vs namespace imports, barrel exports → see **typescript** or **javascript** skill.

```
external libraries first → internal modules → types last
```

### ✅ REQUIRED: DRY — No Duplicate Logic

Before writing new logic, check if it already exists. Extract when the same logic appears in 2+ places.

```typescript
// ❌ WRONG: same validation duplicated
function createUser(email: string) {
  if (!email.includes("@")) throw new Error("Invalid email")
}
function updateUser(email: string) {
  if (!email.includes("@")) throw new Error("Invalid email")
}

// ✅ CORRECT: extracted once
function validateEmail(email: string) {
  if (!email.includes("@")) throw new Error("Invalid email")
}
function createUser(email: string) { validateEmail(email) }
function updateUser(email: string) { validateEmail(email) }
```

```javascript
// ❌ WRONG: formatting logic copy-pasted in 3 components
const price = `$${(amount / 100).toFixed(2)}`  // in CartItem
const price = `$${(amount / 100).toFixed(2)}`  // in OrderSummary
const price = `$${(amount / 100).toFixed(2)}`  // in Invoice

// ✅ CORRECT: one utility
const formatPrice = (amount) => `$${(amount / 100).toFixed(2)}`
```

### ✅ REQUIRED: Security by Default (Non-Negotiable)

These rules are inviolable — never produce code that violates them.

```typescript
// ❌ WRONG: user input concatenated into query
const rows = await db.query(`SELECT * FROM users WHERE id = ${userId}`)

// ✅ CORRECT: parameterized
const rows = await db.query("SELECT * FROM users WHERE id = $1", [userId])

// ❌ WRONG: hardcoded secret
const apiKey = "sk-1234abcd"

// ✅ CORRECT: from environment
const apiKey = process.env.API_KEY

// ❌ WRONG: state-changing endpoint with no auth check
app.post("/admin/delete-user", async (req, res) => {
  await deleteUser(req.body.userId)
})

// ✅ CORRECT: auth check before action
app.post("/admin/delete-user", requireAdmin, async (req, res) => {
  await deleteUser(req.body.userId)
})
```

```javascript
// ❌ WRONG: shell command with user input (command injection)
exec(`convert ${req.query.file} output.pdf`)

// ✅ CORRECT: validated and escaped
const safeName = path.basename(req.query.file)
execFile("convert", [safeName, "output.pdf"])
```

Rules:
- Never concatenate external input into queries or shell commands
- Never hardcode secrets, tokens, or credentials in source
- Validate all external input at the system boundary, not in inner layers
- State-changing endpoints require an auth check

### ✅ REQUIRED: Robustness — Fail Fast, No Swallow

```typescript
// ❌ WRONG: null dereference without guard
function getUsername(user: User | null) {
  return user.name
}

// ✅ CORRECT: guard at entry
function getUsername(user: User | null): string {
  if (user === null) throw new Error("User is required")
  return user.name
}

// ❌ WRONG: exception silenced
try {
  await sendEmail(user)
} catch (e) {}

// ✅ CORRECT: fail fast with context
try {
  await sendEmail(user)
} catch (e) {
  logger.error("Failed to send email", { userId: user.id, error: e })
  throw e
}
```

```javascript
// ❌ WRONG: deeply nested happy-path, no early return
function processOrder(order) {
  if (order) {
    if (order.items.length > 0) {
      if (order.payment) {
        return charge(order)
      }
    }
  }
}

// ✅ CORRECT: fail fast with early returns
function processOrder(order) {
  if (!order) throw new Error("Order is required")
  if (order.items.length === 0) throw new Error("Order has no items")
  if (!order.payment) throw new Error("Payment method missing")
  return charge(order)
}
```

### ✅ REQUIRED: YAGNI — Don't Build What Isn't Needed Today

```typescript
// ❌ WRONG: abstraction for a hypothetical future
class UserRepositoryFactory {
  create(type: "postgres" | "mysql" | "mongo") { ... }  // only postgres exists
}

// ✅ CORRECT: implement what exists now
class UserRepository {
  async findById(id: string): Promise<User> { ... }
}
```

Signals of YAGNI violation:
- Config parameters with only one possible value today
- Abstractions for "when we eventually need X"
- Commented-out code "just in case"
- Feature flags for unplanned functionality

---

## Decision Tree

```
Is this convention universal (any language/framework)?
  → YES: Belongs here
    Naming (camelCase, PascalCase, UPPER_SNAKE_CASE)
    File responsibility (SRP)
    No dead code
    Variable shadowing
    DRY, Security, Robustness, YAGNI

  → NO: Belongs in technology-specific skill
    TypeScript specifics (import type, no any, type safety) → typescript skill
    Import organization details                              → typescript/javascript skill
    React/Vue/Svelte patterns                               → framework skill
    Linting/formatting tools                                → code-quality skill
    Architecture decisions                                  → architecture-patterns skill
    Accessibility                                           → a11y skill

Writing new code?
  → Logic already exists in codebase?
    → YES: reuse it (DRY)
    → NO: proceed
  → Touches external input (user, API, file)?
    → YES: validate at boundary, parameterize queries
    → NO: proceed
  → Value could be null or undefined?
    → YES: guard at function entry, fail fast on invalid state
    → NO: proceed
  → Adding abstraction or configuration?
    → Needed today with a real use case?
      → YES: implement
      → NO: YAGNI — skip
  → Catching an exception?
    → Log with context and re-throw — never swallow silently
```

**Quick reference:**

- Naming a variable/function? → camelCase
- Naming a class/component? → PascalCase
- Naming a constant? → UPPER_SNAKE_CASE
- Naming a file? → kebab-case (non-component), PascalCase (component)
- File has too many responsibilities? → Split by SRP
- Unused import/variable/function? → Delete it
- Variable name conflicts with outer scope? → Rename to avoid shadowing
- Logic duplicated in 2+ places? → Extract (DRY)
- Input from user, API, or file? → Validate at boundary, parameterize queries
- Value could be null? → Guard at entry, fail fast
- Building for a future use case? → YAGNI — don't
- TypeScript-specific question? → See typescript skill

---

## Example

Naming and structure conventions applied to a user authentication module.

```
src/
├── auth/
│   ├── auth.service.ts        # kebab-case file; single responsibility: orchestrates auth
│   ├── auth.validator.ts      # single responsibility: input validation only
│   ├── auth.types.ts          # single responsibility: type definitions only
│   └── AuthForm.tsx           # PascalCase: React component
```

```typescript
// auth.service.ts — all names follow conventions
const MAX_LOGIN_ATTEMPTS = 5;          // UPPER_SNAKE_CASE constant

class AuthService {                    // PascalCase class
  async loginUser(userId: string): Promise<AuthToken> {  // camelCase method + param
    const isLocked = await this.isAccountLocked(userId); // boolean: "is" prefix
    if (isLocked) throw new AccountLockedError();
    // ...
  }

  private isAccountLocked(userId: string): Promise<boolean> {}  // camelCase, boolean prefix
}

// auth.validator.ts — no dead code, no shadowing
function validateLoginInput(input: LoginInput): ValidationResult {
  const { email, password } = input;
  // ✅ `email` and `password` don't shadow outer scope names
  if (!email.includes("@")) return { valid: false, error: "Invalid email" };
  if (password.length < 8)  return { valid: false, error: "Password too short" };
  return { valid: true };
}
```

Every file has one clear name that matches its single responsibility. No `utils.ts`, no shadowed variables, no commented-out code.

---

## Edge Cases

**File naming conflicts:** Match export name (`UserService.ts` exports `UserService`). Use `index.ts` for barrel exports.

**Shared utilities:** A file named `utils.ts` with 10+ unrelated helpers violates SRP. Split by domain (`dateUtils.ts`, `stringUtils.ts`).

**Dead code in tests:** Test helpers are used by tests. Not dead code. Only delete helpers with zero test callers.

**Shadowing in destructuring:** `const { id } = user; const { id } = item;` — avoid repeated names in same scope. Rename: `const { id: userId } = user;`

---

## Resources

- [naming-conventions.md](references/naming-conventions.md) — Boolean prefixes, acronyms, descriptive names
- [code-structure.md](references/code-structure.md) — SRP for files, feature vs layer grouping, colocation
- [documentation-standards.md](references/documentation-standards.md) — JSDoc, inline comments, README guidelines

**TypeScript-specific conventions** (import type, no any, static imports) → [typescript](../typescript/SKILL.md)

Related: [code-quality](../code-quality/SKILL.md), [architecture-patterns](../architecture-patterns/SKILL.md)

Files in this skill

  • SKILL.md11.9 KB
  • source.json678 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.