Domain-Driven Design: Data Access Strategies

Part 1: Domain-Driven Design and MVC Architectures

The Domain Model

Here are some of the features a Domain-driven design framework should support:

  • A domain model that is independent and decoupled from the application.
  • A reusable library that can be used in many different domain-specific applications.
  • Dependency Injection in order to inject Repositories and Services into Domain Objects.
  • Integration with unit testing frameworks, such as PHPUnit.
  • Good integration with other frameworks, such as Zend, Symfony, Doctrine, etc.

The Zend Framework, for example, is part of the infrastructure layer and acts as a supporting library for all the other layers. However, the domain layer should be well isolated from the other layers of the application and should not be dependent on the framework you are using.

Data Access Strategies

When accessing data from a data source, you have to decide how your application will communicate with a data source. Each data access strategy has its own advantages and disadvantages. Here are some design patterns that support DDD:

Generic DAO’s

Data Access Objects (DAO’s) and Repositories play an important role in DDD. The goal of a DAO is to abstract and encapsulate all access to the data and provide an interface. The DAO always connects, reads and saves data to a data source. From the applications point of view, it makes no difference when it accesses a database, XML file or Web service:

$user = new UserDbDao();
$row = $user->findUserById(456);
echo $row->name;

$user = new UserXmlDao();
$row = $user->findUserById(456);
echo $row->name;

Table Data Gateway

An object that acts as a Gateway to a database table. One instance handles all the rows in the table. The Zend_Db_Table solution is an implementation of the Table Data Gateway pattern:

$user = new User();
$rows = $user->find(456);
$row = $rows->current();
echo $row->name;

More info: Table Data Gateway

Row Data Gateway

An object that acts as a Gateway to a single record in a data source. There is one instance per row. Zend_Db_Table_Row is an implementation of the Row Data Gateway pattern:

$user = new User();
$row = $user->fetchRow($user->select()->where('user_id = ?', 1));
echo $row->name;

More info: Row Data Gateway

Active Record

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. The Mad_Model component is an  ORM layer that follows the Active Record pattern where tables map to classes, rows map to objects, and columns to object attributes:

$user = new User();
$userFinder = new UserFinder();
$row = $userFinder->find(456);

More info: Active Record

Data Mapper

A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself:

$user = new User();
$userMapper = new UserMapper();
$row = $userMapper->findByEmail($email);

More info: Data Mapper

Data Transfer Objects

A Data Transfer Object (DTO) in Domain-driven design is not the same as a Value Object. A DTO is often used in combination with a DAO to encapsulate data. It allows you to reduce communication effort when dealing with a lot of small data entities. For example:

class UserData
{
    public function setId($id) {}
    public function getId() {}
    public function setFirstName($firstName) {}
    public function getFirstName() {}
    public function setLastName($lastName) {}
    public function getLastName() {}
}

$user = new UserData();
$user->setFirstName('Jim');
$user->setLastName('Morrison');

$userDao = new UserDbDao();
$userDao->insert($user);

A DTO is a simple container for a set of aggregated data. It should contain no business logic and limit its behaviour to activities such as internal consistency checking and basic validation. Be careful not to make the DTO depend on any new classes as a result of implementing these methods.

Part 3: Domain-Driven Design: The Repository

About these ads

14 thoughts on “Domain-Driven Design: Data Access Strategies

  1. great post, thank you.

    “Each data access strategy has its own advantages and disadvantages.”
    can you explain them?

    thanks, cirpo

  2. @cirpo There’s no one best strategy for persistence. Some strategies can help reduce complexity, others improve performance. Use the strategy that’s most appropriate for your team and your project.

    @Giorgio To achieve PI in DDD you can use the Repository pattern (that’s my next post). In order to implement a strategy correctly, you need to use design patterns and take advantage of OOP concepts.

  3. @federico I known that ” There’s no one best strategy for persistence[…]” that’s why i asked if you can explain or show deeply the differences/advantages/disadvantages not the best one or maybe point me to some online resource for real case studies.
    Anyway IMHO it’s a very good post, can’t wait for the next one.

    thanks

  4. Pingback: fede.carg ( blog )

  5. Pingback: Bashar’s Blog

  6. Pingback: Federico Cargnelutti’s Blog: Domain-Driven Design (Series) | Shoultes.net

  7. If you have an Aggregate that has an Entity with several fields who are Value Objects, but then also the Entity has several fields that are Maps, Sets, or Lists, how would you design a DTO (I believe aka Specification) for using within a Repository?

    For example: A CreditApplication has a field type Money called loanAmount (I want to query the DB on loans of a certain value or range). It also has a Map of Applicants (I only need the Applicant ID – SSN – to perform this query). If I move the Map of Applicants into the DTO, it complicates the DTO when I only need one Applicant’s id (let say there’s 2 people applying for credit). It also complicates the code if I have the DTO (Specification) object as a field in the Root Entity CreditApplication because I don’t get much value of encapsulating data into the DTO (Specication) making it much easier to extend the specification without affecting code in multiple locations.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s