What is Domain-Driven Development?
Software development thrives on approaches that bridge the gap between complex business requirements and technical implementation. Domain-Driven Design (DDD) is one such methodology that emphasizes aligning code with the core business domain.
Domain-Driven Development (DDD) is a software development methodology that focuses on collaborating deeply with domain experts to create software that accurately reflects the business’s reality. Let’s dive into how you can implement DDD principles
What is Domain-Driven Design (DDD)?
Domain-Driven Design is a software development philosophy introduced by Eric Evans in his book Domain-Driven Design: Tackling Complexity in the Heart of Software. It prioritizes understanding the core business domain (the problem space) and structuring code to mirror real-world business rules, processes, and terminology.
The goal of DDD is to create a ubiquitous language a shared vocabulary between developers and domain experts (e.g., business stakeholders) to ensure everyone speaks the same language. This reduces ambiguity and ensures the software model reflects reality.
Key Concepts of DDD
- Ubiquitous Language: A shared terminology between developers and domain experts.
- Bounded Context: A boundary within which a specific domain model is defined and valid (e.g., “Inventory Management” vs. “Order Processing”).
- Entities: Objects with a unique identity (e.g., a
User
with anid
). - Value Objects: Immutable objects defined by their attributes (e.g., a
Money
object withamount
andcurrency
). - Aggregates: Clusters of domain objects (e.g., an
Order
and itsOrderItems
). - Repositories: Mechanisms for persisting and retrieving aggregates.
- Domain Services: Stateless operations that don’t fit within an entity or value object.
Example: Implementing DDD in PHP
Let’s model a simplified e-commerce domain: placing an order.
1. Entity: Order
<?php
namespace App\Domain\Order;
class Order
{
private string $id;
private string $status;
private array $items;
public function __construct(string $id, array $items)
{
$this->id = $id;
$this->items = $items;
$this->status = 'pending';
}
public function getId(): string
{
return $this->id;
}
public function confirm(): void
{
$this->status = 'confirmed';
}
}
2. Value Object: OrderItem
<?php
namespace App\Domain\Order;
class OrderItem
{
public function __construct(
private string $productId,
private int $quantity,
private float $price
) {}
// Value objects are immutable; no setters!
public function getProductId(): string { /* ... */ }
public function getTotal(): float
{
return $this->quantity * $this->price;
}
}
3. Repository Interface
<?php
namespace App\Domain\Order;
interface OrderRepositoryInterface
{
public function save(Order $order): void;
}
4. Domain Service: OrderService
<?php
namespace App\Domain\Order;
class OrderService
{
public function __construct(
private OrderRepositoryInterface $repository
) {}
public function placeOrder(string $orderId, array $items): void
{
$order = new Order($orderId, $items);
$this->repository->save($order);
$order->confirm();
}
}
Testing DDD in PHP
Testing ensures your domain logic behaves as expected. Let’s use PHPUnit to test our Order
entity and service.
1. Testing the Order
Entity
<?php
use App\Domain\Order\Order;
use PHPUnit\Framework\TestCase;
class OrderTest extends TestCase
{
public function testOrderConfirmation(): void
{
$order = new Order('order-123', []);
$order->confirm();
$this->assertEquals('confirmed', $order->getStatus());
}
}
2. Testing the OrderService
Mock the repository to isolate the test:
<?php
use App\Domain\Order\OrderService;
use App\Domain\Order\OrderRepositoryInterface;
use PHPUnit\Framework\TestCase;
class OrderServiceTest extends TestCase
{
public function testPlaceOrderSavesToRepository(): void
{
$mockRepo = $this->createMock(OrderRepositoryInterface::class);
$mockRepo->expects($this->once())
->method('save');
$service = new OrderService($mockRepo);
$service->placeOrder('order-123', [/* items */]);
}
}
Conclusion
Domain-Driven Design is less about the language and more about how you model your code. PHP, with its evolving ecosystem, supports DDD principles effectively. Start small, define your ubiquitous language, isolate domain logic, and write tests to validate behavior. The result? Software that grows with the business, not against it.
Read