Empat Aturan Desain Perangkat Lunak iOS yang Lebih Sederhana

Pada akhir 1990-an, saat mengembangkan Extreme Programming, pengembang perangkat lunak terkenal Kent Beck membuat daftar aturan untuk desain perangkat lunak sederhana.

Menurut Kent Beck, desain perangkat lunak yang baik:

  • Jalankan semua tes
  • Tidak mengandung duplikasi
  • Mengungkapkan maksud programmer
  • Meminimalkan jumlah kelas dan metode

Pada artikel ini, kita akan membahas bagaimana aturan-aturan ini dapat diterapkan pada dunia pengembangan iOS dengan memberikan contoh-contoh praktis iOS dan mendiskusikan bagaimana kita dapat mengambil manfaat darinya.

Jalankan semua tes

Desain perangkat lunak membantu kami menciptakan sistem yang berfungsi sebagaimana mestinya. Tetapi bagaimana kita dapat memverifikasi bahwa suatu sistem akan bertindak sebagaimana dimaksud pada awalnya dengan desainnya? Jawabannya adalah dengan membuat tes yang memvalidasinya.

Sayangnya, dalam uji pengembangan alam semesta iOS sebagian besar kali dihindari ... Tetapi untuk membuat perangkat lunak yang dirancang dengan baik, kita harus selalu menulis kode Swift dengan mempertimbangkan testabilitas.

Mari kita bahas dua prinsip yang dapat membuat penulisan ujian dan desain sistem lebih sederhana. Dan mereka adalah Prinsip Tanggung Jawab Tunggal dan Injeksi Ketergantungan.

Prinsip Tanggung Jawab Tunggal (SRP)

SRP menyatakan bahwa suatu kelas harus memiliki satu, dan hanya satu alasan untuk berubah. SRP adalah salah satu prinsip paling sederhana, dan salah satu yang paling sulit untuk dilakukan dengan benar. Memadukan tanggung jawab adalah sesuatu yang kita lakukan secara alami.

Mari kita berikan contoh beberapa kode yang sangat sulit untuk diuji dan setelah itu refactor dengan menggunakan SRP. Kemudian diskusikan bagaimana itu membuat kode dapat diuji.

Misalkan saat ini kami perlu menampilkan PaymentViewController dari pengontrol tampilan kami saat ini, PaymentViewController harus mengonfigurasi tampilan dengan bergantung pada harga produk pembayaran kami. Dalam kasus kami, harga bervariasi tergantung pada beberapa peristiwa pengguna eksternal.

Kode untuk implementasi ini saat ini terlihat seperti berikut:

Bagaimana kita bisa menguji kode ini? Apa yang harus kita uji dulu? Apakah potongan harga dihitung dengan benar? Bagaimana kita bisa mengejek peristiwa pembayaran untuk menguji diskon?

Tes menulis untuk kelas ini akan rumit, kita harus menemukan cara yang lebih baik untuk menulisnya. Baiklah, pertama mari kita atasi masalah besar. Kita perlu melepaskan ketergantungan kita.

Kami melihat bahwa kami memiliki logika untuk memuat produk kami. Kami memiliki Acara Pembayaran yang membuat pengguna berhak mendapatkan diskon. Kami memiliki Diskon, perhitungan diskon dan daftar berjalan.

Jadi mari kita coba menerjemahkannya ke dalam kode Swift.

Kami membuat PaymentManager yang mengelola logika kami terkait dengan pembayaran, dan Pisahkan PriceCalculator sehingga mudah diuji. Juga, pemuat data yang bertanggung jawab atas interaksi jaringan atau basis data untuk memuat produk kami.

Kami juga menyebutkan bahwa kami membutuhkan kelas yang bertanggung jawab untuk mengelola diskon. Sebut saja CouponManager dan biarkan juga mengelola kupon diskon pengguna.

Pengontrol tampilan pembayaran kami kemudian dapat terlihat seperti berikut:

Kita dapat menulis sekarang seperti tes

  • testCalculatingFinalPriceWithoutCoupon
  • testCalculatingFinalPriceWithCoupon
  • testCouponExists

dan banyak lagi lainnya! Dengan membuat objek terpisah sekarang, kami menghindari duplikasi yang tidak dibutuhkan dan juga membuat kode yang memudahkan untuk menulis tes.

Injeksi Ketergantungan

Prinsip kedua adalah Injeksi Ketergantungan. Dan kami melihat dari contoh di atas bahwa kami sudah menggunakan injeksi ketergantungan pada inisialisasi objek kami.

Ada dua manfaat utama menyuntikkan dependensi kita seperti di atas. Itu memperjelas ketergantungan apa yang tipe kita andalkan dan memungkinkan kita untuk menyisipkan objek tiruan saat kita ingin menguji alih-alih yang asli.

Teknik yang baik adalah membuat protokol untuk objek kita dan memberikan implementasi konkret oleh objek nyata dan tiruan seperti berikut:

Sekarang kita dapat dengan mudah memutuskan kelas mana yang ingin kita suntikkan sebagai dependensi.

Kopling ketat membuatnya sulit untuk menulis tes. Jadi, sama halnya, semakin banyak tes yang kami tulis, semakin banyak kami menggunakan prinsip-prinsip seperti DIP dan alat-alat seperti injeksi ketergantungan, antarmuka, dan abstraksi untuk meminimalkan sambungan.

Membuat kode lebih dapat diuji tidak hanya menghilangkan rasa takut kita untuk memecahkannya (karena kita akan menulis tes yang akan mendukung kita) tetapi juga berkontribusi untuk menulis kode yang lebih bersih.

Bagian artikel ini lebih mementingkan cara menulis kode yang akan diuji daripada menulis unit test yang sebenarnya. Jika Anda ingin mempelajari lebih lanjut tentang cara menulis unit test, Anda dapat memeriksa artikel ini di mana saya membuat game of life menggunakan pengembangan berbasis tes.

Tidak mengandung duplikasi

Duplikasi adalah musuh utama dari sistem yang dirancang dengan baik. Ini merupakan pekerjaan tambahan, risiko tambahan, menambah kompleksitas yang tidak perlu.

Di bagian ini, kita akan membahas bagaimana kita dapat menggunakan pola desain Templat untuk menghapus duplikasi umum di iOS. Untuk membuatnya lebih mudah untuk dipahami, kita akan memperbaiki implementasi obrolan kehidupan nyata.

Misalkan saat ini di aplikasi kami terdapat bagian obrolan standar. Persyaratan baru muncul dan sekarang kami ingin menerapkan jenis obrolan baru - live-chat. Obrolan yang seharusnya berisi pesan dengan maksimum 20 karakter dan obrolan ini akan menghilang ketika kami mengabaikan tampilan obrolan.

Obrolan ini akan memiliki tampilan yang sama dengan obrolan kami saat ini tetapi akan memiliki beberapa aturan berbeda:

  1. Permintaan jaringan untuk mengirim pesan obrolan akan berbeda.

2. Pesan obrolan harus pendek, tidak lebih dari 20 karakter untuk pesan.

3. Pesan obrolan tidak boleh bertahan di basis data lokal kami.

Misalkan kita menggunakan arsitektur MVP dan saat ini kami menangani logika untuk mengirim pesan obrolan di presenter kami. Mari kita coba menambahkan aturan baru untuk tipe obrolan baru kami bernama live-chat.

Implementasi naif akan seperti berikut:

Tetapi apa yang terjadi jika di masa depan kita akan memiliki lebih banyak tipe obrolan?
Jika kami terus menambahkan jika ada yang memeriksa keadaan obrolan kami di setiap fungsi, kode akan menjadi sulit untuk dibaca dan dikelola. Selain itu, ini hampir tidak dapat diuji dan pemeriksaan status akan digandakan di seluruh ruang lingkup presenter.

Di sinilah Pola Templat mulai digunakan. Pola Templat digunakan ketika kita membutuhkan banyak implementasi suatu algoritma. Template ditentukan dan kemudian dibangun dengan variasi lebih lanjut. Gunakan metode ini ketika sebagian besar subclass perlu menerapkan perilaku yang sama.

Kita dapat membuat protokol untuk Presenter Obrolan dan kami memisahkan metode yang akan diimplementasikan secara berbeda oleh objek konkret di Fase Presenter Obrolan.

Kita sekarang dapat membuat presenter kita menyesuaikan diri dengan IChatPresenter

Presenter kami sekarang menangani pengiriman pesan dengan memanggil fungsi-fungsi umum di dalam dirinya sendiri dan mendelegasikan fungsi-fungsi yang dapat diimplementasikan secara berbeda.

Sekarang kami dapat menyediakan objek Buat yang sesuai dengan fase presenter berdasarkan dan mengkonfigurasi fungsi-fungsi ini berdasarkan kebutuhan mereka.

Jika kita menggunakan injeksi dependensi di controller tampilan kita, kita sekarang dapat menggunakan kembali controller tampilan yang sama dalam dua kasus yang berbeda.

Dengan menggunakan Pola Desain, kami benar-benar dapat menyederhanakan kode iOS kami. Jika Anda ingin tahu lebih banyak tentang itu, artikel berikut memberikan penjelasan lebih lanjut.

Ekspresif

Sebagian besar biaya proyek perangkat lunak adalah pemeliharaan jangka panjang. Menulis kode yang mudah dibaca dan memelihara adalah suatu keharusan bagi pengembang perangkat lunak.

Kami dapat menawarkan kode yang lebih ekspresif dengan menggunakan Penamaan yang baik, Menggunakan SRP, dan tes Menulis.

Penamaan

Nomor satu hal yang membuat kode lebih ekspresif - dan itu adalah penamaan. Penting untuk menulis nama yang:

  • Ungkapkan niat
  • Hindari disinformasi
  • Mudah dicari

Ketika datang ke penamaan kelas dan fungsi, trik yang baik adalah dengan menggunakan kata benda atau frasa kata benda untuk kelas dan kata kerja pengguna atau nama frasa kata kerja untuk metode.

Juga ketika menggunakan Pola Desain yang berbeda kadang-kadang ada baiknya menambahkan nama pola seperti Command atau Visitor di nama kelas. Jadi pembaca akan segera tahu pola apa yang digunakan di sana tanpa harus membaca semua kode untuk mencari tahu tentang itu.

Menggunakan SRP

Hal lain yang membuat kode menjadi ekspresif adalah menggunakan Prinsip Tanggung Jawab Tunggal yang disebutkan di atas. Anda dapat mengekspresikan diri dengan menjaga fungsi dan kelas Anda kecil dan untuk satu tujuan. Kelas dan fungsi kecil biasanya mudah disebutkan namanya, mudah ditulis, dan mudah dimengerti. Suatu fungsi harus berfungsi hanya untuk satu tujuan.

Tes menulis

Tes menulis juga membawa banyak kejelasan, terutama ketika bekerja dengan kode warisan. Unit test yang ditulis dengan baik juga ekspresif. Tujuan utama tes adalah bertindak sebagai dokumentasi dengan contoh. Seseorang yang membaca tes kami harus bisa mendapatkan pemahaman yang cepat tentang apa itu kelas.

Minimalkan jumlah kelas dan metode

Fungsi suatu kelas harus tetap pendek, suatu fungsi harus selalu melakukan hanya satu hal. Jika suatu fungsi memiliki terlalu banyak garis yang mungkin merupakan kasus yang melakukan tindakan yang dapat dipisahkan menjadi dua atau lebih fungsi yang terpisah.

Pendekatan yang baik adalah dengan menghitung garis fisik dan mencoba membidik maksimal empat hingga enam garis fungsi, dalam banyak kasus apa pun yang melebihi jumlah garis itu menjadi sulit dibaca dan dipelihara.

Ide yang bagus di iOS adalah memotong panggilan konfigurasi yang biasanya kita lakukan pada fungsi viewDidLoad atau viewDidAppear.

Dengan cara ini, masing-masing fungsi akan menjadi kecil dan dapat dikelola alih-alih satu fungsi viewDidLoad berantakan. Hal yang sama juga harus berlaku untuk delegasi aplikasi. Kita harus menghindari membuang setiap konfigurasi metode ondidFinishLaunchingWithOptions dan memisahkan fungsi konfigurasi atau bahkan kelas konfigurasi yang lebih baik.

Dengan fungsi, ini sedikit lebih mudah untuk mengukur apakah kita menjaganya tetap panjang atau pendek, sebagian besar waktu kita hanya mengandalkan penghitungan garis fisik. Dengan kelas, kami menggunakan ukuran yang berbeda. Kami menghitung tanggung jawab. Jika suatu kelas hanya memiliki lima metode, itu tidak berarti bahwa kelas itu kecil, mungkin saja ia memiliki terlalu banyak tanggung jawab dengan hanya metode itu.

Masalah yang diketahui di iOS adalah ukuran besar UIViewControllers. Memang benar bahwa dengan desain pengontrol tampilan apel, sulit untuk menjaga benda-benda ini untuk melayani satu tujuan tetapi kita harus mencoba yang terbaik.

Ada banyak cara untuk membuat UIViewControllers kecil pilihan saya adalah menggunakan arsitektur yang memiliki pemisahan yang lebih baik dari sesuatu seperti VIPER atau MVP tetapi itu tidak berarti bahwa kita tidak dapat membuatnya lebih baik di apel MVC dengan lebih baik juga.

Dengan mencoba memisahkan sebanyak mungkin masalah kita dapat mencapai kode yang cukup baik dengan arsitektur apa pun. Idenya adalah untuk membuat kelas tujuan tunggal yang dapat berfungsi sebagai pembantu untuk pengontrol tampilan dan membuat kode lebih mudah dibaca dan diuji.

Beberapa hal yang dapat dihindari tanpa alasan dalam pengontrol tampilan adalah:

  • Alih-alih menulis kode jaringan secara langsung, harus ada NetworkManager kelas yang bertanggung jawab untuk panggilan jaringan
  • Alih-alih memanipulasi data dalam pengontrol tampilan, kita cukup membuat DataManager kelas yang bertanggung jawab untuk itu.
  • Alih-alih bermain dengan string UserDefaults di UIViewController kita bisa membuat fasad lebih dari itu.

Kesimpulannya

Saya percaya bahwa kita harus membuat perangkat lunak dari komponen yang secara akurat dinamai, sederhana, kecil, bertanggung jawab untuk satu hal dan dapat digunakan kembali.

Dalam artikel ini, kami membahas empat aturan untuk desain sederhana oleh Kent Beck dan memberikan contoh-contoh praktis tentang bagaimana kami dapat menerapkannya di lingkungan Pengembangan iOS.

Jika Anda menikmati artikel ini, pastikan untuk bertepuk tangan untuk menunjukkan dukungan Anda. Ikuti saya untuk melihat lebih banyak artikel yang dapat meningkatkan keterampilan Pengembang iOS Anda ke tingkat selanjutnya.

Jika Anda memiliki pertanyaan atau komentar, jangan ragu untuk meninggalkan catatan di sini atau mengirim email kepada saya di arlindaliu.dev@gmail.com.