RIB Arsitektur Arsitektur Lintas Platform Uber

Pada 20 Desember 2016, orang-orang dari Uber Engineering menerbitkan sebuah artikel tentang arsitektur baru (di sini adalah terjemahan dari artikel ini di hub). Saya mempersembahkan kepada Anda terjemahan dari bagian utama dokumentasi.

Untuk apa arsitektur RIB?


RIBs adalah kerangka kerja arsitektur lintas platform dari Uber. Itu dirancang untuk aplikasi seluler besar dengan sejumlah besar status tertanam.

Dalam mengembangkan kerangka kerja ini, para insinyur Uber menganut prinsip-prinsip berikut:

  • Dukungan untuk kolaborasi antara orang-orang yang mengembangkan pada platform yang berbeda: sebagian besar dari bagian kompleks aplikasi Uber serupa di iOS dan Android. RIB menyediakan pola pengembangan umum untuk Android dan iOS. Saat menggunakan RIB, insinyur di iOS dan Android dapat berbagi satu arsitektur yang dikembangkan bersama untuk fungsinya.
  • Meminimalkan negara dan keputusan global : perubahan negara global dapat menyebabkan perilaku yang tidak terduga dan mungkin membuat tidak mungkin untuk mengetahui apa yang akan menyebabkan perubahan ini atau perubahan dalam kode program. Arsitektur berbasis RIB mendorong negara yang dienkapsulasi dalam hierarki yang dalam dari RIB yang terisolasi dengan baik untuk menghindari masalah dengan negara global.
  • Testabilitas dan isolasi: kelas harus sederhana agar dapat menulis tes unit, dan juga memiliki alasan untuk diisolasi (mengacu pada SRP ). Masing-masing kelas RIB memiliki tanggung jawab yang berbeda (misalnya, perutean, logika bisnis, logika presentasi, membuat kelas RIB lainnya). Selain itu, logika RIB induk pada dasarnya terpisah dari logika RIB anak. Ini membuatnya mudah untuk menguji kelas RIB dan mengurangi ketergantungan antara komponen sistem.
  • Alat untuk pengembangan produktif: meminjam pola arsitektur non-trivial dapat menyebabkan masalah dengan pertumbuhan aplikasi jika tidak ada alat yang dapat diandalkan untuk mendukung arsitektur. Arsitektur RIB dilengkapi dengan alat IDE untuk membuat kode, analisis statis, dan integrasi runtime, yang meningkatkan produktivitas pengembang di tim besar dan kecil.
  • Prinsip keterbukaan-kedekatan: pengembang, jika mungkin, harus menambahkan fungsi baru tanpa mengubah kode yang ada. Saat menggunakan RIB, implementasi aturan ini dapat dilihat di sejumlah tempat. Misalnya, Anda dapat melampirkan atau membuat RIB anak yang kompleks yang memerlukan dependensi pada RIB induknya, dengan sedikit atau tanpa perubahan pada RIB induknya.
  • Penataan seputar logika bisnis: Struktur logika bisnis suatu aplikasi tidak boleh mencerminkan struktur antarmuka pengguna secara ketat. Misalnya, untuk memfasilitasi animasi dan kinerja tampilan, hierarki tampilan mungkin lebih kecil daripada hierarki RIB. Atau, fungsi RIB tunggal dapat mengontrol tampilan tiga tampilan yang muncul di tempat yang berbeda pada antarmuka pengguna.
  • Kontrak yang tepat: persyaratan harus dinyatakan menggunakan kontrak yang diperiksa pada waktu kompilasi. Kelas tidak boleh dikompilasi jika dependensinya sendiri, dan juga dependensi tamu, tidak terpenuhi. Arsitektur RIB menggunakan ReactiveX untuk mewakili dependensi tamu, sistem injeksi dependensi tipe-aman ( DI ) untuk mewakili dependensi kelas, dan banyak fitur DI lainnya untuk membantu membuat data invarian.

Elemen Komponen RIB


Jika sebelumnya Anda pernah bekerja dengan arsitektur VIPER , maka kelas yang membentuk RIB akan terlihat familier bagi Anda. RIB biasanya terdiri dari elemen-elemen berikut, yang masing-masing diimplementasikan di kelasnya sendiri:



Interactractor


Interactor berisi logika bisnis. Di kelas ini, pemberitahuan Rx dilanggani, keputusan dibuat untuk mengubah status, menyimpan data, dan melampirkan RIB anak.

Semua operasi yang dilakukan dalam Interactor harus dibatasi pada siklus hidupnya. Uber telah menciptakan toolkit untuk memastikan bahwa logika bisnis dijalankan hanya dengan interaksi aktif. Ini mencegah Interactors dari dinonaktifkan, tetapi langganan Rx masih menyala dan menyebabkan pembaruan yang tidak diinginkan ke logika bisnis atau keadaan antarmuka pengguna.

Router


Router memonitor kejadian dari Interactor dan mengubah kejadian ini menjadi melampirkan dan melepaskan RIB anak. Router ada karena tiga alasan sederhana:

  • Router ada sebagai objek pasif, yang menyederhanakan pengujian logika Interactor kompleks tanpa perlu membuat bertopik untuk Interactor anak atau dalam beberapa cara lain untuk menjaga keberadaan mereka.
  • Router membuat lapisan abstraksi ekstra antara orangtua dan anak. Ini membuat komunikasi sinkron antara Interactors sedikit lebih kompleks dan mendorong penggunaan komunikasi Rx daripada komunikasi langsung antara RIB.
  • Router berisi logika perutean yang sederhana dan berulang yang seharusnya diimplementasikan dalam Interactors. Porting kode boilerplate ini ke Router membantu Interactors menjadi kecil dan lebih fokus pada logika bisnis RIB inti.

Pembangun


Builder diperlukan untuk membuat instance untuk semua kelas yang termasuk dalam RIB, serta membuat instance Builder untuk RIB anak.

Menyoroti logika kreasi kelas di Builder menambahkan dukungan bagi kemampuan untuk membuat stubs di iOS dan membuat kode RIB lainnya tidak peka terhadap detail implementasi DI. Builder adalah satu-satunya bagian dari RIB yang perlu mengetahui sistem DI yang digunakan dalam proyek. Dengan menerapkan Builder lain, Anda dapat menggunakan kembali sisa kode RIB dalam proyek menggunakan mekanisme DI yang berbeda.

Presenter


Presenter adalah kelas tanpa kewarganegaraan yang menerjemahkan model bisnis menjadi model presentasi dan sebaliknya. Ini dapat digunakan untuk memfasilitasi transformasi tampilan model pengujian. Namun, seringkali terjemahan ini sangat sepele sehingga tidak membenarkan penciptaan kelas Presenter yang terpisah. Jika Presenter tidak dilakukan, maka terjemahan model tampilan menjadi tanggung jawab View (Controller) atau Interactor.

Lihat (Pengendali)


Lihat membuat dan memperbarui antarmuka pengguna. Ini termasuk membuat dan mengatur komponen antarmuka, menangani interaksi pengguna, mengisi komponen antarmuka pengguna dengan data, dan animasi. Lihat dirancang agar "bodoh" (pasif) mungkin. Mereka hanya menampilkan informasi. Secara umum, mereka tidak mengandung kode untuk tes unit mana yang harus ditulis.

Komponen


Komponen digunakan untuk mengelola dependensi RIB. Ini membantu Builder untuk membuat instance kelas lain yang membentuk RIB. Komponen menyediakan akses ke dependensi eksternal yang diperlukan untuk membuat RIB, serta dependensinya sendiri yang dibuat oleh RIB itu sendiri, dan mengontrol akses ke mereka dari RIB lain. Komponen RIB induk biasanya tertanam dalam RIB-Builder anak untuk memberikan RIB anak akses ke dependensi RIB induk.

Manajemen negara


Keadaan aplikasi terutama dikelola dan diwakili oleh RIB yang saat ini terhubung ke pohon RIB. Misalnya, ketika pengguna melewati berbagai kondisi dalam aplikasi perjalanan bersama yang disederhanakan, aplikasi melampirkan dan melepaskan RIB berikut:



RIB hanya membuat keputusan negara dalam kompetensi mereka. Misalnya, LoggedIn RIB hanya membuat keputusan untuk transisi antara negara-negara seperti Permintaan dan OnTrip. Dia tidak membuat keputusan apa pun tentang bagaimana seharusnya perilaku sistem ketika kita berada di layar OnTrip.

Tidak semua negara dapat disimpan dengan menambahkan atau menghapus RIB. Misalnya, ketika pengaturan profil pengguna berubah, RIB tidak mengikat atau memutuskan sambungan. Sebagai aturan, kami menyimpan keadaan ini di dalam aliran model yang tidak dapat diubah, yang mengirimkan kembali nilai saat mengganti bagian. Misalnya, nama pengguna dapat disimpan dalam file ProfileDataStream, yang berada di bawah kompetensi LoggedIn. Hanya respons jaringan yang memiliki akses tulis ke aliran ini. Kami melewati antarmuka yang menyediakan akses baca ke utas-utas ini di grafik DI.

Tidak ada dalam RIB yang merupakan kebenaran pamungkas untuk kondisi RIB. Ini kontras dengan fakta bahwa kerangka kerja yang lebih ahli seperti Bereaksi sudah disediakan di luar kotak. Dalam konteks setiap RIB, Anda dapat memilih pola yang memfasilitasi aliran data searah, atau Anda dapat membiarkan keadaan logika bisnis dan melihat keadaan sementara menyimpang dari norma untuk mengambil keuntungan dari kerangka animasi yang efisien untuk platform.

Interaksi antara RIB


Ketika Interactor membuat keputusan logika bisnis, mungkin perlu memberi tahu RIB lain tentang peristiwa, seperti penyelesaian dan pengiriman data. Kerangka kerja RIB tidak termasuk cara tunggal untuk mentransfer data antara RIB. Namun, metode ini dirancang untuk memfasilitasi beberapa pola umum.

Sebagai aturan, jika koneksi turun ke RIB anak, maka kami mengirimkan informasi ini sebagai peristiwa dalam aliran Rx. Atau data dapat dimasukkan sebagai parameter dalam metode build () dari RIB anak, dalam hal ini parameter ini menjadi invarian untuk masa hidup anak.



Jika koneksi naik pohon RIB ke Interactor induk RIB, maka koneksi ini dibuat melalui antarmuka pendengar, karena RIB induk dapat memiliki siklus hidup yang lebih lama daripada RIB anak. RIB induk, atau beberapa objek pada grafik DI-nya, mengimplementasikan antarmuka pendengar dan menempatkannya pada grafik DI-nya sehingga RIB anaknya dapat menyebutnya. Menggunakan templat ini untuk mentransfer data ke atas daripada memiliki RIB induk, secara langsung berlangganan aliran Rx RIB anak mereka memiliki beberapa keuntungan. Ini mencegah kebocoran memori, memungkinkan Anda untuk menulis, menguji dan memelihara RIB induk tanpa mengetahui RIB anak mana yang melekat padanya, dan juga mengurangi jumlah keributan yang diperlukan untuk melampirkan / melepaskan RIB anak. Aliran atau pendengar Rx tidak perlu membatalkan pendaftaran atau mendaftar ulang dengan metode melampirkan RIB anak ini.



Toolkit RIB


Untuk memastikan kelancaran implementasi arsitektur RIB dalam aplikasi, insinyur Uber telah menciptakan alat untuk menyederhanakan penggunaan RIB dan menggunakan invarian yang dibuat dengan mengimplementasikan arsitektur RIB. Kode sumber toolkit ini sebagian terbuka dan disebutkan dalam contoh (lihat bagian kanan - kira-kira Per.).

Toolkit, yang saat ini open source, meliputi:


Toolkit di mana Uber berencana untuk membuka sumber di masa mendatang:

  • Analisis statis untuk mencegah berbagai kebocoran memori di RIB
  • Integrasi RIB dengan detektor kebocoran memori selama eksekusi program
  • (Android) Prosesor penjelasan untuk pengujian yang lebih mudah
  • (Android) penganalisa statis RxJava yang memberikan RIB pandangan yang tidak berubah dari utas utama

PS


Kami di sports.ru sangat menyukai pendekatan insinyur Uber, karena berkali-kali kami menemui semua masalah arsitektur yang dijelaskan artikel itu. Meskipun masuk akal, RIB memiliki sejumlah kelemahan, misalnya, ambang batas yang agak tinggi untuk memasuki arsitektur. Kami akan menganalisis secara lebih rinci pro dan kontra arsitektur di artikel berikut, mereka direncanakan setidaknya dua - untuk iOS dan untuk Android. Bagi mereka yang ingin terjun ke RIB sekarang, ada kolom di halaman wiki di sebelah kanan yang memiliki pelajaran bahasa Inggris. Saya sendiri mencatat bahwa arsitektur jelas lahir dari diskusi teknis yang panjang dan mengumpulkan praktik terbaik untuk membangun arsitektur untuk aplikasi seluler yang saat ini tersedia. Dan akhirnya, seorang PR kecil - kami di sports.ru juga menyukai diskusi teknis, sering mengadakan lokakarya teknis untuk kolega, secara teratur mempelajari teknologi baru dan, secara umum, kami memiliki suasana yang hebat. Jadi, jika Anda ingin menjadi bagian dari tim kami - selamat datang !

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


All Articles