Kolaborasi real-time tampak mudah sampai Anda melihat apa yang terjadi di balik layar. Satu orang mengetik. Orang lain menghapus satu baris tiga paragraf di atasnya. Orang ketiga menempelkan cuplikan dari Stack Overflow. Entah bagaimana, dokumen tersebut akhirnya menetap dalam satu keadaan yang koheren. Membangun fluiditas seperti itu dari nol, tanpa pengalaman sebelumnya dalam WebSockets atau state terdistribusi, terdengar ceroboh. Namun, itu juga terdengar seperti cara yang tepat untuk benar-benar belajar.

Proyek ini dimulai dari nol. Tanpa boilerplate pinjaman. Tanpa tutorial YouTube yang sudah dipoles di mana bagian-bagian sulit dilewati dalam montase tiga puluh detik. Tujuannya adalah sebuah editor kode kolaboratif di mana beberapa pengguna dapat mengedit file yang sama secara bersamaan, melihat perubahan satu sama lain—dan kursor satu sama lain—saat hal itu terjadi. Mencapainya akan membutuhkan pemahaman tentang lapisan transport, model konsistensi, dan masalah pelik dalam menggabungkan pengeditan konkuren tanpa merusak dokumen.

Apa Arti Sebenarnya dari “Real-Time”

Sebagian besar aplikasi web sudah nyaman dengan siklus request-response. Anda mengirimkan formulir, server menyimpannya, lalu Anda menyegarkan halaman. Kolaborasi real-time merusak kontrak tersebut sepenuhnya. Setiap ketukan tombol adalah sebuah event yang harus menyebar ke setiap klien terhubung lainnya, biasanya dalam hitungan milidetik, dan tiba dalam urutan yang menjaga makna teks tersebut.

WebSockets adalah pilihan transport yang jelas di sini karena mereka mempertahankan koneksi full-duplex yang persisten antara klien dan server. Berbeda dengan HTTP polling, yang membuang-buang bandwidth dengan bertanya “ada yang baru?” setiap beberapa detik, sebuah WebSocket tetap terbuka. Ketika pengguna A mengetik titik koma, karakter tersebut menjadi pesan yang merambat melalui socket ke server pusat, lalu disebarkan ke pengguna B dan C. Bagian itu relatif mudah.

Bagian yang sulit adalah apa yang terjadi ketika B dan C mengetik pada saat yang bersamaan. Jika kedua perubahan tersebut mencapai server hampir secara bersamaan, mana yang menang? Jika Anda hanya menyiarkan pesan berdasarkan urutan kedatangan, Anda berisiko kehilangan karakter atau teks yang berantakan. Strategi "last-write-wins" yang naif akan gagal karena mengabaikan maksud pengguna. Jika saya mengetik “hello” di awal baris satu sementara Anda mengetik “world” di awal baris satu, hasilnya tidak boleh berupa tabrakan di mana salah satu dari kita terhapus. Hasilnya haruslah “helloworld” atau “worldhello,” yang dipilih secara deterministik. Mencapai hal itu memerlukan strategi sinkronisasi yang memahami struktur dokumen.

Mengapa Memulai dari Nol itu Penting

Ada framework luar biasa yang menyembunyikan kompleksitas ini. Yjs, Automerge, dan Socket.IO dapat mengabstraksi kesulitan tersebut dan menghasilkan prototipe yang berfungsi dalam satu sore. Namun, menggunakannya tanpa memahami primitif di bawahnya seperti menerbangkan pesawat dengan autopilot tanpa tahu cara membaca instrumen. Ketika turbulensi terjadi—dan dalam sistem terdistribusi, hal itu selalu terjadi—Anda perlu tahu apakah masalahnya ada pada lapisan jaringan, resolusi konflik, atau model data Anda.

Komitmen di sini adalah untuk mempelajari konsep-konsepnya sebelum mengandalkan library. Itu berarti melakukan penalaran secara manual tentang apa yang terjadi ketika:

  • Seorang klien terputus di tengah pengetikan dan terhubung kembali sepuluh detik kemudian
  • Dua pengguna memasukkan teks pada posisi kursor yang sama secara bersamaan
  • Seorang pengguna menghapus sebuah blok yang sedang diedit secara aktif oleh pengguna lain
  • Server crash dan node baru harus merekonstruksi state dokumen dari nol

Operational Transformation (OT) dan Conflict-free Replicated Data Types (CRDTs) adalah dua keluarga solusi yang dominan untuk masalah-masalah ini. Google Docs terkenal membangun arsitektur awalnya di atas OT, yang membutuhkan server pusat untuk mentransformasikan operasi satu sama lain sebelum menerapkannya. Sebaliknya, CRDTs dirancang agar pembaruan konkuren dapat digabungkan secara lokal tanpa koordinasi, menjadikannya menarik untuk pengaturan peer-to-peer atau berbasis edge. Memilih di antara keduanya—atau pendekatan hibrida—memerlukan pemahaman tentang trade-off dalam penggunaan memori, jaminan konvergensi, dan kompleksitas implementasi. Membaca tentang trade-off tersebut saja tidak cukup; rencananya adalah mengimplementasikan versi naif dan versi yang telah disempurnakan untuk melihat di mana keduanya gagal.

Proses Membangun Ulang, Kesalahan, dan Jalan Buntu

Ekspektasi dikalibrasi secara jujur. Akan ada masa-masa di mana tidak ada yang berjalan lancar. Upaya pertama mungkin menggunakan JSON patch sederhana untuk merepresentasikan perubahan teks, hanya untuk menyadari bahwa JSON tidak memiliki konsep “indeks 5 dalam sebuah paragraf,” sehingga dua penyisipan bersamaan pada indeks yang sama saling menimpa alih-alih menggabungkan. Upaya kedua mungkin membangun log riwayat linier kustom, hanya untuk menyadari bahwa memutar ulang log tersebut adalah mimpi buruk Big O saat dokumen bertambah besar. Upaya ketiga mungkin berhasil menjalankan WebSockets secara lokal, lalu berantakan di jaringan nyata di mana kehilangan paket (packet loss) dan latensi variabel mengubah semua aturan.

Gesekan itulah intinya. Menyalin repositori yang sudah jadi akan melewatkan investigasi tentang mengapa antrean (queue) dikosongkan dalam urutan tertentu, atau mengapa server mempertahankan version vector. Membangun kembali komponen yang sama sebanyak tiga kali memang lambat, tetapi hal itu memaksa pemahaman tentang batasan antara apa yang dilakukan framework dan apa yang harus ditangani oleh logika Anda sendiri.

Dokumentasi dari proses ini bukanlah sebuah kumpulan pencapaian terbaik (highlight reel). Ia akan mencakup jalan-jalan yang salah. Sebagai contoh, membangun kesadaran kehadiran (presence awareness)—mengetahui siapa yang sedang online dan di mana kursor mereka berada—tampak seperti fitur kosmetik sampai Anda menyadari bahwa hal itu bergantung pada model konsistensi yang sama dengan teks itu sendiri. Jika pengguna A melihat kursor pengguna B di kolom 10, lalu pengguna B menyisipkan empat karakter, ke mana kursor itu berpindah? Tanpa pemahaman bersama tentang topologi dokumen, data kehadiran akan melenceng dari realitas. Menyelesaikan hal tersebut memerlukan pengaitan posisi kursor dengan identitas struktur data yang mendasarinya, bukan sekadar indeks numeriknya. Inilah jenis detail yang sering dilewati oleh tutorial karena membosankan, bukan karena tidak penting.

Apa Selanjutnya

Roadmap jangka pendek sengaja dibuat ringkas. Milestone pertamanya adalah:

  • Sebuah server WebSocket mentah yang memantulkan (echo) peristiwa karakter, untuk merasakan latensi dan siklus hidup koneksi secara langsung
  • Sebuah buffer string sederhana pada klien untuk memahami mengapa pengurutan penyisipan naif gagal dalam kondisi konkurensi
  • Sebuah CRDT yang dibuat dari nol untuk urutan terurut, betapapun tidak efisiennya, untuk melihat sifat komutatif dalam aksi
  • Integrasi bertahap dengan permukaan editor kode yang sebenarnya, kemungkinan seperti CodeMirror atau Monaco, untuk bergulat dengan ketidakcocokan antara API imperatif editor dan sifat fungsional dari riwayat operasional

Setiap langkah akan disertai dengan alasan tertulis. Mengapa pendekatan ini dan bukan yang itu? Asumsi apa yang terbukti salah? Abstraksi apa yang bocor?

Pelajaran Nyata

Memulai proyek seperti ini tanpa pengalaman dalam WebSockets atau CRDTs memang mengintimidasi, tetapi keahlian sering kali hanyalah kebingungan yang berulang dengan label yang lebih baik. Tujuannya bukanlah penyelesaian yang cepat. Tujuannya adalah sebuah sistem yang perilakunya dapat diprediksi karena setiap lapisannya dibangun dengan niat, bukan diimpor dengan harapan.

Jika Anda pernah membangun perangkat lunak kolaboratif sebelumnya—baik itu editor teks, alat desain, atau mesin sinkronisasi status game—bagikan mode kegagalan yang mengejutkan Anda. Jika Anda juga sedang mempelajari sistem ini, ikutilah. Kode akan hadir perlahan, dan akan sering ditulis ulang. Hari ke-0 dimulai sekarang.