1

I have a repository that contains login credentials

interface LoginCredentialRepository {

    LoginCredential fetchCredentials(String username);
}

For this framework, I'm designating one thread to handle all IO-based tasks. This is only by convention, and if someone really wants to submit an IO-based task to a different Executor I suppose they can.

Because I intend on having this designated IO thread, should I change the interface to

Callable<LoginCredential> fetchCredentials(String username);

So that the caller only has to do

ioThread.submit(repository.fetchCredentials("foo"));

instead of something like

ioThread.submit(() => return repository.fetchCredentials("foo"));

On one hand, since I know that the recommended way of processing IO tasks is to submit them to the IO Thread, I feel like I should make the caller's job easier and just have it return what will be used.

On the other hand, the repository then knows that when fetchCredentials is called, it won't actually return the credentials, but rather a way of fetching the credentials, requiring the caller to do

Future<LoginCredential> credentialFuture = ioThread.submit(repository.fetchCredentials("foo"));
LoginCredentials credentials = credentialFuture.get();

2 Answers 2

1

I feel like I should make the caller's job easier . . .

Yes, you should. As Josh Bloch said in How to Design a Good API and Why it Matters,

Don't Make the Client Do Anything the Module Could Do

It's capitalized this way because he considered it important enough to make it the title of a section. Although as Daniel Earwicker suggests, a more literal phrasing of the principle would be

Don't make the client do anything that a large number of clients would be expected to do.

Following this principle, it might be even better to return a Future<Foo>. For the sake of maintainability, you might want to implement the method that returns a Future<Foo> in terms of another method that returns a Callable<Foo>, which in turn would be implemented in terms of a synchronous method that returns a Foo. You may or may not want to expose all of these methods outside the package.

2
  • 1
    Perhaps worth warning against careless interpretation of that page heading from Bloch, as it implies a huge and ever expanding API. It is probably not as well worded as it could be, and cannot be followed as a principle out of context. See the section "API Should Be As Small As Possible But No Smaller" which seems to contradict it at first glance. The XML example is of something that a large number of clients would be expected to do, and so it is worth building in, which is not true for "anything the module could do". Commented Sep 7, 2016 at 6:36
  • @DanielEarwicker Edited. Commented Sep 7, 2016 at 7:14
1

Asynchronism is rarely really needed. But when it is, based on my (little) experience, the design that works the best is when the responsability for handling asynchronism is taken fully by the framework or not taken at all and delegated to the framework's user. Returning a Callable from your API is like beeing in the gray zone and it's very unclear who is reponsible for handling what.

So there it leaves us with three cases

Asynchronism is not really needed

Easy one, the API looks like LoginCredential fetchCredentials(String username);

Asynchronism is needed but you don't want to handle all that stuff

The API stays the same, the framework's user handles it as he wants (with good old Thread, Executor, ...)

Asynchronism is needed and you handle it

In this case, I would return a Future because things are clear that:

  1. The result is not directly available
  2. The framework handle all the async stuff

Future<LoginCredential> fetchCredentials(String username);

2
  • The issue isn't whether you want to handle it but whether you have to. If you implement a method using blocking I/O there's no way for the caller to turn that into non-blocking I/O. They can start a new thread for that request but you're still blocking that thread with your method. So if the client needs non-blocking I/O you have to provide it whether you "want to handle all that stuff" or not.
    – Doval
    Commented Sep 7, 2016 at 17:14
  • @Doval So stick with the third case :)
    – Spotted
    Commented Sep 8, 2016 at 5:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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