frontend
LetCode
Platform latihan soal coding di browser untuk persiapan interview: 11 track, 55 soal, 443 test case, dengan judge yang berjalan sepenuhnya di perangkat pengguna tanpa server eksekusi.
- Peran
- Frontend (dengan komponen serverless untuk penghitung kunjungan)
- Durasi
- Oktober 2026
- Tanggal
- Oktober 2026
Teknologi
- nuxt
- vue
- typescript
- unocss
- monaco-editor
- pyodide
- web worker
- netlify functions
- netlify blobs
- markdown-it
- eslint
- pnpm
Dampak
11 track, 55 soal, dan 443 test case, semuanya dinilai di browser tanpa server eksekusi.
Masalah
Latihan interview menuntut tiga hal sekaligus: kurikulum yang terurut, tempat menulis kode, dan penilaian yang objektif. LeetCode punya ketiganya, tapi berbahasa Inggris dan kurikulumnya tidak selalu selaras untuk orang yang baru mulai. Materi lokal biasanya berhenti di teori tanpa penilaian otomatis, jadi pembaca tidak pernah tahu apakah solusinya benar.
Membangun sendiri punya jebakan yang berbeda: menilai kode hampir selalu berarti server, sandbox, dan tagihan bulanan. Kode orang lain tidak boleh dijalankan di mesin yang sama dengan data Anda. Proyek ini dikunci pada dua batasan yang tidak boleh dilanggar: nol biaya, dan tidak ada server yang mengeksekusi kode.
Solusi
Seluruh eksekusi terjadi di browser. JavaScript berjalan di Web Worker baru untuk setiap percobaan, lalu worker itu dihentikan paksa saat melewati batas waktu, satu-satunya cara menghentikan loop tak berujung di browser. Python memakai Pyodide di worker terpisah yang sengaja tidak dimatikan antar eksekusi, karena memuat ulang runtime Python jauh lebih mahal daripada menghapus variabelnya. Dua bahasa, dua strategi, karena keduanya punya profil biaya yang berlawanan.
Gaya soal adalah function signature, bukan stdin/stdout. Keputusan ini menyederhanakan hampir semuanya: tidak perlu terminal palsu, tidak perlu mem-parse keluaran, dan sistem cukup menyusun ulang kode peserta untuk mengambil fungsi target lalu memanggilnya dengan argumen JSON. Struktur data dikirim sebagai representasi JSON, pohon biner sebagai array level-order dengan null dan linked list sebagai array, sehingga peserta justru harus membangun struktur datanya sendiri di dalam kode.
Arsitektur dibagi empat lapis dengan aturan ketergantungan yang ditegakkan: UI tidak pernah memanggil Worker secara langsung, dan lapis runner tidak pernah menyentuh localStorage. Lapis runner sengaja diletakkan di luar folder auto-import Nuxt supaya setiap pemakaiannya harus lewat impor eksplisit, batas lapisan yang tidak bisa dilanggar tanpa sadar.
Karena situs ini statis, konten adalah satu-satunya pembeda produk. Maka dibangun pipeline validasi yang, saat build, menjalankan setiap reference solution JavaScript dan Python terhadap seluruh test case-nya. Satu soal yang tidak lolos menggagalkan build. Tapi validasi itu sendiri sirkular: ia membuktikan solusi cocok dengan expected, bukan bahwa expected-nya benar. Kalau solusi dan expected sama-sama salah, pipeline tetap hijau.
Jadi saya menulis solver independen untuk seluruh 55 soal, dibangun dari spesifikasi soal tanpa membaca reference solution, lalu membandingkannya dengan setiap expected. Hasilnya 443 test case tanpa satu pun perbedaan, dan dari situlah bug sebenarnya muncul. Komparator “urutan tidak penting” ternyata mengurutkan di semua tingkat, bukan hanya tingkat koleksi. Akibatnya permutations menerima jawaban berupa enam salinan permutasi yang sama, dan k-closest-points menerima koordinat yang dibalik, titik yang berbeda secara matematis. Perbaikannya adalah memisahkan dua semantik: urutan bebas di tingkat teratas saja, versus urutan bebas di semua tingkat untuk hasil yang benar-benar himpunan.
Bug kedua muncul dari batas worker. Konversi bawaan Pyodide tidak simetris untuk nilai kosong: null JavaScript menjadi sentinel JsNull alih-alih None, dan None Python kembali sebagai undefined alih-alih null. Akibatnya soal pohon biner tidak bisa dinilai dengan benar di Python. Solusinya adalah menjadikan JSON sebagai jembatan konversi di kedua arah, dan sejak itu null aman dipakai di expected.
Antarmuka memakai Monaco dengan worker yang di-bundle terpisah, dan Pyodide disajikan dari folder statis sendiri sehingga tidak ada ketergantungan CDN saat runtime. Dua bahasa antarmuka, Indonesia dan Inggris, diterjemahkan penuh termasuk seluruh isi soal dan materi, tanpa library i18n. Kamus Inggris dideklarasikan sebagai tipe yang diwajibkan lengkap, jadi kunci yang lupa diterjemahkan gagal saat kompilasi, bukan saat pengguna membukanya.
Satu-satunya komponen server-side adalah penghitung kunjungan. Netlify Blobs dipilih karena sudah satu penyedia dengan hosting, tapi dua detail menentukan implementasinya: bawaan Blobs adalah konsistensi eventual, yang membuat angka terlihat mundur hingga 60 detik, dan Blobs tidak punya operasi increment atomik. Jadi store dibuka dengan konsistensi kuat, dan penulisan memakai conditional write berbasis etag dengan retry, lebih baik kehilangan satu hitungan daripada menampilkan angka yang salah.
Hasil akhirnya 11 track dari Arrays & Hashing sampai Backtracking, 55 soal dalam dua bahasa pemrograman dan dua bahasa antarmuka, dengan 20 soal easy, 28 medium, dan 7 hard. Pipeline validasi menolak build bila ada satu soal cacat, dan 20 pemeriksaan terpisah menutup perilaku penghitung kunjungan termasuk penanganan bentrokan dan data rusak.
Kontak
Tertarik untuk bekerja sama?
Ceritakan apa yang sedang Anda bangun dan apa yang dibutuhkan. Catatan singkat sudah cukup.