Meilleures pratiques et outils du projet iOS

Avec un modèle de projet Xcode open source

Lorsque je travaillais sur de nouveaux projets iOS, je devais souvent commencer un nouveau projet à partir de zéro. Ce faisant, mon équipe et moi avons toujours passé beaucoup de temps sur la configuration de base d'un projet, comme l'intégration d'outils, la structure de projet, la rédaction de classes de base, l'intégration de bibliothèques externes, etc.

J'ai décidé que le temps passé au démarrage du projet pourrait être économisé et que le processus pourrait être principalement automatisé. J'ai écrit toutes les meilleures pratiques et outils habituels que nous avons utilisés et préparé un modèle de projet que mon équipe et moi-même pourrions utiliser pour démarrer de nouveaux projets. Ce modèle doit permettre de gagner du temps lors de la configuration du projet et de fournir une base commune à laquelle chaque membre de l’équipe sera habituée, de sorte que vous n’aurez pas à réfléchir ni à explorer la structure et les bases du projet. Ils seront toujours les mêmes.

Chaque outil ou meilleure pratique inclus dans le modèle mérite un article à lui seul, mais je voulais essayer de résumer chaque point et d’expliquer brièvement pourquoi je les ai inclus.

Cocoapods

Je ne pense pas que celui-ci a besoin d’une introduction. Il s'agit de la bibliothèque de gestion des dépendances externes pour les projets iOS. Il existe depuis longtemps, il est robuste et a fait l’objet de milliers de projets, voire de millions, au test de combat. Il existe des gestionnaires de dépendances alternatifs comme Carthage, mais j'ai décidé de choisir Cocoapods, car celui-ci possède la plus large gamme de projets open source pris en charge. Utiliser Cocoapods est très facile et vient avec un index de recherche qui vous permet de découvrir facilement les forfaits dont vous pourriez avoir besoin.

Le projet de modèle est fourni avec un fichier Podfile simple comprenant Swiftlint et R. Swift. Le modèle inclut également un Gemfile pour gérer la version de Cocoapods utilisée pour résoudre les dépendances. Il s'agit d'une amélioration souvent négligée qui évite les problèmes lorsque les développeurs de votre équipe installent des dépendances à l'aide de différentes versions de Cocoapods. Gemfile applique la même version de Cocoapod à l’ensemble de l’équipe.

Swiftlint

Swiftlint est un outil très utile pour appliquer certaines règles et styles de codage à tous les programmeurs de l'équipe. Vous pouvez penser à cela comme à un système automatisé de révision de code qui avertit le programmeur de choses dangereuses telles que le déroulage forcé, le lancement forcé, les tentatives forcées, etc. comme les règles d'indentation ou d'espacement. Cela présente d’énormes avantages, car il permet non seulement d’économiser du temps d’examen du code en effectuant ces vérifications de base, mais il permet également à tous les fichiers du projet de se familiariser, ce qui améliore leur lisibilité et, partant, leur compréhension par tous les développeurs. Vous pouvez trouver une liste de toutes les règles ici. Dans le modèle, Swiftlint est installé via Cocoapods et inclus dans l’étape Construire les phases de manière à lisser et avertir le développeur à chaque génération de projet.

Rift

R.swift est un outil permettant d'obtenir des ressources de saisie semi-automatique fortement typées, telles que des images, des séquences de polices et des localisations. Pour ce faire, il analyse votre projet et génère les classes rapides nécessaires pour obtenir les ressources. Le principal argument de vente de cette bibliothèque est que, tout en utilisant des ressources, cela crée votre code:

  • Entièrement typé - moins d'incertitude et de deviner ce qu'une méthode retournera
  • Heure de compilation vérifiée - plus de chaînes incorrectes qui font planter votre application au moment de l'exécution
  • Complété automatiquement - ne jamais avoir à deviner ce nom d'image / nib / storyboard

Considérez le code suivant en utilisant l'API de chaîne officielle:

let icon = UIImage (nommé: “custom-icon”)

Si vous mal orthographiez le nom de l'image, vous obtiendrez un zéro ici. Si un membre de votre équipe change le nom de la ressource image, ce code retournera la valeur nil ou se plantera si vous forcez le déballage de l'image. En utilisant R. Swift, cela devient:

let icon = R.image.customIcon ()

Maintenant, vous pouvez être sûr que l'icône existe vraiment (le compilateur vous avertira si ce n'est pas le cas grâce aux contrôles de compilation) et vous êtes sûr de ne pas faire de faute de frappe dans le nom de l'icône puisque vous utiliserez la complétion automatique.

Rswift est installé via Cocoapods et intégré dans le modèle en tant que phase de construction et générera les classes d'encapsuleur Swift sur chaque construction. Cela signifie que si vous ajoutez un fichier / image / localisation / police / couleur / nib, etc., il sera disponible pour vous à l'aide de R.swift une fois le projet compilé.

Séparez AppDelegate pour les tests

Une bonne pratique souvent négligée consiste à avoir une classe TestAppDelegate séparée lors de l'exécution de tests. Pourquoi est-ce une bonne idée? En règle générale, la classe AppDelegate effectue beaucoup de travail au démarrage de l'application. Il peut configurer une fenêtre, créer la structure d'interface utilisateur de base de l'application, s'inscrire pour recevoir des notifications, configurer une base de données et même parfois faire des appels d'API à un service backend. Les tests unitaires ne devraient avoir aucun effet secondaire. Voulez-vous vraiment faire des appels d'API aléatoires et configurer toute la structure d'interface utilisateur de votre application simplement pour exécuter des tests unitaires?

TestAppDelegate est également un excellent endroit pour que le code que vous ne voulez exécuter qu'une seule fois lors de l'exécution de votre suite de tests. Il pourrait contenir du code qui génère des requêtes génériques, des requêtes de réseau, etc.

Le modèle contient un fichier main.swift qui constitue le point d'entrée principal de l'application. Ce fichier contient des méthodes qui vérifient l’environnement en cours d’application et, s’il s’agit de l’environnement de test, appelle TestAppDelegate.

Indicateurs de profilage des performances du compilateur

Swift est un excellent langage, plus facile à utiliser et beaucoup plus sûr que Objective-C (IMO). Mais quand il a été introduit pour la première fois, il y avait un gros inconvénient: la compilation. À l’époque des 2 jours de Swift, je travaillais sur un projet comportant 40 lignes de code Swift (un projet de taille moyenne). Le code était très lourd en génériques et en inférence de type et il a fallu près de 5 minutes pour compiler une version propre. Même lorsque vous apportiez une petite modification, le projet se recompilait et prenait environ 2 minutes pour voir la modification. Ce fut l’une des pires expériences de développement que j’ai jamais vécues et j’ai presque cessé d’utiliser Swift à cause de cela.

La seule solution à l'époque était d'essayer de définir les temps de compilation du projet et de modifier votre code de manière à accélérer le compilateur. Pour aider avec cela, Apple introduit des drapeaux de compilateur non officiels qui vous avertiraient lorsque la compilation du corps d'une méthode ou la résolution du type d'une expression prenait trop de temps. J'ai ajouté ces indicateurs au projet de modèle afin que vous soyez averti dès le début des longs temps de compilation pour votre application.

De nos jours, les temps de compilation ont été considérablement améliorés et vous avez très rarement besoin de modifier votre code simplement pour améliorer les temps de compilation. Mais il vaut toujours mieux savoir à l’avance que d’essayer de régler le problème lorsque le projet devient trop volumineux.

Configurations Dev / Staging / Production

Une autre bonne pratique (ou devrais-je dire nécessité) consiste à avoir des configurations et des variables d'environnement distinctes pour les environnements de développement, de transfert et de production. De nos jours, presque toutes les applications doivent se connecter à un type de service principal et, généralement, ces services sont déployés sur plusieurs environnements. L'environnement de développement est utilisé pour les déploiements quotidiens et pour que les développeurs testent leur code. L'environnement de transfert est utilisé pour les versions stables que les testeurs et les clients peuvent tester. Nous savons tous à quoi sert l'environnement de production.

Une façon de prendre en charge plusieurs environnements dans un projet iOS consiste à ajouter des configurations au niveau du projet.

Configurations au niveau du projet

Une fois les configurations définies, vous pouvez créer un fichier Configuration.plist contenant les variables pour chaque environnement.

Configuration.plist

Lors de l'exécution du projet, vous pouvez spécifier quelle configuration doit être utilisée. Vous pouvez le faire dans le schéma de construction.

Vous devez ensuite ajouter une propriété supplémentaire dans le fichier Info.plist du projet. La valeur de cette propriété sera résolue dynamiquement au moment de l'exécution avec le nom de la configuration actuelle.

Tout cela est préconfiguré pour vous dans le modèle.

Il ne reste plus qu'à écrire une classe capable de récupérer ces variables lors de l'exécution, en fonction de la configuration sélectionnée dans le schéma de construction. Le modèle contient une classe ConfigurationManager capable d'extraire les variables de l'environnement actuel. Vous pouvez vérifier l'implémentation de cette classe sur Github pour voir comment cela fonctionne.

Lisez moi

Chaque projet doit avoir un fichier Readme de base qui contient au moins des instructions pour installer des dépendances et exécuter le projet. Il devrait également contenir une description de l'architecture du projet et des modules. Malheureusement, les développeurs n’aiment pas écrire de la documentation (un fichier readme en fait partie) et j’ai vu des projets en cours de développement pendant des mois et ils disposaient même d’un fichier Readme de base. Pour alléger ce fichier, le modèle contient un fichier Lisez-moi standard qui couvre l’installation et la structure du projet. Lorsque vous configurez un nouveau projet à l'aide du modèle, le fichier Lisez-moi est automatiquement inclus.

Gitignore

De nos jours, la plupart des projets utilisent GIT comme système de contrôle de version. Lorsque vous utilisez GIT, vous ne devez généralement pas ignorer certains fichiers ou dossiers du projet, tels que le dossier de construction ou le dossier de données dérivé. Pour vous éviter de chercher un fichier gitignore adapté à votre projet iOS, le modèle inclut un gitignore standard fourni par les contributeurs de Github.

Classes de base pour la gestion des liens profonds et des notifications

De nos jours, presque toutes les applications doivent gérer les liens profonds et les notifications. Pour ce faire, un développeur doit écrire une certaine quantité de code d'exécution dans la classe AppDelegate. Le modèle est couvert et fournit également des classes de base qui facilitent l'utilisation des liens profonds et des notifications.

Sommaire

En résumé, le modèle tente d'inclure les meilleures pratiques et intègre des outils tiers utiles. Cela devrait vous permettre, à vous et à notre équipe, de vous épargner des heures consacrées à la configuration du nouveau projet et de fournir une base solide et commune au reste du projet. Que cela vous serve bien!

PS: Si vous avez des problèmes ou des demandes de fonctionnalités pour le modèle, laissez-moi un problème sur Github. Je vais essayer de le résoudre pendant mon temps libre.