Simulateur Web Yandex.Practicum. Comment ça fonctionne

Il est important de rendre le processus éducatif intéressant et aussi interactif que possible. Surtout en ce qui concerne la technologie - c'est beaucoup plus utile quand il y a une opportunité non seulement d'écrire du code, puis d'obtenir une réponse de l'inspecteur, disent-ils, bien fait, tout va bien, mais à la volée pour voir si tout fonctionne pour vous, où sont les montants et comment vous l'avez généralement fait.



Dans une tentative de faire quelque chose de similaire, nous avons une fois lancé un simulateur Web dans Yandex MVP, dans lequel l'utilisateur pouvait écrire du code, des scripts et tout le reste sur différents onglets, et à côté, il a affiché tout cela comme résultat final.







MVP a bien fait ses preuves, et nous avons amené le simulateur Web au niveau d'un outil à part entière pour tester les connaissances de nos étudiants dans Yandex.Practice . Je m'appelle Artem et je vais vous dire comment nous avons créé un simulateur pour enseigner le développement Web, comment cela fonctionne et ce qu'il peut faire.



De l'extérieur, il semble que tout est simple ici - j'ai fourré tout le code personnalisé dans une iframe, je l'ai posté via un message postal, puis je l'ai rendu de toutes les manières possibles, et tout fonctionne. Un tel aperçu du code en ligne légèrement pompé.



Mais il y a des nuances.



Comment ça fonctionne



Au début, nous avons noté un problème possible: si vous déployez le simulateur sur un domaine Yandex (comme l'Atelier lui-même, par exemple), alors il y a une probabilité non nulle que les utilisateurs se révèlent un peu plus curieux. À savoir, ils prendront et jetteront du code dans le simulateur, que le simulateur traitera avec enthousiasme. Et le code se révélera frauduleux et supprimera le cookie Yandex existant, l'insérera dans un service tiers, après quoi le fraudeur aura accès au compte personnel de l'utilisateur dans Yandex et à toutes les données personnelles. Il est assez facile de l'implémenter si cette iframe est située dans le domaine yandex.ru. Par conséquent, nous avons créé un domaine séparé sur yandex.net spécifiquement pour le simulateur et l'avons nommé Feynman. En l'honneur de Richard , oui.



En général, notre simulateur stocke les fichiers que nous l'envoyons au backend au format texte brut, json et base64 pour les images. Ensuite, ils sont convertis en fichiers réels et déjà distribués sous forme de statique, que nous pouvons mettre dans une iframe pour le rendu.



Mais nous ne jouons pas seulement ici la coloration syntaxique, nous avons un simulateur pour tester les connaissances. Par conséquent, nous devons tester et vérifier ce code à la volée, c'est-à-dire nous coincer dans le processus iframe et voir si l'utilisateur a tout fait correctement, par exemple, comment il a nommé la variable, ou si tout va bien avec les divs.







Et ici, nous rencontrons à nouveau des domaines. Le code utilisateur, comme je l'ai déjà écrit, est mis dans le simulateur sur le domaine Feynman, et nous le vérifions depuis Yandex, depuis le domaine praktikum.yandex.ru . La politique de même origine du navigateur est sur ses gardes et ne vous permet pas de falsifier les éléments internes de l'iframe si vous avez des domaines différents.



Par conséquent, nous avons décidé d'entasser l'iframe dans l'iframe.







La situation suivante s'est avérée:



  • Nous créons une iframe, qui est en fait vide au début.
  • Il dessine une sorte de page blanche.
  • De notre front, nous publions un message postal avec un lien vers ce que Feynman nous a donné (d'où il héberge la statique).
  • Le premier iframe prend ce lien et le remplace dans le src de l'iframe interne.


En conséquence, notre premier iframe peut posséder le code et faire ce qu'il veut avec l'iframe interne. De facto, les tests ne sont qu'une fonction d'évaluation qui a accès à: document, fenêtre, etc., tout ce qui se trouve dans l'iframe. Cela nous donne la possibilité de tester un problème et de l'exécuter dans la fenêtre d'une iframe donnée.



Pas uniquement par des tests



Ensuite, nous avons voulu ajouter quelques fonctionnalités utiles: un terminal, une console, la possibilité d'afficher des données utilisateur sur ce qu'il a écrit dans le journal, et d'autres joies. Bien sûr, nous avons créé un mode adaptatif à part entière afin que l'utilisateur puisse voir à quoi ressemblera le résultat sur les smartphones et les tablettes.







Pour cela, une bibliothèque spéciale a été écrite qui charge tous les styles nécessaires et émule le mode réactif. Nous modifions également légèrement notre iframe d'origine et ajoutons tout ce qui permet à l'utilisateur d'afficher son console.log à l'écran, et pas seulement quelques objets simples, mais aussi des arborescences de documents à part entière.



En plus de cela, nous avons appris à exécuter des tests préliminaires. Ceci est utile car il existe de nombreux tests qui vérifient les mêmes choses - par exemple, si l'utilisateur a exagéré avec des boucles dans le code, s'il s'est laissé emporter par l'imbrication, etc. Cela n'a pas beaucoup de sens de décrire cela dans chaque test séparément, nous avons donc écrit une bibliothèque de tests qui a un ensemble de méthodes spéciales de pré-test qui vérifient le code. Si tout va bien à ce stade, le test principal et les problèmes résolus sont déjà vérifiés, après quoi le résultat est montré à l'utilisateur.



Pour renvoyer le résultat des tests préliminaires à l'utilisateur, nous utilisons également des messages postaux - nous envoyons des messages via celui-ci, qu'il y ait des erreurs ou que tout soit cool. À propos, le code de l'élève sur le simulateur Web est également vérifié via le linter es-lint avec traduction en russe et met toujours en évidence les erreurs de syntaxe.



Problèmes avec les révisions de code (et pas seulement)



S'il y avait des notifications système ou navigateur sur la page, par exemple, il était suggéré d'entrer quelque chose, alors souvent lors de l'exécution de notre test, l'utilisateur continuait à voir les fenêtres du navigateur avec des notifications et des demandes de saisie de données. Nous devions le faire comme ceci: lorsqu'un utilisateur lance simplement une page avec son code pour voir comment tout fonctionne, cette alerte doit également fonctionner. Et lorsque le test exécute ce code pour vérification, nous n'avons plus besoin d'alertes pour continuer à apparaître sur l'écran de l'utilisateur. En fait, nous avons remplacé toutes ces alertes par nos propres stubs pour les tests (mock), l'alerte de remplacement, l'invite, la fenêtre de confirmation. Si vous ne le faites pas, vous pourriez obtenir une boucle à la sortie ou une alerte vide qui ne fait rien.



Au fait, à propos de boucles infinies. Le principal problème ici était que l'utilisateur pouvait sciemment prendre et écrire du code qui entrerait volontiers dans une boucle infinie (il n'y a qu'un seul thread javascript dans le navigateur), et par conséquent, tout le navigateur s'est allongé.



Pour lutter contre cela, nous avons appris à suivre tout d'abord ces boucles infinies avant de soumettre le code pour examen. Pour ce faire, il était nécessaire de refaire le script utilisateur d'une certaine manière, nous sommes allés de cette façon:



  • Pour chaque cycle, nous ajoutons une certaine fonction qui compte le nombre d'appels.
  • Si ce nombre d'appels dépasse 100 000, nous lançons immédiatement une exception, que nous renvoyons également par courrier postal. De plus, au cas où, nous vérifions le délai si le cycle dure plus de 10 secondes.
  • En cours de route, nous suivons que, depuis qu'une exception est survenue, quelque chose ne va pas ici, et le test lui-même n'a plus de sens à exécuter - le code est en boucle.


La situation avec les liens doit être notée séparément. Disons qu'un utilisateur dans son code peut avoir des liens qui devraient s'ouvrir au clic dans un nouvel onglet, par exemple, son portefeuille ou un compte github. Et nous n'avions pas besoin de tels liens pour s'ouvrir directement à l'intérieur de l'iframe - sinon, au lieu de l'iframe, nous aurons une page avec son lien. Il est nécessaire d'ouvrir de telles choses dans un nouvel onglet, via Tab. Habituellement, pour ouvrir un lien non pas à l'intérieur du cadre, mais dans le cadre parent, il vous suffit de spécifier target = "_ parent". Mais dans notre cas, nous devions ajouter un gestionnaire qui détermine si le lien est externe.



Et pour tous les liens, nous avons écrit un gestionnaire spécial: si nous voyons que le lien est externe, nous envoyons le postmessage vers l'extérieur, nous interrompons le gestionnaire de lien lui-même (empêche la valeur par défaut), et le postmessage revient à notre tête. Nous voyons que nous avons un lien externe ici, et montrons une notification - sommes-nous sûrs que nous allons sur un site externe? Et après cela, nous ouvrons de nouveaux onglets.



Et aussi les ancres, avec eux tout était beaucoup plus simple. Ils ne fonctionnaient tout simplement pas dans l'iframe. Généralement. Par conséquent, en tant que petit hack, nous nous sommes abonnés pour cliquer sur des événements sur n'importe quel lien - s'il y avait une ancre dessus, nous avons fait le scrollIntoView vers un élément spécifique.



Toutes les métadonnées (si l'utilisateur avait un favicon enregistré sur la page HTML, par exemple, ou un titre spécifique), nous les envoyons également via postmessage après le chargement de l'iframe. En utilisant le querySelector, nous obtenons ces deux balises, nous les renvoyons à notre front par postmessage, et le front lui-même insère toutes ces icônes si nécessaire. Cela semble être une bagatelle, mais l'utilisateur a l'impression qu'il dispose d'un navigateur à part entière dans le navigateur.



Tentatives de contournement du simulateur



Notre simulateur Web, contrairement aux simulateurs que nous avons créés pour Python, SQL et autres, utilise le front pour les vérifications, pas le backend. Par conséquent, lorsque l'utilisateur termine correctement les tests, une requête POST correspondante est envoyée au backend. En principe, l'utilisateur, avec les compétences appropriées, peut faire de même et envoyer une telle demande manuellement.



Il y a une épée à double tranchant. D'une part, c'est cool qu'une personne s'intéresse suffisamment à la technologie et aux hacks de base pour le faire. Par contre, c'est un peu comme un coup de pied dans la jambe, car notre simulateur n'est pas pour recevoir formellement de celui-ci "OK, tu es super en général, tu as tout fait", mais pour apprendre à travailler normalement, remarquer tes erreurs et les corriger. En général, c'est comme aller à la salle de sport, s'asseoir sur un développé couché pendant 5 minutes, puis écrire sur Facebook «J'ai fait 3 sets de cent kilos»: on peut amuser l'estime de soi, mais les exploits s'arrêteront là.



En fait, c'est pourquoi nous ne prenons pas cette vérification au backend, cela résoudrait un problème similaire. Les gens viennent étudier afin d'obtenir un vrai travail (peut-être dans l'atelier lui-même), pas des réalisations virtuelles.



Nous améliorons constamment le simulateur Web, en utilisant à la fois notre propre liste de souhaits et les commentaires des utilisateurs, nous continuerons donc à vous parler de son développement. Maintenant, il est en cours de finalisation, en tenant compte des besoins des étudiants ayant une demande de technologies spécifiques, par exemple, nous avons ajouté des travaux avec React et NodeJS. Le simulateur Web est de loin le plus populaire de tous, suivi du simulateur Python - en grande partie en raison à la fois du seuil d'entrée plus bas et de la popularité des technologies elles-mêmes. En plus de la partie technique, il y a aussi de nombreux mécanismes à l'intérieur du simulateur pour travailler avec la théorie interactive (et il y en a assez dans tous nos cours). Il n'y a pas de simulateur séparé uniquement pour la spécialité QA, où nous avons créé un ensemble spécial de quiz + stands sur lesquels les testeurs étudient. Au fait, quelques testeurs,qui nous aident maintenant à faire l'atelier sont des diplômés de notreCours d'AQ .



Les simulateurs pour C ++ et le simulateur pour l'apprentissage automatique sont plus compliqués, si cela vous intéresse, nous essaierons d'en parler dans les prochains articles.



Merci d'avoir lu, si vous avez des questions sur nos simulateurs ou sur l'atelier en général - écrivez, nous vous répondrons.



All Articles