Rust Design Patterns

repository·main·Indexed 27 days ago

https://github.com/rust-unofficial/patterns

An open source book containing design patterns, anti-patterns, and idioms for the Rust programming language. It covers SOLID principles, the Composite Reuse Principle, and other software design guidelines, while providing specific guidance on avoiding common Rust anti-patterns such as 'Clone to satisfy the borrow checker', misuse of Deref for polymorphism, and global deny(warnings) in crate roots.

Tokens
27.2K
Snippets
55
Records
92
Agent score
93%

What's inside rust-unofficial-patterns

  1. Explore FFI design patterns in Rust

    main

    When writing Foreign Function Interface (FFI) code in Rust, use specific design patterns to manage the boundary between safe and unsafe code and to ensure memory safety. This repository provides guidance on two primary approaches:

    1. Object-Based API Design: Focuses on creating APIs with strong memory safety characteristics and a clear distinction between safe and unsafe boundaries.
    2. Type Consolidation into Wrappers: Involves grouping multiple Rust types into a single opaque "object" to simplify the interface presented to foreign code.
  2. Understand the difference between Imperative and Declarative paradigms

    main

    In Rust, the distinction between imperative and declarative programming lies in whether you describe how to perform a task (steps and state changes) or what the desired outcome is (composing functions).

    Imperative Paradigm

    Focuses on explicit steps, manual state management, and loops. You define a mutable variable and update it through iterations.

    Declarative Paradigm

    Focuses on describing the transformation of data. Instead of loops, you use higher-order functions like fold to compose operations over a collection or range.

  3. Follow CQS and Principle of Least Astonishment (POLA)

    main

    Ensure predictable and clean function behavior:

    • Command-Query-Separation (CQS): Separate functions into two categories: Commands (procedures that produce side effects) and Queries (functions that return data but do not produce abstract side effects).
    • Principle of Least Astonishment (POLA): Design components to behave in a way that is expected by users; behavior should not be surprising.
  4. Use Design by Contract (DbC) and Encapsulation

    main

    Manage component interfaces and data integrity using these techniques:

    • Design by Contract (DbC): Define formal, precise, and verifiable interface specifications using preconditions, postconditions, and invariants.
    • Encapsulation: Bundle data with the methods that operate on it and restrict direct access to an object's components to hide internal state and prevent unauthorized access.
  5. Understand the structure of Rust Design Patterns

    main

    The Rust Design Patterns repository is organized into three primary categories to help developers write better Rust code:

    • Idioms: Guidelines and community 'social norms' to follow when coding in Rust.
    • Design patterns: Reusable and tested methods for solving common engineering problems.
    • Anti-patterns: Common methods that appear to solve problems but actually create more issues and should be avoided.

    When applying patterns, focus on the trade-offs and the reasoning behind choosing a specific pattern rather than just the implementation details.

  6. Apply Bertrand Meyer's software design principles

    main

    The following principles focus on modularity and system consistency:

    • Linguistic-Modular-Units: Modules must correspond to syntactic units in the language used.
    • Self-Documentation: Strive to make all information about a module part of the module itself.
    • Uniform-Access: All services offered by a module should be available through a uniform notation, regardless of whether they are implemented via storage or computation.
    • Single-Choice: When a system supports alternatives, only one module should know the exhaustive list of those alternatives.
    • Persistence-Closure: When storing an object, the mechanism must also store its dependents. When retrieving an object, it must also retrieve any dependents that have not yet been retrieved.
  7. Understand SOLID design principles

    main

    SOLID is an acronym representing five key principles of object-oriented design intended to make software designs more understandable, flexible, and maintainable:

    • Single Responsibility Principle (SRP): A class should have only one reason to change, meaning it should only have a single responsibility.
    • Open/Closed Principle (OCP): Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
    • Liskov Substitution Principle (LSP): Objects in a program should be replaceable with instances of their subtypes without altering the correctness of the program.
    • Interface Segregation Principle (ISP): It is better to have many client-specific interfaces than one general-purpose interface.
    • Dependency Inversion Principle (DIP): Depend upon abstractions rather than concretions.
  8. Understand Functional Language Optics in Rust

    main
    Optics is a functional programming concept used for composing behavior and properties. In Rust, while not natively supported as a primary language feature, the concept is used to facilitate patterns involving failure, type transformation, and composability. Understanding optics can help clarify complex Rust APIs like Serde or the Visitor pattern.
  9. Apply DRY, KISS, and Law of Demeter principles

    main

    Use these principles to manage complexity and coupling:

    • DRY (Don’t Repeat Yourself): Ensure every piece of knowledge has a single, unambiguous, authoritative representation within a system.
    • KISS (Keep It Simple, Stupid): Aim for simplicity in design and avoid unnecessary complexity.
    • Law of Demeter (LoD): An object should assume as little as possible about the structure or properties of other objects (including subcomponents) to support information hiding.