Skip to content

Coding Style and Conventions

Section Overview

Standards for code formatting, naming, structure, and documentation that ensure consistency across our codebase.


Code Formatting Standards

General Guidelines

Core Principle: Code should be immediately readable and maintainable without requiring clarification from the original author.

Key Guidelines:

  • Maintain visual clarity through consistent spacing and alignment
  • Keep code width within comfortable reading limits
  • Group related code elements visually
  • Use meaningful whitespace to improve readability

Why This Matters

Clear visual structure reduces cognitive load and makes code easier to understand, debug, and maintain. When code is visually organized, developers can quickly grasp its structure and purpose.

Implementation:

  • Configure IDE settings to display formatting guides
  • Use vertical alignment for related code elements
  • Implement automated formatting checks
  • Regular code review focusing on readability

Examples:

# Python -- PEP 8 compliant formatting
from typing import List, Optional

class OrderProcessor:
    def process_items(
        self,
        items: List[dict],
        user_id: Optional[int] = None
    ) -> dict:
        processed_items = [
            self._format_item(item)
            for item in items
            if self._validate_item(item)
        ]

        return {
            'items': processed_items,
            'user_id': user_id,
            'timestamp': self._get_timestamp()
        }
// JavaScript -- Clear visual structure
function processOrder(orderItems, customerInfo) {
    // Group related calculations
    const subtotal = orderItems.reduce((sum, item) => sum + item.price, 0);
    const tax = calculateTax(subtotal);
    const shipping = calculateShipping(orderItems);

    // Group related validations
    if (!orderItems.length) {
        throw new Error("Order must contain items");
    }
    if (!customerInfo.address) {
        throw new Error("Shipping address required");
    }

    return {
        orderTotal: subtotal + tax + shipping,
        taxApplied: tax,
        shippingFee: shipping
    };
}
// Java -- Consistent visual organization
public class OrderProcessor {
    public OrderResult processOrder(List<OrderItem> orderItems,
                                   CustomerInfo customerInfo) {
        // Group related calculations
        double subtotal = calculateSubtotal(orderItems);
        double tax = calculateTax(subtotal);
        double shipping = calculateShipping(orderItems);

        // Group related validations
        if (orderItems.isEmpty()) {
            throw new IllegalArgumentException("Order must contain items");
        }
        if (customerInfo.getAddress() == null) {
            throw new IllegalArgumentException("Shipping address required");
        }

        return OrderResult.builder()
            .orderTotal(subtotal + tax + shipping)
            .taxApplied(tax)
            .shippingFee(shipping)
            .build();
    }
}

Language-Specific Formatting

Core Principle: Each programming language should follow its ecosystem's established formatting conventions while maintaining project-wide consistency.

Key Guidelines:

  • Python
  • Indentation: 4 spaces
  • Maximum line length: 88 characters (Black default)
  • Follow PEP 8 guidelines

  • JavaScript/TypeScript

  • Indentation: 2 spaces
  • Maximum line length: 80 characters
  • Use semicolons consistently
  • Follow Standard JS style or Google Style for Typescript

  • Java

  • Indentation: 4 spaces
  • Maximum line length: 120 characters
  • Follow K&R style bracing

Follow the Ecosystem

Following established language conventions makes code more predictable and easier to maintain. It also helps new team members adapt quickly to the codebase.

Examples:

# Python - Strategic whitespace usage
class OrderManager:
    def __init__(self, db_connection, logger):
        self.db = db_connection
        self.logger = logger

    def process_order(self, order_data):
        # Validation block
        if not order_data:
            self.logger.error("Empty order received")
            return None

        # Processing block
        try:
            validated_items = self._validate_items(order_data['items'])
            total_amount = self._calculate_total(validated_items)

            # Database operations block
            order_id = self._save_to_database(
                items=validated_items,
                amount=total_amount
            )

            return {"order_id": order_id, "status": "success"}

        except Exception as e:
            self.logger.error(f"Order processing failed: {e}")
            return {"status": "error", "message": str(e)}
// JavaScript - Standard JS style
class OrderProcessor {
  async processItems(items, userId = null) {
    const processedItems = await Promise.all(
      items
        .filter(item => this.validateItem(item))
        .map(async item => this.formatItem(item))
    );

    return {
      items: processedItems,
      userId,
      timestamp: this.getTimestamp()
    };
  }
}
// Java - Google Style
public class OrderProcessor {
    public ProcessResult processItems(
            List<Item> items, @Nullable Integer userId) {
        List<FormattedItem> processedItems = items.stream()
                .filter(this::validateItem)
                .map(this::formatItem)
                .collect(Collectors.toList());

        return ProcessResult.builder()
                .items(processedItems)
                .userId(userId)
                .timestamp(getTimestamp())
                .build();
    }
}

Whitespace Usage

Core Principle: Whitespace should be used deliberately to improve code readability and indicate logical groupings.

Key Guidelines:

  • Use blank lines to separate logical blocks of code
  • Maintain consistent spacing around operators
  • Group related code elements with consistent spacing
  • Use indentation to show hierarchy and scope

Visual Patterns

Strategic use of whitespace creates visual patterns that make code structure immediately apparent, reducing the time needed to understand code organization and relationships.

Examples:

# Python - Strategic whitespace usage
class OrderManager:
    def __init__(self, db_connection, logger):
        self.db = db_connection
        self.logger = logger

    def process_order(self, order_data):
        # Validation block
        if not order_data:
            self.logger.error("Empty order received")
            return None

        # Processing block
        try:
            validated_items = self._validate_items(order_data['items'])
            total_amount = self._calculate_total(validated_items)

            # Database operations block
            order_id = self._save_to_database(
                items=validated_items,
                amount=total_amount
            )

            return {"order_id": order_id, "status": "success"}

        except Exception as e:
            self.logger.error(f"Order processing failed: {e}")
            return {"status": "error", "message": str(e)}
// JavaScript - Logical grouping with whitespace
class OrderManager {
  constructor(dbConnection, logger) {
    this.db = dbConnection;
    this.logger = logger;
  }

  async processOrder(orderData) {
    // Validation block
    if (!orderData) {
      this.logger.error('Empty order received');
      return null;
    }

    // Processing block
    try {
      const validatedItems = await this._validateItems(orderData.items);
      const totalAmount = this._calculateTotal(validatedItems);

      // Database operations block
      const orderId = await this._saveToDatabase({
        items: validatedItems,
        amount: totalAmount
      });

      return { orderId, status: 'success' };

    } catch (error) {
      this.logger.error(`Order processing failed: ${error}`);
      return { status: 'error', message: error.message };
    }
  }
}

Tool Configuration and Enforcement

Core Principle: Automated tools and consistent configurations should be used to enforce coding standards and maintain code quality across the team.

Automation is Key

Automated enforcement reduces cognitive load on developers, ensures consistent code quality, and prevents style debates by automatically enforcing agreed-upon standards.

Python Tool Setup

What You'll Need:

  • black: A code formatter
  • isort: Sorts and organizes import statements

Setup:

# 1. Install the tools
pip install black isort

# 2. Run formatting
black .    # Formats all Python files
isort .    # Sorts import statements

Configuration File (pyproject.toml):

[tool.black]
line-length = 88
include = '\.pyx?$'

[tool.isort]
profile = "black"
multi_line_output = 3

JavaScript/TypeScript Tool Setup

What You'll Need:

  • eslint: Finds and fixes code quality issues
  • prettier: Enforces consistent code formatting

Setup:

# 1. Install tools
npm install --save-dev eslint prettier

# 2. Run formatting and linting
prettier --write "**/*.{js,jsx,ts,tsx}"
eslint .

Configuration (.prettierrc):

{
  "printWidth": 80,
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}

Java Tool Setup

What You'll Need:

  • Google Java Format: An opinionated code formatter
  • Maven Plugin: Integrates formatting into the build process

Setup:

Add Maven Plugin to pom.xml:

<plugin>
    <groupId>com.googlejavaformat</groupId>
    <artifactId>google-java-format-maven-plugin</artifactId>
    <version>1.15.0</version>
    <executions>
        <execution>
            <goals>
                <goal>format</goal>
            </goals>
            <phase>validate</phase>
        </execution>
    </executions>
</plugin>

Run formatting:

# Format all Java files
mvn google-java-format:format

# Verify formatting compliance
mvn google-java-format:check

Best Practices

  • Run formatter before each commit
  • Integrate with CI/CD pipeline
  • Configure IDE to format on save
  • Use pre-commit hooks for automatic checking

Shared IDE Configuration

To maintain consistency across the team when using different editors and IDEs, we use a shared .editorconfig:

.editorconfig Example:

# Root configuration file
root = true

# Rules for all files
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8

# JavaScript/TypeScript specific
[*.{js,jsx,ts,tsx}]
indent_style = space
indent_size = 2

# Python specific
[*.py]
indent_style = space
indent_size = 4

VSCode Settings:

{
    "editor.formatOnSave": true,
    "editor.defaultFormatter": null,
    "editor.codeActionsOnSave": {
        "source.fixAll": true
    },
    "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[python]": {
        "editor.defaultFormatter": "ms-python.black-formatter"
    }
}

Enforcement Mechanisms

We implement a multi-layered approach to enforce these standards:

Four-Layer Enforcement

1. Pre-commit Hooks - Run checks before allowing commits

2. CI/CD Pipeline - Validate in continuous integration

3. IDE Integration - Real-time feedback while coding

4. Code Review - Human validation with automated checklists


Code Organization and Structure

Project Structure

Core Principle: Code should be organized in a hierarchical, domain-driven structure that promotes maintainability, scalability, and clear separation of concerns.

Key Guidelines:

  • Organize code by business domain or feature
  • Maintain consistent project structure across all services
  • Follow the Single Responsibility Principle
  • Keep related code close together
  • Implement clear dependency management

Reduce Cognitive Load

Well-organized code reduces cognitive load, improves team collaboration, and makes the system easier to maintain and extend over time.

Standard Project Structure:

project-root/
├── src/
│   ├── feature1/
│   │   ├── models/
│   │   ├── services/
│   │   ├── utils/
│   │   └── tests/
│   ├── feature2/
│   │   └── ...
│   └── shared/
├── config/
├── scripts/
└── docs/

Examples:

payment_service/
  └── payment/
      ├── models/
      │   ├── payment.py
      │   └── transaction.py
      ├── services/
      │   ├── payment_processor.py
      │   └── refund_handler.py
      └── utils/
          └── payment_validator.py
# payment_processor.py
from typing import Optional
from .models.payment import Payment
from .utils.payment_validator import validate_payment

class PaymentProcessor:
    def __init__(self, payment_gateway):
        self.payment_gateway = payment_gateway

    def process_payment(self, payment_data: dict) -> Optional[Payment]:
        if not validate_payment(payment_data):
            return None

        payment = Payment.from_dict(payment_data)
        return self.payment_gateway.process(payment)
OrderModule/
  ├── components/
  │   ├── OrderList.js
  │   └── OrderDetail.js
  ├── services/
  │   └── orderService.js
  └── utils/
      └── orderValidator.js
// orderService.js
import { orderValidator } from '../utils/orderValidator';

export class OrderService {
  constructor(orderRepository) {
    this.orderRepository = orderRepository;
  }

  async createOrder(orderData) {
    if (!orderValidator.isValid(orderData)) {
      throw new ValidationError('Invalid order data');
    }

    const order = await this.orderRepository.create(orderData);
    return this.enrichOrderData(order);
  }
}
inventory/
  ├── domain/
  │   └── Product.java
  ├── repository/
  │   └── ProductRepository.java
  └── service/
      └── ProductService.java
// ProductService.java
@Service
public class ProductService {
    private final ProductRepository repository;
    private final ValidationService validator;

    @Autowired
    public ProductService(
            ProductRepository repository,
            ValidationService validator) {
        this.repository = repository;
        this.validator = validator;
    }

    public Product createProduct(ProductDTO dto) {
        validator.validate(dto);
        return repository.save(Product.fromDTO(dto));
    }
}

Language-Specific Idioms and Constructs

Core Principle: Leverage language-specific features and idioms to write clean, efficient, and idiomatic code while maintaining consistency across the codebase.

Use Idiomatic Code

Using language-specific idioms properly results in more maintainable, efficient code that follows established patterns familiar to developers in that ecosystem.

Examples:

# Python - Idiomatic constructs
from dataclasses import dataclass
from typing import List, Optional
from contextlib import contextmanager

@dataclass
class OrderItem:
    product_id: int
    quantity: int
    price: float

class OrderProcessor:
    def __init__(self, db_session):
        self.db_session = db_session

    @contextmanager
    def transaction(self):
        """Idiomatic transaction handling"""
        try:
            yield self.db_session
            self.db_session.commit()
        except Exception:
            self.db_session.rollback()
            raise

    def process_items(self, items: List[OrderItem]) -> Optional[dict]:
        """Pythonic list processing and error handling"""
        if not items:
            return None

        with self.transaction() as session:
            # List comprehension for transformation
            processed = [
                self._process_item(item)
                for item in items
            ]

            # Dictionary comprehension for results
            return {
                'items': processed,
                'total': sum(item.price for item in processed)
            }
// JavaScript - Modern idioms
class OrderManager {
  constructor(repository) {
    this.repository = repository;
  }

  async processOrder({ items, userId, ...metadata }) {
    // Destructuring and rest parameters
    const processedItems = await Promise.all(
      items.map(async item => {
        // Arrow functions and async/await
        const { price, ...itemData } = item;
        return {
          ...itemData,
          processedPrice: await this.calculatePrice(price)
        };
      })
    );

    // Object spread and computed properties
    return {
      orderItems: processedItems,
      metadata: {
        ...metadata,
        timestamp: new Date().toISOString()
      }
    };
  }
}
// Java - Modern patterns and features
public class OrderProcessor {
    private final OrderRepository repository;

    // Constructor injection
    @Inject
    public OrderProcessor(OrderRepository repository) {
        this.repository = repository;
    }

    public Optional<Order> processOrder(OrderRequest request) {
        // Stream API and method references
        return Optional.of(request)
            .filter(OrderValidator::isValid)
            .map(this::createOrder)
            .flatMap(repository::save);
    }

    // Builder pattern
    private Order createOrder(OrderRequest request) {
        return Order.builder()
            .items(request.getItems())
            .status(OrderStatus.PENDING)
            .timestamp(LocalDateTime.now())
            .build();
    }
}

Commenting and Documentation

Core Principle: Comments should explain why rather than what, and documentation should provide clear context for code usage and maintenance.

Document the Why, Not the What

Good documentation and comments make code easier to maintain, understand, and modify while reducing the time needed for new developers to become productive.

Key Guidelines:

  • Write self-documenting code where possible
  • Document the why, not the what
  • Keep comments up to date with code changes
  • Provide clear API documentation
  • Add examples for complex logic

Examples:

# Python - Documentation and comments
from typing import List, Optional
from datetime import datetime

class OrderProcessor:
    """Handles the processing and validation of customer orders.

    This class coordinates the entire order processing workflow,
    including inventory checks, payment processing, and notification
    handling.

    Attributes:
        max_retries: Maximum number of payment processing attempts
        retry_delay: Delay between retry attempts in seconds
    """

    def process_order(
        self,
        order_items: List[dict],
        customer_id: str
    ) -> Optional[dict]:
        """Process a customer order with inventory and payment validation.

        Args:
            order_items: List of items in the order, each containing
                        'product_id' and 'quantity'
            customer_id: Unique identifier for the customer

        Returns:
            Dict containing order details if successful, None if failed

        Raises:
            InvalidOrderException: If order validation fails
            PaymentProcessingError: If payment cannot be processed
        """
        # Validate inventory before processing payment
        # This prevents charging customer for unavailable items
        if not self._validate_inventory(order_items):
            return None

        try:
            # Process payment first to ensure funds are available
            # before modifying inventory
            payment_result = self._process_payment(order_items, customer_id)
            return self._finalize_order(payment_result, order_items)
        except Exception as e:
            # Log error and rollback any partial changes
            self._handle_processing_error(e)
            return None
// JavaScript - Documentation and comments

/**
 * Manages the processing and fulfillment of customer orders.
 * 
 * @class OrderProcessor
 * @description Coordinates order processing workflow including
 *              validation, payment processing, and fulfillment.
 */
class OrderProcessor {
  /**
   * Process a new customer order.
   *
   * @async
   * @param {Object} orderData - The order information
   * @param {Array<Object>} orderData.items - Order items
   * @param {string} orderData.customerId - Customer identifier
   * @returns {Promise<Object>} Processing result with order details
   * @throws {ValidationError} If order validation fails
   */
  async processOrder({ items, customerId }) {
    // Validate order before processing to prevent invalid submissions
    // This includes checking inventory and customer eligibility
    const validationResult = await this.validateOrder(items, customerId);
    if (!validationResult.isValid) {
      throw new ValidationError(validationResult.errors);
    }

    try {
      // Process payment first to ensure funds are available
      // This prevents inventory issues during high concurrency
      const paymentResult = await this.processPayment(items, customerId);
      return this.finalizeOrder(paymentResult, items);
    } catch (error) {
      // Ensure all changes are rolled back if any part fails
      await this.handleProcessingError(error);
      throw error;
    }
  }
}
/**
 * Manages order processing and fulfillment workflows.
 * 
 * <p>This class handles the entire lifecycle of an order, including:
 * <ul>
 *   <li>Order validation</li>
 *   <li>Payment processing</li>
 *   <li>Inventory management</li>
 *   <li>Fulfillment tracking</li>
 * </ul>
 * 
 * <p>Thread-safe and supports concurrent order processing.
 */
public class OrderProcessor {
    /**
     * Processes a customer order through all stages of the workflow.
     * 
     * @param orderRequest Contains order details and customer information
     * @return OrderResult containing the processing outcome and order details
     * @throws ValidationException if order validation fails
     * @throws PaymentException if payment processing fails
     */
    public OrderResult processOrder(OrderRequest orderRequest) {
        // Validate order before processing
        // This prevents invalid orders from entering the system
        ValidationResult validation = validateOrder(orderRequest);
        if (!validation.isValid()) {
            throw new ValidationException(validation.getErrors());
        }

        try {
            // Process payment first to ensure funds are available
            // This prevents inventory holds on unpaid orders
            PaymentResult payment = processPayment(orderRequest);
            return finalizeOrder(payment, orderRequest);
        } catch (Exception e) {
            // Roll back any partial changes to maintain system consistency
            handleProcessingError(e);
            throw e;
        }
    }
}

Last updated: October 2025