PMG Digital Made for Humans

Separating Repositories into Commands & Queries

2 MINUTE READ | October 28, 2015

Separating Repositories into Commands & Queries

Author's headshot

Christopher Davis

Christopher Davis has written this article. More details coming soon.

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.

Stay in touch

Bringing news to you

Subscribe to our newsletter

By clicking and subscribing, you agree to our Terms of Service and Privacy Policy

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.


Related Content

thumbnail image

AlliPMG CultureCampaigns & Client WorkCompany NewsDigital MarketingData & Technology

PMG Innovation Challenge Inspires New Alli Technology Solutions

4 MINUTES READ | November 2, 2021

thumbnail image

Applying Function Options to Domain Entities in Go

11 MINUTES READ | October 21, 2019

thumbnail image

My Experience Teaching Through Jupyter Notebooks

4 MINUTES READ | September 21, 2019

thumbnail image

Working with an Automation Mindset

5 MINUTES READ | August 22, 2019

thumbnail image

3 Tips for Showing Value in the Tech You Build

5 MINUTES READ | April 24, 2019

thumbnail image

Testing React

13 MINUTES READ | March 12, 2019

thumbnail image

A Beginner’s Experience with Terraform

4 MINUTES READ | December 20, 2018

ALL POSTS