- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols. - Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage. - Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
7.3 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
- 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
- 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
- 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:
- Standard library
- Third-party packages
- Django imports
- 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
Logging Standards
Logger Initialization
Every view and middleware file should initialize a logger:
import logging
logger = logging.getLogger(__name__)
Centralized Logging Utilities
Use the centralized logging utilities from apps.core.logging for structured logging:
from apps.core.logging import log_exception, log_business_event, log_security_event
When to Use Each Log Level
logger.debug(): Detailed diagnostic information (disabled in production)logger.info(): General operational events (search queries, user actions)logger.warning(): Unexpected conditions that don't prevent operationlogger.error(): Error conditions that require attentionlog_exception(): Exception handling with full stack trace
Exception Logging
Use log_exception for all exception handlers:
try:
# operation
except Exception as e:
log_exception(
logger,
e,
context={"operation": "get_filtered_queryset", "filters": filter_params},
request=self.request,
)
messages.error(self.request, f"Error: {str(e)}")
Business Event Logging
Use log_business_event for significant business operations:
log_business_event(
logger,
event_type="fsm_transition",
message=f"Park approved: {park.name}",
context={
"model": "Park",
"object_id": park.id,
"old_state": old_status,
"new_state": park.status,
},
request=request,
)
Security Event Logging
Use log_security_event for authentication and security-related events:
log_security_event(
logger,
event_type="user_login",
message=f"User {user.username} logged in successfully",
severity="low", # low, medium, high, critical
context={"user_id": user.id, "username": user.username},
request=request,
)
What NOT to Log
Never log:
- Passwords or password hashes
- API tokens or secrets
- Session IDs
- Full credit card numbers
- Other sensitive PII
Log Message Guidelines
- Use clear, concise messages
- Include relevant context (IDs, usernames, operation names)
- Use consistent naming conventions
- Avoid logging large data structures
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]