Question

I've got a validation function something like this (pseudo-code):

public function validate(Thing thing) {
    if (thing.a != "a") {
        return false; // most of the time
    }
    if (thing.b != "b") {
        return false; // most of the time
    }
    return true;
}

This function is in a domain service class. It's called from lots of controller classes. 90% of the time, all I want is a boolean answer to "is thing valid?" But 10% of the time, I want to display a message on the UI as to why it's invalid, if so. So instead of false when thing.a != "a" occurs, I want a string that says "thing's a is not a" or whatever.

I can think of several ways to manage this, but none of them make me particularly happy.

  1. Just return the string all the time and in the true case just return ok or something similar, but that feels fragile. It also makes the calling code have to do a string compare everywhere.
  2. Return an enumerated type, and have a helper method available to translate the enum into the string for when it's needed, but that feels like I've just hidden the problem. And the calling code has to check a constant -- better than 1, but not by much.
  3. Store the last message in a class property, to be obtained via a getter after a call to validate returns a false. That makes most of my calling code much cleaner since it only deals with boolean results except when it needs to know the cause. But is this fragile? It's a web app, so it's single threaded per request, so race conditions shouldn't be a problem.

I feel like this is a common enough problem that there should be an elegant design pattern for it, but I've been unable to find it.

Was it helpful?

Solution

As you're apparently in a transactional situation - request/response (not ACID) - then consider:

Go with a variation of #3 - but not a class property, just a thread property, and not a single value, but a stack or list of them. Push stuff on the "error message stack" as you're going. Put entire stack traces on it if you wish. Then when you are done with that request and about to return you have the entire history of badness available to format and return - possibly as an header value ("out of band" for the request/response but still available for your logs, and for the client if it fetches it out of the request).

OTHER TIPS

What about a response object, that contains a boolean indicating validity, and an optional reason string? This way you don't need to worry about looking up enum codes, because the reason is contained within the response object.

public Response validate(Thing thing) {
    Response r = new Response();
    if (thing.a != "a") {
        r.valid = false; // most of the time
        r.reason = "the thing.a is not an 'a'!"
    }
    else if (thing.b != "b") {
        r.valid = false; // most of the time
        r.reason = "the thing.b is not an 'b'!"
    }
    else {
        r.valid = true;
    }
    return r;
}
Licensed under: CC-BY-SA with attribution
scroll top