Seri Konkurensi Swift 08|Organisasi kode asinkron dalam proyek nyata
Yang benar-benar sulit adalah apakah seluruh tautan asinkron dapat tetap jelas untuk waktu yang lama.
Ketika hanya ada satu atau dua permintaan asinkron dalam proyek, banyak kode yang tidak terlihat terlalu buruk. DAS yang sebenarnya biasanya terjadi ketika situasi berikut terjadi secara bersamaan:
- Halaman yang sama memiliki pemuatan pertama, penyegaran pull-down, percobaan ulang, dan peralihan filter
- Cache lokal dan permintaan jarak jauh perlu dilibatkan secara bersamaan
- Saat meninggalkan halaman, batalkan beberapa tugas dan simpan yang lain
- Beberapa modul berbagi sumber daya tertentu secara bersamaan
Saat ini, Anda akan menemukan bahwa kesulitan terbesar dari kode asinkron adalah:
Bagaimana mengatur seluruh link asynchronous agar tidak semakin tersebar dan sulit diubah seperti yang tertulis.
Dalam artikel ini, saya tidak ingin berbicara tentang satu API pun, tetapi saya ingin berbicara tentang prinsip-prinsip organisasi yang lebih saya hargai dalam proyek nyata.
1. Yang saya bagikan pertama adalah tanggung jawab.
Ketika kode asynchronous kacau, reaksi pertama sering kali adalah “membongkar fungsi”. Memisahkan fungsi tentu berguna, tetapi jika tanggung jawab sudah tercampur, pemisahannya biasanya hanya berarti membagi kekacauan menjadi beberapa file kecil.
Saya lebih mementingkan pemisahan tanggung jawab terlebih dahulu. Biasanya dibagi menjadi setidaknya tiga lapisan:
1. Lapisan halaman
Lapisan halaman bertanggung jawab untuk:
- Memicu niat pengguna
- Menampilkan status halaman
- Menanggapi perubahan interaktif
Ia mengetahui “apa yang harus dimuat sekarang”, tetapi tidak bertanggung jawab atas “bagaimana mengatur seluruh proses asinkron”.
2. Lapisan status / ViewModel
Lapisan negara bertanggung jawab untuk:
- Terjemahkan maksud pengguna ke dalam tugas
- Putuskan apakah tugas harus diparalelkan, diganti atau dibatalkan
- Kelola semantik halaman seperti memuat, memuat, gagal, dll.
- Tentukan hasil mana yang masih memenuhi syarat untuk menulis kembali halaman tersebut
Ini adalah titik akhir sebenarnya dari proses asinkron.
3. Lapisan layanan
Lapisan layanan bertanggung jawab untuk:
- Sesuaikan antarmuka
- membaca cache
- Gabungkan beberapa sumber data
- Menyediakan kemampuan domain
Seharusnya tidak mengetahui tampilan halamannya, juga tidak boleh menyelinap ke dalam semantik status UI.
Banyak kode asinkron yang kacau karena setelah ketiga lapisan ini digabungkan, perubahan apa pun dalam persyaratan akan memengaruhi UI, proses, status, dan sumber data pada saat yang bersamaan.
2. Prinsip paling penting dari lapisan halaman: mengetahui lebih sedikit tentang detail asinkron
Saya tidak suka halaman tersebut melakukan terlalu banyak langkah asinkron sendirian. Karena begitu halaman tersebut mengetahui terlalu banyak, halaman tersebut akan mulai menangani hal-hal berikut:
- Minta kontrol urutan
- Kesalahan
- Saring hasil
- Kebijakan pembatalan
- memuat semantik subdivisi
Saat mengubah persyaratan seperti ini, UI dan proses sering kali terpengaruh secara bersamaan.
Jadi saya lebih suka halaman tersebut hanya mengungkapkan hal-hal berikut:
- “Saya perlu menyegarkan diri sekarang”
- “Pengguna mengklik untuk mencoba lagi”
- “Kondisi filter berubah”
Adapun apa yang melatarbelakanginya:
- Baca cache terlebih dahulu atau buka antarmuka terlebih dahulu?
- Apakah Anda ingin menghentikan tugas lama?
- Apakah hasilnya telah kedaluwarsa
- Haruskah pemuatan dan penyegaran pertama berbagi tautan yang sama?
Masukkan sebanyak mungkin ke dalam penutupan lapisan status.
3. Status halaman harus eksplisit, jangan bergantung pada sekumpulan potongan-potongan yang tersebar untuk mengeja semantik.
Banyak halaman asinkron akan terlihat seperti ini pada tahap selanjutnya:
isLoadingisRefreshinghasErrorshowRetryisEmptyitems
Nilai-nilai ini masuk akal jika dilihat secara individual, namun rentan terhadap kontradiksi jika digabungkan:
- Memuat dengan kesalahan lama
- Keduanya menampilkan status kosong dan mempertahankan daftar lama
- Menyegarkan, tetapi logo pemuatan pertama masih ada
Jadi saya lebih menghargai “status semantik halaman” daripada “banyak status kecil yang dapat digabungkan secara bebas”.
Karena yang benar-benar penting tentang halaman asinkron adalah apakah halaman tersebut dapat mengetahui dengan jelas di tahap mana halaman tersebut berada.
4. Batasan tugas harus jelas, kalau tidak semuanya hanya akan “dijalankan dulu”
Stabil atau tidaknya struktur asinkron bergantung pada apakah struktur tersebut dapat menjawab pertanyaan berikut:
- Siapa pemilik misi ini? -Apakah ini berlanjut ketika halaman tersisa?
- Ketika tugas baru datang, apakah tugas lama akan langsung menjadi tidak valid?
- Apakah ini tugas yang berdiri sendiri atau merupakan bagian dari proses yang lebih panjang?
Jika pertanyaan tersebut tidak dapat dijawab dengan jelas maka kode berikut pasti akan masuk ke dalam state:
- Di mana-mana sepertinya sudah cukup jelas
- Tapi tidak ada yang bisa menceritakan kembali secara lengkap tentang cara kerja tautan ini.
Jika sepotong kode asinkron sulit diulang dalam bahasa alami, biasanya akan sulit untuk mempertahankannya secara stabil nantinya.
5. Saya akan mencoba sebaik mungkin untuk memasukkan “validitas hasil” ke dalam proses
Banyak halaman yang berantakan. Di permukaan, sepertinya hasilnya gagal, namun sebenarnya lebih mendekati:
- Hasil lama berhasil dikembalikan
- Namun tidak lagi sesuai dengan konteks halaman saat ini
Jenis masalah ini sangat mungkin terjadi ketika:
- Cari
- Sakelar penyaring
- Paginasi
- Akses halaman keluar dengan cepat
Jika keefektifan hasil tidak dirancang dalam desain, cepat atau lambat halaman tersebut akan mengembangkan fenomena aneh berikut:
- Pengembalian konten
- pemuatan berakhir tanpa alasan
- Kesalahan meminta menimpa status sukses saat ini
Jadi saya peduli tentang:
- Siapa yang akan menilai apakah hasilnya sudah habis?
- Apakah setiap titik panggilan harus dinilai sendiri
- Masih menutup antarmuka secara seragam pada lapisan status
Preferensi saya sangat jelas: **Usahakan untuk konsisten dalam menutup, dan jangan biarkan masing-masing cabang tampilan menilai sendiri “apakah hasil kali ini masih diperhitungkan”. **
6. Jangan menyelinapkan semantik halaman ke dalam lapisan layanan
Banyak kode yang kacau. Di permukaan, tampaknya lapisan layanan tidak akan membuat permintaan. Faktanya, ini lebih dekat ke lapisan layanan dan perlahan mulai memasukkan konsep halaman.
Misalnya penamaan atau logika seperti ini mulai muncul di lapisan layanan:
- “Permintaan khusus untuk pemuatan beranda pertama”
- “Halaman detail kosong dan penuh logika”
- “Copywriting yang salah untuk halaman ini”
Setelah tercampur, struktur berikutnya akan semakin sulit untuk digunakan kembali. Karena lapisan layanan mulai mengetahui seperti apa halaman tersebut, dan lapisan halaman mulai mengetahui detail implementasi apa yang dimiliki lapisan layanan, batasannya dengan cepat menjadi kabur.
Lapisan layanan lebih cocok untuk difokuskan pada:
-Data apa yang kamu dapatkan?
- Cara menggabungkan sumber data
- Apa strategi cachingnya?
Daripada “bagaimana seharusnya perilaku halaman ini?”
7. Saya peduli dengan satu prinsip: proses asinkron harus diucapkan dengan jelas
Ini adalah kriteria yang umum digunakan ketika saya melakukan tinjauan kode sendiri.
Jika Anda mengambil sepotong kode asinkron, sudah sulit untuk mengulanginya dalam bahasa alami:
- Apa pintu masuknya?
- Apa proses utamanya?
- Tugas mana yang akan dibatalkan?
- Hasil mana yang akan dibuang
- Negara bagian mana yang diubah oleh lapisan mana?
Meskipun kode ini dapat dijalankan saat ini, kemungkinan besar akan semakin sulit untuk dikembangkan di masa mendatang.
Ketakutan sebenarnya terhadap kode asinkron adalah ketidakjelasannya. Jika Anda tidak dapat membedakannya dengan jelas, setiap iterasi berikutnya hanyalah masalah keberuntungan.
8. Ide organisasi yang mendekati implementasi
Jika saya ingin merangkumnya dalam kalimat yang lebih praktis, saya akan menyusunnya seperti ini:
- Lapisan halaman: mengungkapkan maksud
- Lapisan status: tugas penutup dan semantik status
- Lapisan layanan: menyediakan kemampuan
- Lapisan sumber daya bersama: Gunakan Aktor atau cara isolasi lainnya untuk mengelola status bersama bila diperlukan
Kemudian perjelas hubungan ini di lapisan status:
- Tugas mana yang saling eksklusif
- Tugas mana yang paralel
- Hasil mana yang bisa dibuang
- Negara bagian mana yang harus diupdate oleh aktor utama
Situasi yang umum adalah bahwa ini “tampak seperti lapisan tambahan”, tetapi dalam proyek yang benar-benar kompleks, lapisan ini untuk mencegah logika asinkron menyebar langsung ke setiap peristiwa halaman.
9. Kesimpulan: Inti dari organisasi asinkron dalam proyek nyata adalah batasannya
Hal terpenting dalam proyek nyata bukanlah apakah proyek itu akan menjadi Task, async let, atau Actor.
Yang benar-benar menentukan apakah kode tersebut dapat berkembang dalam jangka panjang adalah apakah batasan-batasan ini jelas:
- Batas antara lapisan halaman dan lapisan proses
- Batas antara lapisan negara dan lapisan layanan
- Batas antara keadaan bersama dan keadaan normal
- Batas antara hasil valid saat ini dan hasil kedaluwarsa
Jadi jika saya harus merangkum artikel ini dalam satu kalimat, saya akan berkata:
Kunci organisasi kode asinkron dalam proyek nyata bukanlah “cara menulis API asinkron”, tetapi “apakah empat batasan tugas, status, hasil, dan tanggung jawab digambarkan dengan jelas.”
Hanya ketika batasan ini jelas, kode asinkron dapat benar-benar berubah dari “dapat berjalan” menjadi “dapat dipertahankan untuk waktu yang lama”.
What to read next
Want more posts about Swift Concurrency?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #Architecture?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant 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