En los últimos tiempos está muy de moda en el mundo del software la filosofía “clean”, hacer de la construcción de software un arte, y que estemos orgullosos del código que escribimos.
Seguramente el mayor defensor de esta filosofía, o al menos el que más ha escrito al respecto sea Robert C. Martin, más conocido como Uncle Bob, y en este texto me basaré en mucho de lo que él ha escrito y contado. También hay que hacer alguna referencia a otros autores, como el conocido Gangs of four, los cuales escribieron mucho sobre patrones de diseño o Martin Fawler, el cual colaboró con Robert C. Martin en la definición de SOLID (que veremos más adelante) y escribió un libro imprescindible llamado Refactoring.
Robert C. Martin fue el que definió esta arquitectura allá por el año 2012 en su web. Existían entonces, y siguen existiendo, muchas arquitecturas definidas que intentan solucionar los mismos problemas:
Como hemos comentado, las arquitecturas existententes solucionaban la mayoría de estos puntos y todas separaban la arquitectura en capas para diferenciar los diferentes conceptos, pero algunas estaban más enfocadas a la interfaz y otras a la lógica de negocio.
En el caso concreto de iOS, la más usada era (y es) MVC, aunque habitualmente esas siglas perdían su significado de “Model View Controller”, para pasar a ser “Massive View Controller”, al terminar siendo cualquier clase u objeto una vista, modelo y controlador a la vez, terminando por desvirtualizar e incluso elimininar la arquitectura.
En este diagrama se intentó unificar todas estas ideas en una sola, que fuera entendible y que cumpliera una serie de reglas.
Los diferentes círculos representan diferentes capas del software. En general, cuanto mas nos alejemos del núcleo mayor es el nivel del software y más unido al framework está. Los círculos exteriores son mecanismos mientras que los interiores son políticas. La regla primordial que hace que esta arquitectura funcione es la regla de dependencia. Esta regla dice que las dependencias a nivel de código fuente sólo pueden apuntar hacia dentro. Nada que se encuentre en un circulo interior puede saber algo sobre lo que hay en un círculo exterior, es decir, algo declarado en un círculo externo no puede ser mencionado desde el código situado en un círculo interno. Eso incluye funciones, clases, variables o cualquier otra entidad software. Por la misma razón, los formatos de datos usados en un círculo exterior no deberían usarse por un círculo interior, especialmente si esos formatos son generados por algún framework en un círculo situado al exterior. No queremos que nada de un círculo exterior impacte en los círculos o niveles interiores.
Las entidades son usadas por la lógica de negocio de la aplicación, por los llamados interactors. Deben ser objetos que solo dependan de esta capa y que no deben ser usados por las capas superiores, teniendo éstas que funcionar con objetos más simples (diccionarios, arrays, struts, …) o con parámetros de una función.
En esta capa, también llamada Interactor, se tienen los casos de uso, lo cual tienen que ser independiente de la fuente de datos o de la visualización de los mismos. Si cambia los datos no debe influir en estos casos de uso, al igual que si la apariencia de nuestro desarrollo cambia. Es donde tendremos la lógica de negocio en nuestra aplicación
O también llamados Presenters, es la capa que comunica los resultados de los casos de uso con la capa más externa. Esta capa recogerá los datos del interactor que a su vez los habrá procesado de la fuente de datos, y los formateará para ser presentado en la capa más externa, ya sea en una UI, en una base de datos o en algún dispositivo.
Es la capa más externa y la más pegada a la tecnología que estamos usando. En una web sería el html/javascript, en una app iOS todo lo referente a UIKit. Esta capa es una de las que está más sujeta a cambios, y la que podemos hacer más intercambiable. Si nos enfocamos en iOS, solo (o casi) cambiando esta capa podremos adaptar nuestra aplicación a iPhone, iPad o Apple TV.
La forma en la que debemos comunicarnos entre capa sería a través de interfaces, protocolos o delegados. Debe ser lo más polimórfico posible y que no cause mucho daño el cambio de una de las capas, siempre respetando la interfaz. Si jugamos con protocolos haremos estas comunicaciones totalmente independiente las unas de las otras, y serán piezas fácilmente intercambiables. Desde la llegada de swift ha proliferado la llamada OPP (Programación orientada a protocolos), la cual, entre otras muchas cosas, ayuda mucho a este cometido.
Antes de hablar de VIPER me gustaría comentar algo sobre SOLID). Para el que aún no lo conozca, SOLID) es una serie de principios básicos definidos por varios autores para el desarrollo orientado a objetos, unificados en este acrónimo inventado por nuestro Uncle Bob. Vamos a echarle un vistazo rápido a cada uno de ellos.
VIPER no es más que una implementación de esta arquitectura, orientada a un desarrollo iOS. VIPER es un conjunto de siglas que describen las diferentes capas, View, Interactor, Presenter, Entity y Routing.
Esta separación cumple la Single Responsibility Principle. El Interactor es responsable de la lógica de negocio, el Presenter representa la interacción con el diseño y la View es responsable del diseño visual.
También es importante que cumpla la norma “Dependency segregation principle”, ya que a la hora de conectar las diferentes capas deberíamos hacerlo con interfaces, protocolos, y de esta forma depender de estas abstracciones y no de implementaciones concretas, pudiendo de esta forma cambiar la implementación de una capa sin que afecte a otras.
Los otros tres principios también deben ser cumplidos, en realidad cualquier arquitectura orientada a objetos debería cumplir SOLID, y aunque no sea fácil debemos obligarnos a ello.
Si en algún momento no estamos cumpliendo las diferentes buenas prácticas y normas no debemos tener miedo a refactorizar y siempre intentar mejorar el código. Si no sabéis qué es la teoría de las ventanas rotas os invito a conocerla.
Para terminar, os dejo un poco de documentación y bibliografía en la que me he apoyado y basado para escribir esto: