Code Style Guide
This guide outlines the coding standards and best practices for Continuwuity development. These guidelines help avoid bugs and maintain code consistency, readability, and quality across the project.
These guidelines apply to new code on a best-effort basis. When modifying existing code, follow existing patterns in the immediate area you're changing and then gradually improve code style when making substantial changes.
General Principles
- Clarity over cleverness: Write code that is easy to understand and maintain
- Consistency: Pragmatically follow existing patterns in the codebase, rather than adding new dependencies.
- Safety: Prefer safe, explicit code over unsafe code with implicit requirements
- Performance: Consider performance implications, but not at the expense of correctness or maintainability
Formatting and Linting
All code must satisfy lints (clippy, rustc, rustdoc, etc) and be formatted using nightly rustfmt (cargo +nightly fmt). Many of the rustfmt.toml features depend on the nightly toolchain.
If you need to allow a lint, ensure it's either obvious why (e.g. clippy saying redundant clone but it's actually required) or add a comment explaining the reason. Do not write inefficient code just to satisfy lints. If a lint is wrong and provides a less efficient solution, allow the lint and mention that in a comment.
If making large formatting changes across unrelated files, create a separate commit so it can be added to the .git-blame-ignore-revs file.
Rust-Specific Guidelines
Naming Conventions
Follow standard Rust naming conventions as outlined in the Rust API Guidelines:
- Use
snake_casefor functions, variables, and modules - Use
PascalCasefor types, traits, and enum variants - Use
SCREAMING_SNAKE_CASEfor constants and statics - Use descriptive names that clearly indicate purpose
Error Handling
- Use
Result<T, E>for operations that can fail - Prefer specific error types over generic ones
- Use
?operator for error propagation - Provide meaningful error messages
- If needed, create or use an error enum.
Option Handling
- Prefer explicit
Optionhandling over unwrapping - Use combinators like
map,and_then,unwrap_or_elsewhen appropriate
Logging Guidelines
Structured Logging
Always use structured logging instead of string interpolation. This improves log parsing, filtering, and observability.
Log Levels
Use appropriate log levels:
error!: Unrecoverable errors that affect functionalitywarn!: Potentially problematic situations that don't stop executioninfo!: General information about application flowdebug!: Detailed information for debuggingtrace!: Very detailed information, typically only useful during development
Keep in mind the frequency that the log will be reached, and the relevancy to a server operator.
Sensitive Information
Never log sensitive information such as:
- Access tokens
- Passwords
- Private keys
- Personal user data (unless specifically needed for debugging)
Lock Management
Explicit Lock Scopes
Always use closure guards instead of implicitly dropped guards. This makes lock scopes explicit and helps prevent deadlocks.
Use the WithLock trait from core::utils::with_lock:
For async contexts, use the async variant:
Lock Ordering
When acquiring multiple locks, always acquire them in a consistent order to prevent deadlocks:
Documentation
Code Comments
- Reference related documentation or parts of the specification
- When a task has multiple ways of being achieved, explain your reasoning for your decision
- Update comments when code changes
Async Patterns
- Use
async/awaitappropriately - Avoid blocking operations in async contexts
- Consider using
tokio::task::spawn_blockingfor CPU-intensive work
Inclusivity and Diversity Guidelines
All code and documentation must be written with inclusivity and diversity in mind. This ensures our software is welcoming and accessible to all users and contributors. Follow the Google guide on writing inclusive code and documentation for comprehensive guidance.
The following types of language are explicitly forbidden in all code, comments, documentation, and commit messages:
Ableist language: Avoid terms like "sanity check", "crazy", "insane", "cripple", or "blind to". Use alternatives like "validation", "unexpected", "disable", or "unaware of".
Socially-charged technical terms: Replace overly divisive terminology with neutral alternatives:
- "whitelist/blacklist" → "allowlist/denylist" or "permitted/blocked"
- "master/slave" → "primary/replica", "controller/worker", or "parent/child"
When working with external dependencies that use non-inclusive terminology, avoid propagating them in your own APIs and variable names.
Use diverse examples in documentation that avoid culturally-specific references, assumptions about user demographics, or unnecessarily gendered language. Design with accessibility and inclusivity in mind by providing clear error messages and considering diverse user needs.
This software is intended to be used by everyone regardless of background, identity, or ability. Write code and documentation that reflects this commitment to inclusivity.