Ini adalah posting pertama dari serangkaian publikasi yang menjelaskan pemahaman saya tentang arsitektur aplikasi Flutter. Saya memperingatkan Anda - itu akan sangat percaya diri .
Sejauh ini direncanakan:
Kata Pengantar
Saya telah pemrograman selama sekitar 20 tahun. Saya memulai pengembangan ponsel 4 tahun yang lalu dengan Xamarin. Karena, cross-platform adalah satu-satunya motivasi bagi saya sebagai pengembang indie. Xamarin.Forms benar-benar mendorong Anda untuk menggunakan pola MVVM, karena UI didefinisikan dalam XAML, dan Anda perlu semacam lapisan untuk merekatkan UI dengan Model. Dalam proses bekerja dengan Xamarin, saya bertemu ReactiveUI dan benar-benar terpikat oleh aliran dan ekstensi reaktif ( Rx ) yang membuat aplikasi saya lebih dapat diandalkan.
Sementara Xamarin. Bentuk MVVM ada di luar kotak, ketika saya beralih ke Flutter, saya terkejut bahwa tidak ada pola desain yang serupa di dalamnya. Saya mulai meneliti berbagai pendekatan yang diusulkan, tetapi tidak ada yang tersedia yang benar-benar memuaskan saya:
- InheritedWidget : Saya tidak bisa memperbarui hanya bagian yang diubah dari pohon widget, jadi saya menggunakannya hanya untuk mengakses kelas model yang menerbitkan aliran panah (Dart Streams), tetapi segera meninggalkan ide ini demi template Layanan Locator
- Model Scoped lebih menarik daripada
InheritedWidget
, tetapi itu tidak memberi saya banyak fleksibilitas seperti yang saya gunakan dengan ReactiveUI - Redux adalah template yang direkomendasikan oleh banyak pengembang yang akrab dengan React Native. Saya memiliki seluruh posting tentang mengapa saya tidak menyukainya.
- BLoC : jika saya belum mulai mengembangkan pola saya sendiri pada saat BLoC mulai maju, kemungkinan besar saya akan mengambilnya, karena sangat fleksibel dan reaktif. Apa yang saya tidak suka adalah itu menerbitkan Stream Sinks dan saya tidak bisa hanya mengambil dan meneruskan fungsi atau perintah ke pengendali acara widget. Selain itu, BLoC tidak memberi tahu Anda bagaimana menyusun aplikasi secara keseluruhan, juga tidak ada definisi yang jelas tentang seberapa besar BLoC tertentu seharusnya atau apa cakupannya.
- MVVM : sejak saya bekerja dengannya, ini adalah hal pertama yang saya harapkan untuk diterapkan di Flutter. Tapi tidak! Inti dari ViewModel adalah memberikan representasi model Anda dengan anggun di View melalui binding. Tapi Flutter tidak memperbarui modelnya dengan data baru, ia selalu membangunnya kembali, seperti yang sudah saya jelaskan . Selain itu, ViewModels harus selalu selaras dengan model dasar, yang mengarah ke bug yang tidak menyenangkan, dan kenyataan menunjukkan bahwa keuntungan yang dijanjikan dari menggunakan kembali ViewModels dalam aplikasi hampir tidak pernah tercapai. Adam Pedley memiliki posting bagus tentang kekurangan ini
Kebenaran yang keras tentang redundansi layer
Hampir merupakan dogma terhadap gagasan bahwa dalam pengembangan Anda harus selalu membangun aplikasi Anda dalam beberapa lapisan, yang masing-masing hanya memiliki akses ke yang mendasarinya, karena ini akan memungkinkan Anda:
- menggunakan kembali lapisan dalam proyek lain
- secara transparan ganti satu lapisan dengan yang lain
- menyederhanakan pengujian
Namun:
- dalam praktik saya tidak ada kasus di mana saya mengamati penggunaan kembali sepenuhnya lapisan. Jika Anda memiliki kode universal yang dapat digunakan kembali, lebih masuk akal untuk meletakkannya di semacam perpustakaan universal;
- mengganti seluruh lapisan juga bukan praktik yang umum. Kebanyakan orang tidak mungkin mengganti database setelah aplikasi mencapai tahap pengembangan tertentu, jadi mengapa menambahkan lapisan abstraksi untuk itu. Nah, jika beberapa alat pengembangan kami saat ini diperlukan, refactoring cukup mudah;
- yang benar-benar berfungsi adalah penyederhanaan pengujian
Namun saya tidak menentang penggunaan layer, jika kita mengikuti aturan ini dengan sembrono seperti sebelumnya. Penggunaannya yang berlebihan menyebabkan peningkatan kode, dan berpotensi menimbulkan masalah sambil mempertahankan satu sumber status aplikasi. Oleh karena itu, terapkan layer ketika benar-benar diperlukan, dan tidak didasarkan pada "praktik terbaik."
Arsitektur ideal untuk Flutter
Jadi apa yang saya harapkan dari arsitektur yang sempurna?
- Kemudahan memahami aplikasi. Bagi saya, ini adalah tujuan terpenting. Pengembang baru yang terlibat dalam bekerja dengan kode yang ada harus dengan mudah memahami struktur pengembangan
- Kemudahan Pengembangan Tim
- Arsitekturnya sendiri harus mudah dipahami dan dipelihara.
- Tidak ada kode templat untuk kruk dalam pengembangan
- Dukungan gaya reaktif bergetar
- Debugging mudah
- Kinerja seharusnya tidak menderita
- Kemudahan ekspansi
- Kemudahan pengujian
- Peluang untuk fokus pada aplikasi alih-alih berkeliaran di sumber
Kemandirian widget
Berdasarkan sifat elemen antarmuka stateless, tidak ada halaman / widget di Flutter yang harus bergantung atau memengaruhi orang lain. Ini mengarah pada gagasan bahwa setiap halaman / widget harus bertanggung jawab secara independen untuk menampilkan dirinya dan semua interaksinya dengan pengguna.
Rxvms
RxVMS adalah evolusi dari pola RxVAMS yang dijelaskan dalam posting sebelumnya , selama aplikasi praktis yang beberapa masalah diidentifikasi dan diperbaiki.
Hasil saat ini dari semua pemikiran ini adalah pola RxVMS, atau Rx-View-Managers-Services. Ia melakukan semua tugas di atas dengan satu-satunya syarat bahwa Anda harus memahami untaian dan elemen Rx. Untuk membantu Anda dengan ini, saya mendedikasikan posting berikut.
Berikut ini adalah ikhtisar singkat dari aplikasi saya

Layanan
Ini adalah abstraksi antarmuka ke dunia luar, yang dapat berfungsi sebagai basis data, API REST, dll. Mereka tidak mempengaruhi keadaan aplikasi.
Manajer
Manajer mengelompokkan fungsionalitas yang hampir sama, seperti otentikasi, prosedur pemesanan, dan sejenisnya. Manajer memanipulasi keadaan suatu objek.
Setiap perubahan status (perubahan data aplikasi) harus dilakukan hanya melalui manajer. Sebagai aturan, manajer itu sendiri tidak menyimpan data, kecuali dalam kasus kritis untuk kinerja atau konstanta runtime.
Manajer dapat berfungsi sebagai sumber data proxy, jika transformasi tertentu diperlukan setelah permintaan dari layanan. Contohnya adalah menggabungkan data dari dua sumber atau lebih untuk ditampilkan dalam Tampilan.
Manajer dapat berinteraksi satu sama lain.
Tampilan
Biasanya, ini adalah StatefullWidget atau StreamBuilder, yang dapat menggunakan data dari manajer dan layanan. Ini bisa berupa seluruh halaman atau widget. Tampilan tidak menyimpan status apa pun dan dapat langsung menghubungi layanan saat aturan ini dihormati.
Objek Domain
Meskipun tidak termasuk dalam diagram, ini adalah entitas penting yang mewakili model bisnis. Dalam pola lain, mereka dapat menjadi bagian dari lapisan terpisah ( model bisnis ) dalam hubungannya dengan logika bisnis. Di sini, di RxVMS, mereka tidak mengandung logika apa pun yang mengubah keadaan aplikasi. Hampir selalu, ini adalah tipe data sederhana - objek data biasa (jika saya memasukkannya dalam pola, ini akan terlihat seperti RxVMMS, yang agak panjang dan menyebabkan kebingungan - VM mungkin keliru sebagai ViewModel). Secara logis, objek domain terletak di lapisan manajer.
Posting berikut akan mengungkapkan esensi dan interaksi elemen-elemen ini.