Desarrollar la mayor plataforma bancaria actual, que abarca más de 160 millones de clientes, más de diez mercados y a la que contribuyen equipos de desarrollo de distintas geografías es un desafío que exige una arquitectura a la altura.
Introducción
En ODS, a lo largo de los años, hemos aprendido que la correcta implementación de una arquitectura nos permite escalar tanto en complejidad como en número de proyectos de una forma más ágil. Incluso cuando esto supone una curva de aprendizaje más elevada para quien se incorpora al equipo. En este articulo profundizaremos un poco en esta arquitectura y en cómo nos ayuda a afrontar los desafíos técnicos que surgen día tras día.
En nuestro caso hemos optado por una arquitectura modular en la que ciertas partes están separadas y aisladas del resto en todos los niveles, desde el código hasta el despliegue. Esto conlleva un costo de mantenimiento, pero la principal ventaja es que esas partes tienen un ciclo de vida (idealmente) independiente. Esto les permite crecer a velocidades distintas y con requerimientos distintos.
Ya que en ODS desarrollamos productos bancarios, tenemos funcionalidades como Cuentas, Préstamos o Tarjetas, entre otras. Además, desplegamos nuestra solución en diferentes mercados donde cada uno tiene sus particularidades. La arquitectura modular nos permite separar estas funcionalidades tanto horizontal como verticalmente, mediante bibliotecas de software (libraries):
- Horizontalmente, ya que cada funcionalidad es independiente.
- Verticalmente, porque esas funcionalidades se pueden extender y sobrescribir.
También hay que tener en cuenta la existencia de unidades globales y locales. Las unidades globales resuelven el gran porcentaje del problema, mientras que las unidades locales, si son necesarias, completan esa última milla con las particularidades antes mencionadas.

Con esta organización hemos logrado estructurar nuestra solución que actualmente contiene más de 100 proyectos y/o repositorios por plataforma.
Conceptos a tener en cuenta
Clean Architecture
El concepto de Clean architecture, propuesto por el ingeniero de software Robert Martin, se basa en un enfoque que permite organizar el código de tal manera que sea más fácil de mantener, escalar y probar sus distintas partes. Este enfoque separa la lógica de negocio de los detalles de implementación, tanto de interfaz de usuario como de capa de datos y dependencias. Aquí la capa de datos y la de presentación dependen de la capa de dominio (lógica de negocio), y entre ellas no existe ningún tipo de relación.

Principios SOLID
Los cinco principios de diseño SOLID buscan mejorar la calidad y mantenibilidad del código:
- Single Responsibility Principle (Principio de Responsabilidad Única): Una clase u entidad debe tener una única responsabilidad o motivo para cambiar. Con ello evitamos clases que realizan múltiples funciones y concentran demasiadas responsabilidades.
- Open-Close Principle (Principio Abierto-Cerrado): La entidad debe estar abierta para la extensión, pero cerrada a modificación.
- Liskov Substitution Principle (Principio de Sustitución de Barbara Liskov): Si una clase B es subclase de una clase A, objetos de la clase A deberían poder reemplazarse con objetos de la clase B sin que nada falle. Por ejemplo, si tengo una clase «ave” con el método “volar”, y creo una clase “avestruz” que hereda de “ave”, al ejecutar “volar” debería fallar porque estas no vuelan. Ese ejemplo no cumple con este principio, y la jerarquía de clases debe reformularse para poder cumplirlo. En cambio, introduciendo una clase “ave” de la cual podría heredar “avestruz”, y una clase “AveVoladora” que herede de “ave” e incorpore el método “volar”).
- Interface Segregation Principle (Principio de Segregación de Interfaces): No deberían existir interfaces grandes que obliguen a una clase a implementar métodos que no utilizan o no pueden implementar. Si hay una interfaz así, la debemos separar en otras más específicas.
- Dependency inversion Principle (Principio de Inversión de Dependencia): Los módulos de alto nivel no deben depender de módulos de bajo nivel y ambos deben dependen de abstracciones. Por ejemplo, una clase no debería instanciar un “EMailSender” específico, sino trabajar con una abstracción (interfaz) que permita luego sustituir la implementación sin modificar a la clase que la utiliza.
Inyección de dependencias
La inyección de dependencias es un patrón de diseño que permite gestionar las dependencias de un objecto. En vez de que un objeto instancie sus dependencias, estas se crean e inyectan desde el exterior. Esto facilita el reemplazo de dependencias y las pruebas unitarias, ya que permite reemplazar implementaciones por mocks que nos ayuden en las distintas pruebas.
La arquitectura de ODS
Las piezas de software que construimos en nuestra arquitectura se pueden poner y sacar como si fuesen de lego. Esto lo logramos, entre otras cosas, porque definimos protocolos, interfaces e implementaciones por defecto, luego cualquier pieza de software puede extender y/o sobrescribir esa implementación. Aquí la inyección de dependencias juega un rol fundamental. Prácticamente todo es inyectable. No sólo para poder crear mocks que nos ayuden a testear, sino también para permitir la extensión y modificación del software.
Esta filosofía se da en todas las plataformas: API, Android, Web, e incluso en iOS, donde, por ejemplo. no existe un estándar de mercado para la inyección de dependencias y, por lo tanto, hemos desarrollado uno propio. La arquitectura modular se aplica con el mismo criterio en todas las plataformas, si en iOS tenemos un repositorio de Cuentas específico para Argentina, en el resto de las plataformas también.
Adoptar y mantener un estándar es fundamental para asegurar una arquitectura ordenada y que se pueda comprender fácilmente.
Dentro de cada una de estas piezas, implementamos la Clean architecture. El dominio es la pieza central, tanto la capa de datos como la de presentación, no solo dependen de él, sino que entre ellas se desconocen. El código está desacoplado, organizado y las responsabilidades de cada pieza están correctamente asignadas. A esta organización se le suma un beneficio producto de la modularización. En cualquier momento se puede reemplazar la capa de Data, Domain o Presentation por otra implementación a través de la inyección de dependencias, y extender o modificar solo una de ellas sin necesidad de reescribir más allá de lo necesario.
Obstáculos de nuestra arquitectura
El primer obstáculo al implementar esta arquitectura tiene que ver con las dimensiones. Muchos proyectos, muchos repositorios, muchos componentes. Para el éxito de esta arquitectura es fundamental contar con un buen nivel de automatización. Desde templates o starters que estandaricen la estructura de cada proyecto, hasta la implementación integración y despliegue continuo en todas las plataformas.
El siguiente obstáculo está relacionado con la comunicación. No solo nos interesa que la arquitectura sea idéntica (o lo más parecida) entre plataformas, también que el código, al menos la interfaz pública, lo sea. Es por esto por lo que los equipos de frontend, sobre todo iOS y Android, deben trabajar sincronizados en cada desarrollo.
Por último, en algunas plataformas es más fácil la implementación de este tipo de arquitecturas que en otras. En el mundo backend / Android la adopción de estos principios lleva muchos años. En otras como iOS, algunas cosas no tienen la madurez que en otras plataformas. Esto lo hemos suplido con desarrollos propios: un inyector de dependencias, integración con Maven y Nexus para desplegar artefactos (xcframeworks) y gestión de proyectos con Tuist, entre otros.
Conclusión
Aunque hemos conseguido alcanzar una mayor madurez en nuestra arquitectura durante el último año, es importante recordar que esta no es rígida, sino que debe poseer la flexibilidad necesaria para evolucionar y, más importante, facilitar el desarrollo de productos de calidad.
Independientemente de lo ambicioso que pueda ser nuestro concepto de arquitectura ideal, debemos tener presente que su propósito es ser el soporte sobre el que construiremos nuestro producto.


Deja un comentario