Let' assume we have an IFiltersRepository
repository that provides data about a list of "filters" that are used on the search screen of an app (filter by color, by price etc).
The repository has the filters in-memory in a HashMap
.
The repository could now expose the data it provides via an interface:
public interface IFiltersRepository {
List<Filter> getFilters();
}
or it could expose the data like:
public interface IFiltersRepository {
Single<List<Filter>> getFilters();
}
One might argue for variant 1:
- this interface makes an assumption about it's implementation, which is that the implementation can deliver these filters right away, without having to fetch them via a long-running operation (e.g. a network call) and that it shouldn't make that assumption. Repositories more often than not provide data via such long-running
operations, and thus, by default, their interfaces should take that
into account and offer data not "directly" but via a type that
enables easy asynchronous handling, for example a Rx
Single
orObservable
. - If at some point the filters are going to be fetched via the network / disk / other long-running operation, both the interface and it's callers are already prepared and the only thing needing to be changed is the implementation, so variant 1 is more future-proof.
For variant 2 one might argue that:
- The interface reflects what it's implementation(s) can do, so it is fine for the interface to expose its' data without being "asynchronous-ready" as long as it's only implementation can deliver the data right away. It's not the interface that "dictates" what the implementation must do, but rather the implementation offering what it can do via it's interface.
- YAGNI. As long as we have our data readily available in-memory, let's not worry about what might be the implications of at one point we need to fetch them from somewhere else. Let's not complicate code in anticipation of future changes.
What's your thoughts on this and how do you handle it in your own projects?