Use case containing the presenter or returning data?

3.9k views Asked by At

Considering the Clean Architecture definition, and especially the little flow diagram describing relationships between a controller, a use case interactor, and a presenter, I'm not sure if I correctly understand what the "Use Case Output Port" should be.

Clean architecture, like ports/adapters architecture, distinguishes between primary ports (methods) and secondary ports (interfaces to be implemented by adapters). Following the communication flow, I expect the "Use Case Input Port" to be a primary port (thus, just a method), and the "Use Case Output Port" an interface to be implemented, perhaps a constructor argument taking the actual adapter, so that the interactor can use it.

To make a code example, this could be the controller code:

Presenter presenter = new Presenter();
Repository repository = new Repository();
UseCase useCase = new UseCase(presenter, repository);
useCase->doSomething();

The presenter interface:

// Use Case Output Port
interface Presenter
{
    public void present(Data data);
}

Finally, the interactor itself:

class UseCase
{
    private Repository repository;
    private Presenter presenter;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.repository = repository;
        this.presenter = presenter;
    }

    // Use Case Input Port
    public void doSomething()
    {
        Data data = this.repository.getData();
        this.presenter.present(data);
    }
}

This interpretation seems to be confirmed by the aforementioned diagram itself, where the relation between the controller and the input port is represented by a solid arrow with a "sharp" head (UML for "association", meaning "has a", where the controller "has a" use case), while the relation between the presenter and the output port is represented by a solid arrow with a "white" head (UML for "inheritance", which is not the one for "implementation", but probably that's the meaning anyway).

However, my problem with this approach is that the use case must take care of the presentation itself. Now, I see that the purpose of the Presenter interface is to be abstract enough to represent several different types of presenters (GUI, Web, CLI, etc.), and that it really just means "output", which is something a use case might very well have, but still I'm not totally confident with it.

Now, looking around the Web for applications of the clean architecture, I seem to only find people interpreting the output port as a method returning some DTO. This would be something like:

Repository repository = new Repository();
UseCase useCase = new UseCase(repository);
Data data = useCase.getData();
Presenter presenter = new Presenter();
presenter.present(data);

// I'm omitting the changes to the classes, which are fairly obvious

This is attractive because we're moving the responsibility of "calling" the presentation out of the use case, so the use case doesn't concern itself with knowing what to do with the data anymore, rather just with providing the data. Also, in this case we're still not breaking the dependency rule, because the use case still doesn't know anything about the outer layer.

However, the use case doesn't control the moment when the actual presentation is performed anymore (which may be useful, for example to do additional stuff at that moment, like logging, or to abort it altogether if necessary). Also, notice that we lost the Use Case Input Port, because now the controller is only using the getData() method (which is our new output port). Furthermore, it looks to me that we're breaking the "tell, don't ask" principle here, because we're asking the interactor for some data to do something with it, rather than telling it to do the actual thing in the first place.

So, is any of these two alternatives the "correct" interpretation of the Use Case Output Port according to the Clean Architecture? Are they both viable?

In this answer to another question, Robert Martin describes exactly a use case where the interactor calls the presenter upon a read request. No mention of MVC, MVVC, etc. can be found, so I guess that the Clean Architecture doesn't play very well with MVC in general?

Clicking on the map causes either the placePinController to be invoked. It gathers the location of the click, and any other contextual data, constructs a placePinRequest data structure and passes it to the PlacePinInteractor which checks the location of the pin, validates it if necessary, create a Place entity to record the pin, constructs a EditPlaceReponse object and passes it to the EditPlacePresenter which brings up the place editor screen.

A possible explanation would be that the application logic that traditionally would go into the controller, here is moved to the interactor, because we don't want any application logic to leak outside the application layer. Thus, here the model is not calling the presenter, because the interactor is not the model, but rather the actual implementation of the controller. The model is just the data structure being passed around. This seems to be confirmed by:

The software in this layer is a set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the Database or the Web.

From the original article, talking about Interface Adapters. Since the controller must just be a thin adapter converting one data format to another, it must not contain any application logic, which is thus moved to the interactor.

4

There are 4 answers

3
k3b On

The article says that the Use-Case is independet of the gui (presenter) so it is the job of the Controller to talk to usecase (aka service or workflow) and presenter

[update 2017-08-29]

if the model uses a presenter-interface this is not a clean mvc, mvp or mvvm architecture any more but something else.

0
user15975708 On

Conforming to the CQS principle (Command Query Separation principle).

The "execute" method shouldn't return a value, as it performs a command. So, the response will be given to the instance that your "execute" method will receive, and then from here, you'll call this parameter "presenter", which implements an appropriate interface described in the UseCase layer.

So from the controller, given :

private IMyUseCase myUseCase; //Injected in Controller constructor

private IMyUseCaseResponseHandler presenter = new MyPresenter();

MyUseCaseRequest myUseCaseRequest = new MyUseCaseRequest();

Don't do :

MyUseCaseResponse myUseCaseResponse = 
    this.myUseCase.handleRequest(this.myUseCaseRequest); //doesn't match CQS

this.presenter.present(myUseCaseResponse);

but do that:

this.myUseCase.handleRequest(this.myUseCaseRequest, this.presenter);

And the UseCase will call the IMyUseCaseResponseHandler method called "present", passing a MyUseCaseResponse instance to it.

2
plainionist On

I think u nicely explained everything already in ur question and in ur comments to the answer from k3b.

The key aspect is: are controller and presenter the same class?

If u use Asp.Net MVC as web framework for example controller and presenter are the same class. in that case the is no need of an output port in the sense of an interface. the controller just calls a method on the interactor and gets some output data as return value.

In case controller and presenter r separate classes there needs to be a way to "pass a result to a presenter". For that the output port is required. The output port in fact is an interface defined in the use cases circle and implemented in the interface adapters circle.

both approaches r viable

If u r interested in a more detailed example u can have a look at my blog series: https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/

Update: I added one more blog post to dive deeper into this discussion here: https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/

1
jflaga On

In a discussion related to your question, Uncle Bob explains the purpose of the presenter in his Clean Architecture:

Given this code sample:

namespace Some\Controller;

class UserController extends Controller {
    public function registerAction() {
        // Build the Request object
        $request = new RegisterRequest();
        $request->name = $this->getRequest()->get('username');
        $request->pass = $this->getRequest()->get('password');

        // Build the Interactor
        $usecase = new RegisterUser();

        // Execute the Interactors method and retrieve the response
        $response = $usecase->register($request);

        // Pass the result to the view
        $this->render(
            '/user/registration/template.html.twig', 
            array('id' =>  $response->getId()
        );
    }
}

Uncle Bob said this:

"The purpose of the presenter is to decouple the use cases from the format of the UI. In your example, the $response variable is created by the interactor, but is used by the view. This couples the interactor to the view. For example, let's say that one of the fields in the $response object is a date. That field would be a binary date object that could be rendered in many different date formats. The wants a very specific date format, perhaps DD/MM/YYYY. Whose responsibility is it to create the format? If the interactor creates that format, then it knows too much about the View. But if the view takes the binary date object then it knows too much about the interactor.

"The presenter's job is to take the data from the response object and format it for the View. Neither the view nor the interactor know about each other's formats."

--- Uncle Bob

Given that answer of Uncle Bob, I think it doesn't matter that much whether we do option #1 (let interactor use presenter)...

class UseCase
{
    private Presenter presenter;
    private Repository repository;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.presenter = presenter;
        this.repository = repository;
    }

    public void Execute(Request request)
    {
        ...
        Response response = new Response() {...}
        this.presenter.Show(response);
    }
}

... or we do option #2 (let interactor return response, create a presenter inside the controller, then pass response to presenter)...

class Controller
{
    public void ExecuteUseCase(Data data)
    {
        Request request = ...
        UseCase useCase = new UseCase(repository);
        Response response = useCase.Execute(request);
        Presenter presenter = new Presenter();
        presenter.Show(response);
    }
}

Personally, I prefer option #1 because I want to be able control inside the interactor when to show data and error messages, like this example below:

class UseCase
{
    private Presenter presenter;
    private Repository repository;

    public UseCase(Repository repository, Presenter presenter)
    {
        this.presenter = presenter;
        this.repository = repository;
    }

    public void Execute(Request request)
    {
        if (<invalid request>) 
        {
            this.presenter.ShowError("...");
            return;
        }

        if (<there is another error>) 
        {
            this.presenter.ShowError("another error...");
            return;
        }

        ...
        Response response = new Response() {...}
        this.presenter.Show(response);
    }
}

... I want to be able to do these if/else that are related to presentation inside the interactor and not outside the interactor.

If on the other hand we do option #2, we would have to store the error message(s) in the response object, return that response object from the interactor to the controller, and make the controller parse the response object...

class UseCase
{
    public Response Execute(Request request)
    {
        Response response = new Response();
        if (<invalid request>) 
        {
            response.AddError("...");
        }

        if (<there is another error>) 
        {
            response.AddError("another error...");
        }

        if (response.HasNoErrors)
        {
            response.Whatever = ...
        }

        ...
        return response;
    }
}
class Controller
{
    private UseCase useCase;

    public Controller(UseCase useCase)
    {
        this.useCase = useCase;
    }

    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        Response response = useCase.Execute(request);
        Presenter presenter = new Presenter();
        if (response.ErrorMessages.Count > 0)
        {
            if (response.ErrorMessages.Contains(<invalid request>))
            {
                presenter.ShowError("...");
            }
            else if (response.ErrorMessages.Contains("another error")
            {
                presenter.ShowError("another error...");
            }
        }
        else
        {
            presenter.Show(response);
        }
    }
}

I don't like parsing response data for errors inside the controller because if we do that we are doing redundant work --- if we change something in the interactor, we also have to change something in the controller.

Also, if we later decide to reuse our interactor to present data using the console, for example, we have to remember to copy-paste all those if/else in the controller of our console app.

// in the controller for our console app
if (response.ErrorMessages.Count > 0)
{
    if (response.ErrorMessages.Contains(<invalid request>))
    {
        presenterForConsole.ShowError("...");
    }
    else if (response.ErrorMessages.Contains("another error")
    {
        presenterForConsole.ShowError("another error...");
    }
}
else
{
    presenterForConsole.Present(response);
}

If we use option #1 we will have this if/else only in one place: the interactor.


If you are using ASP.NET MVC (or other similar MVC frameworks), option #2 is the easier way to go.

But we can still do option #1 in that kind of environment. Here is an example of doing option #1 in ASP.NET MVC:

(Notice that we need to have public IActionResult Result in the presenter of our ASP.NET MVC app)

class UseCase
{
    private Repository repository;

    public UseCase(Repository repository)
    {
        this.repository = repository;
    }

    public void Execute(Request request, Presenter presenter)
    {
        if (<invalid request>) 
        {
            this.presenter.ShowError("...");
            return;
        }

        if (<there is another error>) 
        {
            this.presenter.ShowError("another error...");
            return;
        }

        ...
        Response response = new Response() {...}
        this.presenter.Show(response);
    }
}
// controller for ASP.NET app

class AspNetController
{
    private UseCase useCase;

    public AspNetController(UseCase useCase)
    {
        this.useCase = useCase;
    }

    [HttpPost("dosomething")]
    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        var presenter = new AspNetPresenter();
        useCase.Execute(request, presenter);
        return presenter.Result;
    }
}
// presenter for ASP.NET app

public class AspNetPresenter
{
    public IActionResult Result { get; private set; }

    public AspNetPresenter(...)
    {
    }

    public async void Show(Response response)
    {
        Result = new OkObjectResult(new { });
    }

    public void ShowError(string errorMessage)
    {
        Result = new BadRequestObjectResult(errorMessage);
    }
}

(Notice that we need to have public IActionResult Result in the presenter of our ASP.NET MVC app)

If we decide to create another app for the console, we can reuse the UseCase above and create just the Controller and Presenter for the console:

// controller for console app

class ConsoleController
{    
    public void ExecuteUseCase(Data data)
    {
        Request request = new Request() 
        {
            Whatever = data.whatever,
        };
        var presenter = new ConsolePresenter();
        useCase.Execute(request, presenter);
    }
}
// presenter for console app

public class ConsolePresenter
{
    public ConsolePresenter(...)
    {
    }

    public async void Show(Response response)
    {
        // write response to console
    }

    public void ShowError(string errorMessage)
    {
        Console.WriteLine("Error: " + errorMessage);
    }
}

(Notice that we DO NOT HAVE public IActionResult Result in the presenter of our console app)