Pengembangan frontend modern telah memasuki era di mana kompleksitas alur data tak lagi bisa diselesaikan dengan pola sederhana fetch-then-setState. Seorang insinyur perangkat lunak bernama Luciano mengemukakan argumen teknis yang tajam: mengurangi seluruh pekerjaan asinkronus ke dalam satu saluran yang sama justru menciptakan sumber kebingungan state yang sulit ditebak. Dia membagi pekerjaan asinkronus menjadi tiga kategori semantik yang fundamental berbeda — Query, Mutation, dan Stream — masing-masing dengan siklus hidup, strategi caching, dan tanggung jawab invalidasi yang unik.
Dalam praktik yang masih umum, pengembang memperlakukan respons API, pengiriman formulir, pesan WebSocket, dan pembaruan latar belakang sebagai hal yang sama: tugas asinkronus yang selesai lalu memicu pembaruan state dan render ulang. Pendekatan ini memang familiar dan nyaman, namun Luciano menegaskan bahwa kenyamanan itulah yang menutupi masalah arsitektur yang lebih dalam. Dari perspektif antarmuka pengguna, semuanya berakhir pada pembaruan layar. Namun dari perspektif alur data, membaca data, mengubah state sistem, dan mengamati perubahan berkelanjutan adalah tiga operasi dengan kebutuhan non-fungsional yang saling bertentangan.
Latar belakang masalah ini tumbuh seiring berkembangnya aplikasi single-page yang semakin kaya fitur. Semakin banyak komponen yang membutuhkan akses ke data yang sama — daftar pengguna, detail profil, hasil pencarian, pemeriksaan izin — semakin rawan terjadinya duplikasi fetch dan state yang tidak sinkron. Ketika setiap komponen melakukan fetch sendiri-sendiri, kepemilikan data menjadi kabur. Hasilnya, beberapa potongan state yang tampak identik justru tidak memiliki hubungan semantik sama sekali. Luciano mencontohkan kasus di mana halaman daftar, halaman detail, dan kotak pencarian masing-masing memanggil endpoint yang sama tanpa koordinasi pusat.
Query, menurut definisi Luciano, bukan sekadar pemanggilan await fetchUsers(). Esensinya adalah keinginan mengetahui state fakta data tertentu pada titik waktu sekarang. Operasi seperti GET /users atau GET /posts?authorId=1 mengembalikan data yang identifikasi, cacheable, dan revalidatable. Properti paling kritis dari Query adalah identitas — bagaimana sepotong data diidentifikasi dalam sistem, misalnya users.list() atau posts.byAuthor(authorId). Karena identitas itu, Query seharusnya tidak terikat pada siklus render komponen. Ia harus menjadi Resource Node di dalam Reactive Graph yang memiliki otoritas penuh atas loading state, stale state, dan kapan harus reload.
Berbeda dengan Query, Mutation berurusan dengan perubahan state sistem. Kompleksitasnya tidak terletak pada pengiriman request PATCH /users/:id, melainkan pada konsekuensi pasca-sukses: data mana yang tidak lagi bisa dipercaya? Satu mutasi bisa membatalkan keabsahan cache untuk detail pengguna, daftar pengguna, anggota tim, log audit, hingga izin akses. Pola umum saat ini — memanggil setUser(updatedUser) diikuti refetchUsers(), invalidateQueries(["users"]) — tersebar di seluruh komponen. Logika dampak mutasi menjadi lokal di UI, padahal dampaknya global di graf data. Luciano menawarkan model semantik di mana Mutation mendeklarasikan relasi invalidasinya sendiri: updateUser.mutate({ invalidates: [users.detail(id), users.list(), teamMembers.byUser(id)] }). Tanggung jawab invalidasi pindah dari lapisan UI ke lapisan data.
Stream menempati posisi ketiga yang sering disalahartikan sebagai continuous query. WebSocket, Server-Sent Events, streaming token AI, dan kolaborasi real-time bukanlah sekadar query yang diulang-ulang. Stream adalah sumber data yang berumur panjang dengan karakteristik backpressure, reconnection, dan ordering yang khas. Menggabungkannya ke dalam pipeline Query-Mutation hanya akan memperumit penanganan error, retry, dan manajemen koneksi. Luciano menekankan bahwa Stream memerlukan abstraksi sendiri yang mengakui sifat temporal dan kontinu datanya.
Pendekatan Reactive Graph yang dia usung menempatkan Query sebagai node yang berlangganan sumber data, Mutation sebagai pengubah graf yang memicu invalidasi terstruktur, dan Stream sebagai aliran event yang menyuntikkan update ke node-node relevan. Lapisan render menjadi pasif: hanya berlangganan snapshot node dan merender ulang saat snapshot berubah. Pemisahan tanggung jawab ini mengurangi cognitive load pengembang — komponen tidak perlu tahu kapan harus refetch atau invalidate, cukup tahu data apa yang ingin ditampilkan.
Bagi industri teknologi Indonesia yang sedang mengadopsi React, Vue, Svelte, maupun framework generasi baru seperti Solid dan Qwik, pemahaman ini sangat relevan. Banyak tim lokal masih terjebak pada pola props drilling atau state management global yang terlalu longgar, mengakibatkan bug race condition dan data stale yang sulit direproduksi. Adopsi library seperti TanStack Query (React Query) atau SWR sudah menjadi langkah maju, namun tanpa pemahaman semantik Query vs Mutation vs Stream, tim sering menyalahgunakan fitur invalidation atau justru menonaktifkannya demi kecepatan pengembangan.
Startup fintech dan e-commerce di Jakarta, Bandung, dan Surabaya yang mengelola ribuan transaksi real-time per menit akan mendapat manfaat langsung dari arsitektur ini. Pemisahan Mutation yang deklaratif memungkinkan sistem pembayaran, notifikasi, dan laporan keuangan tetap konsisten tanpa koordinasi manual antar tim. Sementara platform kolaborasi atau live streaming lokal yang mengandalkan WebSocket bisa memanfaatkan abstraksi Stream yang proper untuk menangani reconnection dan backpressure tanpa memblokir thread utama.
Luciano mengakui bahwa transisi ke model ini butuh investasi awal yang lebih besar — mendefinisikan identitas resource, relasi invalidasi, dan skema stream. Namun ia berargumen bahwa biaya pemeliharaan jangka panjang akan jauh lebih rendah. "Komponen bukan pemilik graf data. Komponen hanya tahu apa yang ingin ditampilkan," tulisnya. Filosofi ini selaras dengan tren arsitektur server-driven UI dan local-first software yang mulai naik daun di komunitas pengembang global.
Ke depannya, alat-alat pengembangan (developer tools) diharapkan bisa memvisualisasikan graf reaktivitas ini: menampilkan node Query mana yang stale, Mutation mana yang baru dieksekusi, dan Stream mana yang aktif. Debugging akan bergeser dari "mengapa state ini tidak update?" ke "node mana di graf yang tidak terinvalidasi dengan benar?". Bagi pengembang Indonesia yang ingin membangun aplikasi skala enterprise, memahami perbedaan fundamental tiga jenis async work ini bukan lagi opsional — itu prasyarat arsitektur yang sehat.