Coding Standards¶
Conventions, patterns, and rules for writing code in the HyperbyteDB codebase.
Error Handling¶
- Use
thiserrorfor all error types. The central error type isHyperbytedbErrorinsrc/error.rs. - Return
Result<T, HyperbytedbError>from all fallible functions. - Use
?for propagation. Add context with descriptive error messages. - Never use
.unwrap()in production code. Use.expect()only for programmer errors (invariants that should never fail). - The crate root enforces this with
#![cfg_attr(not(test), warn(clippy::unwrap_used, clippy::expect_used))].
// Good
let db = metadata.get_database(name)
.ok_or_else(|| HyperbytedbError::DatabaseNotFound(name.to_string()))?;
// Bad
let db = metadata.get_database(name).unwrap();
Async Patterns¶
- Use
tokio::task::spawn_blockingfor CPU-intensive work (Parquet conversion, chDB queries). - Use
tokio::spawnfor concurrent I/O tasks. - Never hold a
MutexorRwLockacross an.awaitpoint. - Use
tokio::sync::watchfor shutdown signaling. - Use
tokio::select!for timer + shutdown patterns.
pub async fn run(&self, interval: Duration, mut shutdown_rx: watch::Receiver<bool>) {
let mut ticker = tokio::time::interval(interval);
ticker.set_missed_tick_behavior(MissedTickBehavior::Skip);
loop {
tokio::select! {
_ = ticker.tick() => {
if let Err(e) = self.do_work().await {
tracing::error!("service error: {}", e);
}
}
_ = shutdown_rx.changed() => {
if *shutdown_rx.borrow() {
tracing::info!("service shutting down");
break;
}
}
}
}
}
Naming Conventions¶
| Category | Convention | Examples |
|---|---|---|
| Types | UpperCamelCase | CompactionService, FlushResult |
| Functions | snake_case | partition_by_hour, build_schema |
| Constants | SCREAMING_SNAKE_CASE | WAL_READ_CHUNK, MIN_BATCH_POINTS |
| Getters | No get_ prefix | fn name(&self) -> &str |
| Builders | new() or build() | ChdbPool::new(config) |
Dependencies and Injection¶
- Use
Arc<dyn Trait>for dependency injection. All services accept ports asArc<dyn SomePort>. - Use
async_traitfor async trait methods. - Keep domain types free of I/O dependencies.
- Wire dependencies in
src/bootstrap.rs(the composition root).
Metrics¶
- Use the
metricscrate (counter!,gauge!,histogram!). - Prefix all metrics with
hyperbytedb_. - Use labels sparingly to avoid high-cardinality explosion.
- Emit metrics at the point of observation, not at call sites.
counter!("hyperbytedb_write_requests_total").increment(1);
histogram!("hyperbytedb_query_duration_seconds").record(elapsed.as_secs_f64());
gauge!("hyperbytedb_parquet_files_count", "db" => db, "rp" => rp, "measurement" => meas)
.set(count as f64);
Logging¶
Use tracing with structured fields:
| Level | Usage |
|---|---|
ERROR | Failures that need operator attention |
WARN | Recoverable issues (replication failures, timeout retries) |
INFO | Lifecycle events (startup, shutdown, flush/compaction summaries) |
DEBUG | Per-request/per-operation details |
TRACE | Internal algorithm details |
Port Trait Design¶
Port traits (src/ports/) define the boundaries between application logic and infrastructure:
- Traits must be
Send + Sync(for use in async contexts). - Use
#[async_trait]for async methods. - Prefer
&strand&[T]at trait boundaries over owned types. - Return
Result<T, HyperbytedbError>for all fallible operations.
Module Organization¶
domain/— Pure types with no I/O. Never depends on adapters or application.ports/— Traits only. No implementations, no business logic.application/— Business logic. Depends on ports and domain. Never on adapters.adapters/— Concrete implementations of ports. Depends on domain and ports.cluster/— Clustering subsystem. Internal to the crate; not exposed as a library API.influxql/— Self-contained InfluxQL language support.
Code Review Anchors¶
Key architectural invariants enforced during review:
- Port boundary integrity — Application code never imports from
adapters::*. - Domain purity —
domain/types have no I/O dependencies. - Config documentation — New config keys must appear in
docs/user-guide/configuration.mdandconfig.toml.example. - WAL ordering — Flush must not drop acknowledged writes.
- Identifier quoting — InfluxQL-to-ClickHouse translation must quote/escape user input.
See Contributing for the full review rubric.
See Also¶
- Architecture — System design and patterns
- Contributing — Review process and rubric