Uncle Bob’s Clean Architecture – Dealing with anemic interactors, tiering, and front-end MVVM

clean-architecturelayersmvvm

Background

In Uncle Bob's Clean Architecture, use case interactors are responsible for the orchestration of business objects to accomplish some user goal.
As an easy example, an e-commerce application might have a use case to purchase items in a shopping cart: the interactor receives a request (DTO) to make a purchase, then the interactor might query various output ports (gateways) for instance to check inventory/availability, check to see if a payment can be made, and if so, persist a change to the inventory service, ending with a response (another DTO) indicating the success/failure of the interaction (the user-interface layers then presents this information to the user).

In trying to apply the principles of Clean Architecture to my applications, I continually run into the question of whether the use case interactor and gateways should be implemented on a front-end, back-end, or both. Consider the scenario for a mobile phone app that communicates with a web app – in a scenario like this, I've tended to notice that implementing use case interactors in the front-end lead them to be very anemic. That is, they only relay requests from the user-interface (typically a function call made on a view-model) to an output port (gateway interface). The gateway is good as it provides some level of abstraction about how communication with the back-end occurs (HTTP, sockets, IPC, RPC, etc), a detail that Uncle Bob stresses to be kept open for as long as possible. But I question the value of a use case interactor that merely relays requests – after all, why shouldn't a view-model depend directly on the output port? This is especially the case when the critical business rules must guarded by executing on an external device (e.g. web server, hardware, etc.) to prevent bad or unauthorized requests.

My typical attempt usually ends up as below. The output port provides a separation from the specific mechanism for sending a request. The only problem is that the use case interactor seems very anemic as mentioned since it merely relays a request to the gateway because the interesting business logic occurs on the external device or web app.
enter image description here

Consequently, I'm wondering if I should go with the following approach instead, but I'm not sure what the advantages/disadvantages of removing the use case interactor – it seems improper to depend from one adapter directly to another another adapter (albeit via an abstraction).

enter image description here

Now, in this circumstance, I do not care how external server, hardware, or web app are implemented so long as I obey it's API contract.
Though, supposing I was responsible for implementing the external application, is this where the use case interactor starts to be useful as now I have critical business rules and user flows that require orchestration?

My current conclusion is that it would seem that in a front-end/back-end system, the front-end would only be interested in use case interactors insofar-as the interesting business rules occur only within that tier (i.e. the front-end). If there are interesting business rules that cannot be fully executed in the front-end, perhaps due to security/authorization requirements, then we'll have to move that use-case interactor to the back-end tier instead and can simply have a view-model depend directly on the output port as in the second diagram.

Question

Does anyone have an expert opinion regarding tiering, MVVM, and Clean Architecture who can show me where I might be going astray? I'm hoping to understand:

  1. Is it useful (perhaps for maintainability reasons) in having use case interactors that only relay to a gateway (because the sophisticated business logic occurs on a different tier).
  2. What harms, if any, are there in depending directly from a view-model (an entry-point adapter) to an exit-point adapter via some output port interface?

Best Answer

A mobile e-commerce app that talks to a web service is unlikely to have much business logic in the app itself. In this case, it would be overkill to apply clean architecture independently to the app. Rather, you could consider the app to be the outermost layer of your overall architecture, which talks to the web service, which in turn talks to the interactors that contain the real business logic.

All you need in the app is the MVVM portion. The "model" is likely just the DTOs returned by the web service, and the view-model can handle presentation logic and interactions with the web service gateway.