3.2 KiB
3.2 KiB
Displays & Formatters
Definition
A Display encapsulates reusable, UI-only display logic.
In this codebase, we distinguish between Formatters (Stateless Logic) and Display Objects (Rich Value Objects).
1. Formatters (The "Mouth")
Formatters are pure, stateless utilities. They are the "Experts" on how to transform a raw value into a primitive string/number.
- Usage: Used by
ViewDataBuilders(Server) andViewModels(Client). - Output: MUST return primitive values only (
string,number,boolean,null). - Uncle Bob says: "Data structures (ViewData) should not have behavior. Keep logic in stateless utilities."
2. Display Objects (The "Rich API")
Display Objects are logic-rich Value Objects that live only on the client. They wrap data and provide multiple ways to look at it.
- Usage: Used by
ViewModels(Client) to provide a rich API to the UI. - Output: Can return complex objects or variants.
- Uncle Bob says: "Objects expose behavior, not data. Use them to hide the complexity of the UI."
Responsibilities
A Display/Formatter MAY:
- format values (money, dates, durations)
- handle deterministic localization (mapping stable codes to labels)
- encapsulate UI display conventions
A Display/Formatter MUST:
- be deterministic
- be side-effect free
- be implemented as a class with static methods (Formatters) or as immutable classes (Display Objects)
Restrictions
A Display/Formatter MUST NOT:
- contain business logic (e.g., "Team is full if count > 10")
- enforce domain invariants
- perform validation
- be serialized (only their primitive outputs are stored in
ViewData) - call
Intl.*ortoLocale*(unless explicitly marked for client-only ViewModels)
Relationship to ViewData and ViewModels
The "Primitive Compact" (Server-Side)
ViewDataBuilders MUST use Formatters to produce flat, serializable ViewData.
- Rule:
ViewDataproperties assigned from a Display/Formatter MUST be primitives. - Reason: Ensures
ViewDataremains a "dumb" JSON structure for SSR.
The "Rich API" (Client-Side)
ViewModels MAY use Display Objects to provide interactive formatting.
- Rule:
ViewModelscan returnDisplay Objectinstances to the UI. - Reason: Allows the UI to access multiple variants (e.g.,
date.short,date.relative) without re-fetching data.
Summary of the Flow
graph TD
DTO[Raw DTO] -->|ViewDataBuilder| VD[ViewData]
subgraph "Server: The Formatter Compact"
VD -->|Uses| F[Stateless Formatter]
F -->|Returns| S[Primitive string/number]
end
VD -->|SSR Boundary| T[Template]
subgraph "Client: The DisplayObject Richness"
T -->|Props| CW[ClientWrapper]
CW -->|new| VM[ViewModel]
VM -->|Wraps| DO[Rich Display Object]
DO -->|Provides| R[Rich API: .time, .relative, .date]
end
Final Rule: Where does logic live?
- Is it a business rule? (e.g., "Can join?") → ViewModel.
- Is it a formatting rule? (e.g., "How to show date?") → Formatter/Display.
- Is it for SEO/SSR? → ViewDataBuilder (using a Formatter).
- Is it for interaction? → ViewModel (using a Display Object).