Standards and Guidelines
This page provides cross-language reference material that applies regardless of which stack you are working in. For language-specific rules, see the dedicated section for your language.
Naming Conventions — Cross-Language Reference
Naming is one of the most impactful decisions you make as a developer. A well-named variable, function, or class communicates intent without requiring a comment. The rules below apply universally — the specific casing style varies per language.
Casing styles
| Style | Format | Used for |
|---|---|---|
| PascalCase | UserService, OrderStatus |
Classes, interfaces, types, React components |
| camelCase | getUserById, totalAmount |
Functions/methods, variables (JS/TS/Java) |
| snake_case | get_user_by_id, total_amount |
Functions, variables (Python, Go, SQL columns) |
| UPPER_SNAKE_CASE | MAX_RETRY_COUNT, SESSION_TIMEOUT |
Constants in all languages |
| kebab-case | user-profile, order-service |
File names (React components), URL paths, CSS classes |
| dotted.lowercase | com.cygnus.service.user |
Java/C# package and namespace names |
Universal naming rules
These rules apply across all languages and frameworks:
Be descriptive — names should reveal intent
# ✅ Correct — intent is clear
user_registration_count = 0
is_payment_confirmed = False
eligible_orders = get_orders_eligible_for_refund()
# ❌ Incorrect — vague, cryptic, or abbreviated without reason
n = 0
flag = False
data = get_data()
Booleans should read as true/false questions
// ✅ Correct — reads naturally as a question
const isActive = user.status === 'active';
const hasPermission = roles.includes('admin');
const canRetry = attemptCount < MAX_RETRIES;
// ❌ Incorrect — does not read as a boolean
const active = user.status === 'active';
const permission = roles.includes('admin');
const retry = attemptCount < MAX_RETRIES;
Functions should be named with a verb
// ✅ Correct — verb makes the action clear
getUserById(id)
calculateOrderTotal(items)
validatePaymentMethod(card)
sendWelcomeEmail(user)
isEligibleForDiscount(user)
// ❌ Incorrect — noun or vague name
user(id)
orderTotal(items)
paymentMethod(card)
email(user)
discount(user)
Collections should be plural
// ✅ Correct
var orders []Order
var userIDs []int64
activeUsers := getActiveUsers()
// ❌ Incorrect
var order []Order
var userID []int64
activeUser := getActiveUsers()
Avoid abbreviations unless universally known
// ✅ Acceptable abbreviations — universally understood
const userId = req.params.id;
const apiUrl = process.env.API_URL;
const htmlContent = renderTemplate(dto);
// ❌ Avoid — saves a few characters, costs clarity
const usrId = req.params.id;
const au = process.env.API_URL;
const cnt = items.length;
const mgr = new OrderManager();
Universally accepted abbreviations: id, url, api, dto, html, css, db, ui, io, err, ctx, req, res, idx.
Avoid generic names
Names like data, info, temp, obj, val, item, thing, stuff, and result (when used without a qualifier) convey nothing about what the value represents.
# ✅ Correct — name reflects the actual value
order_response = fetch_order(order_id)
user_email = extract_email(payload)
discounted_total = apply_promo(cart, promo_code)
# ❌ Incorrect — generic names that force the reader to trace the value
data = fetch_order(order_id)
temp = extract_email(payload)
result = apply_promo(cart, promo_code)
File and Module Naming
| Language | Convention | Example |
|---|---|---|
| Java | PascalCase, matches class name | OrderService.java |
| Python | snake_case | order_service.py |
| TypeScript / JavaScript | camelCase for utilities, PascalCase for classes/components | orderUtils.ts, UserCard.tsx |
| Go | snake_case | order_service.go |
| C# | PascalCase, matches class name | OrderService.cs |
| SQL migrations | Timestamp prefix + description | 20260315_001_add_is_gift_to_orders.sql |
| Test files | Match the file under test + test suffix |
order_service_test.go, test_order_service.py |
Error Naming
Errors and exceptions should always end with Error or Exception (language convention) and describe the condition that caused them — not the technical mechanism.
# ✅ Correct — describes the business condition
class OrderNotFoundError(Exception): ...
class InsufficientFundsError(Exception): ...
class InvalidPromoCodeError(Exception): ...
# ❌ Incorrect — describes implementation, not the condition
class DatabaseLookupError(Exception): ... # too vague — what was being looked up?
class NullValueException(Exception): ... # language-level detail — not business language
class Exception1(Exception): ... # completely meaningless
Constants and Configuration
All constants must be:
- Defined in a single place — never duplicated across files.
- Named in
UPPER_SNAKE_CASEin every language. - Accompanied by a comment if the value is not self-explanatory (e.g. why 1800 seconds, why 5 attempts).
# ✅ Correct — named, justified, centralised
MAX_LOGIN_ATTEMPTS = 5 # lock account after 5 failed attempts (security policy SP-03)
SESSION_TIMEOUT_SECONDS = 1800 # 30 minutes — per compliance requirement
DEFAULT_CURRENCY = "GBP"
API_VERSION = "v1"
// ✅ Correct — typed constants with explanation where needed
const MAX_FILE_UPLOAD_BYTES = 10 * 1024 * 1024; // 10 MB — matches nginx limit in infra config
const SUPPORTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/webp'] as const;
const DEFAULT_PAGE_SIZE = 20;
Code Organisation Principles
Keep related things together
Files and modules should be organised around features or domains, not technical layers. Co-locating the service, repository, model, and tests for a feature makes it easier to find and change related code.
# ✅ Feature-based organisation (preferred)
src/
orders/
order.model.ts
order.service.ts
order.repository.ts
order.controller.ts
order.service.test.ts
# ❌ Layer-based organisation (avoid for large codebases)
src/
models/
order.model.ts
services/
order.service.ts
repositories/
order.repository.ts
One public class or function per file
Each file should export one primary concept. Multiple exports in a single file are acceptable for closely related helpers, but the file name should reflect the primary export.
Limit file length
Files over 300 lines are a signal that the file is doing too much. Split by responsibility before the file grows further.
Formatting Principles
The following apply across all languages. Language-specific formatting tools enforce these automatically — see each language section for the approved tool and configuration.
| Principle | Rule |
|---|---|
| Indentation | Use spaces, not tabs. 4 spaces for Java/Python/C#, 2 spaces for JS/TS/Go |
| Line length | Maximum 120 characters. Break long lines logically |
| Trailing whitespace | Never. Configure your editor to strip it on save |
| Blank lines | One blank line between logical sections. Two between top-level declarations |
| Braces | Always use braces for control flow — even single-line bodies (Java, C#, Go, JS/TS) |
| Semicolons | Follow language convention. TypeScript/JavaScript: always use semicolons |
Let the formatter decide
Most formatting decisions should be made by your language's approved auto-formatter — not by personal preference or code review debate. Black (Python), Prettier (JS/TS), Google Java Format, and gofmt (Go) are non-negotiable. Configure them and move on.
Dependency Management
| Rule | Why |
|---|---|
Pin dependency versions in package.json, requirements.txt, or equivalent |
Unpinned versions cause non-reproducible builds |
Never commit node_modules, .venv, or build artefacts |
They belong in .gitignore |
Run dependency vulnerability scans in CI (npm audit, pip-audit, trivy) |
Catch known vulnerabilities before they reach production |
| Review the changelog before upgrading a major version | Major version upgrades can introduce breaking changes |
Use a lockfile (package-lock.json, poetry.lock, go.sum) |
Lockfiles ensure consistent installs across environments |