Software Design Patterns in Rust
Glossary
129 terms from Software Design Patterns in Rust, in plain words, each with the chapter that teaches it.
#
- #[cfg(test)]
- An attribute that compiles the code after it only when building tests. It is used on the `mod tests` block so test code never ships in the real program.
- #[test]
- An attribute marking a function that the test runner calls for you. A test passes if it doesn't panic.
A
- Abstract factory
- A trait with several make methods that builds a family of matching parts together, such as a carrier and its label printer. Callers get a consistent set without naming concrete types.
- Adapter
- A wrapper that holds a library value with an awkward shape and implements your trait, translating each call. Kettle & Crane's UpsCarrier adapts UpsApi, which wants line counts and answers in cents.
- Anti-pattern
- A common answer to a design problem that looks reasonable but causes more trouble than it solves. Examples are the god object and magic numbers.
- API (application programming interface)
- The set of functions or calls a library or service offers to other code. UpsApi stands in for the UPS rate service's API.
- assert_eq!
- A macro used in tests that panics if two values are not equal, which makes the test fail. It is how the tests check that totals like 467.5 stay the same.
- Axum
- A Rust web framework built on the tokio async runtime. It shows dependency injection through `State`, a registry of routes mapping paths to handler functions, and middleware added as layers.
B
- Behavioral pattern
- A pattern about how objects share work and decisions and talk to each other. Strategy, Observer and Command are examples.
- Borrow checker
- The part of the Rust compiler that checks every reference follows the ownership and borrowing rules. Adding `.clone()` just to make its errors go away is a bad habit, because it hides the real ownership problem and copies data for nothing.
- Box
- An owning pointer that puts a value on the heap. `Box<dyn Rule>` lets values of different types, whose sizes differ, sit together in one Vec.
- Builder
- A pattern that collects the parts of a complicated value one method call at a time, then checks and creates it in `build()`. Each step takes and returns `self`, so calls chain.
C
- Cache
- Saved answers kept so the same work isn't repeated. The CachedCarrier proxy remembers a quote per line count and skips the real carrier the second time.
- cargo
- Rust's build tool and package manager. `cargo test` runs tests, `cargo run` builds and runs, and Cargo.toml describes the project (such as the `shop` crate).
- Chain of responsibility
- A pattern where a request passes along a line of handlers, each of which rejects it or passes it on. Kettle & Crane's order checks (known carrier, under limit) work this way.
- Characterization test
- A test that records what existing code does today, right or wrong, so you can refactor safely. For example, the old `place_order` totals of 467.5, 42.6 and 31.25 become expected values that the redesigned code must still produce.
- Clone
- A trait whose `clone()` makes an independent copy of a value, field by field. The prototype pattern uses it, and it should be used for a real second owner, not to silence the borrow checker.
- Closure
- A small inline function that can use values from the code around it, such as `|s| s * 0.9`. Closures can be stored in variables and passed to other functions.
- Cohesion
- How closely the things inside one piece of code belong together. A function that only works out shipping has high cohesion, which is good.
- Command
- A pattern that turns an action into an object with `execute` and `undo`, so actions can be stored, queued and reversed. The cart's AddItem is an example.
- Composite
- A pattern where an item and a group of items answer the same method, so a group can hold other groups. A gift Bundle's price is the sum of its parts' prices.
- Composition
- Building a struct from other values it holds and hands work to ("has-a"), instead of inheriting from a parent. A Product holds a pricing part and a wrapping part.
- Composition root
- The one place, usually `main`, where the real parts are built and handed to the code that needs them. Everything else just receives its dependencies.
- const
- A named value fixed at compile time, such as `const FREE_SHIPPING_AT: f64 = 75.0;`. It is the fix for magic numbers.
- Constructor injection
- Passing a struct the dependencies it needs through its `new` function, so it keeps them instead of creating them. OrderLog::new takes a repo, clock and notifier.
- Copy-paste programming
- An anti-pattern of repeating the same code in several places instead of sharing one function, so one bug fix is always missed somewhere.
- Coupling
- How much one piece of code depends on the details of another. Loose coupling is good: changing the discount code shouldn't break shipping code.
- Crate
- Rust's unit of packaged code, either a program or a library. Examples are the `shop` crate and the external axum and tokio crates.
- Creational pattern
- A pattern about how objects get built, putting the "which type, which settings?" decision in one place. Factory, Builder and Singleton are examples.
- CSV (comma-separated values)
- A plain-text table format with one row per line and columns separated by commas. Jo's report uses lines like `KC-1001,467.50`.
D
- Data race
- A bug where two threads access the same data at once and at least one changes it, giving unpredictable results. It is why Rust makes changeable globals awkward.
- Decorator
- A wrapper with the same interface as the value it wraps that does a little extra work and passes the call on. Priya's LoggedCarrier logs each quote.
- Default (trait)
- A standard trait that gives a type a ready-made starting value. It works with `..Default::default()` to fill unnamed fields.
- Default method
- A trait method with a body that implementing types get for free and may override. The template method pattern uses one to run the fixed steps.
- Default-method surprise
- Rust's version of the fragile base class: changing a trait's default method affects only the types that didn't copy or override it. Adding tax to the default `total` would tax only Retail.
- Delegation
- Handing a job to a value you hold instead of doing it yourself. Product::total asks its pricing part, then its wrapping part, and adds the answers.
- Dependency
- Anything a piece of code needs to do its job, such as a database, a notifier or the clock.
- Dependency injection
- Giving code its dependencies from outside instead of letting it create or find them. That lets tests pass in fakes, so OrderLog can run without disk or the real clock.
- Dependency inversion principle (DIP)
- The SOLID rule that high-level code shouldn't depend on low-level details. Both depend on a trait, and the detail is passed in.
- derive
- An attribute that asks the compiler to write standard trait code for a struct or enum, such as Clone, Debug, PartialEq or Default.
- Design pattern
- A named, reusable solution to a common design problem. It's a shape for your code, not a library to copy.
- DI container
- A library that builds and connects an application's objects automatically from rules. Rust programs usually wire parts by hand in main.
- Drop
- The trait whose `drop` method Rust runs automatically when a value goes out of scope. It is how Rust does cleanup (RAII).
- Dynamic dispatch
- Calling a method through `dyn Trait`, where the exact method is looked up while the program runs. This lets different types share a Vec, at the cost of a pointer and an indirect call.
E
F
- Facade
- One simple function or struct in front of several parts, so only it knows the steps. checkout prices, quotes shipping and saves an order for every caller.
- Factory
- A function that makes values, such as create_carrier turning a name into the right carrier, so callers never need an if chain.
- Factory method
- A pattern where a trait has a required method (like make_carrier) that each implementer uses to choose what to build, while default methods use the result.
- Fake
- A simple working stand-in for a real part, such as an in-memory repository or a notifier that keeps messages in a list. Tests use fakes to avoid disk, network or real email.
- Fixture
- Test setup code that builds fresh inputs for each test. Rust has no built-in fixtures, so a helper function like make_log does the job.
- Flyweight / Bridge / Mediator / Memento / Visitor / Interpreter
- Six further Gang of Four design patterns. Flyweight shares objects to save memory, Bridge splits a concept from its implementation, Mediator has one object manage how others talk, Memento saves state to restore later, Visitor adds operations without editing types, and Interpreter models a small language's grammar as types.
- Fragile base class
- A problem where a change to a parent's code quietly breaks its children.
- Framework
- Code that runs your program and calls your code at the right moments, like the Rust test runner or Axum. A library, by contrast, is called by you.
- Function pointer
- A value of type `fn(...) -> ...` that refers to a plain function. It can't capture values, unlike a closure.
G
- Gang of Four
- The nickname of the four authors of the 1994 book *Design Patterns*, which lists 23 patterns in three families.
- Generic
- Code written for any type that meets a trait bound, like `R: Repo`. The compiler builds a separate copy for each type used, which is fast but fixed at compile time.
- Global mutable state
- A `static` that any code can change, like the old ORDERS list. It hides dependencies and makes parallel tests interfere with each other.
- God object
- One struct or module that does far too much, like a Shop with 40 methods. The fix is to split it by reason to change.
- Golden hammer
- Using one favorite tool, such as a trait, builder or factory, for every problem whether or not it fits.
H
- Handler
- A link in a chain of responsibility that handles a request or passes it on. In Axum it is also a route's function.
- Has-a / is-a
- The test for choosing composition or inheritance: a product *has a* pricing rule (compose), while an error *is a* kind of Error (trait). Rust has no inheritance.
- HashMap
- A standard collection that maps keys to values. It is a natural fit for an event bus's listeners, a registry, or a cache.
- Hook
- The step a template method leaves open for the caller to fill in, such as a closure that formats a report row.
I
- Inheritance
- A feature of class-based languages where a child class reuses its parent's code. Rust has none and uses traits and composition instead.
- Injected clock
- A function passed in that returns the current unix time, so tests can supply a fixed time instead of the real one.
- Interface
- The methods code expects a value to have. In Rust a trait writes the interface down and the compiler checks it.
- Interface segregation principle (ISP)
- The SOLID rule that code shouldn't depend on methods it doesn't use, so keep traits small. USPS only needs a Quoter, not a Tracker.
- Inversion of control
- A framework calling your code instead of your code calling it: "don't call us, we'll call you". The test runner calling your `#[test]` functions is an example.
- Iterator
- Something that steps through a collection one item at a time without exposing how it's stored. Every `for` loop uses one, and you can implement the `Iterator` trait yourself.
J
- JSON (JavaScript Object Notation)
- A text format for structured data using braces, brackets and quoted keys. The old place_order writes orders to `orders.json`.
K
- KISS (Keep it simple)
- A design rule: of two working designs, choose the one that's easier to read.
L
- Library
- Tools your code calls, like `sort_by`. Compare a framework, which calls your code.
- Liskov substitution principle (LSP)
- The SOLID rule that a stand-in must work wherever the original works. In Rust, every type implementing a trait must keep the trait's promises, as a LockedCard that panics in `top_up` does not.
- Listener
- A function or closure that wants to hear about an event and is called when it's emitted. send_email and log_sale are listeners.
M
- Magic number
- A number written in code with no name, like `75.0` or `0.85` in the old place_order. Give it a name with a `const`.
- Middleware
- Code that every web request passes through, such as logging or login checks, and which can stop the request. It is a chain of responsibility.
- Mock
- A test stand-in that also records how it was called, so a test can check those calls. It differs from a fake, which is a simple working version, and from a stub, which returns fixed answers.
- mod
- The keyword that declares a module. In a multi-file crate, `main.rs` needs a line such as `mod discounts;` for the file `discounts.rs` to count as part of the program.
- monkeypatching
- Replacing parts of running code, usually in tests, to fake a dependency. Rust has none, and injection replaces it.
- move (closure)
- A keyword that makes a closure take ownership of the values it uses. It is needed when a boxed closure outlives the function that made it, like percent_off's `pct`.
- Mutex
- A lock that lets one thread or piece of code at a time use the value inside. It is how Rust allows a changeable `static`, via `lock().unwrap()`.
- MVC / hexagonal architecture / CQRS / microservices
- Larger-scale architecture patterns that apply design ideas such as separation of responsibilities and loose coupling to whole applications. Examples are MVC's split into model, view and controller, and splitting a system into many small independent services.
O
- Observer
- A pattern where the code where something happens (the subject) keeps listeners and calls each without knowing what they do. A new reaction, like Alex's packing slip, is one more `on` line.
- OnceLock
- A standard-library slot that is filled once by the first `get_or_init` call and then hands out the same shared reference. It is Rust's safe way to build a read-only singleton.
- Open/closed principle (OCP)
- The SOLID rule that code should be open for extension but closed for modification: add behavior with new code, such as a new `impl Rule`, instead of editing working code.
- Over-engineering
- Building more structure than the problem needs, like a factory, registry and builder for a single discount.
- Ownership
- Rust's rule that each value has one owner, and passing it by value moves it. A consuming builder takes `self` by value, and `Rc` gives a value several owners.
P
- panic!
- A macro that stops the program with an error message. The old place_order panics on an unknown carrier.
- Plugin
- Code, usually a crate, that adds a feature to a framework without changing the framework. It is open/closed applied to a whole tool.
- Premature abstraction
- Adding a trait, builder or factory before two or three real cases exist.
- Prototype
- A pattern that copies a ready-made value and changes a little, like Bloom Café's weekly order template. In Rust it is `Clone` plus `..base.clone()`.
- Proxy
- A same-interface wrapper that controls access to the real value. It might create it late, check permissions, or cache answers like CachedCarrier.
- Publish/subscribe
- Another name for the observer pattern, usually with a message system between the publisher and the subscribers.
R
- RAII (Resource Acquisition Is Initialization)
- Tying cleanup to a value's life: Rust calls `drop` when the value goes out of scope, as with Receipt printing "closing".
- Rc<RefCell<..>>
- A pair of standard types for sharing changeable data: `Rc` gives several owners, and `RefCell` checks borrowing at run time instead of compile time. Overuse turns borrow errors into panics.
- Registry
- A table from names to types or functions that is looked up when needed, such as Axum's routes mapping paths to handlers or a table of carriers.
- Repository
- An interface that stores and finds things so nothing else knows how they're stored. MemoryRepo keeps orders in a private Vec, and a JsonRepo could use a file.
- Result
- Rust's way to report success or failure: `Result` is `Ok(value)` or `Err(message)`, and `Option` is `Some` or `None`. The `?` operator returns an error early, and `ok_or` turns a missing Option into an error.
- Rule of three
- Write it once, notice the repeat the second time, and extract a shared version on the third.
- rustc
- The Rust compiler, installed by rustup. Compiling a file with `rustc --edition 2021 -O file.rs` needs the edition flag, because plain `rustc` assumes the old 2015 edition.
S
- serde
- A Rust library for converting data to and from formats like JSON. It does the work of a hand-written JSON writer, and is what real programs use for this.
- Service locator
- A global registry that code asks for its dependencies. It hides what code needs and forces tests to change the global, the opposite of injection.
- Simple factory
- One function that knows every type and turns a name into the right value, such as create_carrier("ups"). A new carrier is a struct, an impl and a match arm.
- Single responsibility principle (SRP)
- The SOLID rule that a piece of code should have one reason to change. price_items changes only with line pricing, apply_discount only with offers.
- Singleton
- A single value that everyone shares. In Rust it is a `static`, using `OnceLock` for set-once data or `Mutex` for changeable data, and overuse leads to global state.
- SKU (stock keeping unit)
- A product's code used to identify an item, such as ESP-5LB or MUG-BLUE.
- SOLID
- Five design principles named by their first letters: single responsibility, open/closed, Liskov substitution, interface segregation and dependency inversion.
- Spaghetti code
- Code with ifs, globals and jumps so tangled that no path is easy to follow.
- State
- A pattern that allows only the moves an order may make. It can be a lightweight enum plus a `match`, or one type per state held in a `Box<dyn State>`.
- State machine
- Something that is always in exactly one of a fixed set of states, with rules for the allowed moves between them. An order goes placed, paid, shipped, delivered, and can be cancelled before shipping.
- static
- A global that lives for the whole program. Rust lets you change one only behind a `Mutex` (or via `unsafe` with `static mut`).
- Static dispatch
- Accepting "anything with this trait" via `&impl Rule` or generics, where the compiler builds one copy of the function per type. It suits one known type.
- Strategy
- One interchangeable way of doing a job, where all versions share a shape. In Rust it is a function or closure, like the discount functions taking a subtotal and returning a discounted one.
- Struct update syntax
- The `..base` form that fills fields you didn't name from another struct, as in `OrderTemplate { qty: 20, ..weekly.clone() }`.
- Structural pattern
- A pattern about how values fit together: connecting mismatched pieces or wrapping one value in another. Adapter and Decorator are examples.
- Stub
- A test stand-in that returns fixed answers, such as a clock that always says 4:00 p.m.
- Subject
- In the observer pattern, the object where events happen and whose listeners are notified, like the EventBus.
T
- Template method
- A pattern that fixes a job's steps in one place and leaves one step (a hook) for callers. It can be a closure argument or a trait default method calling required methods.
- Trait
- A named set of methods a type promises to have, written with `trait` and implemented with `impl`. It is Rust's interface and replaces inheritance for shared behavior.
- Trait object
- A value used through `dyn Trait`, usually in a `Box`, so different types can share one type. `Box<dyn Pricing>` holds any value implementing Pricing.
- Transition
- A move from one state to another in a state machine, such as Placed to Paid.
- Tree
- Pieces holding smaller pieces, down to single items, like a gift crate holding a box holding items. Composite builds a tree.
- Type explosion
- The growth of one new struct for every mix of choices: two choices make 4 types, three make 8, as with GiftWrappedWholesale.
U
- Undo stack
- A list of commands that have run, newest last, so Undo can pop and reverse the latest one.
- Unix time
- A time stored as the number of seconds since 1 January 1970 UTC. Orders store `placed` this way, and 1,792,771,200 is Oct 23, 2026, 16:00 UTC.
- unsafe
- A Rust keyword marking code the compiler can't fully check for safety. Changing a `static mut` needs it, so safer tools such as `OnceLock` or `Mutex` are used for shared global values instead.
W
- Wrapper
- A value that holds another and stands in front of it. Adapters, decorators and proxies are wrappers.
Y
- YAGNI (You aren't gonna need it)
- A design rule: don't build for a need until it's real, such as a factory "in case we ever sell tea".