Panduan arsitektur aplikasi

Panduan ini mencakup praktik terbaik dan arsitektur yang direkomendasikan untuk mem-build aplikasi yang tangguh dan berkualitas tinggi.

Pengalaman pengguna aplikasi seluler

Aplikasi Android standar memuat beberapa komponen aplikasi, termasuk aktivitas, fragmen, layanan, penyedia konten, dan penerima siaran. Anda mendeklarasikan sebagian besar komponen aplikasi ini di manifes aplikasi. Android OS kemudian menggunakan file ini untuk menentukan cara mengintegrasikan aplikasi Anda ke dalam seluruh pengalaman pengguna di perangkat. Mengingat bahwa aplikasi Android standar mungkin berisi beberapa komponen dan bahwa pengguna sering berinteraksi dengan beberapa aplikasi dalam periode waktu yang singkat, aplikasi perlu beradaptasi dengan berbagai jenis alur kerja dan tugas yang dikelola pengguna.

Ingatlah bahwa ada keterbatasan resource pada perangkat seluler, jadi kapan saja, sistem operasi mungkin perlu menghentikan beberapa aplikasi agar aplikasi lain dapat berjalan.

Mengingat kondisi lingkungan ini, kemungkinan aplikasi Anda dapat diluncurkan secara individual dan tidak berurutan, dan sistem operasi atau pengguna dapat merusak proses ini kapan saja. Karena peristiwa ini tidak berada di bawah kendali Anda, sebaiknya Anda tidak menyimpan atau mempertahankan data atau status aplikasi apa pun di komponen aplikasi Anda, dan komponen aplikasi tidak boleh saling bergantung.

Prinsip arsitektur umum

Jika Anda tidak disarankan menggunakan komponen aplikasi untuk menyimpan data dan status aplikasi, bagaimana caranya Anda mendesain aplikasi?

Seiring bertambahnya ukuran aplikasi Android, penting untuk menentukan arsitektur yang memungkinkan aplikasi melakukan penskalaan, meningkatkan keandalan aplikasi, dan membuat aplikasi lebih mudah diuji.

Arsitektur aplikasi menentukan batas antara bagian aplikasi dan tanggung jawab yang harus dimiliki setiap bagian. Untuk memenuhi kebutuhan yang disebutkan di atas, Anda harus mendesain arsitektur aplikasi untuk mengikuti beberapa prinsip khusus.

Pemisahan fokus

Prinsip paling penting yang perlu diikuti adalah pemisahan fokus. Merupakan kesalahan umum untuk menulis semua kode Anda dalam sebuah Activity atau Fragment. Class berbasis UI ini hanya boleh memuat logika yang menangani UI dan interaksi sistem operasi. Dengan menjaga class tersebut tetap seramping mungkin, Anda dapat menghindari banyak masalah yang terkait dengan lifecycle komponen, dan meningkatkan kemampuan pengujian class ini.

Perlu diingat bahwa Anda bukanlah pemilik implementasi Activity dan Fragment; sebaliknya, keduanya hanyalah class perekat yang merepresentasikan kontrak antara Android OS dan aplikasi Anda. OS dapat mengakhiri class tersebut kapan saja berdasarkan interaksi pengguna atau karena kondisi sistem seperti memori yang rendah. Untuk memberikan pengalaman pengguna yang memuaskan dan pengalaman pemeliharaan aplikasi yang lebih mudah dikelola, sebaiknya minimalkan dependensi Anda terhadap kelas-kelas tersebut.

Menjalankan UI dari model data

Prinsip penting lainnya adalah sebaiknya Anda menjalankan UI dari model data, terutama model persisten. Model data mewakili data aplikasi. Model tidak bergantung pada elemen UI dan komponen lainnya dalam aplikasi Anda. Artinya, modul tersebut tidak terkait dengan UI dan siklus proses komponen aplikasi, tetapi akan tetap dihancurkan saat OS memutuskan untuk menghapus proses aplikasi dari memori.

Model persisten ideal karena alasan berikut:

  • Pengguna Anda tidak kehilangan data jika OS Android memusnahkan aplikasi untuk mengosongkan resource.

  • Aplikasi Anda terus berfungsi saat sambungan jaringan tidak stabil atau tidak tersedia.

Jika Anda mendasarkan arsitektur aplikasi pada class model data, aplikasi Anda akan lebih mudah diuji dan tangguh.

Bagian ini menunjukkan cara menyusun aplikasi berdasarkan praktik terbaik yang direkomendasikan.

Dengan mempertimbangkan prinsip arsitektur umum yang disebutkan di bagian sebelumnya, setiap aplikasi harus memiliki setidaknya dua lapisan:

  • Lapisan UI yang menampilkan data aplikasi di layar.
  • Lapisan data yang berisi logika bisnis aplikasi Anda dan mengekspos data aplikasi.

Anda dapat menambahkan lapisan tambahan yang disebut lapisan domain untuk menyederhanakan dan menggunakan kembali interaksi antara lapisan UI dan data.

Dalam arsitektur aplikasi standar, lapisan UI mendapatkan data aplikasi
    dari lapisan data atau dari lapisan domain opsional, yang berada di antara
    lapisan UI dan lapisan data.
Gambar 1. Diagram arsitektur aplikasi standar.

Lapisan UI

Peran lapisan UI (atau lapisan presentasi) adalah menampilkan data aplikasi di layar. Setiap kali data berubah, baik karena interaksi pengguna (seperti menekan tombol) atau input eksternal (seperti respons jaringan), UI harus diperbarui untuk mencerminkan perubahan tersebut.

Lapisan UI terdiri dari dua hal:

  • Elemen UI yang merender data di layar. Anda membuat elemen ini menggunakan fungsi View atau Jetpack Compose.
  • Pemegang status (seperti class ViewModel ) yang menyimpan data, mengeksposnya ke UI, dan menangani logika.
Dalam arsitektur standar, elemen UI lapisan UI bergantung pada pemegang
    status, yang kemudian bergantung pada class dari lapisan data atau
    lapisan domain opsional.
Gambar 2. Peran lapisan UI dalam arsitektur aplikasi.

Untuk mempelajari lapisan ini lebih lanjut, lihat halaman lapisan UI.

Lapisan data

Lapisan data aplikasi berisi logika bisnis. Logika bisnis adalah yang memberikan nilai bagi aplikasi Anda— aturan ini terdiri dari aturan yang menentukan cara aplikasi Anda membuat, menyimpan, dan mengubah data.

Lapisan data terdiri dari repositori yang masing-masing dapat berisi nol hingga banyak sumber data. Anda harus membuat class repositori untuk setiap jenis data yang ditangani di aplikasi Anda. Misalnya, Anda mungkin membuat class MoviesRepository untuk data yang berhubungan dengan film, atau class PaymentsRepository untuk data yang terkait dengan pembayaran.

Dalam arsitektur standar, repositori lapisan data menyediakan data
    ke seluruh aplikasi dan bergantung pada sumber data.
Gambar 3. Peran lapisan data dalam arsitektur aplikasi.

Class repositori bertanggung jawab atas tugas-tugas berikut:

  • Mengekspos data ke seluruh aplikasi.
  • Memusatkan perubahan pada data.
  • Menyelesaikan konflik antara beberapa sumber data.
  • Mengabstraksi sumber data dari bagian aplikasi lainnya.
  • Berisi logika bisnis.

Setiap class sumber data harus memiliki tanggung jawab untuk menangani hanya satu sumber data, yang dapat berupa file, sumber jaringan, atau database lokal. Class sumber data adalah jembatan antara aplikasi dan sistem untuk operasi data.

Untuk mempelajari lapisan ini lebih lanjut, lihat halaman lapisan data.

Lapisan domain

Lapisan domain adalah lapisan opsional yang berada di antara lapisan UI dan data.

Lapisan domain bertanggung jawab untuk mengenkapsulasi logika bisnis yang kompleks, atau logika bisnis sederhana yang digunakan kembali oleh beberapa ViewModels. Lapisan ini bersifat opsional karena tidak semua aplikasi memiliki persyaratan ini. Sebaiknya hanya gunakan jika diperlukan—misalnya, untuk menangani kompleksitas atau mendukung penggunaan kembali.

Jika disertakan, lapisan domain opsional memberikan dependensi ke
    lapisan UI dan bergantung pada lapisan data.
Gambar 4. Peran lapisan domain dalam arsitektur aplikasi.

Class di lapisan ini biasanya disebut kasus penggunaan atau pemicu interaksi. Setiap kasus penggunaan harus memiliki tanggung jawab atas fungsi tunggal. Misalnya, aplikasi Anda dapat memiliki class GetTimeZoneUseCase jika beberapa ViewModel bergantung pada zona waktu untuk menampilkan pesan yang tepat di layar.

Untuk mempelajari lapisan ini lebih lanjut, lihat halaman lapisan domain.

Mengelola dependensi antarkomponen

Class di aplikasi Anda bergantung pada class lain agar berfungsi dengan baik. Anda dapat menggunakan salah satu pola desain berikut untuk mengumpulkan dependensi class tertentu:

  • Injeksi dependensi (DI): Injeksi dependensi memungkinkan class untuk menentukan dependensi tanpa perlu menyusunnya. Saat waktu proses, kelas lain bertanggung jawab untuk menyediakan dependensi-dependensi ini.
  • Pencari lokasi: Pola pencari lokasi menyediakan registry tempat class dapat memperoleh dependensinya, bukan menyusunnya.

Kedua pola ini memungkinkan Anda menskala kode karena keduanya memberikan pola yang jelas untuk mengelola dependensi tanpa menduplikasi kode atau menambahkan kerumitan. Selain itu, keduanya memungkinkan Anda beralih dengan cepat antara implementasi pengujian dan produksi.

Kami merekomendasikan pola injeksi dependensi berikut dan penggunaan library Hilt pada aplikasi Android. Hilt menyusun objek dengan cara menelusuri hierarki dependensi, menyediakan jaminan waktu kompilasi pada dependensi, dan membuat container dependensi untuk class framework Android secara otomatis.

Praktik terbaik umum

Pemrograman adalah bidang kreatif, begitu juga pengembangan aplikasi Android. Ada banyak cara untuk menyelesaikan masalah; Anda dapat mengomunikasikan data antara beberapa aktivitas atau fragmen, mengambil data jarak jauh dan mempertahankannya secara lokal untuk mode offline, atau menangani sejumlah skenario umum lainnya yang ditemukan oleh aplikasi yang tidak umum.

Meskipun rekomendasi berikut tidak wajib diikuti, dalam sebagian besar kasus, mengikuti rekomendasi berikut akan membuat code base Anda lebih tangguh, dapat diuji, dan mudah dipelihara dalam jangka panjang:

Jangan simpan data di komponen aplikasi.

Hindari menetapkan titik entri aplikasi Anda—seperti aktivitas, layanan, dan penerima siaran—sebagai sumber data. Komponen ini seharusnya hanya berkoordinasi dengan komponen lain untuk mengambil subkumpulan data yang relevan dengan titik entri tersebut. Setiap komponen aplikasi memiliki masa aktif yang singkat, bergantung pada interaksi pengguna dengan perangkatnya dan respons keseluruhan kesehatan dari sistem saat ini.

Mengurangi dependensi di class Android.

Komponen aplikasi Anda harus menjadi satu-satunya class yang mengandalkan API SDK framework Android seperti Context, atau Toast. Mengabstraksi class lain di aplikasi Anda darinya membantu memudahkan pengujian dan mengurangi penggabungan dalam aplikasi Anda.

Buat batasan tanggung jawab yang jelas antara berbagai modul aplikasi Anda.

Misalnya, jangan menyebarkan kode yang memuat data dari jaringan di beberapa kelas atau paket pada basis kode Anda. Demikian pula, jangan menetapkan beberapa tanggung jawab yang tidak terkait—seperti data caching dan data binding—ke dalam class yang sama. Mengikuti arsitektur aplikasi yang direkomendasikan akan membantu Anda mengatasi ini.

Ekspos sesedikit mungkin dari setiap modul.

Misalnya, jangan tergoda untuk membuat pintasan yang mengekspos detail implementasi internal dari modul. Dalam jangka pendek, Anda mungkin menghemat banyak waktu, tetapi Anda mungkin akan menanggung utang teknis berkali-kali lipat seiring berkembangnya codebase Anda.

Fokuskan pada inti unik aplikasi Anda agar lebih menarik dibanding aplikasi lain.

Jangan memulai dari awal dengan menuliskan kode boilerplate yang sama berulang-ulang. Sebaliknya, fokuskan waktu dan energi Anda pada hal yang membuat aplikasi Anda unik, dan biarkan library Jetpack dan rekomendasi library lainnya menangani boilerplate yang berulang-ulang.

Pertimbangkan cara untuk menjadikan setiap bagian aplikasi mudah diuji secara terpisah.

Misalnya, memiliki API yang didefinisikan dengan baik untuk mengambil data dari jaringan akan mempermudah pengujian modul yang mempertahankan data tersebut di database lokal. Sebaliknya, jika Anda mencampur logika dari kedua modul ini di satu tempat, atau mendistribusikan kode jaringan Anda di seluruh code base, pengujian akan menjadi jauh lebih sulit— bahkan mustahil—untuk diuji secara lebih efektif.

Pertahankan sebanyak mungkin data yang relevan dan baru.

Dengan demikian, pengguna dapat menikmati fungsionalitas aplikasi Anda meski perangkat mereka berada dalam mode offline. Ingat, tidak semua pengguna Anda menyukai konektivitas berkecepatan tinggi, dan konstan—dan meskipun mereka menyukainya, mereka bisa mendapatkan penerimaan sinyal yang buruk di tempat yang ramai.

Contoh

Contoh Google berikut menunjukkan arsitektur aplikasi yang baik. Jelajahi untuk melihat panduan ini dalam praktik: