DEV Community

Sebastian Van Rooyen
Sebastian Van Rooyen

Posted on

Introduction to Domain-Driven Design (DDD) in C#

Domain-Driven Design (DDD) is a powerful approach to software development that emphasizes the importance of modeling the business domain and using that model to drive the design of your software. For developers new to DDD, it can seem complex at first, but understanding its core principles can significantly improve the quality and maintainability of your software. In this article, we'll explore DDD concepts and how to apply them using C#.

What is Domain-Driven Design?

DDD is a methodology for designing and developing complex software systems. It focuses on:

  1. Modeling the Domain: Creating a shared understanding of the business problem you're solving.
  2. Ubiquitous Language: Using a common language between developers and domain experts.
  3. Bounded Contexts: Dividing the system into distinct areas, each with its own model and rules.
  4. Entities and Value Objects: Defining the core objects in your domain and how they interact.
  5. Aggregates: Grouping related entities and ensuring their consistency.
  6. Repositories: Managing the retrieval and storage of aggregates.

Basic Concepts of DDD

1. Ubiquitous Language

In DDD, the ubiquitous language is a shared vocabulary that both developers and domain experts use. This language should be used consistently throughout the codebase to ensure clarity and alignment.

2. Entities and Value Objects

  • Entities are objects that have a distinct identity and lifecycle. They are defined by their identity rather than their attributes.
  • Value Objects are objects that represent a descriptive aspect of the domain with no distinct identity. They are immutable.

3. Aggregates

An aggregate is a cluster of entities and value objects that are treated as a single unit for data changes. Each aggregate has a root entity, known as the aggregate root, which ensures the consistency of the aggregate.

4. Repositories

Repositories are responsible for retrieving and storing aggregates. They abstract away the details of data access and provide a way to access aggregates based on their identity.

Implementing DDD in C

Let's illustrate these concepts with a simple example in C#. Suppose we're building a system for managing an online bookstore.

Define Entities and Value Objects

public class Book
{
    public int Id { get; private set; }
    public string Title { get; private set; }
    public string Author { get; private set; }
    public decimal Price { get; private set; }

    public Book(int id, string title, string author, decimal price)
    {
        Id = id;
        Title = title;
        Author = author;
        Price = price;
    }

    // Method to update the price
    public void UpdatePrice(decimal newPrice)
    {
        Price = newPrice;
    }
}

public class Money
{
    public decimal Amount { get; private set; }
    public string Currency { get; private set; }

    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }

    public override string ToString()
    {
        return $"{Amount} {Currency}";
    }
}
Enter fullscreen mode Exit fullscreen mode

Define Aggregates

In this example, Book can be an aggregate root. For simplicity, let's assume that Book is the only entity in our aggregate.

Define Repositories

public interface IBookRepository
{
    Book GetById(int id);
    void Add(Book book);
    void Remove(Book book);
}

public class BookRepository : IBookRepository
{
    private readonly Dictionary<int, Book> _books = new Dictionary<int, Book>();

    public Book GetById(int id)
    {
        return _books.TryGetValue(id, out var book) ? book : null;
    }

    public void Add(Book book)
    {
        _books[book.Id] = book;
    }

    public void Remove(Book book)
    {
        _books.Remove(book.Id);
    }
}
Enter fullscreen mode Exit fullscreen mode

Applying DDD Principles

  1. Model the Domain: Create classes that represent entities and value objects. Ensure that these classes reflect the real-world concepts of your domain.
  2. Use a Ubiquitous Language: Use the same terms in your codebase and discussions as those used by domain experts.
  3. Define Aggregates: Ensure that changes to related entities are managed through aggregate roots.
  4. Implement Repositories: Abstract the data access logic and provide methods to work with aggregates.

Conclusion

Domain-Driven Design helps you build software that closely aligns with business requirements by focusing on the domain model. By using DDD principles such as ubiquitous language, aggregates, and repositories, you can create a more maintainable and understandable codebase.

Remember, DDD is a large topic with many advanced concepts, so start small and gradually incorporate more practices as you become more comfortable with the methodology. Happy coding!

Top comments (0)