Désordre au départ: post-mortem sur la vitesse de lancement d'une application iOS

Une application moderne a de nombreuses exigences non fonctionnelles: taille de l'application, trafic consommé, accessibilité pour les personnes handicapées, stabilité, vitesse de démarrage et de fonctionnement. Notre application a démarré très longtemps, des dizaines de secondes. Aujourd'hui, une mise à jour a été publiée dans laquelle l'application iOS a commencé à s'exécuter beaucoup plus rapidement. Je vous dis comment c'est arrivé et pourquoi seulement maintenant.



Ça commence depuis longtemps


L'application a beaucoup de code, beaucoup de classes et elles sont en quelque sorte connectées. Pour gérer ces relations, nous avons utilisé Dip (lire: Swinject ou tout autre framework DI sans génération de code).

Cela fonctionne comme ceci: au démarrage de l'application, toutes les dépendances sont entassées dans le "conteneur", puis la classe souhaitée en est extraite avec toutes les dépendances supprimées. Il faut du temps pour démarrer, il faut du temps pour ouvrir n'importe quel écran.

Mais les photos sont belles


Pendant longtemps, cela ne nous a même pas effrayé: nous avons juste dessiné de beaux économiseurs d'écran avec de nouvelles pizzas et n'avons pas cuit à la vapeur. Les économiseurs d'écran de pizza ont dû être supprimés lorsque nous avons commencé dans plusieurs pays, car l'assortiment est différent partout. La photo est devenue moins intéressante, attendre le lancement est devenu plus ennuyeux, mais nous avons raté ce point.

Voici nos éclaboussures. Magnifique, mais cachant un problème que nous n'avons même pas essayé de résoudre.



Après la prochaine version, nous avons commencé à ralentir la rotation des cartes dans le contrôleur de page. Time profiler a montré que les dépendances sont supprimées pendant longtemps lorsqu'un nouvel écran apparaît. Pourquoi C'est impossible à comprendre. Le dip est très difficile à déboguer en raison des mêmes appels abstraits. Nous avons essayé de briser un conteneur commun en plusieurs petits, mais cela n'a fait qu'empirer. En conséquence, nous avons désactivé les cartes retournées et poursuivi les mises à jour du Nouvel An.

Voici à quoi ressemble Dip dans le profileur. À la fin de la liste, la limite de pile d'appels est atteinte. Il est impossible de faire quelque chose de raisonnable avec cela.



Vole vers 4S? Réparer plus tard


À ce moment, le bogue «n'a pas démarré la version de build sur 4S» se trouvait dans le backlog, bien que ceux de débogage aient été lancés. Personne n'a remarqué la connexion de problèmes, a augmenté la version minimale d'iOS à 10 et a également reporté les modifications. Il y a peu d'utilisateurs sur 4S, non?

Nous avons vu Dip: pas au début, mais à la compilation


Cependant, il est devenu clair que Dip devait être coupé. Et que changer? Très opportun, nous sommes tombés sur l'article sur l'injection de dépendance dans Swift .

Cela fonctionne simplement: nous écrivons un tas de fonctions resolve() avec un type différent (le compilateur le comprendra). Ainsi, les communications cesseront d'être calculées au début et le compilateur pourra même optimiser le code. Ceci est également utile pour le développement: si vous avez décrit les dépendances de manière incorrecte, vous en serez informé au démarrage, et non lorsque vous ouvrirez l'écran. Bien sûr, il y a des problèmes: si la fonction resolve() ne comprend pas le type, alors elle produira une telle erreur inutile avec une centaine de candidats:



Nous l'avons fait en novembre. Il y a eu BEAUCOUP de changements, et à ce moment-là, nous avons lancé le nouveau produit Combo et nous nous sommes préparés aux derniers changements avant la nouvelle année. Le nouveau code est apparu dans le projet avant le Nouvel An, mais nous ne l'avons publié qu'en janvier en raison du gel de code avant les vacances. Pour cela, pendant trois semaines, nous avons utilisé le programme en mode test, trouvé des problèmes et les avons corrigés.

Voici à quoi ressemble le code de dépendance maintenant. Sale mais fonctionnant. 450 places avec inscription et 1400 places avec extraction.



Fonctionnellement, le code est le même, seule la façon de travailler avec lui diffère. La différence de vitesse est visible sur tous les modèles. Sur XS - deux fois plus vite, et sur SE voyez par vous-même:


Nous avons donc accéléré non seulement le démarrage, mais aussi l'ouverture des écrans. Avant les modifications, chaque écran ne prenait que 0,3 à 1 seconde uniquement en fonction de la dépendance.

Nouvel an sans pizza


En décembre, ils ont commencé à nous écrire que l'application se bloque au démarrage, ne démarre pas, et après le redémarrage, la réinstallation n'aide pas. Auparavant, il n'y avait qu'une seule raison à cela: les migrations de bases de données, mais nous nous en sommes débarrassées et nous n'avons pas vu de nouveaux départs dans Crashlytics. Qu'est-ce qui a mal tourné?


Hypothèse: cet iOS supprime les applications si elles fonctionnent pendant une longue période. La version a été confirmée par le fait que toutes les critiques provenaient d'anciens appareils: 5, 5S, 6. Le nombre de ces critiques a considérablement augmenté, car la pizza est un jour férié, les gens la commandent souvent pour le Nouvel An. L'équipe est inquiète, le produit est inquiet, mais nous ne déployons la nouvelle version qu'en janvier.

Nous avons eu la chance que la solution ait été écrite et ne puisse être testée. Dans un autre scénario, des mois pourraient être consacrés à rechercher des causes et à les corriger.



Parfois, il est difficile de transmettre l'importance d'une tâche technique à une entreprise: il n'y a pas de paramètres, l'importance n'est pas claire, le danger n'est pas prévu. Les entreprises peuvent résoudre le problème de différentes manières: c'est ainsi que nous avons peint de belles images, plutôt que d'accélérer l'application. Mais les performances sont importantes pour chaque utilisateur. Cela affecte grandement:

  • J'attends. Si l'application démarre depuis longtemps, combien de temps prendront-ils une pizza?
  • Le plaisir d'utiliser. Pourquoi stupide sur tous les écrans?
  • Et même pour la stabilité. «L'application ne fonctionne pas !!! Développeurs, faites-vous des tests là-bas? »(C).

Et contournez Dip, Swinject et d'autres frameworks qui fonctionnent avec des conteneurs en temps réel si vous avez un grand projet et beaucoup de dépendances.
Pour ne pas manquer le prochain article, abonnez-vous à la chaîne Dodo Pizza Mobile.

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


All Articles