Justificacion de Arquitectura - CaviedesGitHub/MiProyectoFinal GitHub Wiki

A continuación comento los estilos, tácticas y patrones utilizados en el diseño de la arquitectura.

Estilos

Estilo Capas (Tiers)

La arquitectura en capas consta en dividir la aplicación en capas, con la intención de que cada capa tenga un rol muy definido, como en la presente propuesta, una capa de presentación (FrontEnd), una capa de reglas de negocio (Backend) y una capa de persistencia. La separación de la aplicación en capas busca cumplir con el principio de separación de preocupaciones, de tal forma que cada capa se encargue una tarea muy definida. Además, es fácil de mantener, debido a que cada capa hace una tarea muy específica, es fácil detectar el origen de un bug para corregirlo, o simplemente se puede identificar donde se debe aplicar un cambio. También ofrece seguridad, la separación de capas permite el aislamiento de los servidores en subredes diferentes, lo que hace más difícil realizar ataques.

Estilo Microservicios

La arquitectura de microservicios es un método de desarrollo de aplicaciones software que funciona como un conjunto de pequeños servicios que se ejecutan de manera independiente y autónoma, proporcionando una funcionalidad de negocio completa. En ella, cada microservicio es un código que puede estar en un lenguaje de programación diferente, y que desempeña una función específica. Los microservicios se comunican entre sí a través de APIs, y cuentan con sistemas de almacenamiento propios, lo que evita la sobrecarga y caída de la aplicación. Los microservicios elegidos para la aplicación son: Empresas, Candidatos, Perfiles, Proceso de Selección, Motor de Emparejamiento, Pruebas Técnicas, pruebas Psicológicas y de Idioma.

Tácticas

Táctica Disponibilidad: Votación por Replicación

La realización más común de esta táctica se conoce como triple redundancia modular (TMR), que emplea tres componentes que hacen lo mismo, cada uno de los cuales recibe entradas idénticas, y envía su salida a la lógica de votación, utilizada para detectar cualquier incoherencia entre los tres estados de salida. Ante una incoherencia, el votante informa de un fallo. También debe decidir qué salida utilizar. Puede la regla de la mayoría, o elegir una media calculada de los resultados dispares. Esta táctica depende en gran medida de la lógica de la votación, que suele ser simple, rigurosamente revisada y probada para que la probabilidad de error sea baja.

  • La replicación es la forma más sencilla de votación; en este caso, los componentes son clones exactos unos de otros. Tener múltiples copias de componentes idénticos puede ser eficaz para protegerse contra fallos aleatorios del hardware, pero no puede proteger contra errores de diseño o implementación, en el hardware o en el software, porque no hay forma de evitarlos.
    Esta táctica es aplicable al motor de emparejamiento, ya que la respuesta de este proceso es muy importante se quieren evitar errores y si ocurren poder enmascararlos e informarlos.

Táctica Disponibilidad: Tratamiento de Excepciones

Una vez detectada una excepción, el sistema debe manejarla de alguna manera. Lo más fácil que puede hacer es simplemente bloquearse, pero, por supuesto, eso es una idea terrible desde el punto de vista de la disponibilidad, la usabilidad, la posibilidad de realizar pruebas y el simple sentido común. Hay posibilidades mucho más productivas. El mecanismo empleado para la gestión de excepciones depende en gran medida del entorno de programación empleado, desde simples códigos de retorno de función (códigos de error) hasta el uso de clases de excepción que contienen información útil en caso de fallo, como el nombre de la excepción lanzada, el origen de la excepción y la causa de la excepción lanzada. El software puede utilizar esta información para enmascarar el fallo, normalmente corrigiendo la causa de la excepción y reintentando la operación. Esta táctica se utiliza con el código que utiliza un objeto futuro que espera la respuesta de uno de los motores de emparejamiento.

Táctica Disponibilidad: Reintentar

La táctica de reintento asume que el fallo que causó el fallo es transitorio y que reintentar la operación puede llevar al éxito. Esta táctica se utiliza en redes y en granjas de servidores donde los fallos son esperados y habituales. Debe haber un límite en el número de reintentos que se intentan antes de que se declare un fallo permanente. Esta táctica se utiliza cuando se intenta 3 veces obtener una respuesta correcta del motor de emparejamiento.

Táctica de Modificabilidad: Reducir el tamaño de un módulo (Dividir el modulo)

Si el módulo que se está modificando incluye una gran cantidad de capacidades, los costes de modificación serán probablemente elevados. Refinar el módulo en varios módulos más pequeños debería reducir el coste medio de futuras modificaciones. Esta táctica se cumple de dos maneras: con la división por capas(tiers) y por supuesto con la división en microservicios.

Táctica de Modificabilidad: Aumentar la cohesión (Aumentar la coherencia semántica)

Varias tácticas implican trasladar responsabilidades de un módulo a otro. El objetivo de trasladar una responsabilidad de un módulo a otro es reducir la probabilidad de que los efectos secundarios de un cambio afecten a otras responsabilidades del módulo original.

Si las responsabilidades A y B de un módulo no sirven para lo mismo deben colocarse en módulos diferentes. Esto puede implicar la creación de un nuevo módulo o trasladar una responsabilidad a un módulo existente. Un método para identificar las responsabilidades que deben trasladarse consiste en formular hipótesis sobre los cambios probables que afectan a un módulo. Si algunas responsabilidades no se ven afectadas por estos cambios, es probable que deban eliminarse de este modulo.

Esta táctica también es aplicada cuando dividimos la app en microservicios, cada microservicio va tener responsabilidades que esten relacionadas entre si.

Táctica de Modificabilidad: Reducir el acoplamiento (Encapsular)

La encapsulación introduce una interfaz explícita en un módulo. Esta interfaz incluye una interfaz de programación de aplicaciones (API) y sus responsabilidades asociadas, como "realizar una transformación sintáctica de un parámetro de entrada a una representación interna". Quizás la táctica de modificabilidad más común, la encapsulación reduce la probabilidad de que un cambio en un módulo se propague a otros módulos. Los puntos fuertes del acoplamiento que antes iban al módulo ahora van a la interfaz del módulo. Sin embargo, estos puntos fuertes se reducen porque la interfaz limita las formas en que las responsabilidades externas pueden interactuar con el módulo.
Esta táctica también es aplicada por los microservicios al ofrecer un api para comunicarse con el mundo exterior.

Táctica de Modificabilidad: Reducir el acoplamiento (Utilice un intermediario para romper una dependencia)

Utilizar un intermediario rompe una dependencia. Dada una dependencia entre la responsabilidad A y responsabilidad B (por ejemplo, para llevar a cabo A primero hay que llevar a cabo B), la dependencia puede romperse utilizando un intermediario. El tipo de intermediario depende del tipo de dependencia. Por ejemplo, un intermediario de publicación-suscripción eliminará el conocimiento del productor de datos de sus consumidores. Lo mismo ocurre con un repositorio de datos compartido, que separa a los lectores de un dato de los escritores de ese dato. En una arquitectura orientada a servicios, en la que los servicios se descubren entre sí mediante búsquedas dinámicas, el servicio de directorio es un elemento clave.
Esta táctica la utilice entre los microservicios "Pruebas técnicas" y "Pruebas psicológicas y de Idiomas " que son productores de mensajes para el microservicio "Candidatos" que los consume por medio de una cola.

Táctica de Seguridad: Detectar los Ataques (Verificar la integridad de los mensajes)

Esta táctica emplea técnicas como sumas de comprobación o valores hash para verificar la integridad de los mensajes, archivos de recursos, archivos de despliegue y archivos de configuración. Una suma de comprobación es un mecanismo de validación en el que el sistema mantiene información redundante para archivos de configuración y mensajes, y utiliza esta información redundante para verificar el archivo de configuración o mensaje cuando se utiliza. Un valor hash es una cadena única generada por una función hash cuya entrada puede ser archivos de configuración o mensajes. Incluso un ligero cambio en los archivos o mensajes originales produce un cambio significativo en el valor hash. Los Json Web Token que utilizo en la app tiene esta característica integrada y lo implementa mediante la sección de firma del token.

Táctica de Seguridad: Resistir los Ataques (Autenticar actores)

Autenticar significa asegurarse de que un actor (un usuario o un ordenador remoto) es realmente quien o lo que pretende ser. Las contraseñas, las contraseñas de un solo uso, los certificados digitales y la identificación biométrica son medios de autenticación. la identificación biométrica proporcionan un medio para la autenticación. Esto lo implemento por el uso de una contraseña que administra el microservicio Auth.

Táctica de Seguridad: Resistir los Ataques (Autorizar a los actores)

Autorizar significa asegurarse de que un actor autenticado tiene los derechos para acceder y modificar datos o servicios. Por lo general, este mecanismo se habilita mecanismos de control de acceso en un sistema. El control de acceso puede ser por actor o por clase de actor. Las clases de actores pueden definirse por grupos de actores, por roles de actores o por listas de individuos. Esto lo implemento por el tipo de token generado por el microservicio Auth.

Patrones

Patrón CQRS

CQRS significa segregación de responsabilidades de comandos y consultas, un patrón que separa las operaciones de lectura y actualización de un almacén de datos. La implementación de CQRS en la aplicación puede maximizar el rendimiento, la escalabilidad y la seguridad. Este patrón fue aplicado sobre el servicio "Perfiles" el cual va ser muy demandado por consultas que pueden afectar el rendimiento de los comandos y viceversa.

Patrón API Gateway

Nos permite aislar la conexión directa del cliente a los microservicios de la aplicación, logrando tener un control de orquestación y asegurando políticas de seguridad de los componentes antes de enviar toda la transacción.

Patrón Productor-Consumidor

El patrón productor consumidor (producers/consumers) en un patrón de diseño que designa los procesos para ser productores de recursos, en nuestro caso, mensajes. O consumidores de los mismos. Utilizare el patrón productor-consumidor para la comunicación asincrónica entre los componentes productores de mensajes "Pruebas técnicas" y "pruebas psicológicas y de idiomas" con el componente "Candidatos". Esto desacoplara los componentes involucrados y le permitirá escalar con más facilidad, al tiempo que mejora la disponibilidad del sistema y reduce la complejidad del desarrollo.

Patron MVVM

Se caracteriza por tratar de desacoplar lo máximo posible la interfaz de usuario de la lógica de la aplicación.