On this page
Coding standards ensure consistency, readability, and maintainability across the codebase. Consistent code reduces cognitive load during reviews and makes onboarding easier for new team members.
Why Coding Standards Matter
General Principles
Code Clarity
Code Clarity Principles
Naming Conventions
Language-Specific Standards
TypeScript/JavaScript
// File naming: kebab-case
// user-service.ts, payment-processor.ts
// Interfaces: PascalCase with I prefix (optional)
interface UserProfile {
id: string;
email: string;
createdAt: Date;
preferences?: UserPreferences;
}
// Type aliases for complex types
type UserId = string;
type OrderStatus = 'pending' | 'confirmed' | 'shipped' | 'delivered';
// Functions: clear, descriptive names
async function fetchUserById(userId: UserId): Promise<UserProfile | null> {
// Implementation
}
// Constants at module level
const MAX_LOGIN_ATTEMPTS = 5;
const SESSION_TIMEOUT_MS = 30 * 60 * 1000;
// Avoid magic numbers
// Bad:
if (retries > 3) { /* ... */ }
// Good:
const MAX_RETRIES = 3;
if (retries > MAX_RETRIES) { /* ... */ }
Python
# File naming: snake_case
# user_service.py, payment_processor.py
from typing import Optional
from dataclasses import dataclass
from datetime import datetime
# Classes: PascalCase
@dataclass
class UserProfile:
"""User profile with basic information."""
user_id: str
email: str
created_at: datetime
preferences: Optional[dict] = None
# Functions: snake_case
def fetch_user_by_id(user_id: str) -> Optional[UserProfile]:
"""
Fetch a user profile by ID.
Args:
user_id: The unique identifier of the user
Returns:
UserProfile if found, None otherwise
"""
pass
# Constants: UPPER_SNAKE_CASE
MAX_LOGIN_ATTEMPTS = 5
SESSION_TIMEOUT_SECONDS = 30 * 60
# Private functions: prefix with underscore
def _validate_email(email: str) -> bool:
"""Internal validation helper."""
pass
Go
// File naming: snake_case
// user_service.go, payment_processor.go
package user
import (
"context"
"time"
)
// Exported types: PascalCase
type UserProfile struct {
ID string
Email string
CreatedAt time.Time
Preferences *UserPreferences
}
// Exported functions: PascalCase
func FetchUserByID(ctx context.Context, userID string) (*UserProfile, error) {
// Implementation
}
// Unexported (private): camelCase
func validateEmail(email string) bool {
// Implementation
}
// Constants
const (
MaxLoginAttempts = 5
SessionTimeoutSec = 30 * 60
)
// Interfaces: describe behavior
type UserRepository interface {
FindByID(ctx context.Context, id string) (*UserProfile, error)
Save(ctx context.Context, user *UserProfile) error
}
Java
// File naming: PascalCase matching class name
// UserService.java, PaymentProcessor.java
package com.example.service;
import java.util.Optional;
// Classes: PascalCase
public class UserService {
// Constants: UPPER_SNAKE_CASE
private static final int MAX_LOGIN_ATTEMPTS = 5;
private static final long SESSION_TIMEOUT_MS = 30 * 60 * 1000;
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// Methods: camelCase, descriptive names
public Optional<UserProfile> fetchUserById(String userId) {
return userRepository.findById(userId);
}
// Private methods: camelCase with underscore prefix optional
private boolean validateEmail(String email) {
return email != null && email.contains("@");
}
}
PHP
<?php
// File naming: PascalCase for classes
// UserService.php, PaymentProcessor.php
declare(strict_types=1);
namespace App\Service;
use App\Repository\UserRepository;
use App\Entity\UserProfile;
// Classes: PascalCase
class UserService
{
// Constants: UPPER_SNAKE_CASE
private const MAX_LOGIN_ATTEMPTS = 5;
private const SESSION_TIMEOUT_SECONDS = 1800;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
// Methods: camelCase
public function fetchUserById(string $userId): ?UserProfile
{
return $this->userRepository->find($userId);
}
// Private methods: camelCase
private function validateEmail(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
}
Drupal
<?php
// Drupal follows PSR-4 with specific conventions
// modules/custom/my_module/src/Service/UserService.php
namespace Drupal\my_module\Service;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* Service for user-related operations.
*/
class UserService {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a UserService object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* Loads a user by ID.
*
* @param int $uid
* The user ID.
*
* @return \Drupal\user\UserInterface|null
* The user entity or NULL if not found.
*/
public function loadUser(int $uid) {
return $this->entityTypeManager->getStorage('user')->load($uid);
}
}
WordPress
<?php
// WordPress uses specific naming conventions
// File naming: lowercase with hyphens for includes
// class-user-service.php
/**
* User service class.
*
* @package MyPlugin
*/
class My_Plugin_User_Service {
/**
* Maximum login attempts.
*
* @var int
*/
const MAX_LOGIN_ATTEMPTS = 5;
/**
* Fetch user by ID.
*
* @param int $user_id User ID.
* @return WP_User|false User object or false.
*/
public function fetch_user_by_id( $user_id ) {
return get_user_by( 'id', $user_id );
}
/**
* Validate email address.
*
* @param string $email Email address.
* @return bool True if valid.
*/
private function validate_email( $email ) {
return is_email( $email );
}
}
Angular
// File naming: kebab-case with type suffix
// user.service.ts, user-profile.component.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
// Interfaces: PascalCase
export interface UserProfile {
id: string;
email: string;
displayName: string;
}
// Services: PascalCase with Service suffix
@Injectable({
providedIn: 'root'
})
export class UserService {
private readonly apiUrl = '/api/users';
constructor(private http: HttpClient) {}
// Methods: camelCase
getUserById(userId: string): Observable<UserProfile> {
return this.http.get<UserProfile>(`${this.apiUrl}/${userId}`);
}
// Private methods: camelCase
private validateUserId(userId: string): boolean {
return userId.length > 0;
}
}
HTML/CSS
<!-- HTML: lowercase elements, kebab-case attributes -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Profile</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<!-- Use semantic elements -->
<main class="user-profile" data-user-id="123">
<header class="user-profile__header">
<h1 class="user-profile__title">User Profile</h1>
</header>
<section class="user-profile__content">
<!-- Content here -->
</section>
</main>
</body>
</html>
/* CSS: BEM naming convention recommended */
/* File naming: kebab-case (main.css, user-profile.css) */
/* Component block */
.user-profile {
display: flex;
flex-direction: column;
padding: 1rem;
}
/* Element */
.user-profile__header {
margin-bottom: 1rem;
}
.user-profile__title {
font-size: 1.5rem;
font-weight: 600;
}
/* Modifier */
.user-profile--compact {
padding: 0.5rem;
}
/* Variables */
:root {
--color-primary: #007bff;
--spacing-unit: 8px;
}
Android (Kotlin)
// File naming: PascalCase matching class name
// UserService.kt, UserProfileViewModel.kt
package com.example.app.service
import kotlinx.coroutines.flow.Flow
// Classes: PascalCase
class UserService(
private val userRepository: UserRepository
) {
// Constants: UPPER_SNAKE_CASE in companion object
companion object {
const val MAX_LOGIN_ATTEMPTS = 5
private const val SESSION_TIMEOUT_MS = 30 * 60 * 1000L
}
// Functions: camelCase
suspend fun fetchUserById(userId: String): UserProfile? {
return userRepository.findById(userId)
}
// Flow for reactive patterns
fun observeUser(userId: String): Flow<UserProfile> {
return userRepository.observeUser(userId)
}
// Private functions: camelCase
private fun validateEmail(email: String): Boolean {
return email.contains("@") && email.contains(".")
}
}
// Data classes for models
data class UserProfile(
val id: String,
val email: String,
val displayName: String,
val createdAt: Long
)
iOS/Swift
// File naming: PascalCase matching type name
// UserService.swift, UserProfileViewController.swift
import Foundation
// Protocols: PascalCase, often with -able, -ing suffix
protocol UserFetching {
func fetchUser(byId id: String) async throws -> UserProfile?
}
// Classes/Structs: PascalCase
final class UserService: UserFetching {
// Constants: camelCase for instance, UPPER_SNAKE_CASE less common
private let maxLoginAttempts = 5
private let sessionTimeoutSeconds: TimeInterval = 30 * 60
private let userRepository: UserRepository
init(userRepository: UserRepository) {
self.userRepository = userRepository
}
// Functions: camelCase, clear parameter labels
func fetchUser(byId id: String) async throws -> UserProfile? {
return try await userRepository.find(byId: id)
}
// Private functions: camelCase
private func validateEmail(_ email: String) -> Bool {
return email.contains("@") && email.contains(".")
}
}
// Structs for data models (value types)
struct UserProfile: Codable, Identifiable {
let id: String
let email: String
let displayName: String
let createdAt: Date
}
C#/.NET
// File naming: PascalCase matching class name
// UserService.cs, UserProfileController.cs
using System;
using System.Threading.Tasks;
namespace MyApp.Services
{
// Interfaces: PascalCase with I prefix
public interface IUserService
{
Task<UserProfile?> GetUserByIdAsync(string userId);
}
// Classes: PascalCase
public class UserService : IUserService
{
// Constants: PascalCase
private const int MaxLoginAttempts = 5;
private static readonly TimeSpan SessionTimeout = TimeSpan.FromMinutes(30);
private readonly IUserRepository _userRepository;
// Constructor injection
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
// Methods: PascalCase, async suffix for async methods
public async Task<UserProfile?> GetUserByIdAsync(string userId)
{
return await _userRepository.FindByIdAsync(userId);
}
// Private methods: PascalCase
private bool ValidateEmail(string email)
{
return !string.IsNullOrEmpty(email) && email.Contains("@");
}
}
// Records for immutable data (C# 9+)
public record UserProfile(
string Id,
string Email,
string DisplayName,
DateTime CreatedAt
);
}
Code Organization
File Structure
src/
├── components/ # UI components
│ ├── common/ # Shared components
│ └── features/ # Feature-specific
├── services/ # Business logic
├── repositories/ # Data access
├── models/ # Data models
├── utils/ # Utility functions
├── constants/ # Application constants
└── types/ # Type definitions
Module Organization
// Each module should have clear boundaries
// user/index.ts - Public API
export { UserService } from './user-service';
export { UserRepository } from './user-repository';
export type { User, UserProfile } from './types';
// user/user-service.ts - Business logic
import { UserRepository } from './user-repository';
import { User } from './types';
export class UserService {
constructor(private repository: UserRepository) {}
async getUser(id: string): Promise<User | null> {
return this.repository.findById(id);
}
}
Error Handling
Consistent Error Patterns
// Define custom error types
class ValidationError extends Error {
constructor(
message: string,
public readonly field: string,
public readonly code: string
) {
super(message);
this.name = 'ValidationError';
}
}
class NotFoundError extends Error {
constructor(
public readonly resource: string,
public readonly id: string
) {
super(`${resource} with id ${id} not found`);
this.name = 'NotFoundError';
}
}
// Use consistent error handling
async function processOrder(orderId: string): Promise<Order> {
const order = await orderRepository.findById(orderId);
if (!order) {
throw new NotFoundError('Order', orderId);
}
if (!order.isValid()) {
throw new ValidationError(
'Order validation failed',
'status',
'INVALID_ORDER_STATUS'
);
}
return order;
}
Never Swallow Errors
// Bad: Silently swallowing errors
try {
await processPayment(order);
} catch (error) {
// Error is lost
}
// Good: Log and handle appropriately
try {
await processPayment(order);
} catch (error) {
logger.error('Payment processing failed', { orderId: order.id, error });
throw new PaymentError('Payment processing failed', { cause: error });
}
Code Review Standards
Review Checklist
☐ Code follows naming conventions
☐ Functions are appropriately sized (< 30 lines preferred)
☐ Error handling is comprehensive
☐ Edge cases are considered
☐ No hardcoded values (use constants)
☐ Comments explain "why" not "what"
☐ Tests cover new functionality
☐ No security vulnerabilities introduced
FDA/Regulated Requirements
For life-critical systems, additional requirements apply:
Linting Configuration
// .eslintrc.json (TypeScript/JavaScript)
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"no-console": "warn",
"complexity": ["error", 10],
"max-lines-per-function": ["warn", 50]
}
}
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: eslint
name: ESLint
entry: npx eslint --fix
language: system
files: \.(ts|tsx|js|jsx)$
- id: prettier
name: Prettier
entry: npx prettier --write
language: system
files: \.(ts|tsx|js|jsx|json|md)$
Best Practices Summary
Do
Write self-documenting code with clear names
Keep functions small and focused
Use consistent formatting (automated via tools)
Handle all error cases explicitly
Write tests alongside code
Review code before merging
Don't
Use abbreviations that aren't universally understood
Write functions longer than 50 lines
Nest more than 3 levels deep
Leave TODO comments without tickets
Copy-paste code (extract to shared functions)
Ignore linter warnings
Compliance
This section fulfills ISO 13485 requirements for design and development procedures (7.3.1) and product identification (7.5.3), and ISO 27001 requirements for secure coding practices (A.8.28), secure development lifecycle (A.8.25), and configuration management (A.8.9).
View full compliance matrix