DDD and Microservices
In this article, learn basic concepts of Domain-Driven Design, and explore basic examples of microservices applied with DDD principles.
Join the DZone community and get the full member experience.
Join For FreeDomain-Driven Design (DDD) is a software development methodology that emphasizes the importance of modeling a software system based on the real-world domain it represents. DDD is particularly useful for complex applications with intricate business logic. It was introduced by Eric Evans in his book “Domain-Driven Design: Tackling Complexity in the Heart of Software.”
Basic Concepts in DDD
- Domain: The central focus of DDD is the domain, which represents the core business problem that the software addresses.
- Entities: These are objects with distinct identities and lifecycles within the domain. They have attributes and behaviors.
- Value objects: Value objects are objects without distinct identities. They represent attributes that are conceptually distinct within the domain.
- Aggregates: Aggregates are groups of related entities and value objects treated as a single unit. They are often responsible for enforcing consistency and maintaining data integrity. In other words, you are creating meaningful relations between two or more value objects.
- Repositories: Repositories provide an abstraction for data access, allowing the application to interact with aggregates.
- Services: Services represent actions or behaviors that don’t naturally belong to a single entity or value object.
- Bounded contexts: A bounded context defines a specific, self-contained part of the domain where the domain model and its concepts have clear and consistent meanings.
DDD helps developers create software that is closely aligned with the business domain, making it easier to understand, maintain, and evolve over time.
Let's look at some basic examples of each thing we discussed above:
Entities
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
// Other customer properties and methods
}
public class Account
{
public int AccountId { get; set; }
public int CustomerId { get; set; }
public decimal Balance { get; set; }
// Other properties and methods related to the account
}
Value Objects
public class Money
{
public decimal Amount { get; set; }
public string Currency { get; set; }
// Methods for currency conversion, addition, etc.
}
Aggregate Roots
public class CustomerAggregate
{
//properties to create relation between customer and accounts
public Customer Customer { get; set; }
public List<Account> Accounts { get; set; }
// Methods to manage customer's accounts
}
Repositories
public interface ICustomerRepository
{
Customer GetCustomer(int customerId);
void AddCustomer(Customer customer);
void UpdateCustomer(Customer customer);
}
public interface IAccountRepository
{
Account GetAccount(int accountId);
void AddAccount(Account account);
void UpdateAccount(Account account);
}
Microservice Architecture
Microservice architecture is an architectural style where a large software application is divided into small, independent loosely coupled services. These services are responsible for specific, well-defined functionality and can communicate with each other over the network. Microservices allow for the development, deployment, and scaling of individual services independently, providing benefits like agility, scalability, and maintainability.
Key Features of Microservices
- Independence: Each microservice is responsible for a specific business function, allowing development teams to work independently on different services.
- Decentralization: Microservices can be developed and deployed using various technologies and can run on different platforms.
- Loose coupling: Microservices communicate through well-defined APIs, often using lightweight protocols like HTTP or message queues.
- Scalability: Individual microservices can be scaled independently to handle varying levels of load.
- Resilience: Failure in one microservice doesn’t necessarily impact the entire system since other services can continue to function.
- Continuous deployment: Microservices can be updated and deployed without affecting other parts of the application.
Microservice architecture is especially suitable for large and complex systems where different parts of the application have distinct scaling, maintenance, or technology requirements. It can enhance agility and enable organizations to iterate and innovate more rapidly.
Both DDD and microservices aim to create software that aligns closely with business needs, but they focus on different aspects of software design and architecture. DDD is about modeling the domain and designing the core of the software, while microservices address how to structure the software into separate, independently deployable components. These two concepts can be used together to build scalable, maintainable, and business-focused software systems.
Now, let's create microservices to manage customers and accounts.
Customer Service
public class CustomerService
{
private readonly ICustomerRepository _repository;
public CustomerService(ICustomerRepository repository)
{
_repository = repository;
}
public Customer GetCustomer(int customerId)
{
return _repository.GetCustomer(customerId);
}
public void CreateCustomer(Customer customer)
{
_repository.AddCustomer(customer);
}
}
// HTTP endpoint using ASP.NET Web API
[Route("api/customers")]
public class CustomerController : ApiController
{
private readonly CustomerService _customerService;
public CustomerController(CustomerService customerService)
{
_customerService = customerService;
}
[HttpGet]
public IHttpActionResult GetCustomer(int customerId)
{
var customer = _customerService.GetCustomer(customerId);
return Ok(customer);
}
[HttpPost]
public IHttpActionResult CreateCustomer(Customer customer)
{
_customerService.CreateCustomer(customer);
return Created(Request.RequestUri, customer);
}
}
Account Service
public interface IAccountService
{
Account GetAccount(int accountId);
void CreateAccount(Account account);
}
public class AccountService: IAccountService
{
private readonly IAccountRepository _repository;
public AccountService(IAccountRepository repository)
{
_repository = repository;
}
public Account GetAccount(int accountId)
{
return _repository.GetAccount(accountId);
}
public void CreateAccount(Account account)
{
_repository.AddAccount(account);
}
}
// HTTP endpoint using ASP.NET Web API
[Route("api/accounts")]
public class AccountController : ApiController
{
private readonly AccountService _accountService;
public AccountController(AccountService accountService)
{
_accountService = accountService;
}
[HttpGet]
public IHttpActionResult GetAccount(int accountId)
{
var account = _accountService.GetAccount(accountId);
return Ok(account);
}
[HttpPost]
public IHttpActionResult CreateAccount(Account account)
{
_accountService.CreateAccount(account);
return Created(Request.RequestUri, account);
}
}
These are the basic examples of microservices applied with DDD principles.
Opinions expressed by DZone contributors are their own.
Comments