Reddit Evolusi Arsitektur Bergerak



Ini adalah artikel pertama di mana kita berbicara tentang arsitektur aplikasi Reddit untuk iOS. Di sini kita berbicara tentang fungsionalitas yang bekerja lebih dekat ke UI. Secara khusus, transisi ke arsitektur Model-View-Presenter (MVP). Keuntungan dari refactoring tersebut:

  • Meningkatkan fleksibilitas kode, kejelasan, dan pemeliharaan untuk mendukung pertumbuhan di masa depan dan mempercepat iterasi.
  • Peningkatan kinerja gulir sebesar 1,58 kali.
  • Merangsang pengujian unit. Jumlah tes meningkat dari beberapa menjadi lebih dari 200.

Di bawah ini adalah diagram visual arsitektur berlapis kami. Artikel pertama akan fokus pada level Tampilan dan Presenter.


Tampilan utama arsitektur berlapis kami

Prasyarat untuk Perubahan


Lebih dari setahun yang lalu, kami menerbitkan artikel “Membangun Pita di Aplikasi iOS Reddit” . Ini membahas cara menghasilkan umpan yang produktif dan dapat diperluas dengan tingkat sesi 99,95% yang luar biasa tanpa mogok. Kami menjelaskan cara menggunakan arsitektur Model-View-Controller (MVC) dan membuat abstraksi untuk paging data.

Sekarang Reddit telah tumbuh dan terus tumbuh sebagai organisasi dan sebagai layanan. Akibatnya, persyaratan untuk aplikasi Reddit iOS telah meningkat. Ini harus mendukung lebih banyak permintaan fitur, loop berulang yang lebih cepat, dan standar kualitas yang lebih tinggi. Tim pengembangan telah berkembang dari tiga menjadi lebih dari dua puluh orang. Arsitektur MVC asli hampir tidak memenuhi persyaratan ini, sehingga perubahan arsitektur harus dilakukan.

Inti dari masalah


Seiring waktu, kode tersebut telah kehilangan fleksibilitas dan kejelasan. Dalam komunitas pengembang iOS, singkatan MVC sering diuraikan sebagai Massive View Controller karena pengendali tampilan sering membengkak ke objek ilahi dengan lebih dari seribu baris. Terlepas dari semua upaya kami, masalah memang muncul: hierarki warisan menjadi sangat tidak nyaman, dan pengendali mulai berubah menjadi objek ilahi yang tidak jelas yang menentang perubahan.

Kami mendorong paku terakhir ke peti mati MVC ketika kami memutuskan untuk mengubah tingkat presentasi untuk rekaman itu. Penonton aplikasi Reddit bertambah, sehingga kinerja gulir menjadi terlalu sering menurun dari 60 FPS menjadi 45–55 FPS. Ini berarti bahwa Anda perlu menulis ulang lapisan presentasi tape sambil mempertahankan implementasi asli. Tetapi dalam arsitektur MVC yang ada, kita tidak bisa menulis ulang lapisan presentasi rekaman tanpa menduplikasi ribuan baris kode.

Selain itu, banyak bagian dari basis kode sulit untuk diuji. Kode berada di kelas yang diuji dari lapisan presentasi, dan dependensi sering sendirian (tunggal) atau kode keras di kelas itu sendiri. Kami ingin menyadari kemungkinan pengujian normal.

Tugas lain yang ditetapkan untuk refactoring: jumlah kegagalan harus tetap rendah, arsitektur baru harus meletakkan fondasi untuk pertumbuhan di masa depan dan tidak mengganggu fungsi-fungsi yang bergantung pada infrastruktur yang ada. Yaitu, perubahan evolusioner, bukan revolusioner, diperlukan.

Transisi ke MVP


Kami memutuskan bahwa untuk menyelesaikan masalah di atas diperlukan versi aplikasi yang baru. Setelah mempertimbangkan beberapa opsi, kami memutuskan untuk menggunakan arsitektur Model-View-Presenter (MVP). MVP memenuhi semua kriteria ini, dan merupakan arsitektur yang terkenal dan terdokumentasi, sehingga lebih mudah untuk melatih insinyur. Ini juga mempertahankan konsep "model tampilan". Jika perlu, di Presenter, Anda dapat membuat objek model tampilan berdasarkan prinsip tanggung jawab tunggal - dan menggunakannya untuk memperluas pandangan kami.


Model-View-Presenter Chart

Menyingkirkan Pengendali Tampilan Masif


Untuk aplikasi iOS, diasumsikan bahwa objek tampilan adalah subkelas dari UIView, objek pengontrol adalah subkelas dari UIViewController, dan objek model adalah objek sederhana. Sesuai dengan namanya UIViewController, di sini tampilan dan pengontrol digabungkan dalam satu objek. Artinya, model MVC di iOS sering kehilangan kelebihannya karena koneksi yang ketat antara tingkat presentasi dan pengontrol. Menariknya, Apple sendiri mengakui koneksi ini .


Seringkali, arsitektur Model-View-Controller untuk iOS berubah menjadi

Dalam arsitektur MVP, kami mempertimbangkan konsep ini dan memformalkannya, mengingat UIViewController benar-benar sebagai objek eksplisit dari lapisan presentasi. Konsep memperlakukan UIViewController sebagai objek presentasi dengan nama buruk telah menjadi populer dalam beberapa tahun terakhir.

Jadi, kami menghapus semua logika asing di UIViewControllers kami. Kemudian kami menetapkan Presenter ke perantara antara tampilan dan model. Dalam peran baru ini, ia tidak mengetahui objek tampilan seperti UIViewController. Perhatikan bahwa Presenter berinteraksi dengan tampilan melalui antarmuka. Secara teoritis, Anda dapat mengubah implementasi tampilan ke NSViewController (untuk MacOS), dll.


Kami membuat ViewController lebih mudah dengan memperkenalkan Presenter dan berbagi tanggung jawab

Opsi Merenungkan MVP


Seperti yang Anda lihat dalam diagram MVP, arsitekturnya sangat mirip dengan MVC. Memang, ada lebih banyak kesamaan daripada perbedaan. Arsitektur semacam itu hanya membantu membangun pemisahan kode presentasi dan logika bisnis yang benar yang dicari oleh MVC. Faktanya, semua turunan dari arsitektur MV (x), seperti MVP, MVVM, MVAdapter dan lainnya, hanyalah versi berbeda dari konsep yang sama.

Orang mungkin bertanya mengapa kami benar-benar meninggalkan MVC. Bahkan, Apple menjelaskan berbagai jenis pengontrol : untuk model, perantara, dan koordinasi. Jujur saja, mungkin kita bisa mengganti Presenter kita dengan controller lain. Tetapi mereka memutuskan untuk tidak melakukan ini, karena sebagian besar pengembang iOS untuk beberapa alasan membentuk keyakinan bahwa UIViewController adalah sinonim untuk controller. Menggunakan kata Presenter, kami memberikan sinyal bahwa objek ini sangat berbeda dari pengontrol konvensional dengan serangkaian fungsi dan properti tertentu.

Meningkatkan fleksibilitas, keberlanjutan, dan kejelasan


"Lebih suka komposisi daripada warisan" adalah mantra yang terkenal dalam pemrograman objek. Dengan pewarisan, Anda harus memprediksi masa depan dan membangun taksonomi objek yang sangat besar. Tetapi jika hierarki warisan bawaan “idealnya” mulai berantakan karena perubahan yang tidak terduga, sulit untuk memodifikasi struktur kaku ini. Dalam komposisi, objek dibuat dari objek lain dan mendelegasikan pekerjaan padanya. Ini berguna karena mudah untuk mengubah perilaku suatu objek saat runtime hanya dengan mengubah objek yang terdiri darinya. Objek komposit ini bahkan lebih dapat dimengerti, karena kode dipaksa keluar dari hierarki warisan menjadi abstraksi yang berorientasi pada satu tugas tertentu.

Komposisionalitas seperti itu adalah salah satu keuntungan utama yang diberikan arsitektur MVP kepada kita. Sekarang Anda dapat mengubah perilaku pengontrol hanya dengan mengubah komposisi Presenter tertentu. Kami sekarang kurang peduli tentang menguraikan struktur warisan yang kompleks dan kaku. Akhirnya, pengontrol tampilan dan objek Presenter lebih mudah dipahami karena mereka memiliki serangkaian tugas yang lebih jelas.

Dengan memperkenalkan Presenter dan memindahkan bagian dari logika pengontrol tampilan di sana, kami telah menyederhanakan hierarki warisan pengontrol. Gambar di bawah ini menunjukkan bahwa kami dapat menghapus kelas GalleryFeedViewController, karena kami menempatkan semua logika ini ke dalam Presenter. Seperti yang sudah dibahas, hierarki warisan seperti itu lebih mudah dipahami dan tidak terlalu kaku.


Sederhanakan hierarki warisan melalui komposisi

Perubahan gratis ke implementasi layer presentasi


Seperti dibahas sebelumnya, kinerja penggulungan pita mulai menurun dari 60 FPS menjadi 45–55 FPS. Oleh karena itu, untuk lapisan presentasi rekaman, kami memutuskan untuk menggunakan Tekstur . Ini adalah platform open source Apple UIKit yang meningkatkan kinerja antarmuka melalui preprocessing di utas latar belakang. Dalam arsitektur MVC sebelumnya, kami tidak dapat mengubah implementasi dari lapisan presentasi tanpa banyak duplikasi kode.


Sebelum menerapkan MVP, Anda harus menduplikasi kode asing di ViewController yang tidak terkait dengan View (oranye)

Arsitektur MVP baru memungkinkan pengenalan dukungan Tekstur, daripada menulis ulang hal-hal dari awal. Kami hanya menempatkan semua logika non-View di kelas Presenter generik. Kemudian mereka menulis implementasi baru dari layer presentasi tekstur c dan menggunakan kembali kode Presenter. Ini memberikan dukungan untuk kedua implementasi View hingga tiba saatnya untuk nyaman menggulung rekaman dengan Texture untuk semua pengguna.


Setelah Penerapan MVP: Non-View Code Dipindahkan ke Shared Presenter

Apa hasilnya? Diagram di bawah ini menunjukkan peningkatan kinerja pita gulir. Kami ingin tetap sekitar 60 FPS untuk mencapai pengguliran yang benar-benar mulus.



Pengujian unit


Tentu saja, kami menerapkan unit test bukan hanya karena MVP, tetapi itu adalah faktor penting. Secara khusus, arsitektur MVP telah memperluas area pengujian dengan memindahkan kode ke tingkat yang lebih mudah untuk diverifikasi. Efek sampingnya adalah tingkat tampilan menjadi lebih sederhana - dan karenanya mereka perlu diuji lebih jarang.


Meningkatkan area pengujian setelah memindahkan kode non-Tampilan di luar lapisan ini

Tes unit telah meningkatkan dukungan basis kode: memungkinkan Anda untuk membuat perubahan lebih percaya diri dan membantu untuk memahami apa yang seharusnya menjadi perilaku yang benar. Mereka juga membuat kode lebih fleksibel dan dapat dimengerti karena mereka mendorong metode seperti injeksi ketergantungan, komposisi, dan pemrograman abstraksi. Jumlah tes unit telah meningkat dari beberapa menjadi lebih dari 200.

Analisis Kritis MVP di Reddit


Meskipun beralih ke MVP telah banyak membantu, masih ada beberapa hal yang perlu dipertimbangkan.

Transisi rekaman ke Tekstur menyebabkan masalah baru dengan utas. Aplikasi pada awalnya tidak mendukung implementasi View yang tidak sinkron. Artinya, kesalahan pasti muncul jika terjadi ketidakcocokan antara kondisi tampilan dan kondisi aplikasi. Misalnya, tampilan rekaman mungkin memiliki catatan N. Dan di utas latar belakang, keadaan aplikasi telah diam-diam berubah - dan sekarang mengandung kurang dari N pesan. Jika perbedaan tidak diselesaikan, maka aplikasi hanya akan crash ketika Lihat mencoba untuk menampilkan posting ke-N di aliran.

Yang paling sulit untuk memperbaiki kesalahan dengan utas. Mereka sulit untuk mereproduksi, sehingga mereka sulit untuk di-debug. Saya harus mengubah logika permintaan dan menerima data untuk melihat umpan. Secara khusus, kami menerapkan "perlindungan" dengan melarang segala perubahan pada sumber data ketika tampilan rekaman mengalami beberapa perubahan. Ini dan perbaikan kecil lainnya mengurangi jumlah kesalahan yang terkait dengan pemrosesan streaming. Namun, multithreading asynchronous masih dapat ditingkatkan.

Kedua, lapisan Presenter mewakili "langkah" tambahan dalam pipa. Langkah ini datang pada harga dalam hal meningkatkan kompleksitas kode dan mengurangi kinerja. Kadang-kadang Anda hanya ingin menjalankan logika ini di UIViewController pada kemauan atau karena Anda terbiasa melakukannya. Dalam skenario terburuk, Anda akan menemukan bahwa Presenter hadir hanya sebagai entitas, tanpa logika yang berarti. Dalam situasi seperti itu, Presenter sepertinya tidak membenarkan keberadaannya.


Kadang-kadang Anda dapat beralih dari layer View ke layer RedditCore tanpa Presenter

Faktanya, aplikasi kita tidak sepenuhnya dikonversi ke arsitektur MVP. Pertama, mengonversi setiap UIViewController individu menjadi Presenter akan terlalu memakan waktu - dan bukan evolusi. Kedua, seperti yang disebutkan dalam paragraf sebelumnya, kadang-kadang Presenter sama sekali tidak diperlukan. Seperti yang kami temukan dalam pekerjaan kami tentang penerapan Texture for Ribbon, Presenter sangat bagus untuk memfasilitasi MVC besar atau untuk mengimplementasikan View dengan perilaku variabel, atau jika Anda memiliki logika kompleks yang perlu diperiksa. Tetapi kadang-kadang UIViewController sangat sederhana sehingga Presenter tidak masuk akal. Jadi itu opsional. Presenter seharusnya hanya dilaksanakan jika perlu.

Ringkasan dan rencana masa depan


Refactoring arsitektur MVP di aplikasi Reddit iOS membantu menyelesaikan banyak tugas. Dengan memperkenalkan lapisan Presenter, kami secara bertahap mengembangkan arsitektur aplikasi untuk mendukung implementasi baru dari lapisan presentasi, tanpa mengganggu fungsi lainnya. Kode menjadi lebih jelas dengan memfasilitasi "MVC besar" - mentransfer logika asing ke lapisan Presenter. Kami juga memberi pengembang kemampuan untuk beralih lebih cepat dan menggunakan fitur baru. Dan secara signifikan meningkatkan tes.

Mengingat semua ini, masih ada jalan panjang yang harus ditempuh. Kami terus membuat objek Presenter dan memperbaikinya. Kita perlu terus memindahkan logika asing dari UIViewControllers ke tingkat Presenter. Juga penting bahwa semua Penyaji lebih selaras dengan prinsip tanggung jawab tunggal. Pada akhirnya, baik aplikasi dan arsitektur terus berkembang.

Source: https://habr.com/ru/post/id423531/


All Articles