This website uses cookies to ensure you get the best possible experience. See our Cookies Policy.

PMG Digital Made for Humans

Separating Repositories into Commands & Queries

2 MINUTE READ | October 28, 2015

Separating Repositories into Commands & Queries

A typical repository interface might have a set of methods for finding entities as well as adding, updating, and removing them.

SomeObjectRepository.php

<?phpinterface SomeObjectRepository{    public function getByIdentifier($id);    public function findAll();    public function add(SomeObject $object);    public function remove($objectOrId);    public function update(SomeObject $object);}

That’s okay. It’s easy enough to understand.

We’ve been doing things slightly different on a new project at PMG. Instead of a repository interface containing both the fetching and storage methods, it only contains fetching (query) methods. We keep the same name, SomeObjectRepository.

SomeObjectRepositoryReadOnly.php

<?phpinterface SomeObjectRepository{    public function getByIdentifier($id);    public function findAll();}
The methods that change the state of the repository (commands) are moved into a separate interface that extends the repository.

SomeObjectStorage.php

<?phpinterface SomeObjectStorage extends SomeObjectRepository{    public function add(SomeObject $object);    public function remove($objectOrId);    public function update(SomeObject $object);}
This is just a form of command query separation or, perhaps more accurately, CQRS.

Building a reasonably complex application means splitting things out into smaller modules. The project might have a PMG\AppName\Users namespace that contains all the stuff related to users, including User{Repository,Storage} interfaces and a User object.

Within the user module, there’s probably a lot of code that deals with modifying users and persisting them. Maybe there’s a command that promotes a user to an admin, for instance. Things that modify and persist users likely also need to fetch them first (hence XStorage extends XRepository).

Code external to the users module probaby doesn’t need to modify users as much as fetch them. Separating the interfaces, even if the same object implements both, means external code doesn’t get the entire user kingdom. They can only read things from the repository, not modify it.

Insights meet inbox

Sign up for weekly articles & resources.

We split to keep things contained. If someone wants to read/write users, they have to explicitly ask for the correct interface. In a language with public/private objects, you could enforce external code using the repository only. Static anlysis tools, a compiler (depending on your language), or your tests will error when they see you using command methods on the read-only repository. Splitting the interface is a nice way to make sure clients of a module behave.


Posted by Christopher Davis

Related Content

thumbnail image

Get Informed

PMG Innovation Challenge Inspires New Alli Technology Solutions

4 MINUTES READ | November 2, 2021

Get Informed

Applying Function Options to Domain Entities in Go

11 MINUTES READ | October 21, 2019

thumbnail image

Get Informed

My Experience Teaching Through Jupyter Notebooks

4 MINUTES READ | September 21, 2019

Get Informed

Trading Symfony’s Form Component for Data Transfer Objects

8 MINUTES READ | September 3, 2019

Get Inspired

Working with an Automation Mindset

5 MINUTES READ | August 22, 2019

Get Informed

Parsing Redshift Logs to Understand Data Usage

7 MINUTES READ | May 6, 2019

Get Inspired

3 Tips for Showing Value in the Tech You Build

5 MINUTES READ | April 24, 2019

thumbnail image

Get Informed

Testing React

13 MINUTES READ | March 12, 2019

Get Inspired

Tips for Designing & Testing Software Without a UX Specialist

4 MINUTES READ | March 6, 2019

Get Informed

A Beginner’s Experience with Terraform

4 MINUTES READ | December 20, 2018

All POST