Code Review en Swift : quoi vérifier et comment donner un retour d'expérience en pratique
\n\nLe code review n'est pas une simple formalité, mais un outil puissant pour améliorer la qualité du code, diffuser les connaissances au sein de l'équipe et prévenir les bugs. Cependant, si l'on aborde la revue de manière formelle ou, au contraire, trop agressive, elle peut causer plus de mal que de bien. Dans cet article, nous allons détailler sur quoi porter spécifiquement votre attention lors de la revue de code Swift pour iOS et macOS, et comment formuler un retour d'expérience utile sans blesser vos collègues.
\n\n1. Architecture et conception : voir à la racine
\n\nAvant de plonger dans les détails d'implémentation, évaluez l'architecture globale de la solution. Un bon code ne se limite pas à la syntaxe, c'est aussi une question de structure.
\n\n- \n
- Principe de responsabilité unique (SRP) : La classe/fonction n'essaie-t-elle pas d'en faire trop ? Par exemple, le ViewController ne mélange-t-il pas la logique métier et les requêtes réseau ? \n
- MVVM / MVC / VIPER : Le code respecte-t-il le modèle choisi ? Si le projet utilise MVVM, la ViewModel ne doit pas importer
UIKit. \n - Gestion des dépendances : Utilise-t-on l'injection de dépendances (DI) ou les objets sont-ils créés en interne ? Les dépendances rigides compliquent les tests. \n
- Gestion de la mémoire : Y a-t-il des fuites ? Vérifiez les closures
@escaping, les références fortes àselfet les éventuelles captures cycliques. \n
// Mauvais : référence forte à self dans une closure\nclass NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n URLSession.shared.dataTask(with: URL(string: "https://api.example.com")!) { data, _, _ in\n self.onComplete?() // Fuite ! La closure maintient une référence forte à self\n }.resume()\n }\n}\n\n// Bon : utilisation de [weak self]\nclass NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n URLSession.shared.dataTask(with: URL(string: "https://api.example.com")!) { [weak self] data, _, _ in\n DispatchQueue.main.async {\n self?.onComplete?()\n }\n }.resume()\n }\n}\n\n2. Sécurité des types et optionnalité : exploiter la puissance de Swift
\n\nSwift est un langage à typage fort, et le code review doit le refléter. Évitez le "code ObjC dans une enveloppe Swift".
\n\n- \n
- Force unwrapping : Y a-t-il des
!là où on pourrait les éviter ? Utilisezguard letouif let. \n - Énumérations (Enums) : Sont-elles utilisées à la place de constantes chaînes de caractères ? Par exemple, pour les statuts de réponse ou les types d'erreurs. \n
- Type Result : L'erreur est-elle gérée via
Result<Success, Failure>au lieu de retourner une valeur optionnelle et une erreur séparée ? \n - Generic : Dans quelle mesure l'utilisation de génériques est-elle appropriée ? Parfois, ils complexifient le code inutilement. \n
// Mauvais : force unwrap et constantes chaînes de caractères\nfunc getUser(id: String!) -> User? {\n if id == "admin" {\n return User(name: "Admin")\n }\n return nil\n}\n\n// Bon : enum et extraction sécurisée\nenum UserType: String {\n case admin\n case regular\n}\n\nfunc getUser(id: String?) -> User? {\n guard let userId = id, let userType = UserType(rawValue: userId) else {\n return nil\n }\n // ... logique\n return User(name: userType.rawValue)\n}\n\n3. Performance et travail avec l'UI : préserver la batterie et les FPS
\n\nPour les applications iOS/macOS, la fluidité des animations et l'efficacité énergétique sont cruciales. Portez attention à :
\n\n- \n
- Thread principal : Toutes les mises à jour de l'interface utilisateur doivent se faire sur le thread principal. Vérifiez qu'il n'y a pas d'appels à
UIViewouNSViewdepuis des files d'attente en arrière-plan. \n - Calculs lourds : Les calculs complexes ne sont-ils pas effectués sur le thread principal ? \n