Acerca de arc42

arc42, la plantilla de documentación para arquitectura de sistemas y de software.

Revisión de la plantilla: 7.0 ES (basada en asciidoc), Enero 2017

Por Dr. Gernot Starke, Dr. Peter Hruschka y otros contribuyentes.


1. Introducción y objetivos

La empresa de desarrollo de juegos Micrati ha decidido desarrollar una plataforma web donde los usuarios puedan jugar diferentes variantes del juego Y, un juego estratégico de tablero existente. El objetivo inicial es ofrecer una experiencia entretenida e intuitiva que atraiga a nuevos usuarios y los mantenga comprometidos con el producto a largo plazo. La plataforma (YOVI) estará disponible en web, permitirá jugar contra diferentes estrategias de bots con niveles de dificultad seleccionables. El motor de juego y estará implementado en Rust, mientras que el cliente web principal estará desarrollado en TypeScript.

1.1. Resumen de requisitos

Los requisitos principales del sistema son:

  • Ofrecer una versión clásica del juego Y en la web, donde los usuarios podran registrarse y jugar partidas contra la máquina.

  • Se podrá jugar con distintas estrategias y con varios modos de dificultad. Se necesitan al menos dos estrategias distintas; los jugadores eligirán contra qué estrategias y dificultades jugar.

  • Los usuarios podrán registrarse en el sistema. Una vez registrados, las partidas que jueguen serán almacenadas en un histórico de partidas (número de partidas totales, ganadas y perdidas) que podrán ser consultado desde su cuenta.

  • La aplicación ofrecerá una API que permitirá a terceros interactuar con la aplicación: gestionar usuarios, histórico y registros, para así tener la posibilidad de desarrollar su propia aplicación.

  • La aplicación ofrecerá un API que permitirá a los bots jugar contra la aplicación, utilizando un método play que especificará su posición del tablero en notación YEN mediante un parámetro position. Opcionalmente, también se especificará el ID del bot contra el que jugar mediante un parámetro bot_id.

Además, se decide añadir las siguientes características opcionales:

  • Internacionalización con los idiomas español, inglés, alemás y francés.

  • Ranking de usuarios donde se puedan ver los usuarios con más partidas ganadas.

  • Sugerir movimiento al jugador, limitándolo a una sugerencia por jugador en cada partida.

  • Permitir realizar partidas jugador contra jugador locales utilizando una sola cuenta.

1.2. Objetivos de calidad

Objetivo de calidad Descripción

Usabilidad

El sistema debe ser fácil de usar y de aprender para los usuarios finales. Esto fomentará que utilicen la aplicación nuevamente y disfruten la experiencia. Interfaces intuitivas y flujos de usuario simplificados (≤3 pasos para acciones principales).

Accesibilidad

El juego debería tener en cuenta la usabilidad por parte de personas con problemas de visión o audición para que estas puedan jugar sin problemas.

Rendimiento

La aplicación debe responder a las solicitudes de los usuarios en un tiempo razonable (< 0.5 segundos) para evitar que abandonen la aplicación y garantizar una experiencia fluida en el juego.

Mantenibilidad

El sistema debe ser fácil de mantener y extender. Esto se logra manteniendo una documentación clara y asegurando la modularidad de la aplicación.

Seguridad

Los datos privados de los usuarios registrados deben mantenerse seguros.

Correctitud funcional

El motor del juego debe validar movimientos y detectar correctamente la condición de victoria según las reglas del juego Y, con precisión del 100% en casos de prueba definidos.

1.3. Stakeholders

Role/Name Contact Expectations

Equipo de desarrollo

https://github.com/NachoTS, https://github.com/tonipdd, https://github.com/alonsobayonalejandro-ctrl, https://github.com/Gedepe, https://github.com/UO300475

Responsables de desarrollar la aplicación usando buenas técnicas, trabajar adecuadamente como equipo y lograr una solución lo más mantenible, usable y extensible posible.

Usuarios / Jugadores

-

Tener una buena experiencia utilizando la aplicación, donde puedan jugar al juego usando diferentes estrategias y consultar sus estadísticas.

Consumidores de la API

-

Poder utilizar la API de forma sencilla y sin problemas, teniendo así la capacidad de crear sus propios frontends del juego.

Micrati

-

Espera obtener una aplicación que se alinee con sus ideas y objetivos, que pueda servir como base para futuras extensiones comerciales.

Profesores de la asignatura ASW

-

Asumir el rol de Product Owner, definiendo requisitos de alto nivel, proporcionando retroalimentación al equipo de desarrollo y evaluando el producto desarrollado. Asegurar que se sigan buenas prácticas arquitectónicas y que el código sea mantenible y bien documentado.

2. Restricciones de Arquitectura

Esta sección describe las restricciones que limitan la libertad de decisión de los arquitectos de software en cuanto al diseño, implementación y proceso de desarrollo.

2.1. Restricciones Técnicas

Restricción

Descripción

Stack tecnológico

El sistema debe estar compuesto por servicios que utilizan diferentes tecnologías: TypeScript (Aplicación web) y Rust (Motor de Juego).

Contenedores

Todos los servicios y componentes de infraestructura deben estar contenedorizados mediante Docker en al menos dos subsistemas.

API para bots

Se debe ofrecer un API que permita a bots interactuar con la aplicación que siga una interfaz concreta.

2.2. Restricciones Organizativas

Restricción

Descripción

Control de Versiones

Uso obligatorio de GitHub como repositorio central para el código, seguimiento de incidencias (issues) y colaboración.

Despliegue

Despliegue automatizado mediante GitHub Actions y alojamiento de la documentación técnica en GitHub Pages.

2.3. Convenciones

Conveción

Descripción

Estándar de Documentación

La documentación de la arquitectura debe seguir la plantilla Arc42 y estar escrita en formato AsciiDoc.

Estándar de Notación

El motor de juego debe utilizar formatos específicos para la representación de las partidas: YEN (Y Exchange Notation).

Documentación OpenAPI

Se debe utilizar el estándar OpenAPI para documentar la API pública.

Actas

Se debe crear un registro de actas de reunión por cada reunión realizada.

3. Contexto y alcance

Esta sección describe el entorno en el que opera el sistema YOVI y las interacciones con actores externos. El sistema se presenta como una caja negra, mostrando únicamente sus relaciones con el exterior.

3.1. Contexto de negocio

Diagram

El sistema YOVI proporciona al jugador información sobre el estado del juego y diferentes estadísticas.

El actor externo principal del sistema es el jugador, que puede registrarse y participar en partidas.

Además, existe el actor de bot externo, el cual se conectra con el API de la aplicación para jugar y que también puede utilizar los endpoints de la API para gestionar información como usuarios o rankings.

3.2. Contexto técnico

Diagram

El sistema YOVI expone una interfaz basada en servicios web accesibles mediante protocolo HTTP/HTTPS.

Las llamadas que requieren autenticación serán gestionadas mediante cookies de sesión obtenidas en los endpoints públicos de inicio de sesión y registro.

Los actores externos interactúan con el sistema mediante peticiones y respuestas estructuradas en formato JSON.

3.2.1. Mapeo de entrada/salida a canales

Actor Canal Entrada al sistema Salida del sistema

Jugador

HTTP/HTTPS

Datos de registro, autenticación, acciones del juego

Estado del juego, resultados, estadísticas

Bot

HTTP/HTTPS + JSON

Llamadas a la API pública y a la API play

Estado del juego y resultados

4. Estrategia de Solución

4.1. Tecnologías seleccionadas

Basándonos en los requisitos del proyecto, se han seleccionado las siguientes tecnologías para garantizar un sistema modular y eficiente:

  • Frontend:

    • React con Vite: Para construir una interfaz de usuario rápida y reactiva como Single Page Application (SPA).

    • TypeScript: Añade tipado estático para reducir errores en el desarrollo del frontend.

  • Backend de Usuarios:

    • Node.js & Express: Entorno ligero y escalable para gestionar la lógica de usuarios y la API REST.

    • express-session: módulo de Express para gestionar la autenticación mediante cookies de sesión

  • Motor de Juego:

    • Rust: alto rendimiento y seguridad de memoria para el motor de juego y la lógica de bots.

  • Persistencia y Datos:

    • MySQL: base de datos relacional para gestionar de forma eficiente el modelo de datos de la aplicación, el cual sigue una estructura relacional.

    • Sequelize: ORM de MySQL para facilitar la interacción con el modelo relacional de la aplicación.

  • Orquestación:

    • Docker: se utiliza Docker para la orquestación y despliegue de los distintos contenedores que forman la aplicación.

  • Pruebas:

    • Pruebas unitarias: se utiliza la biblioteca vitest y las herramientas estándar de Rust de pruebas unitarias.

    • Pruebas de aceptación: se utilizan las bibliotecas vitest y playwright.

4.2. Decisiones de organización del equipo

Se utilizan las siguientes herramientas de GitHub:

  • Sistema de issues

  • Sistema de pull requests para revisión de código

  • Proyectos y vista de kanban para gestión de issues

  • Wiki de GitHub para el registro de acta, decisiones y guías misceláneas.

Las comunicaciones en tiempo real se llevarán a cabo mediante Whatsapp o Discord.

Se asigna a cada miembro del equipo la responsabilidad de ser capaz de entender el comportamiento general del código resto de miembros del equipo, independientemente de qué parte del código haya programado el mismo.

5. Vista de Bloques

5.1. Sistema General de Caja Blanca

vista bloques 1
Motivación

La aplicación web YOVI permite a los usuarios registrarse en su sistema para jugar partidas al juego Y. Una vez registrados, los jugadores pueden jugar partidas contra la máquina; el sistema registrará su histórico de juego y diversas estadísticas.

Además, la aplicación ofrece un API externo que permite a los bots interactuar con ella y obtener información de partidas y de jugadores, así como jugar contra ella.

Bloques de construcción contenidos
Nombre Responsabilidad

Usuario

 Interactúa con la aplicación web para registrarse en ella y jugar partidas al juego Y

Bot

 Interactúa con el API pública de la aplicación para obtener información de jugadores/partidas y para jugar contra la máquina mediante el método play

Aplicación web YOVI

 Muestra la interfaz web al usuario y expone el API público para los bots.

5.2. Nivel 2

5.2.1. Caja Blanca Aplicación web YOVI

vista bloques 2 yovi
Motivación

La aplicación se divide en tres servicios: el motor de juego, Gamey, el módulo de gestión de usuarios, Users, y la interfaz de la aplicación web, Webapp. Webapp se comunica con Gamey y Users para poder llevar a cabo sus funciones de gestionar sesiones de usuarios y estadísticas. A su vez, Users se conecta con la base de datos para obtener la información relativa a los usuarios y estadísticas.

Bloques de construcción contenidos
Nombre Responsabilidad

Usuario

 Interactúa con la aplicación web para registrarse en ella y jugar partidas al juego Y

Bot

 Interactúa con el API de la aplicación para obtener información de jugadores/partidas y para jugar contra la máquina

Gamey

 Gestiona el motor del juego Y tanto como para usuarios como para bots

Users

 Gestiona el registro e inicio de sesión de usuarios, así como su histórico

Webapp

 Muestra la aplicación web al usuario y expone el API de juego a los bots

BD

 Almacena la información sobre los usuarios e histórico de partidas

5.3. Nivel 3

5.3.1. Caja Blanca Gamey

vista bloques 3 gamey
Motivación

El módulo de juego Gamey separa las responsabilidades de gestión de peticiones de juego, gestión de mecánicas del juego y selección de IAs contra las que jugar en submódulos diferentes con el objetivo de que estos sean fácilmente configurables o reemplazables.

Bloques de construcción contenidos
Nombre Responsabilidad

Bots

 Provee lógica de juego contra la que otros usuarios y bots podrán jugar

BotServer

 Gestiona las peticiones de juegos (movimientos de juego, estado de la partida) realizadas por usuarios y bots.

Core

 Provee la lógica base de las mecánicas del juego tales como los movimientos válidos o las condiciones de victoria

Notation

 Provee estructura sobre la notación YEN de movimientos y estado del juego

5.3.2. Caja Blanca Users

Motivación

El módulo de juego Users separa las responsabilidades de registro/inicio de sesión de usuarios y recopilación de estadísticas de juego en dos submódulos distintos con acceso a la base de datos.

Bloques de construcción contenidos
Nombre Responsabilidad

service/users

 Gestiona el registro e inicio de sesión de usuarios

service/stats

 Gestiona las estadísticas de juego y rankings de usuarios

vista bloques 3 users

6. Vista de ejecución

A continuacion se presentan los distintos escenarios que describen las interacciones entre las instancias del sistema. Cada escenario se centra en un caso de uso específico, que seran:

  • Registro de un nuevo usuario

  • Inicio de sesión

  • Partida de juego

  • Consultar ranking de jugadores

6.1. Registro de un nuevo usuario

Al entrar por primera vez a la aplicación, el usuario se encuentra con la pantalla de registro. En esta pantalla, el usuario introduce sus datos y al hacer clic en el botón de registro, se envía una solicitud al servidor para crear una nueva cuenta. Si es valida se crea la cuenta y se muestra un mensaje de éxito, de lo contrario se muestra un mensaje de error.

registro usuario

6.2. Inicio de sesión

Tras crear un usuario, el usuario puede iniciar sesión en la aplicación. En la pantalla de inicio de sesión, el usuario introduce su nombre de usuario y contraseña. Al hacer clic en el botón de inicio de sesión, se envía una solicitud al servidor para autenticar al usuario. Si las credenciales son correctas, se muestra la pantalla principal de la aplicación, de lo contrario se muestra un mensaje de error indicando que las credenciales son incorrectas.

inicio sesion usuario

6.3. Secuencia de partida de juego

Una vez que el usuario ha iniciado sesión, puede comenzar una partida de juego. Al hacer clic en el botón "Start Game", se envía una solicitud al servidor para iniciar una nueva partida. El servidor responde con los detalles de la partida, como el número de jugadores y el estado del juego. La aplicación muestra la pantalla de juego con la información recibida.

secuencia partida juego

7. Vista de Despliegue

7.1. Nivel de infraestructura 1

diagrama despliegue 1
Motivación

La infraestructura del sistema se divide en varios servicios desplegados en sendos contenedores Docker con el objetivo de conseguir una arquitectura modular que permita que cada servicio sea fácilmente reemplazable y desplegable en otra máquina o entorno.

Nótese que desde el navegador web, el usuario tiene acceso a

  • Webapp: puerto HTTP 80

  • API pública de la aplicación: Puerto HTTP 3000

    Características de Calidad/Rendimiento
    • Tolerancia a fallos: un módulo concreto puede fallar sin que esto afecte al resto.

    • Modularidad: los componentes pueden ser reemplazados de forma sencilla.

    • Reusabilidad: componentes concretos pueden ser instalados en otros entornos de forma sencilla.

    • Coexistencia: la infraestructura puede desplegarse correctamente en entornos que comportan otros productos.

    • Adaptabilidad: la infraestructura puede ser desplegada en un sistema abstrayéndose de su configuración concreta.

    • Instalabilidad: la infraestructura puede ser instalada de forma sencilla en un nuevo sistema.

    Mapeo de los Bloques de Construcción a Infraestructura

    Cada módulo de la aplicación es desplegado en un contenedor Docker distinto. De la misma forma, el sistema gestor de bases de datos también es desplegado en su propio contenedor Docker.

A continuación se detalla el mapeo de artefactos de software a infraestructura.

Artefacto Infraestructura

Gamey

Contenedor Docker Gamey

Users

Contenedor Docker Users

Webapp

Contenedor Docker Webapp

Base de datos

Contenedor Docker MySQL

8. Conceptos Transversales (Cross-cutting)

8.1. Tecnología utilizada

La persistencia de datos se gestiona mediante una base de datos MySQL, accedida a través del ORM Sequelize en el backend Node.js. Sequelize se encarga de la creación y sincronización de las tablas, así como de la gestión de las relaciones entre entidades.

8.2. Entidades y esquema relacional

El modelo de datos está compuesto por dos tablas: Usuarios y Partidas. La relación entre ellas es de uno a muchos: un usuario puede tener asociadas múltiples partidas, pero cada partida pertenece exactamente a un usuario. La integridad referencial se gestiona mediante la clave foránea id_usuario en la tabla Partidas.

Base de datos de Yovi

8.2.1. Tabla Usuarios

Almacena los datos de registro y autenticación de cada jugador registrado en el sistema.

Campo Tipo Restricciones Descripción

id_usuario

INTEGER

PK, AUTO_INCREMENT

Identificador único del usuario

nombre

VARCHAR(255)

NOT NULL

Nombre real del usuario

nom_usuario

VARCHAR(255)

NOT NULL, UNIQUE

Nombre de usuario para login

contraseña

VARCHAR(255)

NOT NULL

Contraseña del usuario (hash)

8.2.2. Tabla Partidas

Registra el historial de partidas jugadas, asociando cada partida a un usuario y al bot oponente.

Campo Tipo Restricciones Descripción

id_partida

INTEGER

PK, AUTO_INCREMENT

Identificador único de la partida

id_usuario

INTEGER

NOT NULL, FK

Referencia al usuario que jugó la partida

oponente

VARCHAR(255)

NOT NULL

Identificador del bot oponente

ganada

BOOLEAN

NOT NULL

true si el usuario ganó, false si perdió

8.3. Decisiones de diseño relevantes

  • Resultado de la partida: se almacena como un valor booleano (true si el usuario gana y false si el usuario pierde) porque los empates no son posibles en el juego Y.

  • Almacenamiento de contraseñas: El campo contrasena debe almacenar exclusivamente el hash de la contraseña. La responsabilidad del hasheo recae en la capa de servicio, no en el modelo.

8.4. Ámbito de las pruebas de aceptación y comportamiento general de la IU

Las pruebas de aceptación se ejecutan sobre Chrome, y el resto de pruebas han sido realizadas en navegadores basados en Chromium y Firefox. Es posible que en algunos navegadores no probados, como Safari, algunas características visuales de la aplicación no se muestren correctamente.

Además, las pruebas se han realizado en pantallas de resoluciones 1920x1080 y 1280x800. No se garantiza el correcto funcionamiento de la interfaz en resoluciones inferiores.

9. Decisiones de arquitectura

Para más decisiones arquitectónicas, véase el punto 4 de esta documentación.

9.1. Selección de sistema gestor de base de datos

9.1.1. Contexto

Existía la necesidad de seleccionar un sistema de persistencia para la aplicación.

9.1.2. Decisión

Se tomó la decisión entre los desarrolladores de utilizar un SGBD relacional, puesto que el modelo de datos seguía un modelo entidad-relación.

Además, de entre múltiples SGBD relacionales, se decidió utilizar MySQL debido a que los desarrolladores ya conocían la tecnología y a que este SGBD se comporta adecuadamente en entornos concurrentes.

9.1.3. Estado

Aceptado

9.1.4. Consecuencias

El modelo de persistencia de la aplicación queda atado a un modelo entidad relación, lo cual complicaría el cambio a un SGBD no relacional.

Por otra parte, cambiar de un SGBD relacional a otro no debería suponer mayor problema.

9.2. Selección de ORM

9.2.1. Contexto

Existía la necesidad de facilitar la interacción con el SGBD.

9.2.2. Decisión

Se tomó la decisión de utilizar un ORM para facilitar y acelerar el desarrollo. Pese a que inicialmente no se estaba seguro de cuál utilizar por falta de experiencia en el entorno actual (Node.js + Express), se decidió utilizar el ORM Sequelize por ser compatible con MySQL y estar bien documentado.

9.2.3. Estado

Aceptado

9.2.4. Consecuencias

La lógica de de interacción con la persistencia queda atada al API de Sequelize. Cambiar este ORM por otro puede incurrir en tiempo de desarrollo adicional.

Por otra parte, se espera que el uso de este ORM acelere el desarrollo del módulo users.

9.3. Uso de Test Driven Design

9.3.1. Contexto

Existía la necesidad de agilizar el desarrollo de las pruebas unitarias para mantener el mínimo de cobertura de código.

9.3.2. Decisión

Se tomó la decisión de, en ciertos módulos como el módulo stats de users, desarrollar primero las pruebas unitarias y después implementar la funcionalidad de acorde a estas.

9.3.3. Estado

Aceptado

9.3.4. Consecuencias

Si bien al principio hubo un coste de adaptación, se consiguió agilizar el desarrollo de pruebas unitarias.

Sin embargo, usar esta metodología para todo el código no siempre es posible, así que solo se utiliza en partes críticas del código donde existen muchos casos de prueba.

9.4. Arquitectura de comunicación con gamey

9.4.1. Contexto

Se debía decidir cómo comunicar el estado de la partida con el motor de juego (gamey).

9.4.2. Decisión

Se tomó la decisión de utilizar una arquitectura cliente servidor sin estado; de esta forma, no se envía un movimiento como tal, sino la disposición actual de las fichas en el tablero. A partir de esta información, Gamey calcula y devuelve su jugada sin depender de acciones previas en la partida.

9.4.3. Estado

Aceptado

9.4.4. Consecuencias

No tener que gestionar el estado de la partida en gamey ayuda al desacoplamiento entre gamey y el cliente, pues gamey no necesita conocer el estado de movimientos de la partida para poder responder a las peticiones de juego. También facilita la programación de bots, puesto que estos no necesitan acceder al estado de movimientos previos de la partida para dar su respuesta.

Sin embargo, esto limita qué tipo de bots pueden programarse, ya que dificulta la programación de bots que se basen en jugadas previas concretas para calcular su respuesta.

10. Requisitos de calidad

10.1. Árbol de Calidad

arbol calidad

10.2. Escenarios de Calidad

Usabilidad

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Usuario

 Intenta acceder a la pantalla de juego

Interfaz de usuario

Operación normal

Número de pasos realizados

⇐ 3 pasos

Accesibilidad

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Usuario

 Juega una partida con problemas de visión

Interfaz de usuario

Operación normal

Elementos visualizados de forma clara

>90% elementos

Rendimiento

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Usuario

 Realiza una partida

Interfaz de usuario

Operación normal

Tiempo de respuesta media por acción

<0.5 segundos

Bot

 Interactúa con la API

API para bots externos

Operación normal

Tiempo de respuesta media por acción

<1 segundo

Mantenibilidad

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Stakeholder

 Sugiere añadir un nuevo modo de juego

Componentes de la aplicación

Operación de modificación

Coste de añadir nuevo modo de juego

Proporcional al tiempo usual de desarrollo, sin coste adicional por deuda técnica

Seguridad

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Usuario

 Se registra en la aplicación

Interfaz de registro

Operación normal

Privacidad de los datos introducidos

Datos cifrados y accesibles solo por el propio usuario

Bot

 Accede a información de usuarios

API de usuarios

Operación normal

Privacidad de los datos solicitados

Solo mostrar información no sensible

Correctitud funcional

Fuente Estímulo Artefacto Entorno Respuesta Medida de la respuesta

Usuario

 Realiza una jugada

Interfaz de juego

Operación normal

Consistencia de la operación

La respuesta debe ser siempre la esperada por las reglas del juego

Bot

 Realiza una jugada

API de juego

Operación normal

Consistencia de la operación

La respuesta debe ser siempre la esperada por las reglas del juego

11. Riesgos y deuda técnica

11.1. Dependencia de framework de React

La parte de la interfaz de juego está implementada en React el cual, a diferencia de otro frameworks como Express, impone una forma de desarrollo muy específica que puede dificultar el cambio a otro framework de front-end.

11.2. Formato YEN

El cliente (webapp) posee su propio código para representar el formato YEN y enviarlo de vuelta al servidor. Un cambio en el formato YEN provocará cambios tanto en el código del cliente como el del servidor.

Esta duplicación del código del formato YEN facilita en el desarrollo la representación de la partida, pero puede ser problemática si el formato cambia.

11.3. Programación de bots basados en jugadas concretas

Por cómo se ha realizado la arquitectura de comunicación con el motor de juego, se complica el programar bots que necesiten el historial de jugadas concretas de una partida dada para calcular sus respuestas.

Dar soporte a este tipo de bots requeriría modificar la arquitectura o complicar la implementación de un bot concreto de este tipo.

12. Pruebas realizadas

12.1. Pruebas de carga

A continuación se detallan las pruebas de carga llevadas a cabo con Gatling y los resultados obtenidos.

12.1.1. Metodología

Para llevar a cabo las simulaciones se grabó una secuencia real de uso de la aplicación, que se repite de diferentes formas para recrear diferentes escenarios.

La secuencia consiste en:

  • Un nuevo usuario accede a la página por primera vez

  • Se registra en la aplicación

  • Juega una partida

  • Vuelve al menú principal

  • Consulta sus estadísticas

  • Cierra sesión

12.1.2. Escenarios simulados

Carga10

Este escenario simula una carga baja de usuarios (concretamente 10). Se espera que todos los usuarios puedan registrarse en la página, jugar y consultar sus estadísticas sin ningún problema y con tiempos de espera muy bajos.

Los resultados son los siguientes:

Resultados Carga10

Como se puede ver, no ha habido ningún error, y los tiempos de respuesta son muy cortos. En la siguiente imagen se ve como la gran mayoría de las respuestas tardan alrededor de los 35 milisegundos:

Tiempos de respuesta de Carga10
PicoCarga100

Este escenario simula un pico inusual de 100 usuarios en la aplicación.

Los resultados de esta prueba son:

Resultados PicoCarga100

Los resultados son buenos, ya que en ningún caso la página ha dejado de responder y todos los usuarios han tenido una buena experiencia, aunque cabe destacar que un pequeño porcentaje de las peticiones (~0,5%) tardaron alrededor de 3 segundos en recibir respuesta:

Tiempos de respuesta de PicoCarga100
Carga1000

En este caso se simula una carga muy alta de usuarios (1000 en total) que van entrando de forma escalonada para jugar.

Los resultados de esta prueba son:

Resultados Carga1000

Como era de esperar, la aplicación no soporta un número tan alto de usuarios concurrentes. Los primeros fallos comienzan a ocurrir cuando se sobrepasan los 500 usuarios.

Respuestas por segundo de Carga1000

A continuación se muestran los errores ocurridos:

Errores Carga1000

Alrededor del 48% de los errores corresponde a timeouts al hacer peticiones al puerto 3000, donde se encuentra alojado el servicio de users. Esto demuestra que muchos usuarios no podrían registrarse en la aplicación.

Un 43% de los errores corresponde al servicio de gamey, alojado en el puerto 4000, por lo que muchos usuarios experimentarían caídas del servicio durante sus partidas.

El 8% restante corresponde a errores de autenticación (código 403). Esto puede deberse a que los usuarios simulados intentan navegar por la aplicación aunque no hayan conseguido registrarse debido a la sobrecarga del servicio de users. En un escenario real esto no ocurriría, ya que en principio los usuarios no intentarían acceder manualmente a las rutas que requieren autenticación, aunque por otro lado podrían intentar registrarse o iniciar sesión más veces, por lo que se sobrecargaría aun más el servicio users.

PicoCarga500

Para afinar los resultados anteriores, se comprueba si la aplicación soportaría esos 500 usuarios a la vez.

Resultados PicoCarga500

En este escenario se obtienen más errores de los esperados. Como se puede ver en la siguiente captura, la mayoría de los errores se debe a "connection time outs", ya que la aplicación se satura cuando los 500 usuarios tratan de jugar simultáneamente.

Errores de PicoCarga500

Analizando los resultados con más detalle, se observa cómo durante el primer minuto de las pruebas, en las que los usuarios se están registrando y accediendo a la partida, no hay errores. Las respuestas fallidas comienzan a aparecer cuando los usuarios tratan de jugar sus partidas, por lo que parece que el cuello de botella de la aplicación es el servicio de gamey.

Respuestas por segundo de PicoCarga500

12.1.3. Conclusiones

La aplicación responde correctamente bajo condiciones de carga normal y picos puntuales. Con 10 usuarios, todas las peticiones se resolvieron por debajo de los 0,5 segundos sin ningún error, cumpliendo los requisitos de calidad, y con el pico de 100 usuarios simultáneos el sistema siguió siendo estable, con únicamente un ~0,5% de peticiones rozando los 3 segundos. El límite de la infraestructura actual se sitúa en torno a los 500 usuarios concurrentes navegando la web en conjunto (repartidos entre registro, jugando partidas y consultando estadísticas). A partir de ese punto, los servicios de users (puerto 3000) y gamey (puerto 4000) comienzan a saturarse, acumulando entre ambos más del 90% de los errores registrados en la prueba de 1000 usuarios. No obstante, si los 500 jugadores llevaran a cabo las mismas acciones al mismo tiempo, se ha podido observar que el servicio de gamey no soporta una carga tan elevada, siendo este el principal cuello de botella de la aplicación. Para dar servicio a un número mayor de usuarios, sería necesario escalar o replicar estos dos servicios, especialmente el de gamey.

12.2. Pruebas de Usabilidad

12.2.1. Condiciones de realización de las pruebas

  • Para realizar las pruebas, se ha usado el portátil personal de un integrante del equipo, donde se desplegó la web en local.

  • Las tres personas que han realizado las pruebas tienen un grado de conocimiento y de experiencia media con el uso de dispositivos tecnológicos.

  • Con el fin de comprobar si una persona que nunca usó la aplicación puede desenvolverse bien con ella, la única información que se le aportó a los usuarios de prueba fue que deberían registrarse en la aplicación para poder jugar un juego de tablero.

  • Se les dejará a los usuarios desenvolverse por la aplicación por ellos mismos, solo interfiriendo si se comprueba que se atascan en un sitio o si tienen una duda que les dificulta demasiado el uso de la aplicación.

12.2.2. Registro de las pruebas

Usuario Observaciones y Feedback

Primer usuario

El usuario vio la ventana de registro y procedió sin problema. En la pantalla de seleccionar el bot y el tamaño del tablero no tuvo ningún problema de entendimiento, al parecer sin siquiera necesitar leer las instrucciones. A la hora de entrar al juego, le costó unos segundos darse cuenta de que podía deslizar la pantalla hacia abajo y no entendió el juego. Una vez deslizó hacia abajo, vio las instrucciones del juego y lo entendió. Pudo jugar sin problema, aunque para entender el juego del todo tuvo que volver a leer las instrucciones un par de veces. Le costó entender que los hexágonos de las esquinas estaban en contacto con dos esquinas al mismo tiempo.

Segundo usuario

El usuario se registró sin problema. En la pantalla de seleccionar el bot y el tamaño del tablero no entendió en un primer vistazo lo que tenía que hacer ni qué era el bot y el tamaño. En seguida leyó las instrucciones y entendió el funcionamiento de la pantalla y continuó sin problema. Al entrar al juego, instantáneamente deslizó la pantalla hacia abajo y vió las reglas, por lo que desde el principio se hizo una idea de cómo funcionaba el juego. Aunque le costó un par de intentos empezar a entender de verdad cómo se ganaba, pudo jugar varias partidas por sí misma sin ningún inconveniente. Tuvo el mismo problema que el usuario anterior en cuanto a los hexágonos de las esquinas, ya que no entendía que contaban por los dos lados.

Tercer usuario

A diferencia del resto de usuarios, este último ha sabido desenvolverse con total destreza por toda la aplicación. Entendió que debía regitrarse sin problemas, leyó las reglas del funcionamiento de selección de bot y tablero y entendió a la primera como usarlos, y nada más entrar al juego vio las reglas, las leyó y pudo jugar entendiendo el funcionamiento de Y a la perfección.

12.2.3. Cambios introducidos tras las pruebas

En vista de la confusión que tuvieron los dos primeros usuarios para entender que rellenar uno de los hexágonos de las esquinas contaba como entrar en contacto con dos lados, se ha añadido una explicación de esto mismo en las instrucciones del juego.

12.3. Pruebas de seguridad

El objetivo de estas pruebas es identificar vulnerabilidades que pudieran ser explotadas por un actor malicioso, con el fin de mitigarlas antes de que representen un riesgo real para el sistema o sus usuarios.

Para la evaluación y categorización de las vulnerabilidades, se emplea el estándar CVSS 3.0, que permite medir su gravedad de forma objetiva y estandarizada.

Las pruebas se han realizado siguiendo un enfoque de caja blanca, es decir, con acceso total al código.

NOTA IMPORTANTE: Algunas de las vulnerabilidades descritas en este apartado siguen presentes en el entorno de producción. Al tratarse de un proyecto académico, su posible explotación no supone un impacto real; sin embargo, en un contexto profesional, la gestión de vulnerabilidades debe seguir un proceso controlado y responsable.

12.3.1. Vulnerabilidades encontradas

Durante el análisis, se revisó el código en busca de vulnerabilidades comunes como inyecciones SQL, XSS y otras amenazas similares, sin encontrarse evidencias de este tipo de fallos. No obstante, se identificaron otro tipo de debilidades de seguridad, relacionadas con la disponibilidad de la web y la divulgación de información sensible. A continuación se detallan las dos vulnerabilidades identificadas:

1 - Denegación de servicio
Vector CVSS

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Severidad

Alta (7.5): la vulnerabilidad es explotable remotamente sin necesidad de autenticación ni interacción con otro usuario. Afecta a la disponibilidad de la aplicación en gran medida pero no afecta a la confidencialidad ni a la integridad.

Descripción

Es posible saltarse los límites establecidos por la web para elegir el tamaño del tablero de juego. Si se pasa un número muy alto, la memoria del componente gamey se satura y el servicio se cae.

Ejecutando este comando curl, se envía una petición al servicio de gamey indicando "99999" como tamaño de tablero.

curl -X "GET" "http://20.199.9.107:4000/v1/play?position=%7B%22size%22%3A%2099999%2C%22turn%22%3A%201%2C%22players%22%3A%5B%22B%22%2C%22R%22%5D%2C%22layout%22%3A%20%22.%22%7D&bot_id=random_bot&strategy=normal" -H "accept: application/json"

Como se puede ver en la siguiente imagen, al realizar la petición se colapsa el servicio y deja de responder:

Denegación de servicio

Aunque se pueda navegar por la página web, como el servicio de gamey está caído, no es posible jugar una partida, y todas las llamadas a /status, que comprueban si el juego está disponible, devuelven un error:

Gamey caído
Remediación

Para que no se pueda producir la denegación de servicio, se debe implementar en el backend de la aplicación una comprobación de los parámetros introducidos por el usuario que establezca un límite máximo para el tamaño del tablero.

2 - Enumeración de usuarios
Vector CVSS

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Severidad

Media (5.3): la vulnerabilidad es explotable remotamente sin requerir privilegios ni interacción con otro usuario. Su impacto se limita a una filtración parcial de información (confidencialidad baja), sin afectar a integridad ni disponibilidad.

Descripción

La aplicación presenta una vulnerabilidad de enumeración de usuarios basada en diferencias en el tiempo de respuesta del endpoint de inicio de sesión. Midiendo el tiempo que tarda el servidor en responder ante distintas combinaciones de credenciales, un atacante puede inferir si un nombre de usuario existe en el sistema sin necesidad de autenticarse.

Si el usuario no existe en el sistema, el servidor no realiza ninguna verificación de la contraseña, produciendo un tiempo de respuesta muy bajo, de unos 41 ms de media.

Usuario incorrecto

En cambio, cuando el usuario sí existe, el servidor calcula y verifica el hash de la contraseña proporcionada, lo que aumenta el tiempo de respuesta significativamente (alrededor de 360 ms):

Usuario correcto

Por otro lado, el formulario de registro de la web también se podría considerar una enumeración de usuarios, ya que cuando se intenta registrar un usuario que ya existe, la aplicación lo dice explícitamente:

Registro de usuario que ya existe
Remediación

Para solucionar esta vulnerabilidad, se debe realizar siempre el cálculo del hash de la contraseña proporcionada. De esta forma, los tiempos de respuesta siempre serán consistentes, independientemente de si el usuario existe o no.

Sobre el formulario de registro, la recomendación sería unificar los mensajes de error en un mismo error genérico, para evitar dar información de más. No obstante, eliminar los mensajes de error descriptivos puede afectar negativamente a la experiencia de usuario, por lo que debe valorarse con cuidado aplicar esta medida.

13. Glosario

Término Definición

Yovi

Aplicación web que permite a usuarios jugar al juego Y

Juego Y

Juego de tablero de dos jugadores que no puede acabar en empate

Jugador

Persona humana que se conecta a la aplicación con el objetivo de jugar al juego Y

Bot

Entidad externa que se conecta al API de Yovi para jugar o ver el registro de estadísticas o usuarios

YEN

Formato de texto utilizado para representar el estado de una partida del juego Y en Yovi

gamey

Motor del juego Y que sirve a la aplicación Yovi

users

Sistema de gestión de usuarios que se conecta con la base de datos de Yovi

webapp

Cliente de la aplicación web con el que interactúan los jugadores

ORM

Mapeo objeto relacional, técnica de gestión de datos de base de datos mediante objetos.