| name | architecture-design |
| description | Use when designing module placement, type design, and API surface for new features in rvlibs. Load during the Design phase of SDLC. |
architecture-design
SDLC Phase: Design
Design the architecture, module placement, type system, and API surface for new features.
Principles
- Module placement first — Before writing any code, decide where it lives: new crate, new submodule, or existing module.
- Single responsibility — Every module should answer to one concern. If you cannot describe a module's purpose in one sentence, it is doing too much.
- Minimal public surface — Expose only what other crates need. Everything else is
pub(crate) or private.
- Zero circular deps — The dependency graph must remain a DAG. Shared types go in
rvlibs.
- Generic by default — Write functions over traits unless there is a concrete reason not to.
Module Placement Decision Tree
| Where | When | Example |
|---|
New crate (crates/) | Distinct capability, no circular dep risk | Adding a physics engine would be rvphysic |
| New submodule | Related to existing crate, extends its scope | Adding B-spline interpolation to rvmath |
| Existing module | Belongs to an existing concern | Adding a new shape formula to geometry |
Shared contract (rvlibs) | Type/trait needed by 2+ crates | Error types, Result<T>, Version |
Not preemptive — Do not create new crates speculatively. A crate is created only when concrete code demands extraction.
Type Design Guidelines
- Use newtypes for type safety over raw primitives (e.g.,
NodeId(usize) in graph module).
- Implement standard traits:
Debug, Clone, PartialEq where semantically valid.
- Prefer
pub fields over getters/setters for simple data structs. Use getters only when the field has invariants.
- For generic types, choose meaningful constraints. Prefer trait bounds on
impl blocks rather than on struct definitions.
- Use const generics for fixed-size dimensions (
VecN<T, N>, MatN<T, R, C>).
Trait Design Guidelines
- A trait should represent one capability. If it has 5+ methods, consider splitting.
- Prefer static dispatch (generics) over
dyn trait objects unless dynamic dispatch is explicitly needed.
- Provide blanket impls where useful (e.g.,
Numeric impls for all standard numeric primitives).
- Traits that combine multiple capabilities should extend sub-traits.
API Surface Guidelines
- All public items must have doc comments (
///) explaining what they do, with an example where helpful.
- Fallible functions return
Result<T, String> or rvlibs::Result<T>. Panics are reserved for programming errors.
- Builder patterns consume
self and return Self. The terminal method is .build(), .run(), or .finish().
- Re-export key types in a
prelude module for ergonomic one-line access.
Output Requirements
A design brief covering:
- Module placement — Where does the code live and why?
- Type definitions — All new structs, enums, and their fields
- Trait definitions — All new traits and their method signatures
- Public API — Every exported function signature
- Integration — How it connects to existing modules
- Dependencies — Any new external dependencies and why they are needed