0

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 or Observable.
  • 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?

1

This depends on a few things, maybe more but these are what I can think of off the top of my head.

  1. Is your repository responsible for Async or are you going to treat it as sync.
  2. Are you ok with stringing Rx through your entire application.

Both of these are sort of a matter of personal opinion and have tradeoffs to consider.

For example, in 1. Using Rx gives the notion of Async to the caller. It's clearly more flexible as you mentioned, but there's an argument to be made around whether the multithreading belongs in your repository.

For example 2, it depends on how tightly coupled you want Rx to be in your app. It's perfectly fine if that's the decision you make, but it is a hard one to undo. An alternative would be to hand your method a simple callback.

In practice, I tend towards Single>, becaue I like the flexibility of it. It lets me then continue the stream, filter data with ease, etc.

Another consideration is the user of this API. If it's a team that is comfortable with Rx, then that seems like the way to go, but if this is unfamiliar and going to cause confusion, it would probably be better to hide it (Say if this were part of a library)

So I guess the answer is "it depends", like a lot of answers in software.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.