Skip to main content

Value Objects

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Component Details
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendix

Introduction

This document revolves around the concept and implementation of "value objects", combining commands, snapshots, entities, and repositories in the repository to systematically explain the role of value objects in domain-driven design, immutability design, equality comparison, constructor validation, data encapsulation, and business semantic expression. It also provides practices for creation, validation, serialization, composition and nested structures, performance optimization, and best practices.

Project Structure

This repository adopts an organization method based on functional domains and layers, with key locations related to value objects as follows:

  • Command and snapshot interfaces and implementations are located in the entity package
  • Value objects are used in combination in entity structs and persisted and read through the repository layer
  • Tool classes provide naming conversion and type conversion capabilities to assist in value object serialization and mapping
  • Command: Unifies command identity and aggregate root identity, providing a basic command struct to ensure system consistency and serialization mapping.
  • Snapshot: Abstracts the snapshot interface and generic implementation of aggregate state, providing serialization/deserialization capabilities for event sourcing recovery.
  • Entity: Entity interface and base entity struct, carrying the combination and persistence of value objects.
  • Repository: SQL repository's recursive extraction and mapping of value object fields, ensuring consistency in reading and writing nested structures.
  • Utils: Naming conversion and type conversion, assisting in value object field serialization and database mapping.

The interaction path of value objects in the system is as follows: After a command enters the system, the aggregate root applies the event, the event is persisted; at the same time, a snapshot can be generated to accelerate recovery; the entity layer carries value object combinations and is persisted and queried through the repository.

Command and Snapshot Design Patterns

  • The command interface and base command struct ensure all commands have a unified command identity and aggregate root identity, avoiding systematic exceptions caused by duplicate implementations.
  • The snapshot interface abstracts the reading, version, creation time, and serialization/deserialization capabilities of aggregate state; the generic implementation supports snapshot storage and recovery of any aggregate state.
  • Value objects express business semantics through struct fields, such as Address and ContactInfo, with the latter nesting the former to reflect composition relationships.
  • Entity (UserWithValueObjects) combines value objects, carries their business meaning, and is persisted and read in the repository.
  • Creation: Initialize value objects through struct literals, with constructor-level validation in upper-level logic if necessary.
  • Validation: Validation rules can be extended through template-generated aggregate roots or business layers to ensure value object fields meet business constraints.
  • Serialization: Snapshots provide Marshal/Unmarshal; the repository layer recursively extracts and maps value object fields to ensure consistency in serialization/deserialization.
  • Nested Structure: ContactInfo contains Address, and the repository maps nested fields to database columns like contact_info_email, contact_info_address_street through recursive field extraction functions.
  • Database Mapping: Test cases demonstrate how to map nested fields to columns, ensuring consistent reading and writing.
  • Immutability: Value objects should be designed as read-only structs to avoid modifying their internal state during their lifecycle, thereby reducing concurrency and side effect risks.
  • Equality: Perform structural equality comparison based on the field collection of value objects, avoiding reference equality; custom comparison logic can be implemented when needed to meet business semantics.

[This section is conceptual content and does not directly analyze specific files]

Constructor Validation

  • It is recommended to perform parameter validation during the construction phase of value objects to ensure fields meet business constraints; for complex validation, it can be handled uniformly in the upper-level aggregate root or service layer.

[This section is conceptual content and does not directly analyze specific files]

Dependency Analysis

  • Command and Snapshot: As domain layer contracts, they are indirectly relied upon by repositories and event/snapshot storage.
  • Entity and Repository: Entities combine value objects, and repositories are responsible for recursive extraction and mapping of value object fields.
  • Tools: Naming conversion and type conversion assist in value object field serialization and database mapping.
  • The nesting depth and number of fields of value objects will affect the overhead of serialization/deserialization and database mapping; it is recommended to reasonably split value objects to avoid excessive nesting.
  • The field extraction of the repository uses reflection recursion, so attention should be paid to performance impact in high-frequency scenarios; consider caching field metadata or reducing unnecessary serialization.
  • The serialization/deserialization cost of snapshots is related to the size of the aggregate state; it is recommended to generate snapshots regularly and optimize recovery performance with event replay strategies.

[This section provides general guidance and does not directly analyze specific files]

Troubleshooting Guide

  • Value Object Field Mapping Abnormalities: Check whether the repository field extraction function is consistent with the database column name mapping, and confirm the naming rules for nested fields.
  • Snapshot Serialization Failure: Confirm the serializability of the snapshot State, avoiding unexportable fields or circular references.
  • Command and Aggregate Root Identity Inconsistency: Follow the basic command struct conventions to avoid system exceptions caused by custom aggregate root identity fields.

Value objects are an important part of the domain model. Through clear business semantic encapsulation, reasonable composition and nesting, strict constructor validation, and serialization strategies, they can significantly improve the maintainability and evolvability of the system. Combined with the collaboration of commands, snapshots, and repositories, a stable and efficient event sourcing and query separation architecture can be built.

[This section is summary content and does not directly analyze specific files]

Appendix