MegaFon telah memilih kesempatan untuk bekerja dengan komunikasi yang tidak stabil sebagai salah satu poin pertumbuhan penting. Ada tempat-tempat di Rusia di mana komunikasi terputus sementara atau hilang untuk waktu yang lama. Dan bahkan dalam kasus ini, aplikasi harus bekerja tanpa kegagalan.
Valentin berbicara tentang bagaimana tugas ini dilakukan selama lima bulan terakhir, bagaimana arsitektur proyek dipilih dan diimplementasikan, teknologi apa yang digunakan, serta apa yang mereka capai dan apa yang direncanakan untuk masa depan, Valentin berbicara di Apps Live 2020 Conference of Mobile Applications Developers.
Sebuah tugas
Bisnis mengatakan - kami pergi offline sehingga pengguna dapat berhasil berinteraksi dengan aplikasi dalam koneksi jaringan yang tidak stabil. Kami, sebagai tim pengembangan, harus menjamin Offline terlebih dahulu - aplikasi akan berfungsi bahkan dengan Internet yang tidak stabil atau sama sekali tidak ada. Hari ini saya akan memberi tahu Anda tentang di mana kami memulai dan langkah pertama apa yang kami ambil ke arah ini.
Tumpukan teknologi
Selain arsitektur MVC standar, kami menggunakan:
Swift + Objective-C
Sebagian besar kode (80% dari proyek kami) ditulis dalam Objective-C. Dan sudah kami tulis kode baru di Swift.
Arsitektur modular
Kami secara logis membagi potongan kode global menjadi beberapa modul untuk mencapai kompilasi, peluncuran dan pengembangan proyek yang lebih cepat.
Submodul (perpustakaan)
Kami menghubungkan semua pustaka tambahan melalui git submodule untuk mendapatkan kontrol lebih besar atas pustaka yang digunakan. Oleh karena itu, jika dukungan untuk salah satu dari mereka tiba-tiba berhenti, kami akan dapat memperbaiki situasi sendiri.
Data Inti untuk penyimpanan lokal
Saat memilih, kriteria utama kami adalah keaslian dan integrasi dengan kerangka kerja iOS. Dan keuntungan dari Data Inti ini sangat menentukan:
- Simpan otomatis tumpukan dan data yang kami terima;
- , ( , ..)
- ;
- ;
- ;
- ;
- UI (FRC);
- (NSPredicates).
UIManaged document
Kit UI memiliki kelas bawaan yang disebut UIManagedDocument, yang merupakan subkelas UIDocument. Perbedaan utamanya adalah ketika dokumen terkelola diinisialisasi, URL ditentukan untuk lokasi dokumen di penyimpanan lokal atau jarak jauh. Objek dokumen kemudian benar-benar membuat tumpukan Data Inti langsung dari kotak, yang digunakan untuk mengakses penyimpanan persisten dokumen menggunakan model objek (.xcdatamodeld) dari paket aplikasi utama. Nyaman dan masuk akal, meskipun kita sudah hidup di abad ke-21:
- UIDocument otomatis menyimpan status saat ini, pada frekuensi tertentu. Untuk bagian yang sangat penting, kami dapat memicu penyimpanan secara manual.
- . - ā , , - , ā , , .
- UIDocument .
- Core data .
- iCloud . , .
- .
- Paradigma aplikasi berbasis dokumen digunakan - merepresentasikan model data sebagai wadah untuk menyimpan data ini. Jika kita melihat model MVC klasik dalam dokumentasi Apple, kita dapat melihat bahwa data Inti dibuat dengan tepat untuk memanipulasi model ini dan membantu kita bekerja dengan data pada tingkat abstraksi yang lebih tinggi. Pada tingkat model, kami bekerja dengan menghubungkan UIManagedDocument dengan seluruh tumpukan yang dibuat. Dan kami menganggap dokumen itu sendiri sebagai wadah yang menyimpan data Inti dan semua data dari cache (dari layar, pengguna). Selain itu, dapat berupa gambar, video, teks - informasi apa pun.
Kami menganggap aplikasi kami, peluncurannya, otorisasi pengguna, dan semua datanya sebagai sejenis dokumen (file) besar, yang menyimpan riwayat pengguna kami:
Proses
Bagaimana kami mendesain arsitektur
Proses desain kami berlangsung dalam beberapa tahap:
- Analisis spesifikasi teknis.
- Merender diagram UML. Kami terutama menggunakan tiga jenis diagram UML: diagram kelas, diagram alir, diagram urutan. Ini adalah tanggung jawab langsung dari pengembang senior, tetapi pengembang dengan pengalaman yang kurang juga dapat melakukannya. Ini bahkan diterima, karena memungkinkan Anda untuk menyelami tugas dengan baik dan mempelajari semua seluk-beluknya. Itu membantu menemukan kekurangan dalam tugas teknis, serta menyusun semua informasi tentang tugas. Dan kami mencoba mempertimbangkan sifat lintas platform aplikasi kami - kami bekerja sama dengan tim Android, menggambar diagram yang sama pada dua platform dan mencoba menggunakan pola desain utama yang diterima secara umum dari kelompok empat orang.
- Review arsitektur. Biasanya, kolega dari tim yang berdekatan melakukan peninjauan dan penilaian.
- Implementasi dan pengujian pada contoh satu modul UI.
- Penskalaan. Jika pengujian berhasil, kami menskalakan arsitektur ke seluruh aplikasi.
- Refactoring. Untuk memeriksa apakah kita melewatkan sesuatu.
Sekarang, setelah lima bulan mengembangkan proyek ini, saya dapat menunjukkan keseluruhan proses kita dalam tiga tahap: apa yang terjadi, bagaimana itu berubah dan apa yang terjadi sebagai hasilnya.
Apa yang terjadi
Titik awal kami adalah arsitektur MVC standar - ini adalah lapisan yang saling berhubungan:
- Lapisan UI, sepenuhnya diprogram menggunakan Objective C;
- Kelas presentasi (model);
- Lapisan layanan tempat kami bekerja dengan jaringan.
Indikator aktivitas terletak di tempat diagram di mana proses penerimaan data sensitif terhadap kecepatan Internet - pengguna menginginkan hasil yang cepat, tetapi dipaksa untuk melihat beberapa pemuat, indikator, dan sinyal lainnya. Ini adalah poin pertumbuhan kami dalam pengalaman pengguna:
Periode transisi
Selama masa transisi, kami harus menerapkan caching untuk layar. Tetapi karena aplikasinya besar dan berisi banyak kode Objective C lama, kita tidak bisa begitu saja mengambil dan menghapus semua layanan dan model dengan memasukkan kode Swift - kita harus memperhitungkan bahwa secara paralel dengan caching, kita masih memiliki banyak tugas produk lain dalam pengembangan.
Kami menemukan cara mudah untuk mengintegrasikan kode saat ini seefisien mungkin, tanpa merusak apa pun, dan melakukan iterasi pertama semulus mungkin. Di sisi kiri diagram sebelumnya, kami sepenuhnya menghapus semua yang terkait dengan permintaan jaringan - layanan sekarang berkomunikasi dengan DataSourceFacade melalui antarmuka. Dan sekarang ini adalah fasad tempat layanan bekerja. Ini mengharapkan dari Sumber Data data yang sebelumnya diterima dari jaringan. Dan di Sumber Data itu sendiri, logika untuk mengekstrak data ini disembunyikan.
Di sisi kanan diagram, kami telah memecah akuisisi data menjadi perintah - pola Perintah ditujukan untuk menjalankan beberapa perintah dasar dan mendapatkan hasilnya. Dalam kasus iOS, kami menggunakan pewaris NSOperation:
Setiap perintah yang Anda lihat di sini adalah operasi yang berisi unit logis dari tindakan yang diharapkan. Ini mendapatkan data dari database (atau jaringan) dan menyimpan data ini dalam data Inti. Misalnya, tugas utama AcquireCommand tidak hanya mengembalikan sumber data ke fasad, tetapi juga memberi kita kemampuan untuk mendesain kode sedemikian rupa untuk menerima data melalui fasad. Artinya, interaksi dengan operasi melewati fasad ini.
Dan tugas utama operasi adalah meneruskan data DataSource ke DataSourceFacade. Tentu saja, kami membangun logika sedemikian rupa untuk menampilkan data kepada pengguna secepat mungkin. Biasanya, di dalam DataSourceFacade, kami memiliki antrian operasional tempat kami memulai NSOperations kami. Bergantung pada kondisi yang dikonfigurasi, kami dapat memutuskan kapan menampilkan data dari cache dan kapan menerima dari jaringan. Pada permintaan pertama untuk sumber data di fasad, kita pergi ke database data Inti, mendapatkan data dari sana melalui FetchCommand (jika ada) dan langsung mengembalikannya ke pengguna.
Pada saat yang sama, kami meluncurkan permintaan paralel untuk data melalui jaringan, dan ketika permintaan ini dijalankan, hasilnya masuk ke database, disimpan di dalamnya, dan setelah itu kami menerima pembaruan dari Sumber Data kami. Pembaruan ini sudah termasuk dalam UI. Dengan cara ini kami meminimalkan waktu tunggu untuk data, dan pengguna, yang menerimanya secara instan, tidak melihat perbedaannya. Ini akan menerima data yang diperbarui segera setelah database menerima respons dari jaringan.
Bagaimana jadinya
Kami pergi ke skema yang lebih singkat (dan kami akan sampai pada akhirnya):
Sekarang dari sini kami memiliki:
- Lapisan UI,
- fasad tempat kami menyediakan Sumber Data kami,
- perintah yang mengembalikan Sumber Data ini bersama dengan pembaruan.
Apa itu Sumber Data dan mengapa kita sering membicarakannya
DataSource adalah objek yang menyediakan data untuk lapisan presentasi dan mengikuti protokol yang telah ditentukan sebelumnya. Dan protokol harus disesuaikan dengan UI kami dan menyediakan data untuk UI kami (tidak masalah untuk layar tertentu atau untuk sekumpulan layar).
Sebuah Sumber Data biasanya memiliki dua tanggung jawab utama:
- Menyediakan data untuk ditampilkan di lapisan UI;
- Memberi tahu lapisan UI tentang perubahan data dan mengirimkan kumpulan perubahan yang diperlukan ke layar saat kami menerima pembaruan.
Kami menggunakan beberapa varian DataSource di sini, karena kami memiliki banyak kode warisan Objective C - artinya, kami tidak dapat dengan mudah menempelkan Swift DataSource kami di mana-mana. Kami juga belum menggunakan koleksi di mana-mana, tetapi di masa mendatang kami akan menulis ulang kode secara khusus untuk menggunakan layar CollectionView.
Contoh dari salah satu Sumber Data kami:
Ini adalah Sumber Data untuk koleksi (disebut CollectionDataSource) dan ini adalah kelas yang cukup sederhana dalam hal antarmuka. Dibutuhkan koleksi yang dikonfigurasi oleh fetchedResultsController dan CellDequeueBlock. Di mana CellDequeueBlock adalah tipe alias di mana kami menjelaskan strategi untuk membuat sel.
Artinya, kita membuat DataSource dan menugaskannya ke koleksi dengan memanggil performFetch pada fetchedResultsController, lalu semua keajaiban ditetapkan ke interaksi kelas DataSource kita, fetchedResultsController dan kemampuan delegasi untuk menerima pembaruan dari database:
FetchedResultsController adalah jantung dari DataSource kita. Anda akan menemukan banyak informasi tentang bekerja dengannya di dokumentasi Apple. Sebagai aturan, kami menerima semua data dengan bantuannya - baik data baru maupun data yang telah diperbarui atau dihapus. Pada saat yang sama, kami secara bersamaan meminta data dari jaringan. Segera setelah data diterima dan disimpan dalam database, kami menerima pembaruan dari Sumber Data, dan pembaruan tersebut datang kepada kami di UI. Artinya, dengan satu permintaan, kami menerima data dan menampilkannya di tempat yang berbeda - keren, nyaman, asli!
Dan di mana pun dimungkinkan untuk menggunakan Sumber Data yang sudah jadi dengan tabel atau dengan koleksi, kami melakukannya:
Di tempat-tempat di mana kami memiliki banyak layar dan tidak menggunakan tabel dan koleksi (dan kami menggunakan tata letak pemrograman Objective C), kami mengevaluasi data apa yang kami butuhkan untuk layar, dan melalui protokol kami menjelaskan Sumber Data kami. Setelah itu, kami menulis fasad - sebagai aturan, ini juga merupakan protokol Objective C publik yang melaluinya kami meminta Sumber Data kami. Dan pintu masuk ke kode Swift sedang berlangsung.
Segera setelah kami siap untuk mentransfer layar sepenuhnya ke implementasi Swift, itu sudah cukup untuk menghapus pembungkus Objective C - dan, berkat DataSource khusus, kami dapat bekerja langsung dengan protokol Swift.
Saat ini kami menggunakan tiga varian utama Sumber Data:
- TableViewDatasource + strategi sel (strategi untuk membuat sel);
- CollectionViewDatasource + strategi sel (opsi dengan koleksi);
- CustomDataSource adalah opsi kustom. Kami paling sering menggunakannya sekarang.
hasil
Setelah semua langkah untuk merancang, menerapkan, dan berinteraksi dengan kode warisan, bisnis menerima perbaikan berikut:
- Kecepatan pengiriman data ke pengguna meningkat secara signifikan karena cache. Ini mungkin hasil yang jelas dan logis.
- Kami sekarang selangkah lebih dekat ke paradigma pertama offline.
- Proses tinjauan lintas platform arsitektur telah disiapkan dalam tim iOS & Android - semua pengembang yang terlibat dalam proyek ini memiliki informasi dan dengan mudah bertukar pengalaman antar tim.
- . , , legacy , .
- , ā . , , , , , .
Bonusnya bagi kami adalah kami memahami bagaimana bekerja dengan arsitektur dan diagram bisa menarik dan menyenangkan (dan ini membuat pengembangan lebih mudah). Ya, kami menghabiskan banyak waktu untuk menggambar dan menyelaraskan pendekatan arsitektural kami, tetapi ketika sampai pada implementasi, kami menskalakan dengan sangat cepat di semua layar.
Jalan kita ke Offline pertama berlanjut - kita tidak hanya perlu caching untuk menjadi offline, tetapi juga pengguna dapat bertindak tanpa koneksi jaringan, dengan sinkronisasi lebih lanjut dengan server setelah Internet muncul.
Tautan
- Panduan pemrograman berbasis dokumen . Ini adalah dokumen yang agak lama, Apple tidak lagi merekomendasikan untuk menggunakannya. Tetapi saya akan merekomendasikan mencari setidaknya untuk pengembangan tambahan. Ada banyak informasi berguna di sana.
- Document-based WWDC:
- DataSources
Apps Live 2020 .
ā Android iOS, . , , .