-1

I am implementing a clean architecture in an application. I have a layer where the application/usecase classes which does the business logic and interacts with mutliple outgoing ports (interfaces to adapters for database calls, http api calls etc). The usecase returns a value/model to a web controller (Which renders the output to the user of the app).

Due to the complexity of the business logic there are many sad paths and a happy path (which are different types of objects with different state), as well as exceptions which can bubble up to the web controller. Exceptions are handled by an error handler with a generic http response and logged.

To return the happy and sad paths, I have wrapped it in an object of two fields. But I feel this is a code smell, as I will always have one field returning null. So in the web controller/servlet there are checks on the populated field to determine the correct http response. Is this a good way of doing this?

I have seen usecases, return the happy path, and all sad paths are given a specific business exception. This exception is caught at the web controller/servlet, and creates the http response using the exception message. I feel this is a code smell too, as we are using exceptions as control flow in the web controller/servlet.

I have seen other ways of returning multiple values such as

  • using a tuple
  • Having one object returned, but each field is a list, thus removing the need for a null as an empty field, and using an empty list
  • Using a map

Are there any other ways of returning multiple values, without having null fields or using exceptions (as explained above)?

cani
  • 190
  • 2
  • 10
  • Your use cases shouldn't return paths. Just primitive types , or dtos grouping them. Apart from that, the use case may throw exceptions too. Your web controller receives the use case output and shows a page. I don't see any problem. – choquero70 Oct 15 '19 at 09:50

1 Answers1

0

Are there any other ways of returning multiple values, without having null fields or using exceptions (as explained above)?

In Java (and POO languages) the usual way to do it is inheritance.

Probably sooner rather than later you'll fall into the Expression problem, that is, you must be careful when to include a process in your class hierarchy, and when to define that process in isolation.

If your process makes sense in the hierarchy, define it in it:

abstract class Response {
    abstract boolean isSuccess();
    abstract String getMessage();
}

class ErrorResponse extends Response {
    boolean isSucess() { return false; }
    String getMessage() { return "Something went wrong."; }
}

class SuccessResponse extends Response {
    boolean isSucess() { return true; }
    String getMessage() { return "Everything went well."; }
}

But you can't expect your hierarchy to contain the logic for any situation, so you can use introspection. Eg. in some view controller:

Color getResponseColor(Response rs) {
    if(rs instanceof NetworkErrorResponse || rs instanceof ServerErrorResponse) {
        return Colors.WITHOUT_SERVICE_COLOR;
    }
    return rs.isSuccess() ? Colors.SUCCESS_COLOR: Colors.ERROR_COLOR;
}

As you can see, including color decision making in the class hierarchy wouldn't make much sense.

Finally, since you are going to serialize your messages, you must make sure that the transport protocol supports inheritance.

josejuan
  • 7,057
  • 19
  • 23