Simulador web Yandex.Practicum. Cómo funciona

Es importante hacer que el proceso educativo sea lo más interesante y interactivo posible. Especialmente cuando se trata de tecnología: es mucho más útil cuando existe la oportunidad no solo de escribir un código y luego obtener una respuesta del inspector, dicen, bien hecho, todo está bien, pero sobre la marcha para ver si todo funciona para usted, dónde están las jambas y cómo generalmente lo hiciste.



En un intento de hacer algo similar, una vez lanzamos un simulador web en Yandex MVP, en el que el usuario podía escribir código, scripts y todo lo demás en diferentes pestañas, y al lado mostró todo esto como resultado final.







MVP se mostró bien y llevamos el simulador web al nivel de una herramienta completa para probar el conocimiento de nuestros estudiantes en Yandex.Practice . Mi nombre es Artem, y te contaré cómo hicimos un simulador para enseñar desarrollo web, cómo funciona y qué puede hacer.



Desde el exterior, parece que todo es simple aquí: metí todo el código personalizado en un iframe, lo publiqué a través de un mensaje posterior, luego lo rendericé de cualquier manera posible y todo funciona. Una vista previa de código en línea ligeramente bombeada.



Pero hay matices.



Cómo funciona



Al principio, notamos un posible problema: si implementa el simulador en un dominio Yandex (como el propio Workshop, por ejemplo), entonces existe una probabilidad distinta de cero de que los usuarios resulten ser un poco más curiosos. Es decir, tomarán y arrojarán código al simulador, que el simulador procesará con entusiasmo. Y el código será fraudulento y eliminará la cookie Yandex existente, la insertará en algún servicio de terceros, después de lo cual el estafador tendrá acceso a la cuenta personal del usuario en Yandex y a todos los datos personales. Es bastante fácil implementar esto si este iframe está ubicado en el dominio yandex.ru. Por lo tanto, creamos un dominio separado en yandex.net específicamente para el simulador y lo llamamos Feynman. En honor a Richard , sí.



En general, nuestro simulador almacena los archivos que le enviamos al backend en formato de texto plano, json y base64 para imágenes. Luego se convierten en archivos reales y se distribuyen como estáticos, que podemos poner en un iframe para renderizar.



Pero no solo estamos jugando al resaltado de sintaxis aquí, tenemos un simulador para probar el conocimiento. Por lo tanto, necesitamos probar y verificar este código sobre la marcha, es decir, de alguna manera encajar en el proceso de iframe y ver si el usuario hizo todo bien, digamos, cómo nombró la variable, o si todo está bien con los divs.







Y aquí volvemos a encontrarnos con dominios. El código de usuario, como ya escribí, se coloca en el simulador en el dominio Feynman y lo verificamos desde Yandex, desde el dominio praktikum.yandex.ru . La política del mismo origen del navegador está en guardia y no le permite alterar las partes internas del iframe si tiene diferentes dominios.



Por lo tanto, decidimos meter el iframe en el iframe.







Resultó la siguiente situación:



  • Creamos un iframe, que en realidad está vacío al principio.
  • Dibuja una especie de página en blanco.
  • Nosotros desde nuestra portada publicamos un postmensaje con un enlace a lo que Feynman nos dio (desde donde aloja las estadísticas).
  • El primer iframe toma este enlace y lo sustituye en el src del iframe interno.


Como resultado, nuestro primer iframe puede poseer el código y hacer lo que quiera con el iframe interno. De facto, las pruebas son solo una función de evaluación que tiene acceso a: documento, ventana, etc., todo en el iframe. Esto nos da la oportunidad de realizar una prueba para detectar un problema y ejecutarla en la ventana de un iframe determinado.



No solo por pruebas



Luego, queríamos agregar algunas características útiles: una terminal, una consola, la capacidad de mostrar datos del usuario sobre lo que escribió en el registro y otras alegrías. Por supuesto, hicimos un modo adaptativo completo para que el usuario pueda ver cómo se verá el resultado en teléfonos inteligentes y tabletas.







Para esto, se escribió una biblioteca especial que carga todos los estilos necesarios y emula el modo receptivo. También cambiamos ligeramente nuestro iframe original y agregamos todo lo que permite al usuario mostrar su console.log en la pantalla, y no solo algunos objetos simples, sino también árboles de dom de documentos completos.



Además de esto, aprendimos cómo ejecutar pruebas preliminares. Esto es útil porque hay muchas pruebas que verifican las mismas cosas, por ejemplo, si el usuario se ha exagerado con bucles en el código, si se ha dejado llevar por el anidamiento y cosas por el estilo. No tiene mucho sentido describir esto en cada prueba por separado, así que escribimos una biblioteca de prueba que tiene un conjunto de métodos especiales de prueba previa que verifican el código. Si todo está bien en esta etapa, entonces la prueba principal y los problemas resueltos ya están verificados, después de lo cual se muestra el resultado al usuario.



Para devolver el resultado de las pruebas preliminares al usuario, también usamos postmensaje: enviamos mensajes a través de él, ya sea que haya algún error o que todo esté bien. Por cierto, el código del alumno en el simulador web también se verifica a través del linter es-lint con traducción al ruso y siempre resalta los errores de sintaxis.



Problemas con las revisiones de código (y no solo)



Si había notificaciones del sistema o del navegador en la página, por ejemplo, se sugirió ingresar algo, luego, a menudo, al ejecutar nuestra prueba, el usuario continuaba viendo ventanas del navegador con notificaciones y solicitudes de ingreso de datos. Tuvimos que hacer esto: cuando un usuario simplemente abre una página con su código para ver cómo funciona todo, esta alerta también debe funcionar. Y cuando la prueba ejecuta este código para verificación, ya no necesitamos que las alertas sigan apareciendo en la pantalla del usuario. De hecho, reemplazamos todas estas alertas con nuestros propios códigos auxiliares para pruebas (simulacros), alerta anuladora, aviso, confirmación dentro de la ventana. Si no hace esto, podría obtener un bucle en la salida o una alerta vacía que no hace nada.



Por cierto, sobre bucles infinitos. El principal problema aquí era que el usuario podía tomar y escribir código a sabiendas que entraría felizmente en un bucle infinito (solo hay un hilo de javascript en el navegador) y, como resultado, todo el navegador se hundió.



Para combatir esto, aprendimos en primer lugar a rastrear esos bucles infinitos antes de enviar el código para su revisión. Para hacer esto, fue necesario rehacer el script de usuario de alguna manera, fuimos de esta manera:



  • Para cada ciclo agregamos una determinada función que cuenta el número de llamadas.
  • Si este número de llamadas supera las 100.000, inmediatamente lanzamos una excepción, que también enviamos a través de un mensaje posterior. Además, por si acaso, verificamos el tiempo de espera si el ciclo se ejecuta durante más de 10 segundos.
  • A lo largo del camino, hacemos un seguimiento de que, dado que ha surgido una excepción, algo anda mal aquí y la prueba en sí ya no tiene sentido de ejecutar: el código está en bucle.


La situación con los enlaces debe anotarse por separado. Digamos que un usuario dentro de su código puede tener algunos enlaces que deberían abrirse al hacer clic en una nueva pestaña, por ejemplo, su cartera o una cuenta de github. Y no necesitábamos que dichos enlaces se abrieran directamente dentro del iframe; de ​​lo contrario, en lugar del iframe, tendremos una página con su enlace. Es necesario abrir tales cosas en una nueva pestaña, a través de Tab. Por lo general, para abrir un enlace no dentro del marco, sino en el marco principal, solo necesita especificar target = "_ parent". Pero en nuestro caso, necesitamos agregar un controlador que determina si el enlace es externo.



Y para todos los enlaces, escribimos un controlador especial: si vemos que el enlace es externo, enviamos el mensaje posterior al exterior, interrumpimos el controlador del enlace en sí (evitar el valor predeterminado) y el mensaje posterior vuelve a nuestro frente. Vemos que tenemos un enlace externo aquí y mostramos una notificación: ¿estamos seguros de que vamos a un sitio externo? Y después de eso abrimos nuevas pestañas.



Y también anclas, con ellas todo era mucho más sencillo. Simplemente no funcionaban dentro del iframe. Generalmente. Por lo tanto, como un pequeño truco, nos suscribimos para hacer clic en eventos en cualquier enlace; si había un ancla en él, hicimos scrollIntoView a un elemento específico.



Todos los metadatos (si el usuario tenía un favicon registrado en la página HTML, por ejemplo, o un título específico), también los enviamos por mensaje posterior después de que se haya cargado el iframe. Usando querySelector, obtenemos estas dos etiquetas, las enviamos de regreso a nuestro frente a través de postmensaje, y el frente mismo inserta todos estos íconos donde sea necesario. Parece una insignificancia, pero el usuario tiene la impresión de que tiene un navegador completo dentro del navegador.



Intenta omitir el simulador



Nuestro simulador web, a diferencia de los simuladores que hicimos para Python, SQL y otros, usa el frente para las comprobaciones, no el backend. Por lo tanto, cuando el usuario completa las pruebas correctamente, se envía una solicitud POST correspondiente al backend. En principio, un usuario con la habilidad adecuada puede hacer lo mismo y enviar dicha solicitud manualmente.



Hay una espada de doble filo. Por un lado, es genial que una persona esté lo suficientemente interesada en la tecnología y los trucos básicos para hacer esto. Por otro lado, es un poco como un tiro en la pierna, porque nuestro simulador no es para recibir formalmente de él “OK, eres genial, hiciste todo”, sino para aprender a trabajar con normalidad, notar tus errores y corregirlos. En general, es como ir al gimnasio, sentarse en un banco de press durante 5 minutos y luego escribir en Facebook “Hice 3 series con cien kilos”: se puede divertir la autoestima, pero los logros se detendrán ahí.



En realidad, es por eso que no vamos a llevar esta verificación al backend, resolvería un problema similar. La gente viene a estudiar para conseguir un trabajo real (tal vez en el propio Taller), no logros virtuales.



Mejoramos constantemente el simulador web, utilizando tanto nuestra propia lista de deseos como los comentarios de los usuarios, por lo que seguiremos informándote sobre su desarrollo. Ahora se está finalizando, teniendo en cuenta las necesidades de los estudiantes con una solicitud de tecnologías específicas, por ejemplo, hemos agregado trabajo con React y NodeJS. El simulador web es, con mucho, el más popular de todos, seguido por el simulador de Python, en gran parte debido tanto al umbral de entrada más bajo como a la popularidad de las tecnologías en sí. Además de la parte técnica dentro del simulador, también hay muchas mecánicas para trabajar con teoría interactiva (y hay suficientes en todos nuestros cursos). No hay un simulador separado solo para la especialidad de QA, donde hicimos un conjunto especial de cuestionarios + soportes en los que estudian los evaluadores. Por cierto, un par de probadores,quienes ahora nos ayudan a hacer el Taller son graduados de nuestraCurso de control de calidad .



Los simuladores para C ++ y el simulador para aprendizaje automático son más complicados, si te interesa trataremos de hablarte de ellos en los próximos posts.



Gracias por leer, si tienes alguna duda sobre nuestros simuladores o el Practicum en su conjunto - escribe, te responderemos.



All Articles