Hai, Habr. Nama saya Anton Potapov, saya adalah pengembang iOS di
FINCH . Hari ini saya ingin berbicara secara rinci tentang bagaimana menerjemahkan proyek seluler ke GraphQL, menjelaskan pro dan kontra dari pendekatan ini. Mari kita mulai.
Pengantar singkat
"Warisan." Saya pikir semua orang mendengar kata mengerikan ini, dan sebagian besar bertemu muka dengannya. Karenanya, Anda tidak perlu memberi tahu betapa sulitnya mengintegrasikan fitur baru dan hebat ke dalam proyek Anda.

Salah satu proyek kami adalah aplikasi untuk perusahaan lotre besar (saya tidak bisa memberi nama sejak NDA). Baru-baru ini, saya perlu menerjemahkannya ke GraphQL tanpa kehilangan akal.
Proyek ini sangat besar - pada pandangan pertama, perlu menghabiskan setidaknya 200-300 jam, tetapi ini melampaui semua kemungkinan sprint dua minggu. Kami juga tidak dapat mengalokasikan seluruh sprint hanya untuk satu tugas, karena ada juga fitur samping, yang tidak kalah pentingnya dari GraphQL.
Kami sudah lama berpikir apa yang harus dilakukan dan memutuskan untuk menerjemahkan proyek langkah demi langkah, model demi model. Dengan pendekatan ini, transisi akan mulus, dan 200-300 jam akan didistribusikan dalam beberapa sprint.
Poin teknis
Untuk mengerjakan proyek, saya menggunakan perpustakaan Apollo.
Sudah ada artikel tentang Habré yang menjelaskan semua seluk-beluk bekerja dengannya, jadi saya tidak akan mengulanginya lagi. Saya memperingatkan Anda sebelumnya - bekerja dengan model yang dihasilkan kode tidak terlalu nyaman dan lebih baik menyimpannya sebagai "jaringan". Setiap entitas berisi __typename: bidang String, yang, anehnya, mengembalikan nama jenis.
Dekomposisi tugas
Hal pertama yang harus dilakukan adalah menentukan model Legacy mana yang akan kami terjemahkan ke dalam GraphQL. Dalam kasus saya, logis untuk menerjemahkan salah satu model GameInfo besar, dan DrawInfo tertanam di dalamnya.
- GameInfo - berisi informasi tentang permainan lotere dan undian.
- DrawInfo - berisi data tentang sirkulasi
Setelah menyelesaikan pilihan, saya memutuskan untuk menginisialisasi model lama dengan yang baru diperoleh dengan GraphQL. Dengan pendekatan ini, tidak perlu mengganti bagian-bagian aplikasi di mana model lama digunakan. Menyelesaikan model sebelumnya sepenuhnya berisiko - bukan fakta bahwa proyek akan bekerja seperti sebelumnya, dan itu akan memakan waktu terlalu banyak.
Secara total, ada tiga tahap implementasi GraphQL:
- Ciptaan pelanggan;
- Membuat penginisialisasi untuk model Legacy;
- Mengganti permintaan API dengan GraphQL.
GraphQLClient
Seperti halnya klien mana pun, GraphQLClient harus memiliki metode pengambilan, setelah itu akan memuat data yang kami butuhkan.
Menurut pendapat saya, metode mengambil untuk GraphQLClient harus mengambil enum, berdasarkan permintaan yang sesuai akan dieksekusi. Pendekatan ini akan memungkinkan kita untuk dengan mudah menerima data untuk entitas yang diinginkan atau bahkan layar. Jika permintaan menerima parameter, maka mereka akan diteruskan sebagai nilai terkait. Dengan pendekatan ini, lebih mudah menggunakan GraphQL dan membuat kueri yang fleksibel.
enum GraphQLRequest { case image(ImageId?) }
Klien GraphQL kami yang disesuaikan harus mengandung ApolloClient yang dikustomisasi untuk fitur yang ada, serta metode pengambilan pemuatan yang disebutkan di atas.
func fetch<Response>(requestType: GraphQLRequest, completion: @escaping (QLRequestResult<Response>) -> Void)
Apa itu QLRequestResult? Itu biasa
typealias QLRequestResult<Response> = Result<Response, APIError>
Metode pengambilan memungkinkan Anda untuk mengakses klien melalui protokol dan melakukan pergantian pada requestType. Bergantung pada requestType, Anda dapat menggunakan metode pemuatan pribadi terkait, tempat Anda dapat mengonversi model yang dihasilkan ke yang lama. Sebagai contoh:
private func fetchGameInfo<Response>(gameId: String? = "", completion: @escaping (QLRequestResult<Response>) -> Void) {
Hasilnya, kami mendapatkan model lama yang sudah jadi yang diperoleh dari GraphQL.
Jenis skalar
Dalam dokumentasi GraphQL, tipe skalar dijelaskan sebagai berikut: "Tipe skalar adalah pengidentifikasi unik yang sering digunakan untuk memilih ulang objek atau sebagai kunci untuk cache." Untuk cepat, tipe skalar dapat dengan mudah dikaitkan dengan typealias.
Saat menulis klien, saya mengalami masalah bahwa dalam skema saya ada jenis skalar Long, yang pada dasarnya
typealias Long = Int64
Semuanya akan baik-baik saja, tetapi Apollo secara otomatis melemparkan semua skalar pengguna ke String, yang menyebabkan crash. Saya memecahkan masalah seperti ini:
Di masa depan, untuk setiap jenis skalar, Anda perlu menambahkan typealias baru. Dengan Apollo versi 14.0, mereka menambahkan "dukungan untuk skal khusus Int." Jika Anda ingin menghindari menggunakan pendekatan ini dan bendera di codegen, maka periksa solusi untuk masalah ini di
Apollo git .
Pro dan kontra
Mengapa pendekatan ini bagus? Transisi yang cukup cepat untuk menggunakan GraphQL, mengenai pendekatan dengan menghapus semua model lama.
Di masa depan, ketika kita perlu mendapatkan data untuk layar / model apa pun, kita dapat beralih ke GraphQLClient dan mendapatkan data yang diperlukan.
Dari minus:
- Mengkonversi jenis model di klien, seseorang dapat mentransfer ke entitas lain sejak itu bekerja dengan data bukan tanggung jawab klien.
- Grafik LuasQLClient. Setelah menambahkan kueri baru, kelas kami akan tumbuh semakin besar. Salah satu solusinya adalah ekstensi di mana metode pemuatan akan dijelaskan, yang saya bicarakan di bab GraphQLClient.
Kesimpulan
Secara umum, beralih ke GraphQL bisa cepat dan tidak menyakitkan dengan klien yang ditulis dengan baik. Butuh waktu sekitar tiga hari = 24 jam kerja. Selama waktu ini, saya berhasil membuat klien, menerjemahkan model dan membuat kembali model GameInfo. Pendekatan yang diuraikan bukanlah obat mujarab, tetapi murni keputusan saya, dilaksanakan dalam waktu singkat.
Jika Anda memiliki guru GraphQL di antara Anda, saya sarankan berbagi pengalaman Anda dan mengatakan betapa nyamannya menggunakan GraphQL + Apollo dalam proyek-proyek besar. Atau apakah gamenya tidak bernilai lilin?
Terima kasih atas perhatian anda!