Terhubung dengan kami

Pemimpin Pikiran

Menerapkan Prinsip SOLID dalam Pengembangan Android

mm

Menulis perangkat lunak adalah sebuah tindakan penciptaan, dan pengembangan Android tidak terkecuali. Ini lebih dari sekadar membuat sesuatu berfungsi. Ini tentang merancang aplikasi yang dapat tumbuh, beradaptasi, dan tetap dapat dikelola dari waktu ke waktu.

Sebagai pengembang Android yang telah menghadapi banyak tantangan arsitektur, saya menemukan bahwa mematuhi prinsip SOLID dapat mengubah basis kode yang paling rumit sekalipun menjadi sistem yang bersih. Ini bukanlah prinsip abstrak, tetapi cara yang berorientasi pada hasil dan dapat direproduksi untuk menulis kode yang tangguh, dapat diskalakan, dan dapat dipelihara.

Artikel ini akan memberikan wawasan tentang bagaimana prinsip SOLID dapat diterapkan pada pengembangan Android melalui contoh dunia nyata, teknik praktis, dan pengalaman dari tim Meta WhatsApp.

Memahami Prinsip SOLID

Prinsip SOLID, yang diusulkan oleh Robert C. Martin, adalah lima prinsip desain untuk pemrograman berorientasi objek yang menjamin arsitektur perangkat lunak yang bersih dan efisien.

  • Prinsip Tanggung Jawab Tunggal (SRP): Suatu kelas seharusnya punya satu dan hanya satu alasan untuk berubah.
  • Prinsip Terbuka/Tertutup (OCP): Entitas perangkat lunak harus terbuka untuk perluasan tetapi tertutup untuk modifikasi.
  • Prinsip Substitusi Liskov (LSP): Subtipe harus dapat menggantikan tipe dasarnya.
  • Prinsip Pemisahan Antarmuka (ISP): Antarmuka harus spesifik klien dan tidak memaksa penerapan metode yang tidak digunakan.
  • Prinsip Pembalikan Ketergantungan (DIP): Modul tingkat tinggi seharusnya bergantung pada abstraksi, bukan pada modul tingkat rendah.

Dengan mengintegrasikan prinsip-prinsip ini ke dalam pengembangan Android, kita dapat membuat aplikasi yang lebih mudah ditingkatkan, diuji, dan dipelihara.

Prinsip Tanggung Jawab Tunggal (SRP): Menyederhanakan Tanggung Jawab

Prinsip Tanggung Jawab Tunggal merupakan dasar penulisan kode yang dapat dipelihara. Prinsip ini menyatakan bahwa setiap kelas harus memiliki satu masalah yang menjadi tanggung jawabnya. Pola anti-umum adalah menganggap Aktivitas atau Fragmen sebagai beberapa "kelas Tuhan" yang menangani tanggung jawab mulai dari rendering UI, kemudian pengambilan data, penanganan kesalahan, dsb. Pendekatan ini membuat pengujian dan pemeliharaan menjadi mimpi buruk.

Dengan SRP, pisahkan berbagai masalah ke dalam berbagai komponen: misalnya, dalam aplikasi berita, buat atau baca berita.


class NewsRepository {
    fun fetchNews(): List {
        // Handles data fetching logic
    }
}

class NewsViewModel(private val newsRepository: NewsRepository) {
    fun loadNews(): LiveData<List> {
        // Manages UI state and data flow
    }
}

class NewsActivity : AppCompatActivity() {
    // Handles only UI rendering
}

 

Setiap kelas hanya memiliki satu tanggung jawab; karenanya, mudah untuk diuji dan dimodifikasi tanpa menimbulkan efek samping.

Dalam pengembangan Android modern, SRP sebagian besar diimplementasikan bersama dengan arsitektur yang direkomendasikan menggunakan Jetpack. Misalnya, logika yang terkait dengan logika manipulasi data mungkin berada di dalam ViewModel, sementara Aktivitas atau Fragmen seharusnya hanya peduli dengan UI dan interaksi. Pengambilan data mungkin didelegasikan ke beberapa Repositori terpisah, baik dari basis data lokal seperti Room atau lapisan jaringan seperti Retrofit. Ini mengurangi risiko pembengkakan kelas UI, karena setiap komponen hanya mendapat satu tanggung jawab. Secara bersamaan, kode Anda akan jauh lebih mudah untuk diuji dan didukung.

Prinsip Terbuka/Tertutup (OCP): Mendesain untuk Ekstensi

Prinsip Terbuka/Tertutup menyatakan bahwa suatu kelas harus dibuka untuk perluasan, bukan untuk modifikasi. Prinsip ini lebih masuk akal untuk aplikasi Android karena aplikasi tersebut terus-menerus memperbarui dan menambahkan fitur baru.

Contoh terbaik tentang cara menggunakan prinsip OCP dalam aplikasi Android adalah antarmuka dan kelas abstrak. Misalnya:


interface PaymentMethod {
    fun processPayment(amount: Double)
}

class CreditCardPayment : PaymentMethod {
    override fun processPayment(amount: Double) {
        // Implementation for credit card payments
    }
}

class PayPalPayment : PaymentMethod {
    override fun processPayment(amount: Double) {
        // Implementation for PayPal payments
    }
}

 

Penambahan metode pembayaran baru tidak memerlukan perubahan pada kelas yang sudah ada; tetapi memerlukan pembuatan kelas baru. Di sinilah sistem menjadi fleksibel dan dapat ditingkatkan skalanya.

Dalam aplikasi yang dibuat untuk perangkat Android, Prinsip Terbuka/Tertutup cukup berguna dalam hal fitur pengalih dan konfigurasi yang diambil secara dinamis. Misalnya, jika aplikasi Anda memiliki antarmuka dasar AnalyticsTracker yang melaporkan peristiwa ke berbagai layanan analitik, Firebase dan Mixpanel, serta pelacak internal kustom, setiap layanan baru dapat ditambahkan sebagai kelas terpisah tanpa mengubah kode yang ada. Ini membuat modul analitik Anda terbuka untuk perluasan—Anda dapat menambahkan pelacak baru—tetapi tertutup untuk modifikasi: Anda tidak menulis ulang kelas yang ada setiap kali menambahkan layanan baru.

Prinsip Substitusi Liskov (LSP): Memastikan Pertukaran

Prinsip Substitusi Liskov menyatakan bahwa subkelas harus dapat menggantikan kelas dasarnya, dan perilaku aplikasi tidak boleh berubah. Di Android, prinsip ini merupakan dasar untuk merancang komponen yang dapat digunakan kembali dan diprediksi.

Misalnya, aplikasi menggambar:


abstract class Shape {
    abstract fun calculateArea(): Double
}

class Rectangle(private val width: Double, private val height: Double) : Shape() {
    override fun calculateArea() = width * height
}

class Circle(private val radius: Double) : Shape() {
    override fun calculateArea() = Math.PI * radius * radius
}

 

Kedua empat persegi panjang dan Lingkaran dapat digantikan dengan yang lain secara bergantian tanpa menyebabkan kegagalan sistem, artinya sistem tersebut fleksibel dan mengikuti LSP.

Pertimbangkan Android RecyclerView.Adapter subkelas. Setiap subkelas adaptor diperluas dari Tampilan Daur Ulang.Adapter dan mengesampingkan fungsi inti seperti diCreateViewHolder, diBindViewHolder, dan dapatkanJumlahItem. itu Tampilan Pendaur Ulang dapat menggunakan subkelas apa pun secara bergantian selama metode tersebut diimplementasikan dengan benar dan tidak merusak fungsionalitas aplikasi Anda. Di sini, LSP dipertahankan, dan RecyclerView Anda dapat fleksibel untuk mengganti subkelas adaptor apa pun sesuai keinginan.

Prinsip Pemisahan Antarmuka (ISP): Antarmuka yang Ramping dan Terfokus

Dalam aplikasi yang lebih besar, biasanya antarmuka didefinisikan dengan tanggung jawab yang terlalu besar, terutama di sekitar jaringan atau penyimpanan data. Sebaliknya, bagi antarmuka tersebut menjadi antarmuka yang lebih kecil dan lebih terarah. Misalnya, antarmuka ApiAuth yang bertanggung jawab atas titik akhir autentikasi pengguna harus berbeda dari antarmuka ApiPosts yang bertanggung jawab atas posting blog atau titik akhir umpan sosial. Pemisahan ini akan mencegah klien yang hanya memerlukan metode terkait posting dipaksa untuk bergantung pada dan mengimplementasikan panggilan autentikasi, sehingga kode Anda, serta cakupan pengujian, tetap ramping.

Prinsip Pemisahan Antarmuka berarti bahwa alih-alih memiliki antarmuka yang besar, beberapa antarmuka yang lebih kecil dan terfokus harus digunakan. Prinsip ini mencegah situasi di mana kelas mengimplementasikan metode yang tidak diperlukan.

Misalnya, daripada memiliki satu antarmuka besar yang mewakili tindakan pengguna, pertimbangkan kode kotlin:


interface Authentication {
    fun login()
    fun logout()
}

interface ProfileManagement {
    fun updateProfile()
    fun deleteAccount()
}

 

Kelas yang mengimplementasikan antarmuka ini dapat berfokus hanya pada fungsionalitas yang mereka perlukan, sehingga membersihkan kode dan membuatnya lebih mudah dipelihara.

Prinsip Pembalikan Ketergantungan (DIP): Mengabstraksi Ketergantungan

Prinsip Pembalikan Ketergantungan mendorong pemisahan dengan memastikan modul tingkat tinggi bergantung pada abstraksi, bukan implementasi konkret. Prinsip ini selaras sempurna dengan praktik pengembangan Android modern, terutama dengan kerangka kerja injeksi ketergantungan seperti Dagger dan Hilt.

Sebagai contoh:


class UserRepository @Inject constructor(private val apiService: ApiService) {
    fun fetchUserData() {
        // Fetches user data from an abstraction
    }
}

 

Di sini, Repositori Pengguna tergantung pada abstraksinya Layanan Api, membuatnya fleksibel dan dapat diuji. Pendekatan ini memungkinkan kita mengganti implementasi, seperti menggunakan layanan tiruan selama pengujian.

Kerangka kerja seperti Hilt, Dagger, dan Koin memfasilitasi penyuntikan dependensi dengan menyediakan cara untuk memasok dependensi ke komponen Android, sehingga menghilangkan kebutuhan untuk membuat instance-nya secara langsung. Dalam repositori, misalnya, alih-alih membuat instance implementasi Retrofit, Anda akan menyuntikkan abstraksi—misalnya, antarmuka ApiService. Dengan cara itu, Anda dapat dengan mudah mengganti implementasi jaringan—misalnya, layanan tiruan dalam memori untuk pengujian lokal—dan tidak perlu mengubah apa pun dalam kode repositori Anda. Dalam aplikasi kehidupan nyata, Anda dapat menemukan bahwa kelas diberi anotasi dengan @Inject atau @Provides untuk menyediakan abstraksi ini, sehingga membuat aplikasi Anda modular dan ramah pengujian.

Manfaat Praktis Prinsip SOLID

Mengadopsi prinsip SOLID dalam pengembangan Android menghasilkan manfaat nyata:

  1. Peningkatan Testabilitas: Kelas dan antarmuka yang terfokus memudahkan penulisan pengujian unit.
  2. Pemeliharaan yang Ditingkatkan: Pemisahan masalah yang jelas menyederhanakan proses debugging dan pembaruan.
  3. Skalabilitas: Desain modular memungkinkan penambahan fitur yang mulus.
  4. Kolaborasi: Kode yang terstruktur dengan baik memfasilitasi kerja tim dan mengurangi waktu orientasi bagi pengembang baru.
  5. Optimasi Kinerja: Arsitektur yang ramping dan efisien meminimalkan pemrosesan dan penggunaan memori yang tidak perlu.

Aplikasi Dunia Nyata

Dalam aplikasi yang kaya fitur, seperti aplikasi e-commerce atau jejaring sosial, penerapan prinsip SOLID dapat mengurangi risiko kemunduran setiap kali fitur atau layanan baru ditambahkan. Misalnya, jika persyaratan baru memerlukan alur pembelian dalam aplikasi, Anda dapat memperkenalkan modul terpisah yang akan mengimplementasikan antarmuka yang diperlukan (Pembayaran, Analisis) tanpa mengubah modul yang sudah ada. Pendekatan modular semacam ini, yang digerakkan oleh SOLID, memungkinkan aplikasi Android Anda beradaptasi dengan cepat terhadap permintaan pasar dan menjaga basis kode agar tidak berubah menjadi spageti seiring berjalannya waktu.

Saat mengerjakan proyek besar yang mengharuskan banyak pengembang untuk berkolaborasi, sangat disarankan untuk mempertahankan basis kode yang kompleks dengan prinsip SOLID. Misalnya, memisahkan pengambilan data, logika bisnis, dan penanganan UI dalam modul obrolan membantu mengurangi kemungkinan regresi saat menskalakan kode dengan fitur baru. Demikian pula, penerapan DIP sangat penting untuk operasi jaringan abstrak, sehingga dapat berubah hampir tanpa gangguan di antara klien jaringan.

Kesimpulan

Lebih dari sekadar panduan teoritis, prinsip-prinsip SOLID sebenarnya adalah filosofi praktis untuk menciptakan perangkat lunak yang tangguh, mudah beradaptasi, dan mudah dipelihara. Dalam dunia pengembangan Android yang bergerak cepat, dengan persyaratan yang berubah hampir sesering teknologi, kepatuhan terhadap prinsip-prinsip ini memberikan dasar yang kuat untuk membangun kesuksesan.

Kode yang baik bukan hanya tentang membuat sesuatu berfungsi—tetapi tentang menciptakan sistem yang dapat terus berfungsi dan berkembang seiring dengan kebutuhan yang terus berkembang. Dengan menerapkan prinsip SOLID, Anda tidak hanya akan menulis kode yang lebih baik tetapi juga membangun aplikasi yang menyenangkan untuk dikembangkan, ditingkatkan skalanya, dan dipelihara.

Farhana adalah pengembang aplikasi seluler ahli yang telah berhasil membuat banyak aplikasi seluler dari awal. Ia telah menyelenggarakan pelatihan pengembangan Android untuk pejabat TIK pemerintah di Bhutan, membimbing banyak karyawan baru, dan memimpin tim untuk mencapai kesuksesan bersama.