CornerJob es una startup que se dedica al sector de búsqueda de empleo en una especialidad denominada ‘Blue collar’. Básicamente son trabajos que se caracterizan por ser temporales, en buena medida, y con una alta tasa de rotación. La gran baza de CornerJob siempre ha sido estar muy orientado al mundo móvil y en la eliminación de procesos burocráticos para poner en contacto al candidato y la empresa. Para cumplir estos objetivos, desarrollaron Android y iOS Objective-c app.

Apiumhub comenzó a colaborar con CornerJob en Septiembre de 2016 para poder llevar a cabo tareas de mejora en iOS Objective-c app, y cuyo principal objetivo era desacoplar la aplicación de Parse y modularizar.

CornerJob ya tenía trazado un road map de cómo querían que evolucionara la aplicación y la arquitectura que querían aplicar en ciclos iterativos para llevar a cabo la inmensa tarea que tenían entre manos en su Objective-c app. 

La aplicación inicial se desarrolló creando Objective-c app, utilizando el framework Parse (un ‘mobile backend as a service’ que fue comprado por Facebook y finalmente convertido en proyecto open source),sin una arquitectura claramente definida, ya que los objetos de Parse predominaban en toda la aplicación.

La mayor parte del código estaba fuertemente acoplado y Parse estaba presente en todas las partes de la aplicación. Además las vistas estaban todas creadas por código lo que muchas veces dificultaba la legibilidad de lo que hacía un flujo concreto, porque la lógica era compartida por la parte de gestionar la información del cliente y la de gestionar la información de la compañía. Una foto de como era la aplicación a nivel técnico en aquel momento, podría ser algo así:

ios objective-c app cornerjob

 

La primera tarea según el plan trazado por CornerJob fue crear el modelo de negocio donde se separó la lógica de negocio del código de Parse. En esta fase también se crearon las bases de la capa de red y el local storage.

En paralelo se fue dando forma al sistema de integración continua, del que ya había una primera versión basado en XCode server y bots que se encargaban de ejecutar cada una de las fases del ciclo de vida y deployment. En este caso, optaron para agilizar el proceso probando la solución de Fastlane que no estuvo exenta de ciertas complejidades debido a las versiones de ruby y problemas con los certificados.

La solución de desacoplamiento del modelo quedaba algo así

ios objective-c model decoupling

 

Mediante el uso de metodologías Agiles utilizando Scrum y trabajando por sprints se fue completando la tarea de migrar todas las entidades, así como extraer la funcionalidad de las vistas y reemplazarlas por ficheros Xib donde quedaban más claras las responsabilidades de la vista.

 

Para modelar las vistas se utilizó autolayout de forma bastante intensa para poder manejar toda la variedad y tamaño de dispositivos que soportan la aplicación y esta se viera de forma correcta bajo cualquier circunstancia.

 

Una vez terminada esta fase, la aplicación ya tenía un mayor grado de componentización lo que permitía tener una visión más global de las capas que formaban la aplicación y cómo empezar a hacer una separación más estricta. En esta fase partimos de esta división:

ios objective-c app corberjob entry

 

Con este punto de partida ya teníamos una mayor facilidad para conocer cómo añadir las siguientes capas lógicas y aumentar la modularización, reducir el acoplamiento y añadir los test unitarios.

Los ViewController ahora ya tenían cierto grado de responsabilidad y se había acotado a través de los entities del modelo el alcance de Parse, lo que permitía crear componentes de una forma más rápida y más clara.

La arquitectura diseñada por CornerJob constaba de una fase intermedia, donde se haría especial énfasis en modularizar la parte del modelo. Para ello se pensó en añadir una capa denominada Interactors que contienen los casos de uso de negocio de la aplicación, por lo que la única responsabilidad de los viewControllers es la de pintar los datos. Para ello los Interactors colaboran con objetos de tipo Repository para ejecutar las operaciones de negocio necesarias. Un repository recibe una clase de configuración, que se denomina Query, esta se pasa al Datasource Manager que es el que decide qué tipo de datasource será ejecutado (de red, local storage o caché) en función de la query que se le ha pasado. En esta fase es cuando se empieza a hacer uso intensivo de test unitarios y también cuando se introducen los primeros test de interfaz. La gran ventaja de esta solución es que permite crear flujos de trabajo por configuración, ya que la mayor parte del código es común entre capas y la parte variable es la parte de las Query que le indican al sistema como ha de comportarse.

En paralelo al desarrollo de esta parte, se introdujo el uso de Realm como sistema de local storage lo que aportó 2 grandes ventajas a la aplicación, reducir el número de llamadas a las APIs de servidor y convertir cierta parte de los flujos de datos en un sistema reactivo. Gracias al sistema de objetos de entidad montado en la aplicación de CornerJob (cada objeto tiene un correspondiente para local storage y para entidad de negocio) cada vez que se modifica la base de datos local, las vistas se actualizan reactivamente a través de notificaciones de Realm. El proceso es el siguiente, el usuario desencadena un evento, si ese evento, por configuración se debe salvar en algún momento Realm, una vez la API devuelva la respuesta del backend, los datos se actualizan en el local storage (Realm) y la vista se actualiza automáticamente de forma reactiva. La foto de este momento es la siguiente:

ioc objective-c app data source

Como se puede comprobar en el gráfico ya tenemos una aplicación altamente modular y con test unitarios en la parte de la lógica de negocio y en el Core de la aplicación (interactor,datasource, query,entity, CJObjectBase, layers…).

Se ha reducido enormemente el acoplamiento con Parse y se ha logrado una aplicación lo suficientemente flexible y modular para poder aplicar en ella cualquiera de las arquitecturas actuales con el menor coste posible, como por ejemplo la arquitectura MVVM con Swift, que es una de las posibilidades que se está estudiando. Los flujos de operaciones de la aplicación ahora son más atómicos, lo que permite poder hacer un mejor seguimiento de los mismos para tareas de depuración y mejora, añadiendo nuevas funcionalidades.

Debemos tener en cuenta que todo este proceso se llevó a cabo sin cambiar el lenguaje de programación, que sigue siendo iOS Objective-c app. Lo que ha permitido centrarse en las tareas de mejora y evitar los diferentes problemas de nuevas versiones o fallos de lenguajes tan actuales como Swift en esta plataforma. Así mismo hay que destacar que el proceso iterativo ha permitido evolucionar la arquitectura al tiempo que se añadían nuevas funcionalidades y se corregían errores, lo que pone de relieve el gran logro llevado a cabo para evolucionar la aplicación disponiendo siempre de una versión plenamente funcional.

Suscríbete a nuestro newsletter para estar al día de los eventos, meet ups y demás artículos!

 

Si este artículo sobre iOS Objective-c app te gustó, te puede interesar:

 

F-Bound en Scala

Tendencias en aplicaciónes móviles

Patrón MVP en iOS

Debugging con Charles Proxy en Android emulator

Por qué Kotlin?   

Integración Continua en iOS usando Fastlane y Jenkins