Com triar l'arquitectura iOS adequada (part 2)

MVC, MVP, MVVM, VIPER o VIP

Podeu consultar la primera part aquí.

Les arquitectures iOS més importants

Una breu visió general.

MVC

Les capes MVC són les següents:

M: lògica empresarial, capa de xarxa i capa d'accés a dades

V: nivell d’interfície d’usuari (objectes UIKit, storyboards, Xibs)

C: Coordina la mediació entre model i visualització.

Per entendre MVC hem d’entendre el context en què es va inventar. MVC es va inventar en els vells temps de desenvolupament web quan Views no tenia estat. Antigament, el navegador recarrega tot l’HTML cada vegada que necessitem un canvi visual al lloc web. En aquell moment, no tenia ni idea que l'estat de visualització es mantenia i es desava.

Per exemple, hi havia alguns desenvolupadors que utilitzaven els mateixos fitxers HTML, PHP i accés a la base de dades. Per tant, la principal motivació de MVC era separar el nivell de visualització del nivell de model. Això va augmentar la probabilitat del nivell del model. Suposadament a MVC, les capes de visualització i model no haurien de conèixer-se. Per fer-ho possible, es va inventar una capa intermèdia anomenada controlador. Aquest va ser el SRP que es va aplicar.

Un exemple del cicle MVC:

  1. S'activa una acció de l'usuari / un esdeveniment d'usuari al nivell de visualització (per exemple, "acció d'actualització") i aquesta acció es comunica al controlador
  2. El controlador que envia dades al nivell del model
  3. Modeleu les dades retornades al controlador
  4. El controlador diu que la vista actualitzarà el seu estat amb les dades noves
  5. Veure actualització del seu estat

Apple MVC

A iOS, el controlador de visió s’uneix a la vista UIKit i al cicle de vida, de manera que no és un MVC pur. No obstant això, a la definició de MVC no hi ha res que digui que el controlador no pugui conèixer la implementació específica del model o de la vista. El seu propòsit principal és separar les responsabilitats del nivell del model del nivell de visualització per poder-les reutilitzar i provar el nivell del model aïlladament.

El ViewController conté la vista i és propietari del model. El problema és que estem escrivint tant el codi del controlador com el codi de visualització al ViewController.

MVC sol causar el que s’anomena el problema del controlador de visió massiva, però només es produeix en aplicacions amb prou complexitat i esdevé un negoci seriós.

Hi ha alguns mètodes que el desenvolupador pot utilitzar per fer més clar el View Controller. Alguns exemples:

  • Extraieu la lògica de VC per a altres classes, com ara la font de dades dels mètodes de visualització de taula, i delegueu per a altres fitxers mitjançant el patró de disseny de delegats.
  • Creeu un desglossament més clar de les responsabilitats de composició (p. Ex., Dividir el VC en controls de visualització infantil).
  • Utilitzeu el patró de disseny de coordinadors per eliminar la responsabilitat d’implementar la lògica de navegació al controlador virtual
  • Utilitzeu una classe d’embolcall de DataPresenter que encapsuli la lògica i converti el model de dades en sortida de dades que representi les dades presentades a l’usuari final.

MVC versus MVP

Com podeu veure el diagrama de MVP, MVC és molt similar

El MVC era un pas endavant, però encara estava marcat per una absència o silenci sobre algunes coses.

Mentrestant, la World Wide Web creixia i es desenvolupaven moltes coses a la comunitat de desenvolupadors. Per exemple, els programadors van començar a utilitzar Ajax i només carreguen parts de pàgines en lloc de tota la pàgina HTML alhora.

A MVC, al meu entendre, no hi ha cap indicació que el controlador no hagi de conèixer la implementació específica de View (absència).

L’HTML formava part de la capa de visualització i molts casos eren tan estúpids. En alguns casos, només rep esdeveniments de l'usuari i mostra el contingut visual de la GUI.

A mesura que es van carregar parts de les pàgines web en parts, aquesta segmentació va conduir a la preservació de l'estat de visualització i a una major necessitat de separar les responsabilitats de la lògica de presentació.

La lògica de presentació és la lògica que controla com es mostra la interfície d'usuari i com interactuen els elements de la interfície d'usuari. Un exemple és la lògica de control de quan un indicador de càrrega hauria de començar a mostrar-se / animar-se i quan hauria de deixar de mostrar-se / animar-se.

A MVP i MVVM, la capa de visualització ha de ser tan tonta que no conté cap lògica ni intel·ligència, i a iOS el controlador de visualització ha de formar part de la capa de visualització. El fet que View sigui ximple significa que fins i tot la lògica de presentació es manté fora del pla View.

Un dels problemes amb MVC és que no està clar cap a on hauria d’anar la lògica de presentació. Simplement en fa silenci. La lògica de presentació hauria de ser al nivell de visualització o de model?

Si el paper del model és proporcionar només les "dades en brut", significa que el codi de la visualització és el següent:

Penseu en el següent exemple: tenim un usuari amb nom i cognoms. A la vista hem de mostrar el nom d'usuari com a "Cognom, nom" (per exemple, "Flores, Tiago").

Si la funció del model és proporcionar les dades "en brut", significa que el codi de la visualització és el següent:

let firstName = userModel.getFirstName () let lastName = userModel.getLastName () nameLabel.text = Cognom + “,“ + Nom

Això significa que View és responsabilitat de gestionar la lògica de la interfície d'usuari. Tanmateix, això fa que no es pugui provar la lògica de la interfície d'usuari.

L'altre enfocament és deixar que el model mostri només les dades que cal mostrar i amagar la lògica empresarial de la vista. Però després tenim models que gestionen tant la lògica de negoci com la lògica de la interfície d’usuari. Seria una entitat comprovable, però llavors el model depèn implícitament de la visió.

let name = userModel.getDisplayName () nameLabel.text = name

Això és clar per al MVP i la lògica de presentació es manté al nivell del presentador. Això augmenta la probabilitat del nivell de presentador. Ara el model i la capa de presentador es poden provar sense problemes.

Normalment, en les implementacions de MVP, la vista s’amaga darrere d’una interfície / protocol i no hi ha d’haver referències a l’UIKit al presentador.

Una altra cosa a tenir en compte són les dependències transitives.

Si el controlador té una capa empresarial com a dependència i la capa empresarial té una capa d'accés a dades com a dependència, el controlador té una dependència transitiva per a la capa d'accés a dades. Com que les implementacions de MVP solen utilitzar un contracte (protocol) entre tots els nivells, no hi ha dependències transitives.

Les diferents capes també canvien per diferents motius i a ritmes diferents. Per tant, si canvieu un nivell, això no hauria de provocar problemes / efectes secundaris en els altres nivells.

Els protocols són més estables que les classes. Els registres no contenen cap detall d’implementació i no estan vinculats als contractes. Per tant, és possible canviar els detalls d’implementació d’un nivell sense afectar els altres nivells.

Els contractes (protocols) creen un desacoblament entre les capes.

MVP contra MVVM

Diagrama MVVM

Una de les principals diferències entre MVP i MVVM és que en MVP el presentador interfície amb la vista, i en MVVM la vista se centra en canvis de dades i esdeveniments.

A The MVP creem un enllaç manual entre el presentador i la visualització mitjançant interfícies / protocols. Al MVVM realitzem un enllaç automàtic de dades amb RxSwift, KVO o un mecanisme amb genèrics i tancaments.

Al MVVM ni tan sols necessitem cap contracte (per exemple, interfície Java / protocol iOS) entre ViewModel i View, ja que normalment ens comuniquem mitjançant el patró de disseny d’observadors.

El MVP utilitza el patró de delegat perquè la capa de presentador delega ordres a la capa de visualització. Per tant, ha de saber alguna cosa sobre la vista, encara que només sigui la signatura de la interfície / protocol. Penseu en la diferència entre el centre de notificacions i els delegats de TableView. El Centre de notificacions no necessita cap interfície per crear un canal de comunicació. No obstant això, els delegats de TableView utilitzen un protocol que les classes haurien d'implementar.

Penseu en la lògica de presentació d’un indicador de càrrega. A MVP, el presentador executa ViewProtocol.showLoadingIndicator. A MVVM, pot haver-hi una propietat isLoading al ViewModel. La capa de visualització utilitza l'enllaç automàtic de dades per reconèixer quan aquesta propietat canvia i s'actualitza. MVP és més atractiu que MVVM perquè el presentador emet ordres.

MVVM tracta més dels canvis de dades que de les comandes directes i enllaçem els canvis de dades per veure les actualitzacions. Quan fem servir RxSwift i un paradigma de programació reactiva funcional juntament amb MVVM, hem fet que el codi sigui encara menys convincent i més declaratiu.

MVVM és més fàcil de provar que MVP perquè MVVM utilitza el patró de disseny d’observadors, que transfereix dades entre components de manera desacoblada. Per tant, podem provar només mirant els canvis de les dades comparant els dos objectes, en lloc de burlar-nos de les trucades del mètode per provar la comunicació entre la vista i el presentador.

PD: Vaig fer algunes actualitzacions de l’element que el van fer créixer molt. Per tant, era necessari dividir-lo en tres parts. Podeu llegir la tercera part aquí.

La segona part acaba aquí. Tots els comentaris són benvinguts. La tercera part tracta sobre VIPER, VIP, programació reactiva, compensacions, restriccions i sentit contextual.

Gràcies per llegir! Si us ha agradat aquest article, aplaudeu perquè altres també el puguin llegir :)