Diseño de juegos
Al diseñar el juego, nuestro principal objetivo era preparar un entretenimiento divertido para los programadores, además de hacer algo interesante como parte del trabajo en nuestra empresa. Hasta ahora, no habíamos tenido ninguna competencia en la creación de juegos, por lo que nos planteó un reto importante. En primer lugar, nos centramos en lo que realmente era este juego. Tras idear el plan inicial, nos pusimos manos a la obra.
Como parte del trabajo en el juego, decidimos hacer un hackathon y dividirnos en grupos que realizaran tareas específicas. Con esta división de 8 horas de trabajo, pudimos realizar la apariencia de los oponentes en el juego, todo el diseño y la base tanto de las tareas como de las API de todo el sistema. Durante la siguiente etapa, nos reunimos durante 4 horas una vez al mes, gracias a lo cual conseguimos terminar el juego en 3 reuniones.
Aplicación
Como estamos especializados en RubyOnRails, elegimos esta tecnología como la principal. Sin embargo, el juego no estaba destinado a ser textual y por lo tanto el enfoque de la misma se reflejó en la aplicación de tipo SPA. Como parte de la tarea, trabajamos sobre un conocido pipeline de assets de rails (en 2016 no había nada mejor en principio) y todo el javascript basado en nuestra código con la ayuda de TypeScript. En la aplicación, había una división estándar de responsabilidades: Rails como activo y fuente de API, javascript y afines como interacción con el usuario. Aquí, sin embargo, funcionaba como un híbrido y algunas vistas simplemente se renderizaban desde rails mientras que otras - desde JS.
Texto mecanografiado
Fue nuestro primer experimento en este campo. Eran tiempos en los que se creía en el éxito de CoffeScript. El uso de TypeScript requería la introducción de una gema typescript-rails. Desafortunadamente, esto no fue lo definitivo, ya que typescript, al ser un lenguaje tipado estáticamente, también lo requería de las librerías adjuntas por defecto a rails.
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/jquery.d.ts (especialmente cuando se utiliza el sistema de gestión de activos integrado con rails).
Cody como juego requería mucha dinámica en el lado del navegador, así como la modificación del árbol de DOM. El uso de TypeScript en lugar de javascript vainilla fue un gran salto en la calidad del código, la presencia misma de las clases y la encapsulación era muy tentador para nosotros.
API y SPA
En 2019, las aplicaciones SPA se gestionan utilizando los magníficos React o Vue bibliotecas. Sin embargo, en 2015, lo hicimos de una manera diferente. El typescript antes mencionado fue útil en la implementación del juego, mientras que jQuery revocó todo el trabajo relacionado con la solicitud http xml. Ahora podemos utilizar fetch, mientras que en aquellos días `$ .ajax` era todo lo que se necesitaba para el trabajo. ¡Echa un vistazo a nuestra api cliente!
Si era api entonces había que resolver el problema de la autenticación de alguna manera, ¿no? Bueno, así es. Pero en ese caso, fuimos tras (¡¿es posible escribir aquí - usamos la banda?!) la banda y en la sesión de rails creamos cookie_key y después la guardamos en la base de datos. Por lo tanto sabíamos que todo estaba más que bien.
https://github.com/codesthq/cody_the_game/search?q=cookie_key&unscoped_q=cookie_key
El estado del juego se almacenaba en la base de datos y la información sobre cuántos usuarios tenían puntos procedía de la base de datos (¿es la misma base de datos? ¿Podemos cambiarla por un pronombre?). ACID siempre viene bien cuando no hay caché en el lado del sistema;)
En el caso del spa, es lo mejor sin recargar la página. Lo hemos resuelto de forma clásica y el ancla html era la mejor solución sin ampliar dependencias innecesarias. Porque ¿quién usaría turbolinks?
SnapSVG
Si diseñamos un juego, debe salir al mercado sólo con grandes gráficos y animaciones. Por aquel entonces pasamos muchas horas preguntándonos cómo satisfacer esas exigencias en nuestra aplicación. Por un lado, el lienzo puede hacer milagros, por otro, en un html limpio es mucho más fácil ponerse al día y todo el mundo lo sabe. Tras una minuciosa búsqueda de la mejor solución, hemos descubierto que la combinación de estas dos soluciones es svg. Permite presentar fácilmente gráficos vectoriales, está escrito en lenguaje de marcado y, lo que es más importante, se puede modificar sobre la marcha. Es importante destacar que existe una biblioteca para archivos svg que funciona de forma similar a jQuery y permite realizar operaciones sobre la imagen de forma unificada. Se trata de: http://snapsvg.io, tenemos muy buenos recuerdos del uso de esa solución en particular.
A continuación encontrará un ejemplo de cómo hemos utilizado snap.svg:
https://github.com/codesthq/cody_the_game/blob/master/app/assets/javascripts/intro.js.ts
El propio archivo haml con el esqueleto gráfico:
https://github.com/codesthq/cody_the_game/blob/master/app/views/game/show.html.haml
Como puedes ver, es casi como un árbol DOM normal y una aplicación Rails normal.
TrustedSandbox
Bueno, por fin teníamos API, Gráficos, SPA. Pero ¿qué pasa con la aplicación de las soluciones enviadas por los usuarios?
Lo primero que nos viene a la mente es el método eval, pero no estamos locos;) Allá por 2016, docker estaba en auge, así que nos pareció una opción natural. Los contenedores por sí mismos no garantizaban un aislamiento y protección completos, por lo que utilizamos una solución preparada en Ruby llamada https://github.com/vaharoni/trusted-sandbox. Permitía proteger mejor el código antes de salir del sandbox y configurar de forma estandarizada los requisitos del sistema operativo. Era muy importante limitar adecuadamente el tiempo de ejecución del código, la memoria necesaria para funcionar y los ciclos de la CPU. Nuestra configuración está disponible a continuación
https://github.com/codesthq/cody_the_game/blob/master/config/trusted_sandbox.yml.example
Por supuesto, el mismo sandbox de confianza no garantizaba nada, por lo que ideamos un sitio web especial para ejecutar el código.
https://github.com/codesthq/cody_the_game/blob/master/app/services/task_runner/base_task.rb
Cada una de las tareas tenía su propio caso de prueba, que nos permitía verificar la corrección de la solución implementada. Para ello, se inyectaba el código de usuario en el caso de prueba, de modo que todo se ejecutaba de forma aislada.
https://github.com/codesthq/cody_the_game/blob/master/app/challenges/challenge/case.rb
Por supuesto, esta acción costaba bastante tiempo y, mientras recogíamos las respuestas, no podíamos permitirnos ejecutar el sandbox, por lo que nos limitábamos a guardar el código en la base de datos, creando un envío y, a continuación, utilizando long pooling, pedíamos al endpoint que obtuviera el estado del código. Esto nos permitió aliviar el servidor de aplicaciones y verificar los datos adecuadamente. Por supuesto, también teníamos que protegernos contra el "colapso del script" y, por lo tanto, limitamos el número de consultas al servidor utilizando la variable ttl, que se puede ver a continuación.
Resumen del concurso
Hasta septiembre de 2011, las estadísticas de juego eran las siguientes:
- número de sesiones: 1945 - tareas enviadas: 4476 - envió respuestas correctas: 1624 - terminó el partido: 31
Como puede ver, las mayores escaleras empezaron en la tarea # 2 porque ya no era un ejemplo ordinario de hola mundo.
Lea también:
Una rápida inmersión en Ruby 2.6. ¿Cuáles son las novedades?
Escribir documentación es ahora más fácil gracias a VuePress