BeyondNet.Ddd, Understanding Value Object
The ValueObject
class in the BeyondNet.Ddd library is a foundational element for developers implementing Domain-Driven Design (DDD) in C# and . NET. This class encapsulates the essence of DDD value objects, immutable objects identified by their values rather than identity.
Key Characteristics of the ValueObject
Class:
Immutability: Value objects are immutable by design, meaning their state cannot change after instantiation. This ensures predictability and consistency in business logic.
Equality Comparison: The class overrides equality operators (
==
and!=
) and implementsEquals
andGetHashCode
methods. This enables accurate comparisons between instances based on their values, a crucial concept in DDD since value objects do not have a distinct identity.Ease of Use: Developers can derive their value objects by inheriting from this base class, simplifying the process of managing domain logic through consistent patterns.
Error Reduction: Using value objects helps in reducing bugs by encapsulating complex logic within domain-driven structures, promoting a more maintainable codebase.
This class is part of a broader library designed to assist developers with strategic and tactical DDD principles, including bounded contexts, aggregates, and repositories. The emphasis on following DDD patterns ensures better alignment between software design and the underlying business domain, improving communication and maintainability in the process.
If you’d like to dive deeper into this library and see examples of how to use it in practical projects, visit the repository’s main page here or explore sample projects linked within the documentation.
Building a Simple ValueObject named SampleName
The SampleName
class from the BeyondNet.Ddd library showcases the use of the ValueObject
concept in a practical way. In this class, the domain concept of a "name" is modeled as a value object. This means the identity of the object is based solely on its values—like FirstName
and LastName
—rather than an identifier. It ensures immutability, meaning once created, its values cannot change, and it implements equality comparison through overrides of methods like Equals
.
This approach encourages clarity and consistency in code, following Domain-Driven Design principles. You can explore the full code here.
using BeyondNet.Ddd.ValueObjects.Common;
namespace BeyondNet.Ddd.Test.Entities
{
public class SampleName : StringValueObject
{
private SampleName(string value) : base(value)
{
}
public static SampleName Create(string value)
{
return new SampleName(value);
}
public static SampleName Default()
{
return new SampleName(string.Empty);
}
public override void AddValidators()
{
base.AddValidators();
var validator = new SampleNameValidator(this);
AddValidator(validator);
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return GetValue();
}
}
}
Now, How we can apply Validation Rules
The SampleNameValidator
class in BeyondNet.Ddd demonstrates how to apply validation logic using the AbstractRuleValidator
. This validator ensures the SampleName
object follows specific rules, such as non-empty FirstName
and LastName
. You can extend AbstractRuleValidator
to define domain-specific validations, centralizing logic to avoid scattered checks. If any rule fails, validation errors are returned, making it easy to enforce consistency across the system.
using BeyondNet.Ddd.Rules;
using BeyondNet.Ddd.Rules.Impl;
namespace BeyondNet.Ddd.Test.Entities
{
public class SampleNameValidator : AbstractRuleValidator<ValueObject<string>>
{
public SampleNameValidator(ValueObject<string> subject) : base(subject)
{
}
public override void AddRules(RuleContext? context)
{
var value = Subject.GetValue();
if (string.IsNullOrWhiteSpace(value))
{
AddBrokenRule("Value", "The value cannot be null or empty.");
}
if (value.Length > 100)
{
AddBrokenRule("Value", "The value cannot be longer than 100 characters.");
}
if (value.Length < 5)
{
AddBrokenRule("Value", "The value cannot be shorter than 5 characters.");
}
}
}
}
Conclusion
The SampleName
class from the BeyondNet.Ddd library illustrates the use of value objects by encapsulating names with immutability and equality logic. It aligns with Domain-Driven Design principles, ensuring that instances are compared based on their values. This approach promotes code clarity, consistency, and maintainability across applications. You can integrate it with validation mechanisms, such as the, to enforce domain-specific rules effectively. In the next post, I will explain to you in detail how is built the ValueObject class inside the library BeyondNet.Ddd and how it is related to all the rest of the components.
Subscribe to my newsletter
Read articles from Alberto Arroyo Raygada directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Alberto Arroyo Raygada
Alberto Arroyo Raygada
Dynamic and motivated professional with a proven record of generating and building software, from concept to implementation, designing architectures, and coaching teams to technical improvement skilled in building cross-functional teams, demonstrating communication skills, and making critical decisions during challenges. I am an adaptable and transformational leader who can work independently, create effective presentations, and develop opportunities that further establish organizational goals. Technical Skills C#, NET Core, NET, NodeJS, NestJS, JavaScript, TypeScript, React, NextJS, Tailwind, Langchain, TFS, Azure DevOps, Kubernetes, Azure and AWS. Business and Management Skills Experience with Agile Projects, Senior Analyst, Technical Lead, Lead Process, Software Manager, and Technical Manager, experience working on Supply Chain, WMS, TMS, YMS, CMMS, BMS, OMS, Foreign Trade, Retail, e-commerce and Direct Sales, Lead Management for Assurance, FinTech and Learning Management.