Dalam upaya untuk melakukan sesuatu yang serupa, kami pernah meluncurkan simulator web di Yandex MVP, di mana pengguna dapat menulis kode, skrip, dan lainnya di tab yang berbeda, dan di sebelahnya ia menampilkan semua ini sebagai hasil akhir.

MVP telah menunjukkan dirinya dengan baik, dan kami telah membawa simulator web ke tingkat alat yang lengkap untuk menguji pengetahuan siswa kami di Yandex.Practice . Nama saya Artem, dan saya akan memberi tahu Anda bagaimana kami membuat simulator untuk mengajarkan pengembangan web, cara kerjanya, dan apa yang bisa dilakukannya.
Dari luar, tampaknya semuanya sederhana di sini - saya memasukkan semua kode khusus ke dalam iframe, mempostingnya melalui postmessage, lalu merendernya dengan cara apa pun, dan semuanya berfungsi. Sedikit pratinjau kode online yang dipompa.
Tapi ada nuansa.
Bagaimana itu bekerja
Pada awalnya, kami mencatat kemungkinan masalah: jika Anda menerapkan simulator pada domain Yandex (seperti Lokakarya itu sendiri, misalnya), maka ada kemungkinan bukan nol bahwa pengguna akan menjadi sedikit lebih penasaran. Yaitu, mereka akan mengambil dan melempar beberapa kode ke dalam simulator, yang akan diproses dengan antusias oleh simulator. Dan kode tersebut akan berubah menjadi penipuan dan akan mengambil cookie Yandex yang ada, memasukkannya ke beberapa layanan pihak ketiga, setelah itu penipu akan memiliki akses ke akun pribadi pengguna di Yandex dan semua data pribadi. Sangat mudah untuk menerapkan ini jika iframe ini terletak di domain yandex.ru. Oleh karena itu, kami membuat domain terpisah di yandex.net khusus untuk simulator dan menamakannya Feynman. Untuk menghormati Richard , ya.
Secara umum, simulator kami menyimpan file yang kami kirim ke backend dalam format teks biasa, json dan base64 untuk gambar. Kemudian mereka diubah menjadi file nyata dan didistribusikan dalam bentuk statis, yang dapat kita masukkan ke dalam iframe untuk rendering.
Tapi kami tidak hanya memainkan penyorotan sintaks di sini, kami memiliki simulator untuk menguji pengetahuan. Oleh karena itu, kita perlu menguji dan memeriksa kode ini dengan cepat, yaitu, entah bagaimana masuk ke dalam proses iframe dan melihat apakah pengguna melakukan semuanya dengan benar, katakanlah, bagaimana dia menamai variabel, atau apakah semuanya baik-baik saja dengan div.
Dan di sini kita kembali mengalami domain. Kode pengguna, seperti yang sudah saya tulis, dimasukkan ke dalam simulator di domain Feynman, dan kami memeriksanya dari Yandex, dari domain praktikum.yandex.ru . Kebijakan browser asal yang sama dijaga dan tidak mengizinkan Anda untuk merusak internal iframe jika domain Anda berbeda.
Oleh karena itu, kami memutuskan untuk menjejalkan iframe ke dalam iframe.

Situasi berikut ternyata:
- Kami membuat iframe, yang pada awalnya kosong.
- Dia menggambar semacam halaman kosong.
- Kami dari depan memposting pesan pos dengan tautan ke apa yang diberikan Feynman kepada kami (dari mana dia menjadi tuan rumah statika).
- Iframe pertama mengambil tautan ini dan menggantinya di src dari iframe bagian dalam.
Hasilnya, iframe pertama kita dapat memiliki kode dan melakukan apa pun yang diinginkannya dengan iframe internal. De facto, tes hanyalah fungsi eval yang memiliki akses ke: dokumen, jendela, dan seterusnya, semua yang ada di iframe. Ini memberi kami kesempatan untuk melakukan tes untuk suatu masalah dan menjalankannya di jendela iframe yang diberikan.
Bukan dengan tes saja
Kemudian kami ingin menambahkan beberapa fitur yang berguna: terminal, konsol, kemampuan untuk menampilkan data pengguna tentang apa yang dia tulis ke log, dan kesenangan lainnya. Tentu saja, kami membuat mode adaptif lengkap sehingga pengguna dapat melihat bagaimana hasilnya di smartphone dan tablet.

Untuk ini, pustaka khusus telah ditulis yang memuat semua gaya yang diperlukan dan mengemulasi mode responsif. Kami juga sedikit mengubah iframe asli kami dan menambahkan semua yang memungkinkan pengguna untuk menampilkan console.log-nya di layar, dan tidak hanya beberapa objek sederhana, tetapi juga pohon dom dokumen lengkap.
Selain itu, kami belajar cara menjalankan tes pendahuluan. Ini berguna karena ada banyak pengujian yang memeriksa hal-hal yang sama - misalnya, apakah pengguna telah berlebihan dengan loop dalam kode, apakah dia terbawa oleh nesting, dan sejenisnya. Tidak masuk akal untuk mendeskripsikan hal ini dalam setiap pengujian secara terpisah, jadi kami menulis pustaka pengujian yang memiliki sekumpulan metode pra-pengujian khusus yang memeriksa kode. Jika semuanya baik-baik saja pada tahap ini, maka tes utama dan masalah yang diselesaikan sudah diperiksa, setelah itu hasilnya ditampilkan kepada pengguna.
Untuk mengembalikan hasil pengujian awal kepada pengguna, kami juga menggunakan postmessage - kami mengirim pesan melaluinya, apakah ada kesalahan atau semuanya keren. Ngomong-ngomong, kode siswa di simulator web juga diperiksa melalui linter es-lint dengan terjemahan ke dalam bahasa Rusia dan selalu menyoroti kesalahan sintaks.
Masalah dengan tinjauan kode (dan tidak hanya)
Jika ada notifikasi sistem atau browser pada halaman tersebut, misalnya disarankan untuk memasukkan sesuatu, maka seringkali saat menjalankan pengujian kami, pengguna terus melihat jendela browser dengan notifikasi dan permintaan entri data. Kami harus melakukan ini: ketika pengguna baru saja meluncurkan halaman dengan kodenya untuk melihat bagaimana semuanya bekerja, peringatan ini juga perlu berfungsi. Dan saat pengujian menjalankan kode ini untuk verifikasi, kami tidak lagi memerlukan peringatan untuk terus muncul di layar pengguna. Faktanya, kami mengganti semua peringatan ini dengan rintisan kami sendiri untuk pengujian (tiruan), mengganti peringatan, prompt, konfirmasi di dalam jendela. Jika Anda tidak melakukan ini, Anda bisa mendapatkan loop pada output atau peringatan kosong yang tidak melakukan apa-apa.
Omong-omong, tentang loop tak terbatas. Masalah utama di sini adalah bahwa pengguna dapat dengan sengaja mengambil dan menulis kode yang akan dengan senang hati masuk ke loop tak terbatas (hanya ada satu utas javascript di browser), dan sebagai hasilnya, seluruh browser menjadi tiarap.
Untuk mengatasi ini, pertama-tama kami belajar melacak loop tak terbatas seperti itu sebelum mengirimkan kode untuk ditinjau. Untuk melakukan ini, perlu untuk membuat ulang skrip pengguna dengan beberapa cara, kami melakukannya dengan cara ini:
- Untuk setiap siklus kami menambahkan fungsi tertentu yang menghitung jumlah panggilan.
- Jika jumlah panggilan ini melebihi 100.000, maka kami segera melontarkan pengecualian, yang juga kami kirimkan kembali melalui postmessage. Plus, untuk berjaga-jaga, kami memeriksa batas waktu jika siklus berjalan lebih dari 10 detik.
- Sepanjang jalan, kami memantau bahwa, karena pengecualian telah muncul, ada yang salah di sini, dan pengujian itu sendiri tidak lagi masuk akal untuk dijalankan - kode diulang.
Situasi dengan tautan harus dicatat secara terpisah. Katakanlah pengguna di dalam kodenya mungkin memiliki beberapa tautan yang harus dibuka saat diklik di tab baru, misalnya, portofolionya atau akun github. Dan kami tidak memerlukan tautan seperti itu untuk membuka langsung di dalam iframe - jika tidak, alih-alih iframe, kami akan memiliki laman dengan tautannya. Hal-hal seperti itu perlu dibuka di tab baru, melalui Tab. Biasanya, untuk membuka link tidak di dalam frame, tetapi di frame induk, Anda hanya perlu menentukan target = "_ parent". Namun dalam kasus kami, kami perlu menambahkan penangan yang menentukan apakah tautan tersebut eksternal.
Dan untuk semua tautan, kami menulis penangan khusus: jika kami melihat bahwa tautan itu eksternal, maka kami mengirim pesan pos ke luar, menghentikan penangan tautan itu sendiri (mencegah default), dan postmessage kembali ke depan kami. Kami melihat bahwa kami memiliki tautan eksternal di sini, dan menampilkan pemberitahuan - apakah kami yakin akan membuka situs eksternal? Dan setelah itu kami membuka tab baru.
Dan juga jangkar, dengan mereka semuanya jauh lebih mudah. Mereka hanya tidak berfungsi di dalam iframe. Umumnya. Oleh karena itu, sebagai peretasan kecil, kami berlangganan acara klik di tautan mana pun - jika ada jangkar di atasnya, kami membuat scrollIntoView ke elemen tertentu.
Semua metadata (jika pengguna memiliki favicon yang terdaftar di halaman HTML, misalnya, atau judul tertentu), kami juga mengirim melalui postmessage setelah iframe dimuat. Dengan menggunakan querySelector, kami mendapatkan dua tag ini, mengirimnya kembali ke depan kami melalui postmessage, dan bagian depan itu sendiri menyisipkan semua ikon ini jika diperlukan. Tampaknya ini sepele, tetapi pengguna mendapat kesan bahwa dia memiliki browser lengkap di dalam browser.
Mencoba melewati simulator
Simulator web kami, tidak seperti simulator yang kami buat untuk Python, SQL, dan lainnya, menggunakan bagian depan, bukan bagian belakang, untuk pemeriksaan. Oleh karena itu, ketika pengguna menyelesaikan pengujian dengan benar, permintaan POST yang sesuai dikirim ke backend. Pada prinsipnya, pengguna, dengan keterampilan yang tepat, dapat melakukan hal yang sama dan mengirimkan permintaan semacam itu secara manual.
Ada pedang bermata dua. Di satu sisi, itu keren bahwa seseorang cukup tertarik pada teknologi dan peretasan dasar untuk melakukan ini. Di sisi lain, ini seperti tembakan di kaki, karena simulator kami tidak untuk secara resmi menerima darinya "OK, Anda hebat, Anda melakukan segalanya", tetapi untuk belajar bagaimana bekerja secara normal, perhatikan kesalahan Anda dan perbaiki. Secara umum, ini seperti pergi ke gym, duduk di bench press selama 5 menit, dan kemudian menulis di Facebook "Melakukan 3 set dengan seratus kilo": Anda dapat menghibur harga diri, tetapi pencapaiannya akan berhenti di situ.
Sebenarnya, itu sebabnya kami tidak membawa cek ini ke backend, itu akan menyelesaikan masalah serupa. Orang datang untuk belajar untuk mendapatkan pekerjaan nyata (mungkin di Bengkel itu sendiri), bukan prestasi virtual.
Kami terus meningkatkan simulator web, menggunakan daftar keinginan kami sendiri dan umpan balik dari pengguna, jadi kami akan terus memberi tahu Anda tentang perkembangannya. Sekarang sedang diselesaikan, dengan mempertimbangkan kebutuhan siswa dengan permintaan untuk teknologi tertentu, misalnya, kami telah menambahkan pekerjaan dengan React dan NodeJS. Simulator web sejauh ini adalah yang paling populer, diikuti oleh simulator Python, sebagian besar karena ambang masuk yang lebih rendah dan popularitas teknologinya sendiri. Selain bagian teknis, ada juga banyak mekanik di dalam simulator untuk bekerja dengan teori interaktif (dan jumlahnya cukup banyak di semua kursus kami). Tidak ada simulator terpisah hanya untuk spesialisasi QA, di mana kami membuat satu set kuis + stand khusus yang dipelajari penguji. Omong-omong, beberapa penguji,yang sekarang membantu kami melakukan Lokakarya adalah lulusan kamiKursus QA .
Simulator untuk C ++ dan simulator untuk machine learning lebih rumit lagi, jika anda tertarik, kami akan mencoba membahasnya pada postingan selanjutnya.
Terima kasih telah membaca, jika Anda memiliki pertanyaan tentang simulator kami atau tentang Workshop secara umum - tulis, kami akan menjawab.