Value Objects

Value objects are immutable, strongly typed domain objects that encapsulate a single value. They help combat stringly typed code and “primitive obsession.” ^1

Value objects are a fundamental concept in Domain-Driven Design (DDD). They provide a way to model the business domain in a way that is clear, concise, and robust.

Why Use Value Objects?

  • Stronger typing: Value objects provide a more expressive and type-safe way to represent domain concepts. The compiler enforces the type of the value object, preventing runtime errors.
  • Immutability: Value objects are immutable. This means that once a value object is created, its value cannot be changed. This helps to prevent accidental data corruption and makes your code more predictable.
  • Encapsulation: Value objects encapsulate the logic for validating and manipulating the underlying value. This makes your code easier to understand and maintain.

Example of a Value Object

Consider the example of a customer ID. A customer ID is a unique identifier that can be used to track a customer. Using an int to represent a customer ID can lead to problems:

public void DoSomething(int customerId, int supplierId, int amount)
          

The compiler won’t warn you if you accidentally swap customerId and supplierId.

Using a value object, the method signature becomes much more strongly typed:

public void DoSomething(CustomerId customerId, SupplierId supplierId, Amount amount) 
          

Now the caller can’t mess up the order of parameters, and the objects themselves are guaranteed to be valid and immutable.

Implementing a Value Object

public class CustomerId : ValueObject
          {
          }
          

This example shows how a CustomerId is defined. CustomerId derives from the package’s ValueObject type. Value objects can have validation as well:

public class CustomerId : ValueObject
          {
              public override Validation Validate() => Value > 0 
                  ? Validation.Ok 
                  : Validation.Invalid("Customer IDs cannot be zero or negative.");
          }
          

Using Value Objects

Instead of using an int to represent a customer ID, we can now use the CustomerId value object:

var customerId = CustomerId.From(42); 
          

Benefits of Value Objects

  • Improved code readability: Using value objects makes your code easier to read and understand.
  • Reduced code duplication: Validation is in one place.
  • Increased testability: Value objects are easier to test than primitives.
  • Improved domain modeling: Value objects help you model the business domain in a way that is more accurate and expressive.

Resources:

Note:

The code in this outline is taken from the stringlytyped repository and related files. ^1 ^2


          ## Top-Level Directory Explanations
          
          <a class='local-link directory-link' data-ref="samples/" href="#samples/">samples/</a> - This directory contains example projects demonstrating the usage of StringlyTyped library.
          
          <a class='local-link directory-link' data-ref="src/" href="#src/">src/</a> - This directory contains the source code of the StringlyTyped library.
          
          <a class='local-link directory-link' data-ref="tests/" href="#tests/">tests/</a> - This directory contains unit tests for the StringlyTyped library. It includes benchmark tests and small tests.