Monday, August 22, 2022

Architecture

 A layered architecture is used to build applications based on domain-driven design. It consists of three main layers:

  • Domain
  • Application
  • Infrastructure


Domain Layer


A domain layer is used to encapsulate the domain model and its behavior. The domain model should not depend on anything else and it should be agnostic to the technicalities of the clients it serves and data stores that persist in the domain objects.

Application Layer

The application layer is used to process business use cases.

Infrastructure


The infrastructure layer is concerned with purely technical capabilities.



Sunday, August 21, 2022

Domain Service

Domain service is used to encapsulate business logic, which could not sit comfortably within an entity or aggregate in the system. Usually, a domain service is created then multiple entities are involved and behavior can't be owned by a single entity.

Characteristics


Every domain service has to match such characteristics:
  • Represent behavior
  • Stateless
  • No identity

public class PricingService : DomainService, IPricingService
{
    public Money CalculateTotalPriceFor(IList<item> items, Coupon coupon) 
    {
        // ...
    }
}


Application Service


Application services are used to implement the use cases of an application. They do not contain business logic. They are responsible for orchestration, for hydrating domain objects from a database and mapping.

The main difference between application service and domain services is that domain service holds domain logic where application services don’t.

public interface ProfileService : ApplicationService, IProfileService
{
    public Task<Profile> CreateProfileAsync(string username)
    {
        // ...
    }

    public Task<Profile?> GetProfileAsync(int id, CancellationToken cancellationToken)
    {
        // ...
    }
}

Application services are similar to ASP.NET  Core controller actions. Controller actions contain logic to control the user interface interactions in the same manner that application services contain logic that represents business tasks or use cases that coordinate communication with services and objects within the domain layer.

In case then ASP.NET  Core controllers are used, there is no need to created dedicated application controllers. Controllers can be used as application services to implement use cases of an application.

As an alternative, commands can be used to process business use cases.


Infrastructure Service


Infrastructure Services is used to abstract technical concerns. The are responsible notifying other systems of changes in domain state via messaging systems or web calls, authorization, and logging.

public class MailService : InfrastructureService, IMailService
{
    public virtual async Task SendMailAsync(MailMessage mailMessage)
    {
        // ...
    }
}

Wednesday, August 3, 2022

Value Object

One of the domain modeling building blocks is a value object. Value objects are an entity's state, describing something about the entity or the things it owns.

Value objects are always preferred over entities because they are immutable and lightweight. Due this reason, it is easy to work with them.

In the .NET world, records are good candidates to implement value objects. Below, you can see how a value object can look implemented in C#.


public record Money
{
    public decimal Amount { get; init; }

    public Money(decimal amount)
    {
        if (amount % 0.01m != 0)
        {
            throw new ArgumentException("More than two decimal places", nameof(amount));
        }

        Amount = amount;
    }

    public Money Add(Money value)
    {
        return new Money(Amount + value.Amount);
    }

    public Money Substract(Money value)
    {
        return new Money(Amount - value.Amount);
    }
}

Characteristics

Every value object has to match such characteristics:

  • Identity-Less
  • Attribute-Based Equality
  • Immutable
  • Behavior-Rich
  • Self-Validating

Now let's dive deep into each value objects characteristics. 

Identity-Less

Value objects have no identity.

Attribute-Based Equality

Value objects are considered equal if they have the same value.

var a = new Money(10M);
var b = new Money(10M);
Console.WriteLine(a == b); // True

Immutable

Once created, a value object can not be changed.

var a = new Money(10M);
a.Amount = 12M; // Can't be assigned

Behavior‐Rich

As much as possible, value objects should expose expressive domain‐oriented behavior and encapsulate the state.

var a = new Money(10M);
var b = a.Substract(new Money(2M));
Console.WriteLine(b); // Money { Amount = 8 }

Self‐Validating

Value objects should never be in an invalid state.

var a = new Money(10.0348M); // Throws exception "More than two decimal places"