Pemisahan komponen yang rumit dan masalah kepemilikan negara
Setelah membagi suatu negara menjadi beberapa kebenaran lokal, rangkaian tersebut menjadi peristiwa yang bersifat probabilistik
Gejala bug online ini sangat mirip dengan “sesekali”, tetapi tidak acak.
Pada halaman yang sama, status bisnis akan ada dalam bentuk berbeda di komponen berbeda: parameter URL, status komponen induk, status lokal komponen anak, cache yang dikembalikan oleh permintaan, dan bahkan nilai turunan yang dihitung oleh pemilih tertentu. Semakin halus komponen-komponennya dipecah, semakin banyak “kebenaran parsial” yang terjadi. Selama “siapa yang bisa menulis, siapa yang tahu, dan siapa yang bertanggung jawab atas pengaturan waktu” tidak disatukan menjadi satu aturan terlebih dahulu, akar penyebab status kesalahan online akan berubah dari “sepotong kode tertentu ditulis salah” menjadi “beberapa bagian kode ditulis dengan benar, tetapi urutan penulisannya tidak stabil.”
Hal tersulit dalam masalah seperti ini adalah pemecahan masalah, bukan perbaikan. Karena tampaknya setiap komponen sangat masuk akal: mereka mempertahankan sebagian kecil statusnya, melakukan caching, dan memuat. Namun jika digabungkan, sistem tidak memiliki pemilik status unik, dan performa akhirnya adalah: cukup segarkan, ganti tab, dan coba lagi. Jika Anda ingin menggunakan log untuk menghubungkan tautan, Anda akan menemukan bahwa bidang yang sama berasal dari alat peraga, cache lokal, dan paket permintaan pengembalian. Siapa yang meliput siapa sepenuhnya bergantung pada ritme rendering dan penundaan permintaan.
Penilaian artikel ini sederhana:
Jika pemisahan komponen tidak terlebih dahulu menyatu pada “siapa yang menulis keadaan, siapa yang mengetahui detailnya, dan siapa yang bertanggung jawab atas waktunya”, keadaan yang sama akan terpotong menjadi beberapa kebenaran parsial, dan urutan pembaruan akan menjadi peristiwa probabilistik. Pada akhirnya, manfaat penggunaan kembali akan digantikan oleh status kesalahan yang sesekali terjadi, dan akan timbul biaya rendering berulang serta pemecahan masalah.
Di bawah ini saya akan menggunakan pemecahan masalah status kesalahan online yang sangat umum untuk menjelaskan cara menyatukannya langkah demi langkah.
Adegan: Status kesalahan “sesekali”.
Halaman tersebut adalah daftar + bilah filter atas.
- Ada pertanyaan:
?tab=all&sort=latest&city=shdi URL - Bilah filter atas dibagi menjadi beberapa komponen kecil: Tab, Sortir, Kota drop-down
- Komponen daftar membuat cache dari “hasil permintaan terakhir” untuk menghindari kedipan saat mengganti filter.
Umpan balik pengguna adalah: Saat berpindah Tab dan Sortir dengan cepat, terkadang daftar akan menampilkan “filter item dari Sortir baru”, tetapi data daftar masih “hasil Sortir lama”. Mengklik Sortir yang sama lagi berfungsi dengan baik.
Pada pandangan pertama, sepertinya antarmukanya tidak konsisten, tetapi penangkapan paket menunjukkan bahwa antarmuka tidak menimbulkan masalah, dan gema sort di badan yang dikembalikan juga benar. Dengan kata lain, servernya benar, dan yang salah adalah “status yang ditampilkan” di front end.
Kesalahan penilaian pertama: mengira itu adalah kondisi balapan permintaan
Intuisi akan membuat Anda curiga: Permintaan A lambat, permintaan B cepat, B kembali terlebih dahulu dan memberikan hasil yang benar, lalu A kembali dan menimpa hasil lama.
Kondisi balapan seperti ini memang umum terjadi, jadi pertama-tama kita tambahkan requestId dan membuang paket pengembalian: hanya permintaan terakhir yang dikirim yang diterima.
Setelah online, masalahnya sedikit mereda, tapi tidak hilang. Jelaskan bahwa “cakupan paket balik” bukanlah satu-satunya saluran.
Nilai dari langkah ini adalah: pertama-tama memotong sebagian dari ruang masalah yang tampaknya besar. Sekarang dapat dipastikan bahwa setidaknya beberapa kondisi yang salah tidak disebabkan oleh tatanan jaringan.
Kesalahan penilaian kedua: Saya pikir itu adalah kesalahan dalam logika cache.
Lalu mari kita lihat cache komponen daftar.
Strategi cachingnya adalah:
- Lulus
filtersdari alat peraga - Komponen daftar secara internal menggunakan
useRefuntuk menyimpanlastGoodData - Memicu permintaan jika
filtersberubah - Terus tampilkan
lastGoodDataselama permintaan, lalu ganti saat data baru kembali
Tidak ada yang salah dengan logika “mengurangi kedipan” ini, tetapi logika ini mengubur premis: filters harus menjadi sumber kebenaran yang stabil dan tunggal. Kalau tidak, mudah untuk muncul: filters telah berubah, tetapi daftarnya masih menggunakan lastGoodData yang lama, dan di permukaan akan dianggap hanya menutup-nutupi saat memuat.
Saya pikir itu karena referensi objek filters tidak stabil, menyebabkan waktu pemicu efek menjadi bingung. Diubah menjadi kunci serialisasi eksplisit: filtersKey = tab + sort + city.
Masih belum ada obatnya.
Akar permasalahan sebenarnya: kepemilikan negara terkoyak
Setelah akhirnya mengetik semua log, masalahnya menjadi jelas:
- Komponen Tab hanya peduli pada
tab, ia akan: - Saat diklik,
setLocalTab(nextTab)akan langsung disorot - Kemudian
onChange(nextTab)memberitahukan komponen induk - Buka
setFilters({ ... })setelah menerima komponen induk - Sortir komponen juga memiliki pola yang sama
- Untuk mendukung “refresh resumable”, komponen induk akan:
- Pertama ekstrak filter awal dari penguraian URL
- Lalu tuliskan ke negara bagian
- Komponen daftar juga menerima:
- Alat peraga
filtersdari komponen induk - dan satu
getCachedResult(filtersKey)dari modul cache
Dengan kata lain, suatu negara memiliki setidaknya tiga sumber:
- Keadaan subkomponen lokal: digunakan untuk interaksi umpan balik langsung
- Status komponen induk: sebagai filter tingkat halaman
- Modul cache: digunakan sebagai backend tampilan data
Tidak ada kontrak “perintah tulis” yang ketat di antara mereka.
Tautan tempat terjadinya masalah biasanya sebagai berikut:
- Poin pengguna Sortir
- Komponen Sortir segera memperbarui status lokalnya, dan UI menampilkan “Urutan Baru dipilih”
filterskomponen induk belum sempat diupdate (atau sudah diupdate namun tidak akan diteruskan hingga frame berikutnya)- Komponen daftar akan menghitung ulang
filtersKeysaat ini - Tapi itu tidak termasuk filter baru dari komponen induk
- Sebaliknya, jalur turunan bercampur dengan nilai lokal Sortir (seperti melalui konteks atau pemilih)
filtersKeyberubah, jadi daftarnya masuk ke modul cache dan mengambil hasil lama yang “tampak cocok”- Ketika permintaan muncul kembali, karena kebijakan pembuangan requestId, selama ini bukan yang terakhir kali, permintaan tersebut akan dibuang
- UI akhir memiliki kombinasi yang aneh: bilah filter adalah nilai baru, dan data daftar berasal dari cache lama
Ini adalah “beberapa bagian kode ditulis dengan benar, tetapi urutannya tidak stabil.”
Pemisahan komponen memotong hak penulisan status menjadi beberapa bagian: komponen anak menulis satu salinan terlebih dahulu untuk interaksi umpan balik instan, komponen induk menulis salinan lain untuk diputar, dan cache menulis salinan lain demi pengalaman. Tidak ada yang salah dengan apa pun, namun sistem ini tidak memiliki kepemilikan negara yang bersatu.
Cara berhenti bicara: Putuskan kepemilikannya terlebih dahulu, lalu bicarakan tentang penggunaan kembali
Solusi terhadap masalah seperti ini adalah dengan menuliskan hak tertulis negara, aturan derivasi, dan strategi menutup-nutupi ke dalam kontrak yang dapat dilaksanakan.
Saya akhirnya menetapkan tiga aturan.
Aturan 1: Filter halaman hanya memiliki satu sumber yang dapat ditulis
Komponen turunan tidak lagi mempertahankan status filter lokalnya sendiri.
Umpan balik interaktif langsung disediakan oleh status komponen induk, dan komponen anak hanya bertanggung jawab untuk mengirimkan peristiwa dan bukan menyimpan nilai. Yaitu:
- Subperakitan:
onSelect(next) - Komponen induk:
setFilters(reduce(prev, action)) - Tampilan subkomponen:
value={filters.sort}hanya-baca
Kerugian dari hal ini adalah: subkomponen akan menjadi “bodoh” dan lebih banyak alat peraga yang perlu diteruskan ketika digunakan kembali. Namun yang dipertukarkannya adalah jalur penulisan tertentu.
Aturan 2: Nilai turunan harus secara eksplisit menunjukkan sumbernya
Semua kunci yang digunakan untuk permintaan dan cache hanya diperbolehkan dibuat dari filters.
Dilarang membuat kumpulan kunci lain langsung dari konteks, pemilih, atau URL.
Ini mungkin tampak seperti sebuah mistik, tetapi hal ini untuk menghindari “bidang dengan nama yang sama berasal dari sumber yang berbeda”. Setelah sort diizinkan berasal dari negara bagian lokal dan negara bagian induk, Anda akan menemukan “satu kumpulan UI dan kumpulan data lainnya” saat ini.
Aturan 3: Cache hanya menampilkan detail dan tidak berpartisipasi dalam penilaian status.
Modul cache hanya menyediakan satu kemampuan: getLastGoodData(filtersKey).
Ia tidak dapat menentukan filterKey saat ini, apalagi menggunakan data kunci lama sebagai “hasil saat ini”.
Langkah-langkah spesifiknya adalah:
- Status permintaan daftar jelas:
currentFiltersKeyditeruskan dari komponen induk - Diizinkan saat menunjukkan:
data = loading ? cache[currentFiltersKey] ?? null : result- tapi caching tidak pernah mempengaruhi filter kembali
Ini menurunkan versi cache dari “berpartisipasi dalam status sistem” menjadi “murni menampilkan keuntungan”. Ini akan mengorbankan sedikit pengalaman, misalnya beberapa sakelar akan kosong untuk sementara waktu, tetapi akan mengembalikan kepastian.
Contoh tandingan: “Promosikan semua negara bagian ke komponen induk” juga akan gagal
Setelah mendengarkan ini, beberapa orang akan berkata: Angkat saja semua negara bagian ke tingkat teratas.
Versi yang saya lihat gagal adalah: lapisan atas memang menjadi satu-satunya sumber kebenaran, tetapi juga memuat:
- Sinkronisasi URL
- Kegigihan lokal
- Minta pembatasan
- tembolok terkena
- Status interaktif UI (arahkan kursor, fokus, panel terbuka)
Akibatnya, peredam tingkat atas menjadi inti bisnis, dan setiap interaksi kecil harus melalui banyak logika, dan biaya modifikasi meroket. Pada akhirnya, semua orang mulai mengabaikannya dan diam-diam menambahkan kembali negara bagian lokal ke dalam subkomponen, dan sistem kembali ke “berbagai kebenaran lokal”.
Jadi kuncinya adalah “menjelaskan negara bagian mana yang memerlukan kepemilikan tunggal”.
Saya biasanya menilainya dalam satu kalimat: Selama itu memengaruhi permintaan, kunci cache, atau konsistensi lintas komponen, itu harus dimiliki secara unik. Transien UI murni dapat dilokalisasi.
Batasan yang berlaku: Tidak semua pemisahan komponen akan menyebabkan kesalahan
Kritik ini bukan tentang pemisahan komponen itu sendiri.
Pemisahan awalnya dimaksudkan untuk mengendalikan kompleksitas, tetapi memiliki dampak implisit: “batas penulisan negara” harus dirancang tambahan.
Jika laman memenuhi salah satu kondisi berikut, jebakan ini akan muncul dengan mudah:
- Memiliki URL/pemulihan persisten
- Ada permintaan atau pembatalan secara bersamaan
- Ada tampilan cache
- Memiliki filter yang dibagikan ke seluruh komponen
Di sisi lain, jika halamannya sangat sederhana, negara tidak mempengaruhi permintaan, dan tidak ada caching dan pemulihan, negara lokal tidak akan menjadi bencana.
Ringkasan
Memecah komponen menjadi bagian-bagian kecil tidak secara otomatis memberikan manfaat penggunaan kembali; hal ini pertama-tama akan menciptakan masalah kepemilikan negara.
Jika Anda tidak menjawab terlebih dahulu “Siapa yang bisa menulis, siapa yang mengetahui detailnya, dan siapa yang bertanggung jawab atas pengaturan waktu”, sistem akan menjawab dengan sendirinya: siapa pun yang merender terlebih dahulu akan mengambil keputusan akhir, dan siapa pun yang kembali terlambat akan menanggungnya.
Ketika status kesalahan “sesekali” terjadi di telepon, Anda akan menemukan bahwa yang benar-benar mahal adalah memulihkan status dari beberapa kebenaran parsial ke dalam tautan tulis tertentu. \
What to read next
Want more posts about Uncategorized?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home