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.
Ver https://arc42.org.
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
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
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
- 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
- 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
- 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 |
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.
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.
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.
7. Vista de Despliegue
7.1. Nivel de infraestructura 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.
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 |
|---|---|---|---|
|
INTEGER |
PK, AUTO_INCREMENT |
Identificador único del usuario |
|
VARCHAR(255) |
NOT NULL |
Nombre real del usuario |
|
VARCHAR(255) |
NOT NULL, UNIQUE |
Nombre de usuario para login |
|
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 |
|---|---|---|---|
|
INTEGER |
PK, AUTO_INCREMENT |
Identificador único de la partida |
|
INTEGER |
NOT NULL, FK |
Referencia al usuario que jugó la partida |
|
VARCHAR(255) |
NOT NULL |
Identificador del bot oponente |
|
BOOLEAN |
NOT NULL |
|
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
contrasenadebe 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
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:
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:
PicoCarga100
Este escenario simula un pico inusual de 100 usuarios en la aplicación.
Los resultados de esta prueba son:
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:
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:
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.
A continuación se muestran los errores ocurridos:
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.
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.
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.
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:
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:
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.
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):
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:
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. |
