Réusinage de code legacy en Swift : de A à Z

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Réusinage de code legacy en Swift : de A à Z

\n

Travailler avec du code obsolète (legacy code) est une partie inévitable de la vie du développeur iOS/macOS. Il s'agit souvent de code écrit dans les premières versions de Swift ou même en Objective-C, dépourvu de tests, avec des "nombres magiques" et des UIViewController gigantesques. Dans cet article, nous allons détailler une stratégie étape par étape pour réusiner ce code, le transformant en un projet moderne, maintenable et testable.

\n\n

1. Préparation et sécurité : avant de toucher au code

\n

La règle la plus importante du réusinage : ne casse pas ce qui fonctionne. Sans tests, tout changement est un saut dans l'inconnu.

\n
    \n
  • Tests de caractérisation (Characterization Tests) : Écrivez des tests qui figent le comportement actuel. Même si le code semble incorrect, documentez d'abord son fonctionnement.
  • \n
  • Système de contrôle de version : Faites un commit avec l'état actuel. Utilisez une branche de fonctionnalité (feature branch).
  • \n
  • Outils : Xcode avec Edit > Refactor (Renommer, Extraire une méthode), ainsi que des linters (SwiftLint) pour respecter un style uniforme.
  • \n
\n\n
// Exemple de "gel" du comportement pour une ancienne méthode\nclass LegacyCalculator {\n    func calculateTotal(items: [Int]) -> Int {\n        // Ancienne logique illisible\n        var result = 0\n        for i in items {\n            result += i * 2\n        }\n        return result + 10\n    }\n}\n\n// Test qui fige le comportement\nfunc testCalculateTotal() {\n    let sut = LegacyCalculator()\n    let result = sut.calculateTotal(items: [1, 2, 3])\n    XCTAssertEqual(result, 22) // (1+2+3)*2 + 10 = 22\n}\n
\n\n

2. Stratégie "Homme de paille" : Variables globales et singletons

\n

Le code legacy est tristement célèbre pour ses états globaux et ses singletons. Cela rend le code fortement couplé et imprévisible.

\n

Problème :

\n
class NetworkManager {\n    static let shared = NetworkManager()\n    var baseURL: String = "http://old.api.com"\n    func fetchData() { ... }\n}\n
\n

Solution : Injection de dépendances (Dependency Injection). Créez un protocole et transmettez les dépendances via l'initialiseur.

\n
protocol NetworkService {\n    func fetchData()\n}\n\nclass ModernViewModel {\n    private let network: NetworkService\n    \n    init(network: NetworkService) {\n        self.network = network\n    }\n    \n    func load() {\n        network.fetchData()\n    }\n}\n
\n

Cette approche permet de remplacer facilement les services dans les tests et rend le code modulaire.

\n\n

3. Lutte contre le "Contrôleur massif" (Massive View Controller)

\n

Un classique du legacy iOS : un UIViewController qui gère tout, des requêtes réseau au formatage de l'interface utilisateur. Le réusinage passe par la séparation des responsabilités (SRP).

\n\n

Étape 1 : Extrayez la logique métier dans un modèle séparé (ViewModel).

\n
// Avant, dans le contrôleur\nfunc buttonTapped() {\n    let data = fetchData()\n    let total = data.reduce(0, +)\n    label.text = "Somme : \\(total)"\n}\n\n// Après : ViewModel\nclass MyViewModel {\n    func calculateTotal(data: [Int]) -> String {\n        let total = data.reduce(0, +)\n        return "Somme : \\(total)"\n    }\n}\n
\n\n

Étape 2 : Externalisez la configuration de l'interface utilisateur dans des méthodes ou des fabriques séparées.

\n
    \n
  • Créez une classe ViewBuilder pour les hiérarchies complexes.
  • \n
  • Utilisez UICollectionViewDiffableDataSource à la place de l'ancien dataSource.
  • \n
\n\n

4. Modernisation : d'Objective-C à Swift et aux nouvelles API

\n

Le code legacy contient souvent un mélange d'Objective-C et de Swift. Lors du réusinage, il est important de mettre à jour les constructions obsolètes :

\n\n
    \n
  • Remplacement de NSError par throws : Le Swift moderne utilise les exceptions pour la gestion des erreurs.
  • \n
  • Abandon de ! (
  • \n

Blogs

Book Recommendations