Files
thrillwiki_django_no_react/backend/docs/code_standards.md
pacnpal 2e35f8c5d9 feat: Refactor rides app with unique constraints, mixins, and enhanced documentation
- Added migration to convert unique_together constraints to UniqueConstraint for RideModel.
- Introduced RideFormMixin for handling entity suggestions in ride forms.
- Created comprehensive code standards documentation outlining formatting, docstring requirements, complexity guidelines, and testing requirements.
- Established error handling guidelines with a structured exception hierarchy and best practices for API and view error handling.
- Documented view pattern guidelines, emphasizing the use of CBVs, FBVs, and ViewSets with examples.
- Implemented a benchmarking script for query performance analysis and optimization.
- Developed security documentation detailing measures, configurations, and a security checklist.
- Compiled a database optimization guide covering indexing strategies, query optimization patterns, and computed fields.
2025-12-22 11:17:31 -05:00

5.1 KiB

Code Standards

This document defines the code quality standards for the ThrillWiki backend.

Formatting & Style

PEP 8 Compliance

All Python code must comply with PEP 8, verified using:

  • black: Code formatting (line length: 88)
  • flake8: Style checking (max-line-length: 88, max-complexity: 10)
  • ruff: Fast linting and import sorting

Running Formatters

# Format code
uv run black backend/

# Check style
uv run flake8 backend/ --max-line-length=88 --max-complexity=10

# Lint and fix
uv run ruff check backend/ --fix

Docstring Requirements

Coverage

  • 100% coverage for public classes and methods
  • 100% coverage for all functions
  • Optional for private methods (but encouraged)

Style

Follow Google-style docstrings:

def function_name(arg1: Type1, arg2: Type2) -> ReturnType:
    """
    Brief description of what this function does.

    Longer description if needed, explaining the purpose,
    behavior, and any important details.

    Args:
        arg1: Description of arg1
        arg2: Description of arg2

    Returns:
        Description of return value

    Raises:
        ExceptionType: When this exception is raised

    Example:
        >>> function_name("value1", "value2")
        "result"
    """

Class Docstrings

class ClassName:
    """
    Brief description of what this class does.

    Longer description if needed.

    Attributes:
        attr1: Description of attr1
        attr2: Description of attr2

    Example:
        instance = ClassName()
        instance.method()
    """

View Docstrings

Views should include URL patterns and permissions:

class MyView(DetailView):
    """
    Brief description of what this view does.

    View Type: CBV (DetailView)
    URL Pattern: /resource/<slug>/
    Template: app/resource_detail.html
    Permissions: LoginRequired
    """

Complexity Guidelines

Limits

  • Maximum McCabe complexity: 10
  • Maximum method length: 50 lines
  • Maximum nesting depth: 3 levels

Checking Complexity

# Check McCabe complexity
uv run flake8 backend/ --max-complexity=10 --select=C901

# Get complexity metrics
uv run radon cc backend/apps/ -a

Refactoring Strategies

  1. Extract helper methods for distinct responsibilities:
# Before
def process_data(self, data):
    # Validate data (10 lines)
    # Transform data (10 lines)
    # Save data (10 lines)
    # Send notifications (10 lines)
    pass

# After
def process_data(self, data):
    self._validate_data(data)
    transformed = self._transform_data(data)
    result = self._save_data(transformed)
    self._send_notifications(result)
    return result
  1. Use early returns to reduce nesting:
# Before
def process(self, data):
    if data:
        if data.get('field1'):
            if data.get('field2'):
                return result
    return None

# After
def process(self, data):
    if not data:
        return None
    if not data.get('field1'):
        return None
    if not data.get('field2'):
        return None
    return result
  1. Move complex logic to service layer

Service Layer Patterns

Service Method Signature

Always use keyword-only arguments for service methods:

class MyService:
    @staticmethod
    def create_entity(
        *,  # Force keyword-only arguments
        name: str,
        description: str = "",
        created_by: Optional[User] = None,
    ) -> Entity:
        """Create a new entity."""
        pass

Validation Pattern

Always call full_clean() before save:

@staticmethod
def create_park(*, name: str, ...) -> Park:
    with transaction.atomic():
        park = Park(name=name, ...)
        park.full_clean()  # Validate before save
        park.save()
        return park

Import Organization

Imports should be organized in this order:

  1. Standard library
  2. Third-party packages
  3. Django imports
  4. Local app imports
import logging
from typing import Any, Dict, Optional

from django.contrib.auth import get_user_model
from django.db import transaction
from rest_framework import status

from apps.core.exceptions import ServiceError
from .models import MyModel

Type Hints

Use type hints for all function signatures:

def process_data(
    data: Dict[str, Any],
    user: Optional[User] = None,
) -> ProcessResult:
    """Process data and return result."""
    pass

Testing Requirements

  • Maintain or improve test coverage with changes
  • Add tests for new service methods
  • Add tests for new mixins and base classes
  • Run tests before committing:
pytest backend/tests/ --cov=backend/apps --cov-report=html

Pre-commit Configuration

The following pre-commit hooks are configured:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

  - repo: https://github.com/pycqa/flake8
    rev: 7.1.1
    hooks:
      - id: flake8
        args: [--max-line-length=88, --max-complexity=10]

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.12.10
    hooks:
      - id: ruff
        args: [--fix]