Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do operations on models belong in Application Design Patterns?

Say we want to make an application containing the following:

  • Asynchronous and time consuming operations on selected objects
  • For a certain object we want to access the status of an associated operation.
  • The ability to show, cancel and pause these operations from multiple views.

Then my question is the following:

Where do these operations and their progress/status belong in an Application Design Pattern?

To put it into context here is a dummy application:

Example Application:

We have an application where you can apply different Filters to Images. Application consists of a Directory View and Detail View.

  • Each filter can be applied asynchronously to any image from each view.
  • The filter-operation can be observed and canceled from both views.
  • A filter operation can not be started if there is already one initiated for that filter-type and image, or if such a filter has already produced a result.
  • In this dummy application the views are subsequent, but in the general case you would not be able to pass information directly between the views.

Directory View

enter image description here

Progress

Decoupling the Service Layer or Network Controller from the View and Model in a design pattern like MVC or MVVM is quite straight forward, as long as you don't provide more UX feedback than a spinner when there's an active network request.

But when I am working on an application confirming to the criteria above, I always end up either

  • Not allowing the user to change view during an operation
  • Tagging operations with the id of the object currently processed and passing this to the views, or looking in the Network Controller directly from the views/view controllers
  • Creating a separate entities for operations, and suddenly I have a request operation in my model

So obviously there are (very smelly) ways to come around this, but they all feel dirty and not inline with how the patterns are intended.

So purely from a software architecture and design pattern point of view, how would you approaching this?

like image 948
Aerows Avatar asked Sep 15 '16 23:09

Aerows


1 Answers

I generally prefer a promise object for this design issue. The promise object can contain methods to cancel the operation, check on the status of the operation and even contain closures to be executed depending on what happens with the operation (success, failure, cancel, etc.).

That promise object can either be handed from view to view or can be served from the network layer upon multiple requests (view A kicks off operation, view B tries later to kick it off but it is already running so gets the same promise object).

That means that the service layer, or network layer in this case, needs to present which operations, requests, are ongoing for which object, right? Because you don't want to kick of a request just to get the promise object, in case a button should be hidden if the operation is already started. I guess you would keep these promise objects outside your app model since they don't live between sessions, and the network layer would store them by url, but how would you generally serve this back from the network layer without exposing to much the network layer to the ui?

Network layer has convenience methods for the UI to utilize to kick off requests that the user initiates. The network layer determines if a request has already started and returns the same promise. Even if the network layer kicked off the process internally (auto refresh, etc) it can still deliver the promise back to the UI if the UI tries to start the same process.

The promise objects only live as long as the operation is on-going. I actually have the operation be the true holder of the promise object and the network controller holds the queue of operations. Then when a request comes in, I search the queue for the existence of that operation and if it exists return the promise from the operation. If it doesn't exist, I create a new operation, put it in the queue and return its promise object.

The interface between the UI and the back end is the exposed methods on the network controller. The UI has no knowledge of operations, it just has a function that says "go refresh this or go get that" and gets a promise back. It does not need to know or care how the job is performed, it just knows that the promise is its way to check on the status of that operation.

Now, if it is a data refresh, then the promise isn't needed for data updates, the NSFetchedResultsController will handle that. The promise in that situation handles "am I active" and "cancel me" type requests only.

like image 184
Marcus S. Zarra Avatar answered Nov 03 '22 15:11

Marcus S. Zarra