¿Dónde pertenecen las operaciones en los models en los patrones de layout de aplicaciones?

Digamos que queremos hacer una application contenga lo siguiente:

  • operations asíncronas y que requieren mucho time en objects seleccionados
  • Para un object determinado, queremos acceder al status de una operation asociada.
  • La capacidad de show , cancel y pause estas operaciones desde multiple views .

Entonces mi pregunta es la siguiente:

¿Dónde pertenecen estas operations y su progress/status en un patrón de layout de aplicaciones?

Para ponerlo en context aquí hay una aplicación ficticia:

Ejemplo de aplicación:

Tenemos una aplicación donde puedes aplicar diferentes Filters a las Images . La aplicación consiste en una Directory View y una Detail View .

  • Cada filter se puede aplicar de asynchronously a cualquier image de cada view .
  • El filter operación se puede observed y canceled desde ambas views .
  • Una operación de filter no se puede iniciar si ya hay una iniciada para ese filter-type e image , o si dicho filter ya ha producido un result .
  • En esta aplicación ficticia, las vistas son posteriores, pero en el caso general, no podrá pasar información directamente entre las vistas.

Vista de directorio

introduzca la descripción de la imagen aquí

Progreso

Desacoplar la Service Layer o el Network Controller de la View y el Model en un patrón de layout como MVC o MVVM es bastante sencillo, siempre y cuando no proporcione más UX feedback que una spinner cuando hay una network request activa.

Pero cuando estoy trabajando en una aplicación que confirme los criterios anteriores, siempre termino

  • No permite que el user cambie de view durante una operation
  • Tagging operaciones con el id del object procesado actualmente y pasando esto a las views , o buscando en el Network Controller directamente desde los views/view controllers
  • Crear entities separadas para operations , y de repente tengo una request operation en mi model

Así que obviamente hay forms ( muy malolientes ) de resolver esto, pero todos se sienten sucios y no en línea con la forma en que se diseñan los patrones.

Tan puramente desde el punto de vista de la architecture del software y el patrón de layout , ¿cómo te acercarías a esto?

Generalmente prefiero un object de promise para este problema de layout. El object de promise puede contener methods para cancelar la operación, verificar el estado de la operación e incluso contener cierres que se ejecutarán según lo que suceda con la operación (éxito, falla, cancelación, etc.).

Ese object de promise puede ser entregado desde la vista para ver o puede ser servido desde la capa de networking en múltiples requestes (ver A inicia la operación, ver B intenta más tarde para iniciarlo, pero ya está ejecutándose, obtiene el mismo object de promise).

Eso significa que la capa de service, o capa de networking en este caso, necesita presentar qué operaciones, requestes, están en curso para qué object, ¿verdad? Porque no quieres patear una request solo para get el object de promise, en caso de que un button se oculte si la operación ya se inició. Supongo que mantendría estos objects de promise fuera de su model de aplicación, ya que no viven entre las sesiones, y la capa de networking los almacenaría por url, pero ¿cómo lo haría en general desde la capa de networking sin exponerse a la capa de networking a la ui

La capa de networking tiene methods de conveniencia para que la UI la utilice para iniciar requestes que el usuario inicia. La capa de networking determina si una request ya ha comenzado y devuelve la misma promise. Incluso si la capa de networking inicia el process internamente (actualización automática, etc.), puede devolver la promise a la interfaz de usuario si la interfaz de usuario intenta iniciar el mismo process.

Los objects de la promise solo viven mientras la operación esté en curso. De hecho, tengo la operación como el verdadero titular del object de promise y el controller de networking tiene la queue de operaciones. Luego, cuando entra una request, busco en la queue la existencia de esa operación y, si existe, devuelvo la promise de la operación. Si no existe, creo una nueva operación, la pongo en la queue y devuelvo su object de promise.

La interfaz entre la interfaz de usuario y el back-end son los methods expuestos en el controller de networking. La interfaz de usuario no tiene conocimiento de las operaciones, simplemente tiene una function que dice "ir a actualizar esto o ir a search eso" y get una promise de vuelta. No necesita saber ni preocuparse de cómo se realiza el trabajo, solo sabe que la promise es su manera de verificar el estado de esa operación.

Ahora, si se trata de una actualización de datos, entonces la promise no es necesaria para las actualizaciones de datos, el NSFetchedResultsController se encargará de eso. La promise en esa situación se encarga únicamente de las requestes de tipo "estoy activo" y "cancelarme".

Habrá muchas forms de hacer esto. Pero esta es una idea … Tal vez pueda utilizar la postría como estilo: defina un canal de "estado", posiblemente use un model pub-sub para get el estado / progreso de las operaciones en curso. De esta forma, el process de realizar las operaciones publica el estado en un canal, y sus múltiples vistas se suscriben a ese canal y muestran el estado. Ahora, si tiene que cancelar / pausar operaciones, posiblemente necesite tener otro canal de control. Tienes que administrar la concurrency, el order, etc.