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

Pattern 8: Composition Over Duplication

Context

You are adding a feature to an extension crate and need functionality already available in the base layer.

Problem

Copying helpers or macros breaks the single source of truth. Over time the copies diverge, and bug fixes must be applied in multiple places.

Solution

Compose existing primitives. Wrap fixtures inside domain fixtures, embed builders into higher-level builders, and use assertion macros rather than writing bespoke checks. When missing functionality is truly generic, add it to the base crate instead of forking it downstream.

Forces

  • Launch speed vs. long-term maintenance: composition keeps future upgrades cheap
  • Ergonomics vs. explicitness: wrappers can augment APIs without obscuring the base
  • Ownership vs. contribution: contribute upstream when the behavior benefits all users

Examples

#![allow(unused)]
fn main() {
pub struct OrderBuilder {
    base: TestDataBuilder,
}

impl OrderBuilder {
    pub fn new() -> Self {
        Self { base: TestDataBuilder::new() }
    }

    pub fn with_amount(mut self, amount: u64) -> Self {
        self.base = self.base.with_var("amount", amount.to_string());
        self
    }

    pub fn build_json(self) -> serde_json::Value {
        self.base.build_json().expect("json")
    }
}
}
  • Pattern 6: Generic Base Layer
  • Pattern 7: Extension Layer
  • Pattern 9: Single Source of Truth