I have been assigned a project to develop a set of classes that act as an interface to a storage system. A requirement is that the class support a get method with the following signature:
public CustomObject get(String key, Date ifModifiedSince)
Basically the method is supposed to return the CustomObject
associated with the key
if and only if the object has been modified after ifModifiedSince
. If the storage system does not contain the key
then the method should return null.
My problem is this:
How do I handle the scenario where the key exists but the object has not been modified?
This is important because some applications that use this class will be web services and web applications. Those applications will need to know whether to return a 404 (not found), 304 (not modified), or 200 (OK, here's the data).
The solutions I'm weighing are:
key
ifModifiedSince
fails.I'm not happy with any of these three options. I don't like options 1 and 2 because I don't like using exceptions for flow control. Neither do I like returning a value when my intent is to indicate that there was no value.
Nonetheless, I am leaning towards option 3.
Is there an option I'm not considering? Does anyone have strong feelings about any of these three options?
Answers to this Question, Paraphrased:
contains
method and require caller to call it
before calling get(key,
ifModifiedSince)
, throw
exception if key does not exist,
return null if object has not been
modified.UNMODIFIED, KEY_DOES_NOT_EXIST
).Why I Cannot Choose Answer #1
I agree that this is the ideal solution, but it was one I have already (reluctantly) dismissed. The problem with this approach is that in a majority of the cases in which these classes will be used, the backend storage system will be a third party remote system, like Amazon S3. This means that a contains
method would require a round trip to the storage system, which would in most cases be followed by another round trip. Because this would cost both time and money, it is not an option.
If not for that limitation, this would be the best approach.
(I realize I didn't mention this important element in the question, but I was trying to keep it brief. Obviously it was relevant.)
Conclusion:
After reading all of the answers I have come to the conclusion that a wrapper is the best approach in this case. Essentially I'll mimic HTTP, with meta data (headers) including a response code, and content body (message).
Another way to avoid exceptions is to return null (or default) for most common error cases instead of throwing an exception. A common error case can be considered a normal flow of control. By returning null (or default) in these cases, you minimize the performance impact to an app.
According to many references like here and here, using Exceptions to control application flow is an anti-pattern that is not recommended. (Because of performance issues, Less readable and etc).
By using exceptions for something that is not exceptional, you are using inappropriate abstractions for the problem you are trying to solve. But there can also be a performance penalty.
It sounds like you actually want to return two items: the response code and the object found. You might consider creating a lightweight wrapper that holds both and return them together.
public class Pair<K,V>{
public K first;
public V second;
}
Then you can create a new Pair that holds your response code and the data. As a side effect to using generics, you can then reuse this wrapper for whatever pair you actually need.
Also, if the data hasn't expired, you could still return it, but give it a 303 code to let them know that it is unchanged. 4xx series would be paired with null
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With