2

in the clear architecture, what uncle bob suggested.

I have a lot of questions about how to correctly distribute the responsibility. enter image description here

it seems that there is no relationship between controller and presenter. the controller's job is to take the input and trigger the use case and the presenter's job is to take the output data provided from the use case and display it on the view.

here it seems that the view very dumb object and its only function is to display the data to the UI, it makes sense in case the controller is invoked by an external agency only.

but how the controller is accessed in the case of the web?. the user interacts with the view so the view should hold the instance of the controller and enough intelligence to invoke the correct methods of the controller. in this case, the view. is not really a dumb object it has the intelligence to how to invoke the controller,

or it's the job of the presenter to invoke the controller? depending upon the Contax and then finally invoke the view to display the data.

or the controller is closely bonded to the view? so that all the intelligence exists in the controller only and the view transfers the raw event and data. But doing so the controller will know too much about the view and will be dependent on the view.

one final question, say suppose after invoking the use case, u which was successful but the UI wants some more data to display the result to the UI.

so where does the logic of fetching more data reside. ?

  1. is it in the view hereafter the use case was successful the use case will invoke the presenter, and the presenter will send the msg to view, then the view will request more data from the controller to display.?

  2. is it in the Presenter? so after the use case was successful with the success message. then presenter will invoke the controller to get the additional data to display and pass it to the view.

  3. is it in the controller? where after getting the success return response from the use case the controller will again invoke the other use case which will display the additional data to the view via presenter.

  4. is it in the use case?. where the use case will itself decide to send additional data to display to the user, however, I am not convinced with this since it should not be up to the use case to think about which data is being presented, it will bind the use case to the one type of presentation since the same could not be a true presentation, for example, CLI might not require the additional data.

Also who actually creates the controller and presenter, is the main function creating every presenter and controller, or does the high-level controller create the low-level controller and presenter and pass it to the presenter?

1
  • I really think that Uncle Bob is a trickster, deliberately making up more and more complex crap to pull our legs and see if we ever notice that it's just plain silly.
    – user949300
    Jul 31 at 2:48

4 Answers 4

3

Alright, so, Presenters, yet again. I think this is the most confusing part about Clean Architecture, and after spending much time researching this topic, I can only say that it depends on your application goal.

If you read the book (Clean Architecture, Chapter 23), you will find that Uncle Bob's proposal for the presenters is to make the "view" as dumb as possible. Which means, easy to test (or not tested at all, because all of your tests would be focused on other layers). I will quote some of UB's book parts here:

The View is the humble object that is hard to test. The code in this object is kept as simple as possible. It moves data into the GUI but does not process that data.

(Martin, R.C. Clean Architecture; ch23. Presenters and Views)

The Presenter is the testable object. Its job is to accept data from the application and format it for presentation so that the View can simply move it to the screen. For example, if the application wants a date displayed in a field, it will hand the Presenter a Date object. The Presenter will then format that data into an appropriate string and place it in a simple data structure called the View Model, where the View can find it.

(Martin, R.C. Clean Architecture; ch23. Presenters and Views)

Now, let's compare this with your statement:

it seems that there is no relationship between controller and presenter. the controller's job is to take the input and trigger the use case and the presenter's job is to take the output data provided from the use case and display it on the view.

here it seems that the view very dumb object and its only function is to display the data to the UI, it makes sense in case the controller is invoked by an external agency only.

Pretty similar, right? Now, let's move on:

but how the controller is accessed in the case of the web?. the user interacts with the view so the view should hold the instance of the controller and enough intelligence to invoke the correct methods of the controller. in this case, the view. is not really a dumb object it has the intelligence to how to invoke the controller,

Now, here you will begin to understand why I said earlier, "it depends". In your "web" situation, you would have a "view" that may differ from the "view" pictured on the model, or not. If you follow the model strictly, the button on your "view" would have to call the controller.getSomething() (this is a missing arrow on the model, something has to call the controller). After that, your view would have to update itself after the call finished, because the controller would return void, but ONLY after the presenter was called inside the usecase. If you follow the model strictly, your "view" also has a reference to the "ViewModel" which is marked as a (Data Structure), so your view can access this variable to update the screen with the correct data.

In a syncronous code, you would have this "flow of control":

controller.getSomething("cool")
|_useCase.execute(what)
| |_output.present("something " + what) 
| | |_viewModel.setLabel(something + " and nice!");
| | |_return void;
| |_return void;
|_return void;
myTextField = viewModel.label; // "something cool and nice!"

Note that your view received void from the controller, but still got the response updated from the viewModel. And that's what Uncle Bob's meant by [...]a simple data structure called the View Model, where the View can find it. [...]. Got it?

or it's the job of the presenter to invoke the controller? depending upon the Contax and then finally invoke the view to display the data.

or the controller is closely bonded to the view ? so that all the intelligence exists in the controller only and the view transfers the raw event and data. But doing so the controller will know too much about the view and will be dependent on the view.

No and No. As you may have guessed from earlier, there is no need. And this is a leak in the responsibility (the controller would know too much as you stated).

one final question, say suppose after invoking the use case, u which was success full but the UI want some more data to display the result to the UI. so where does the logic of fetching more data reside. ?

You need to call another controller, Clean Architecture is oriented by use cases, so your project would have plenty. If you want to stick with the model proposed, in the view, or inside another class/object that encapsulates the view and the controller, and this class is not presented in UB's diagram.

Also who actually creates the controller and presenter, is the main function creating every presenter and controller, or does the high-level controller create the low-level controller and presenter and pass it to the presenter?

Yes, the "main" is where you initialize all your dependencies and tie it all up. You could use a framework to do the DI (Dependency Injection) for you tho, makes things easier if you know what you're doing.

Now, why it depends? In your "web" example, you could "pack" your inner and adapter layers into a library. This library could be imported in a web application where something would read the ViewModel, but also, the same library could be imported in a mobile application (if the programming language barrier permits)... see the benefit?

It depends because these both are two different applications, with two entrypoints where you can set your dependencies as you like. In other cases however, where you have a single application and different views referencing the same viewModel, you might run into some concurrency problems, which could serve as an excuse to leak some responsibility to the controller. In some other cases (pretty specific cases), the presenters might serve as a pretty good way to apply CQRS.

I hope it helps.

2

You can use callbacks to have the view interact with the controller without having any direct knowledge of the controller.

For instance, imagine you have a button that does something, you can have the view accept a function that it binds to the 'onClick' action of that button (or equivalent). The view then calls that function, but doesn't need to know anything beyond that. In a test example this could just be a mock, or you could bind it to a method of the controller in a real system.

I'm not sure how this is stuck together in the particular architecture you're referencing, what I've mentioned above is the standard way to do this in the Model-View-ViewModel architecture, and I imagine Bob Martin's approach does something similar.

0

The presenter knows nothing about the controller. Now let’s say the controller wants the end user to see and edit the first name (and the last name, and a dozen other things). So it tells the presenter: “Show ‘Joe’ as the first name”, “The first name is editable by the end user”, and “when the user edits the first name, call this method to report the name change”.

0

So, there are a couple of things to understand about this image - the primary purpose of this diagram is to depict how to organize dependencies between components that are in different layers. So, the central focus here is on the Interactor; the important bit is that, besides the Interactor, there are some ancillary types + data structures that form the input boundary (it's like the Interactor saying "this is how you request my services"1), and the output boundary (the Interactor saying "here's what to submit if you want me to call you"2).


1 That is, the Interactor provides an interface (a set of public methods and properties), including their parameter and return types, that external code can call. It's the public API of the Interactor.

2 What I mean by "submit" is: you give an output object to the Interactor at construction time (dependency injection). The Interactor accepts as a dependency anything that implements the output boundary. The Interactor has to define what its output boundary is going to look like, and then clients calling code conforms to that. E.g. it could be an interface (say IPresenter) where you'd inject a presenter into the interactor, or in simple cases, it could just be a signature for a callback method, where you'd inject a callback.
The code that constructs the Interactor will also pick the presenter/callback so that the Interactor can push data to it.


enter image description here

The fact that there's a Controller and a Presenter in this diagram is less important - these just represent some UI-related (or presentation side–related) pattern that makes use of the input boundary, and plugs into the Interactor via the output boundary. The way the boundary is crossed is the important bit. As for the exact presentation-side pattern, you could in principle have some other arrangement, this doesn't go against the ideas/principles of Clean Architecture.

"but how the controller is accessed in the case of the web?"

What Robert Martin is depicting here is some variant of the Model-View-Controller or Model-View-Presenter UI pattern, which is something you'll find in desktop applications, or JavaScript-based client-side framework such as Angular, or, arguably, React. As depicted, it doesn't necessarily map 1-to-1 to server-side web controllers, which handle requests from a remote client. But read on, you'll see that these differences don't really matter.

Another thing to understand, which I already hinted at, is that the boxes in the diagram represent somewhat abstractly the elements or components of the architecture - i.e., the roles these code artifacts play within the architecture. A box isn't necessarily an object/class: most boxes here can be implemented in different ways depending on the language you use, complexity of the project, or other factors like the frameworks you use, or personal preference. So, for example, the Presenter could be an object, but it could also just be a function (a callback, a lambda), or even an object composed of a couple of other objects (which you can think of as being a small encapsulated bundle of objects that work together).

Finally, the input boundary and the output boundary are different from the perspective of the Interactor, but ultimately, it's code that calls or, more typically, the code that creates the Interactor, that decides what implementations to pass in. This is the flexibility that's afforded by the CA decoupling. The controller and the presenter can in principle be one and the same object. Or, the presenter could be separate object that the controller holds on to internally (it could be a member field of the controller), and knows how to interact with. The "presenter" could just be a method on the controller itself, that's passed in as a callback to the Interactor; such a method would thus have access to controller's private data. Or the two could actually be separate objects. Or you could do it differently in different places of your application (this may be warranted at times, but I'd try to stay consistent).

The output boundary is typically supplied to the Interactor's constructor (constructor injection), but you can also have a variant where you supply the output boundary (the presenter) as a parameter to the method you call on the Interactor - this lets you decide what should handle the output at each call site. In the simplest case, your "presenter" could just be a lambda created in-place, that updates something when it gets called by the Interactor.

See my answer here for more details.

So, it all depends on your needs, on how you compose the components of the application together. But for the most part, try to keep things as simple as possible.

In the same vein - as in basically any diagram - not every detail of an actual application is captured in the diagram. You'll have to fill in some of the blanks. For example, the "Entities" box is certainly not one object, but is more of a stand in for a class diagram of the domain entities that the Interactor manipulates. So don't take the diagram too literally.

"one final question, say suppose after invoking the use case, u, which was successful but the UI wants some more data to display the result to the UI.

so where does the logic of fetching more data reside. ?"

While this exact scenario is not depicted in the diagram, something very similar is. Fetching more data is, in other words, calling some remote service. A database is a remote service that has a certain API. There's a "Data Access Interface" associated with the Interactor (Interactor saying "I know when to fetch data and what to do with it, but you have to tell me where from") - so you implement an object that conforms to this interface required by the Interactor, and you inject it.

enter image description here

You'd do the same thing for the remote service - the Interactor needs to specify how it wants to interact with the remote service by defining some sort of an interface (we could call it "Service Access Interface"), and then you have to implement it in some outer layer, and inject it.

If the decision to do the fetch can be made within the flow of the use case, then there's a use-case level (business) rule that determines when and under what circumstances the fetch should be initiated. This rule would be the responsibility of the Interactor (the rule would be, well - encoded - by the code of the Interactor), and the actual fetching mechanism would be the responsibility of whatever component implements the "Service Access Interface").

If the decision cannot be made during the execution of the use case - if, for example, it's the user who makes this decision, by performing some action - then the fetch would be the result of a separate round-trip. The Interactor performs the initial use case; after that, its job is done for the time being. The user then does something in the UI, the controller calls some method on the Interactor, and the Interactor performs the fetch, eventually pushing the result through the output boundary (side note: the "eventually" part can be quite literal when it comes to async calls).

Or, if the Interactor itself can determine that there's going to be a fetch at a later time, but cannot know when (again, maybe this depends on user actions), the Interactor can return to the caller an object that can perform the fetch on demand ("here, when you're ready to fetch the data, call a method on this thing"). Or some such scheme.

So you have to think about the usage patterns, business rules, etc., and design your interfaces to support that. The CA gives you an overall structure, a way to think and talk about the architecture in broad terms, but doesn't impose on you the details of the actual design - it's not prescriptive when it comes to that, because these details depend on the intricacies of your business domain.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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