implement-value-object
Creates immutable domain value objects using frozen dataclass pattern with validation. Use when implementing domain value objects, creating immutable data structures, or adding validation to values. Covers @dataclass(frozen=True), object.__setattr__() pattern in __post_init__, factory methods (from_string, from_dict, from_content), and validation in frozen context. Triggers on "create value object for X", "implement immutable Y value", "add validation to Z value", or "build value object".
What this skill does
Works with Python dataclasses in domain/value_objects/ and domain/values/ directories.
# implement-value-object
## Purpose
Create immutable domain value objects using the frozen dataclass pattern with proper validation, factory methods, and immutability guarantees enforced at the type system level.
## When to Use
Use this skill when:
- **Implementing domain value objects** - Creating validated, immutable domain concepts
- **Creating immutable data structures** - Building type-safe value containers
- **Adding validation to values** - Ensuring domain constraints are enforced
**Trigger phrases:**
- "Create a value object for X"
- "Implement immutable Y value"
- "Add validation to Z value"
- "Build value object with validation"
## Quick Start
Create immutable domain value objects using the frozen dataclass pattern with proper validation, factory methods, and immutability guarantees enforced at the type system level.
**Most common use case:**
For a simple validated value object:
```python
from dataclasses import dataclass
@dataclass(frozen=True)
class EmailAddress:
"""Immutable email address value object."""
value: str
def __post_init__(self) -> None:
"""Validate email format."""
if not self.value:
raise ValueError("Email address cannot be empty")
if "@" not in self.value:
raise ValueError(f"Invalid email format: {self.value}")
```
## Table of Contents
### Core Sections
- [Purpose](#purpose) - Immutable domain value objects with frozen dataclass pattern
- [Instructions](#instructions) - Complete implementation guide
- [Step 1: Define Frozen Dataclass](#step-1-define-frozen-dataclass) - Basic immutable structure
- [Step 2: Add Validation in __post_init__](#step-2-add-validation-in-__post_init__) - Validation while respecting immutability
- [Step 3: Add Factory Methods](#step-3-add-factory-methods) - Convenient constructors for different input types
- [Step 4: Add String Representations](#step-4-add-string-representations) - Useful string representations
- [Step 5: Add Domain Behavior](#step-5-add-domain-behavior) - Methods expressing domain operations
- [Step 6: Add Type Hints and Documentation](#step-6-add-type-hints-and-documentation) - Full type safety
- [Examples](#examples) - 4 production-ready patterns
- [Example 1: Simple String Value Object](#example-1-simple-string-value-object) - Basic validation pattern
- [Example 2: Path Value Object with Normalization](#example-2-path-value-object-with-normalization) - Type coercion in frozen context
- [Example 3: Hash Value Object with Factory](#example-3-hash-value-object-with-factory) - Computing values from content
- [Example 4: Multi-Field Value Object with Validation](#example-4-multi-field-value-object-with-validation) - Complex constraints
### Advanced Topics
- [Requirements](#requirements) - Dependencies and environment setup
- [Common Patterns](#common-patterns) - Reusable implementation patterns
- [Pattern: Computed Properties](#pattern-computed-properties) - Derived values with @property
- [Pattern: Type Coercion in Frozen Context](#pattern-type-coercion-in-frozen-context) - Ensuring type consistency
- [Pattern: Validation with Custom Errors](#pattern-validation-with-custom-errors) - Clear error messages
- [Pattern: Serialization](#pattern-serialization) - Dictionary conversion support
- [Testing Value Objects](#testing-value-objects) - Test strategies for validation, immutability, equality, factories, serialization
- [File Locations](#file-locations) - Domain layer placement conventions
- [See Also](#see-also) - Templates, examples, architecture references
### Utility Scripts
- [Convert to Value Object](./scripts/convert_to_value_object.py) - Analyze codebase to suggest value object candidates
- [Generate Value Object](./scripts/generate_value_object.py) - Generate value objects with validation, factory methods, and tests
- [Validate Value Objects](./scripts/validate_value_objects.py) - Validate value object patterns in the codebase
## Purpose
Create immutable domain value objects using the frozen dataclass pattern with proper validation, factory methods, and immutability guarantees enforced at the type system level.
## Instructions
### Step 1: Define Frozen Dataclass
Create the basic immutable structure:
```python
from dataclasses import dataclass
@dataclass(frozen=True)
class YourValueObject:
"""Immutable value object representing [domain concept].
Encapsulates [what logic/behavior].
"""
value: str # Primary value
# Optional additional fields for metadata
```
**Key points:**
- Always use `@dataclass(frozen=True)` for immutability
- Add comprehensive docstring explaining domain meaning
- Use `value` as primary field name for simple value objects
- All fields are immutable after construction
### Step 2: Add Validation in __post_init__
Validate constraints while respecting immutability:
```python
def __post_init__(self) -> None:
"""Validate value object constraints."""
# Validation checks (raise ValueError on failure)
if not self.value:
raise ValueError("Value cannot be empty")
# For type coercion or normalization in frozen context:
if not isinstance(self.value, ExpectedType):
object.__setattr__(self, "value", ExpectedType(self.value))
# For normalization (e.g., path resolution):
object.__setattr__(self, "value", self.normalize(self.value))
```
**CRITICAL: Modifying Frozen Dataclass Fields**
Since `frozen=True` prevents normal attribute assignment, use `object.__setattr__()` to modify fields during `__post_init__`:
```python
# ❌ WRONG - Will raise FrozenInstanceError
def __post_init__(self) -> None:
self.value = self.value.lower() # FAILS with frozen=True
# ✅ CORRECT - Use object.__setattr__()
def __post_init__(self) -> None:
object.__setattr__(self, "value", self.value.lower())
```
**Validation patterns:**
- Empty checks: `if not self.value: raise ValueError(...)`
- Format validation: `if not re.match(pattern, self.value): raise ValueError(...)`
- Type coercion: `object.__setattr__(self, "field", Type(field))`
- Normalization: `object.__setattr__(self, "value", normalized_value)`
### Step 3: Add Factory Methods
Provide convenient constructors for different input types:
```python
@classmethod
def from_string(cls, value_str: str) -> "YourValueObject":
"""Create from string representation.
Args:
value_str: String to parse
Returns:
YourValueObject instance
"""
return cls(value=value_str)
@classmethod
def from_dict(cls, data: dict) -> "YourValueObject":
"""Create from dictionary representation.
Args:
data: Dictionary with value object data
Returns:
YourValueObject instance
"""
return cls(value=data["value"])
@classmethod
def from_content(cls, content: str) -> "YourValueObject":
"""Create from raw content (e.g., compute hash).
Args:
content: Raw content to process
Returns:
YourValueObject instance
"""
# Process content (e.g., hash it)
processed = process(content)
return cls(value=processed)
```
**Common factory method patterns:**
- `from_string()` - Parse string representation
- `from_dict()` - Deserialize from dictionary
- `from_content()` - Compute value from content (hashes)
- `from_components()` - Build from multiple parts
- `from_bytes()` - Create from binary data
### Step 4: Add String Representations
Provide useful string representations:
```python
def __str__(self) -> str:
"""User-friendly string representation.
Returns:
The value as a string
"""
return str(self.value)
def __repr__(self) -> str:
"""Developer-friendly representation.
Returns:
String showing class and value
"""
return f"YourValueObject('{self.value}')"
```
**For long values (like hashes), truncate in __repr__:**
```python
def __repr__(self) -> str:
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.