The Repository Pattern

Kevin Schweitzer
4 min readJul 6, 2021

If you’ve worked professionally for an App you may have seen the term “Repository”, as it is a word that refers to the “Manager of data”. And every app needs to manage data.

The problem is that the word spreads across the industry, but not always the real responsibility of the Repository class follow that path. So the aim of this post is to explain what repository is and how it can be implemented.

As we said before, the Repository is the “Manager of data”. What does it mean? It means that if we need some data for the app, no matter if it is from server or database, we need to ask for that data to the repository. And no matter is bold on purpose, because it is the core of this pattern.

Let’s assume that my app manages clients and we want to make a CRUD for clients. I have a backend that can manage those requests so everything will be saved in server. Obviously we will have some performance issues if we ask the server every time we want to see the list of clients, so we also want some cache to have quick access to that data.

If we put this logic in our ViewModel/Controller/etc (depending on which MVX pattern you are using) we would have something like this:

//This code is thought as pseudocode 
fun getClients(): List<Clients> {
val clients = database.getClientsFromDatabase()
if(clients.isEmpty()) {
val clientsFromServer = server.getClientsFromServer()
database.saveClients(clientsFromServer)
return clientsFromServer
} else {
return clients
}
}

Here we have our first stop. This code, as it is, doesn’t change anything from view. Eventually we will use the returned clients to refresh our view, but this is only the logic for getting the clients. If we put ourselves in the ViewModel/Controller/etc side we would say “I want the clients to show them to the user” but in that assertion we doesn’t matter where the data is coming from. So, we want to delegate that responsibility, to whom? Yes, the Repository.

Now we can make a little diagram

Note: We are just explaining Repository so we are referencing it from ViewModel directly. In other approaches like Clean Architecture the Repository would be referenced by UseCases.

Here we are using a ViewModel as I took MVVM pattern to make the example. If you are using MVP it would be the Presenter and in case of MVC the Controller.

As we can see, this way the ViewModel only cares about getting the list of clients, no matter how, and the repository is the one in charge of looking the correct source of data.

Now that we know more or less what repository is, let’s dive deeper into it.

Responsibilities

Repository’s responsibility as we said before is data source management, but, is there only one way to achieve this? The answer is NO.

The way Repository decides which source of data it should consult depends on the project/feature you are developing. For example, in the previous Clients example we know that we should refresh the clients list every time we add/delete/update a client, so we always have the last version of the clients list. The ways of doing this could be actually calling the server every time we change the list, or just save somewhere (for example in SharedPreferences for Android) if we have made a change, and check that data in the getClients implementation.

A different problem would be if we can create/delete/update clients also from another app, for example from a web. If we can change the clients list outside our app we should have a way to refresh the list when necessary, consulting last modification date and comparing to the version we have, or just refreshing the list every X time.

In this case the code will change to something like this:

fun getClients(): List<Clients> { 
val clients = database.getClientsFromDatabase()
if(clients.isEmpty() || isClientsUpdateNecessary()) {
val clientsFromServer = server.getClientsFromServer()
database.saveClients(clientsFromServer)
return clientsFromServer
} else {
return clients
}
}

And isClientsUpdateNecessary will check for example if we have requested clients data within 15 minutes or so.

There are plenty of possibilities, so it’s up to you how you will implement the repository to achieve the “Select Source” responsibility. And Isay it that way because we have to be careful of not putting inside the Repository the accesses to database or the server queries. Repository just select the source, does not implement the source. For that we need other classes, like DatabaseManager and ServiceManager for example, which will be referenced by the Repository.

Advantages

  • Single Responsibility: We can separate the responsibility of selecting source from the data consulting. If we want to follow SOLID principles this pattern is a must.
  • Loose coupling: If we have to change the behavior of the way we select the source we don’t need to change the ViewModel. Just changing Repository Implementation will do the thing. ViewModel will use the data the same way.
  • Testability: We are able to test better our code having the data access separately.

Conclusion

This pattern is like a separation between layers. In one side we have the data management and in the other side we have how we use that data. Having this separation help us to identify where changes have to be done, and more important, cut the scope of changes. We will be able to understand our code better and make more robust apps.

--

--

Kevin Schweitzer

Ingeniero en Sistemas, Agente Inmobiliario y Emprendedor