Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Library vs Application Conventions

Rule

Classify code before applying policy: published or independently consumed library, shared in-repo crate, application or service, CLI, test support, or tests.

Why

External callers update independently, while application code can change with its callers. The classification determines which half of context-sensitive policy applies.

Do

  • Treat published crates and independently consumed APIs as long-lived contracts.
  • Treat shared in-repo crates as application code until an outside consumer updates independently.
  • Treat applications, services, and CLIs as owners of process-wide setup and concrete integrations.
  • Route context-specific choices to their owner pages:

Avoid

  • Do not impose published-library abstraction on private application internals.
  • Do not use application conveniences in reusable library signatures or global setup.
  • Do not assume every pub item in an internal crate needs external semver treatment.
  • Do not classify by crate type alone; classify by who consumes and updates the API.

Example

#![allow(unused)]
fn main() {
// Reusable boundary: callers inspect a stable error type.
pub fn parse_manifest(source: &str) -> Result<Manifest, ManifestError> {
    parse_manifest_source(source).map_err(ManifestError::from)
}

// Application boundary: the application owns reporting and context.
pub async fn run_deploy(args: DeployArgs) -> anyhow::Result<()> {
    execute_deploy(args).await
}
}

Exceptions

  • Keep application internals typed when callers branch on failures.
  • Treat an internal API as external when another team, plugin, service, or generated client consumes it independently.