Infografía · Blupoli Journal

Construir, medir, documentar, repetir

ProductoCambios
IngenieríaSistema
JournalMemoria pública
Una lectura visual del sistema de restricciones que define este capítulo.

Cuando este artículo se publicó por primera vez, el producto todavía se llamaba Blupoli. Hoy forma parte de Blupoli como Blupoli Puzzles. El nombre cambió y varias piezas de la arquitectura también, pero la pregunta que motivó aquel texto sigue siendo la misma: ¿cómo se construye una plataforma que puede alojar muchos puzzles diferentes sin convertirse en una colección de páginas independientes?

La dificultad aparece porque «hacer un juego» y «hacer una plataforma de juegos» no son el mismo trabajo. El primero puede concentrarse en una mecánica: reglas, estado, interacción y victoria. El segundo tiene que resolver todo lo que se repite alrededor: navegación, catálogo, dificultad, ayuda, estadísticas, persistencia, temas, accesibilidad, localización, responsive, contenido editorial y una forma segura de publicar cambios. Cuanto más diverso es el catálogo, más importante se vuelve separar esas responsabilidades.

Con el tiempo empezamos a pensar Blupoli Puzzles como tres sistemas superpuestos. El primero son los juegos: motores, generadores, solvers y representaciones específicas. El segundo es la plataforma: la experiencia que hace que todos esos títulos pertenezcan al mismo producto. El tercero es el proceso: datos, Git, pruebas, CI, documentación y herramientas que nos permiten cambiar ambos sistemas sin depender de memoria o revisiones manuales imposibles de escalar.

La primera capa: cada puzzle merece un modelo que entienda su lógica

Una plataforma grande invita a buscar una abstracción universal. Sería cómodo disponer de un único «motor de puzzles» capaz de recibir reglas declarativas y resolver cualquier cosa. En la práctica, las mecánicas hablan idiomas matemáticos diferentes. Sudoku trabaja con restricciones de unicidad en filas, columnas y cajas. Slant combina pistas locales con ausencia de ciclos. Aquarium razona sobre niveles dentro de regiones. Dominosa se puede formular como cobertura exacta. Un Logic Grid representa relaciones entre entidades. Un juego competitivo añade turnos y evaluación de posiciones.

Intentar esconder toda esa variedad detrás de una única implementación puede terminar desplazando la complejidad en vez de reducirla. Por eso preferimos compartir contratos antes que algoritmos. Cada motor puede tener la representación que mejor encaja con su puzzle, siempre que la plataforma sepa cómo iniciar una sesión, aplicar o recibir acciones, detectar estado de finalización, guardar lo necesario y exponer metadatos útiles.

Esta filosofía está desarrollada con más detalle en el artículo sobre arquitectura de motores. La idea central es sencilla: la especialización es aceptable dentro del motor; la experiencia común vive fuera. Eso permite optimizar cada problema sin renunciar a una plataforma coherente.

Un motor no termina cuando acepta movimientos

La primera versión de un puzzle puede parecer completa cuando el tablero responde y existe una condición de victoria. Para una plataforma, ese punto es apenas el comienzo. Una partida publicada debe generarse o cargarse de manera fiable, respetar sus reglas, producir estados reproducibles cuando sea necesario y ofrecer una dificultad que signifique algo. En muchos géneros, además, necesitamos verificar que exista exactamente una solución.

Ahí aparecen dos piezas que al principio pueden parecer herramientas internas: generador y solver. El generador propone instancias. El solver comprueba propiedades. Mezclarlos demasiado hace difícil saber qué estamos validando. Separarlos crea una frontera útil: producir un candidato no equivale a demostrar que merece publicarse.

Lo contamos en profundidad en «Generar un puzzle no es resolverlo». Desde la perspectiva de plataforma, la consecuencia es que calidad lógica forma parte de la cadena de publicación. No queremos descubrir después de varios minutos de partida que un puzzle era ambiguo, trivial o imposible.

La dificultad no debería ser solo otro tamaño

Una de las tentaciones más frecuentes es mapear dificultad a dimensiones: pequeño es fácil, grande es difícil. A veces existe correlación, pero no es una definición suficiente. Un tablero grande puede contener deducciones obvias repetidas; uno pequeño puede exigir una cadena muy precisa. Una buena dificultad debería reflejar el tipo de razonamiento, la cantidad de branching, la información revelada o alguna métrica apropiada al puzzle.

Esto vuelve a justificar motores especializados. No existe un único número de «dificultad lógica» que tenga el mismo significado en todas las familias. La plataforma puede presentar una escala común —por ejemplo, niveles legibles para el jugador—, mientras cada motor traduce esa escala a parámetros y mediciones propios.

La separación evita que la interfaz tenga que entender teoría específica de cada juego. El shell pregunta por una dificultad; el motor decide qué significa y cómo generar o seleccionar una instancia que cumpla razonablemente esa promesa.

La segunda capa: una plataforma evita que cada juego tenga que inventar una aplicación

Si cada motor tuviera que resolver navegación, botones, ayuda, tema, estadísticas, persistencia y responsive, el proyecto crecería por copia. Al principio las diferencias serían pequeñas. Después de muchas iteraciones, cada pantalla tendría su propia interpretación de «nueva partida», sus propios márgenes, su propia forma de explicar errores y su propio conjunto de atajos.

La plataforma existe para retirar ese trabajo repetido de los motores. El game shell proporciona una jerarquía, un espacio para el tablero, zonas de configuración y acciones, estados globales y una conexión con el resto del producto. No convierte los tableros en plantillas idénticas; les quita responsabilidades que no son específicas de su lógica.

Este enfoque evolucionó mucho a partir de nuestro trabajo con Sudoku. En el artículo sobre Sudoku como laboratorio de diseño explicamos cómo una mecánica conocida nos ayudó a separar decisiones locales de principios generales. Después, el artículo sobre el sistema de UI compartido muestra cómo esas decisiones se convierten en una capa reutilizable.

Diagrama sin texto con varios motores de puzzle en la base, una capa de plataforma en el centro y una capa de proceso y verificación por encima
Las tres capas tienen responsabilidades distintas: los motores entienden las mecánicas, la plataforma organiza la experiencia y el proceso comprueba que ambas puedan evolucionar con seguridad.

La consistencia útil vive alrededor del tablero

Una plataforma de puzzles necesita consistencia, pero no debe borrar el carácter de cada juego. El lugar más seguro para compartir decisiones suele estar alrededor de la superficie de razonamiento: navegación, estructura de la página, ayuda, estados de producto, accesibilidad, tema y herramientas recurrentes. Dentro del tablero, la mecánica manda.

Esta regla evita dos extremos. Si todo es específico, cambiar de juego obliga a reaprender la aplicación. Si todo es uniforme, el tablero pierde las señales que necesita. Un Nonogram debe seguir pareciendo un Nonogram; un Slitherlink debe poder utilizar aristas y pistas; un Logic Grid necesita matrices; un juego contra CPU necesita expresar turnos. Lo común es que todos sepan cómo empezar una nueva sesión, dónde buscar ayuda y qué comportamiento esperar de acciones globales.

Con el tiempo esta frontera se convirtió en uno de los principios de producto más importantes: aprender Blupoli una vez y aprender después solo aquello que hace especial al siguiente puzzle.

Persistencia antes que cuentas: guardar valor sin esperar a toda la infraestructura

Una plataforma puede caer en otra trampa: bloquear funciones útiles hasta tener un sistema completo de usuarios, backend y sincronización. Para muchas experiencias de puzzle, una primera capa de persistencia local ya aporta valor: continuar una partida, conservar preferencias, recordar progreso y registrar estadísticas básicas.

Construir estos conceptos localmente también ayuda a diseñarlos antes de sincronizarlos. ¿Qué identifica una sesión? ¿Qué datos son parte del motor y cuáles son metadatos? ¿Qué estadísticas tienen sentido para un puzzle y cuáles para un juego competitivo? ¿Qué ocurre si cambia una versión del tablero? Resolver esas preguntas primero reduce el riesgo de consolidar un modelo pobre en el servidor.

Si más adelante una cuenta sincroniza datos entre dispositivos, el modelo tendrá una historia previa de uso real. La infraestructura llega a sostener una necesidad conocida, no a inventarla.

Las estadísticas necesitan respetar la mecánica

«Partidas jugadas» y «partidas ganadas» pueden servir como base, pero no describen todo. En un puzzle importa la resolución, quizá el tiempo, movimientos, ayudas o variante. En un juego contra CPU aparecen victoria, derrota, empate y dificultad del rival. Mezclar métricas incompatibles solo porque comparten una página produce números fáciles de almacenar y difíciles de interpretar.

Por eso la plataforma debería compartir el marco de estadísticas sin forzar un esquema plano. El juego expone contexto; la capa común registra y presenta. La misma filosofía que usamos en UI y motores vuelve a aparecer: contrato compartido, semántica especializada.

Este patrón es una señal de que la arquitectura no depende de una sola tecnología. Es una forma de pensar responsabilidades. Cuando una capa conoce demasiado detalle de otra, el crecimiento empieza a requerir excepciones.

El catálogo se convierte en producto cuando deja de caber en la cabeza

Con unas pocas opciones, una lista de títulos puede funcionar. Cuando la variedad crece, descubrir se convierte en una tarea. Una persona puede buscar un juego conocido o querer un tipo de reto sin saber su nombre. Las categorías, filtros, búsqueda y descripciones dejan de ser decoración y pasan a guiar decisiones.

Esto cambia la importancia de los datos. Categoría, familia, dificultad, disponibilidad, controles y descripción necesitan fuentes de verdad. La página de catálogo no debería reconstruir manualmente información que ya existe en cada juego. Del mismo modo, artículos editoriales o páginas de categoría deberían poder enlazar a esos datos sin copiar cifras que se vuelven obsoletas.

La auditoría posterior del producto —contada en «Cuándo dejar de añadir funciones y auditar el producto que ya tienes»— hizo todavía más evidente que el catálogo no podía seguir comportándose como una simple lista.

Internacionalizar pronto es una prueba de arquitectura

Los idiomas son otra capa que castiga las copias. Si los nombres de categorías viven en varios lugares, si un motor genera directamente frases en español o si la navegación contiene rutas hardcodeadas, añadir otro idioma multiplica inconsistencias. Internacionalizar obliga a separar identidad de presentación.

Un puzzle debe seguir siendo la misma entidad aunque cambie el idioma. Sus reglas y estado no se duplican; se localizan nombres, descripciones, UI y contenido editorial. Las pistas generadas en lenguaje natural necesitan una representación semántica antes de convertirse en frases.

Esta presión hizo visibles muchas fronteras débiles y terminó alimentando una arquitectura editorial y de rutas más explícita. La internacionalización no fue solo traducir. Fue una forma de comprobar si el producto tenía fuentes de verdad claras.

La accesibilidad mejora cuando forma parte de la capa común

Revisar accesibilidad juego por juego al final es caro y poco fiable. Hay comportamientos que pueden heredarse: foco visible, semántica de botones, estados deshabilitados, estructura del documento, contraste base y navegación común. Cuanto más vive esto en componentes compartidos, menos depende de recordar la misma checklist en cada motor.

La mecánica todavía necesita trabajo específico. Una cuadrícula compleja puede exigir etiquetas particulares; un canvas puede necesitar alternativas; un gesto puede requerir equivalente de teclado. La plataforma no puede resolverlo todo. Pero sí puede elevar el mínimo y hacer que las excepciones sean explícitas.

Este es otro ejemplo de apalancamiento: una mejora en la base puede beneficiar muchas experiencias. El valor de la arquitectura aparece precisamente cuando la calidad puede propagarse.

La tercera capa: el proceso evita que velocidad signifique descontrol

Cuanto más rápido puede cambiar un producto, más importante es disponer de mecanismos para comprobarlo. Esta afirmación se vuelve especialmente relevante cuando el desarrollo utiliza agentes de IA para investigación, implementación o revisión. La capacidad de producir código aumenta; la necesidad de contexto, tareas acotadas y validación independiente aumenta con ella.

Git proporciona historia y unidades de cambio. La documentación conserva decisiones que el diff no explica. Las tareas convierten objetivos grandes en trabajo revisable. CI ejecuta contratos repetibles. Los tests protegen reglas. Los builds verifican rutas, metadatos, assets y otras invariantes. Ninguna pieza garantiza calidad por sí sola, pero juntas reducen la dependencia de memoria humana.

En el artículo sobre IA como parte del equipo de desarrollo contamos con más detalle cómo esta forma de trabajar cambia la relación entre velocidad y revisión. El principio relevante aquí es que automatizar producción sin automatizar verificación solo acelera la creación de incertidumbre.

Git es memoria técnica, pero necesita contexto para convertirse en memoria de producto

Un repositorio sabe exactamente qué cambió, pero no siempre por qué fue importante. Un commit puede decir que se añadió un validador, se cambió una ruta o se corrigió un generador. Meses después, la razón de producto puede no ser evidente. Por eso intentamos conectar código, documentación y contenido editorial.

El proceso no necesita registrar cada detalle públicamente. Necesita conservar suficiente contexto para que una decisión se pueda revisar y para que un futuro cambio no repita un error por desconocer su origen. Esta disciplina también mejora la colaboración con agentes: cuanto más explícito es el contrato, menos tiene que inferirse desde archivos dispersos.

La memoria del proyecto se convierte así en una herramienta de calidad. No pretende evitar que cambiemos de opinión; pretende hacer que sepamos cuándo y por qué lo hacemos.

CI debería proteger propiedades del producto, no solo compilación

Un pipeline que solo confirma que JavaScript es sintácticamente válido deja fuera buena parte de los riesgos reales. En Blupoli Puzzles el build puede comprobar rutas, localización, metadatos, catálogo, assets y otros contratos. Los motores pueden tener self-tests. Los generadores pueden recorrer presets públicos. Los quality gates pueden detectar contenido incompleto o referencias rotas.

Cuanto más cerca esté la verificación de la propiedad que queremos proteger, menos útil es una regresión silenciosa. Si una variante debe tener solución única, conviene comprobarlo automáticamente. Si una entrada editorial necesita metadatos y alternates, el build puede validarlo. Si un catálogo no debe anunciar como jugable algo incompleto, los datos deberían expresarlo y las páginas derivarse de ahí.

La automatización no sustituye a jugar ni a leer. Sirve para que la revisión humana no tenga que comprobar una y otra vez invariantes que una máquina puede demostrar mejor.

Los agentes de IA aumentan el valor de las tareas bien definidas

Una instrucción como «mejora la web» permite demasiadas interpretaciones. Una tarea que describe problema, alcance, restricciones, precedentes y criterio de terminado produce un trabajo mucho más revisable. Esto siempre ha sido útil en ingeniería; con agentes se vuelve central.

El proceso necesita dividir la autonomía. Un agente puede investigar una mecánica, implementar una pieza, revisar tests o preparar contenido, pero cada cambio debe tener una frontera y una forma de verificar el resultado. La velocidad viene de paralelizar trabajo bien especificado, no de eliminar revisión.

Esta disciplina también beneficia al desarrollo humano. Las tareas claras reducen cambios gigantes, hacen que los PR sean comprensibles y permiten saber cuándo algo está realmente terminado.

La simplicidad de la web estática sigue siendo una ventaja cuando se usa con intención

Una gran parte de Blupoli Puzzles puede servirse como HTML, CSS, JavaScript y assets generados. Esa simplicidad reduce infraestructura y hace que muchas páginas sean rápidas y fáciles de desplegar. No significa que todo deba permanecer estático. Significa que un servicio debería aparecer cuando protege una responsabilidad que el cliente no puede resolver correctamente.

Cuentas, sincronización entre dispositivos, rankings competitivos o funciones que exigen autoridad podrían necesitar backend. La regla es introducir esa frontera por una necesidad, no porque una plataforma «seria» deba tener necesariamente más servidores.

Esta filosofía de capas mínimas también influyó en el camino hacia Android. Como explicamos en el artículo sobre Capacitor, preferimos reutilizar la web y añadir capacidades nativas donde aporten valor antes que duplicar todo el producto.

La arquitectura debe permitir que un problema local siga siendo local

Una plataforma compartida puede caer en el extremo contrario y convertir cada necesidad específica en infraestructura global. Eso también genera complejidad. Si un puzzle necesita una herramienta única, quizá deba vivir en ese motor. Si dos o tres familias repiten el patrón, entonces puede merecer una extensión común.

La clave es observar recurrencia. No abstraemos por anticipación; abstraemos después de tener evidencia. Esta estrategia mantiene pequeño el núcleo compartido y evita que el game shell se convierta en una colección de opciones que nadie entiende.

La capacidad de aceptar especialización es lo que permite que Blupoli Puzzles crezca sin perder diversidad. Una plataforma no es un molde. Es una infraestructura que hace más baratas las cosas que realmente se repiten.

Construir en público también sirve como herramienta de reflexión

Escribir sobre el proceso obliga a formular decisiones que dentro del repositorio pueden permanecer implícitas. Explicar por qué separamos motores, por qué auditamos antes de expandir o por qué elegimos una estrategia móvil concreta hace más evidente si la razón se sostiene.

El contenido público no debe ser un changelog disfrazado. Su valor aparece cuando convierte trabajo técnico en una idea útil para quien lee. Para nosotros también funciona como registro: permite ver cómo cambió la definición de terminado, cómo evolucionaron las prioridades y qué supuestos fueron reemplazados.

Con la evolución editorial de Blupoli, parte de estos textos vive como Blog y parte como Devlog según su intención. La separación mejora la claridad, pero el objetivo original permanece: contar el producto sin fingir que las decisiones aparecen de la nada.

La auditoría fue la señal de que la plataforma había cambiado de fase

En algún momento añadir otro puzzle dejó de ser automáticamente la mejor forma de avanzar. El catálogo ya era suficientemente diverso para revelar problemas sistémicos. La UI necesitaba consolidación. Los estados de disponibilidad tenían que ser más honestos. El build debía proteger más invariantes. La taxonomía y el descubrimiento empezaban a importar tanto como la cobertura.

Parar para auditar no contradijo la ambición del producto. La hizo más sostenible. La primera etapa demostró que podíamos construir motores. La siguiente tenía que demostrar que podíamos mantenerlos, explicarlos, verificar su calidad y hacer que cada incorporación heredara más capacidades de la anterior.

Ese cambio de fase es una de las razones por las que hoy resulta más útil hablar de tres capas que de un simple catálogo.

El producto mejora cuando cada capa puede evolucionar a su propio ritmo

Los motores no necesitan cambiar cada vez que cambia el header. El catálogo no debería depender de cómo un solver representa estados internos. El proceso de CI puede endurecerse sin rediseñar los tableros. Esta independencia reduce el radio de cada cambio y permite experimentar de forma más segura.

Al mismo tiempo, las capas necesitan contratos. Un motor debe exponer suficiente información para que el shell funcione. La plataforma debe producir datos que el build pueda verificar. El proceso debe conocer las invariantes sin reimplementar la lógica de cada puzzle. Diseñar esos contratos es una parte importante de la arquitectura.

Cuando una frontera funciona, se nota porque las mejoras viajan en la dirección correcta. Una corrección común mejora muchos juegos; una innovación específica no obliga a tocar todos; un nuevo gate detecta problemas sin acoplarse a detalles irrelevantes.

No queremos que el siguiente juego empiece desde cero

La medida más interesante de una plataforma no es cuántas páginas contiene, sino cuánto trabajo evita repetir. Si un motor nuevo recibe navegación, temas, persistencia, ayuda, estados comunes, localización y contratos de calidad por defecto, la energía puede dedicarse a la mecánica. Cada incorporación anterior ha dejado infraestructura.

Ese efecto compuesto es el objetivo. El primer juego cuesta mucho porque también construye parte de la plataforma. El segundo pone a prueba la separación. El décimo revela patrones. El siguiente debería empezar con un suelo más alto, no con una copia más grande.

Esta idea conecta con la historia del propio proyecto: Blupoli Puzzles nació precisamente de preguntarnos qué debía cambiar para que el segundo puzzle no obligara a rehacer el primero.

Tres capas, una sola experiencia para quien juega

Todo este análisis puede sonar arquitectónico, pero el usuario no debería ver tres sistemas. Debería abrir una página, elegir un puzzle, entender qué hacer, disfrutar del reto y confiar en que el producto responde de manera coherente. Los motores, el shell y el pipeline existen para que esa experiencia parezca sencilla.

La arquitectura es buena cuando absorbe complejidad sin imponerla. El proceso es bueno cuando detecta problemas antes de que lleguen al usuario. La plataforma es buena cuando lo familiar desaparece en segundo plano y deja al puzzle ocupar el centro.

Hoy seguimos construyendo Blupoli con esa idea. Los nombres, herramientas y scripts continuarán cambiando. Algunas decisiones de 2026 serán sustituidas. Pero la estructura mental sigue siendo útil: especializar la lógica donde importa, compartir la experiencia donde ayuda y verificar el cambio con un proceso que no dependa de recordar todo. Eso es lo que convierte una colección de juegos en una plataforma capaz de aprender mientras crece.