Refactoring von Legacy-Code in Swift: Von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Refactoring von Legacy-Code in Swift notwendig ist

Jeder iOS/macOS-Entwickler stößt früher oder später auf Legacy-Code. Das kann ein Projekt sein, das in Objective-C geschrieben und teilweise nach Swift migriert wurde, oder eine App, die in der Swift 2.0-Ära mit Massive View Controller erstellt wurde. Solcher Code funktioniert oft, aber seine Wartung wird zur Hölle: Jede Änderung erfordert stundenlanges Testen, und das Hinzufügen einer neuen Funktion zerstört alte.

Refactoring von Legacy-Code in Swift ist nicht nur "Code aufhübschen". Es ist ein strategischer Prozess, der die App testbarer, erweiterbarer und leistungsfähiger macht. In diesem Artikel analysieren wir, wie man das Refactoring richtig angeht, mit Beispielen in Swift, um die Produktion nicht zu beschädigen und ein funktionierendes Ergebnis zu erzielen.



1. Diagnose: Wie erkennt man, dass Legacy-Code refactoringbedürftig ist

Bevor Sie Code ändern, müssen Sie verstehen, was genau geändert werden muss. Hauptmerkmale von Legacy-Code in Swift:

  • Massive View Controller (MVC-Antipattern) — Dateien mit 500+ Zeilen, in denen Logik, UI und Netzwerkanfragen in einer Klasse vermischt sind.
  • Starke Kopplung (tight coupling) — Klassen hängen direkt voneinander ab, es gibt keine Protokolle und Dependency Injection.
  • Fehlende Tests — wenn Sie Angst haben, eine Codezeile zu ändern, weil Sie nicht wissen, was kaputtgeht.
  • Globale Variablen und Singletons — Verwendung von UserDefaults.standard oder NotificationCenter.default im gesamten Projekt.
  • Force Unwrapping — allgegenwärtige Verwendung von ! anstelle der sicheren Extraktion von Optionals.


1.1. Werkzeuge zur Analyse von Legacy-Code in Swift

Für eine objektive Bewertung des Codezustands verwenden Sie Werkzeuge:

  • SwiftLint — ein statischer Analysator, der Verstöße gegen den Code Style erkennt.
  • Xcode Instruments — zum Auffinden von Speicherlecks und Leistungsproblemen.
  • Code Coverage — zeigt, wie viel Code durch Tests abgedeckt ist (normalerweise 0-10% in Legacy-Projekten).

Beispiel für typischen Legacy-Code, der refactoringbedürftig ist:

class LegacyViewController: UIViewController {        @IBOutlet weak var label: UILabel!    var data: [String] = []        override func viewDidLoad() {        super.viewDidLoad()        // Mischung aus Logik und UI        let url = URL(string: "https://api.example.com/data")!        let data = try! Data(contentsOf: url)        let json = try! JSONSerialization.jsonObject(with: data) as! [[String: Any]]        for item in json {            data.append(item["name"] as! String)        }        label.text = data.first    }}

Hier gibt es mehrere Probleme auf einmal: Force Unwrapping, synchrone Netzwerkanfrage im Hauptthread, Vermischung von Logik und Darstellung.



2. Strategie für das Refactoring von Legacy-Code in Swift: Schritt-für-Schritt-Plan

Refactoring ohne Strategie ist der Weg zur Katastrophe. Verwenden Sie den Ansatz des "Kampfmittelräumers": Sichern Sie zuerst das Gebiet, dann ändern Sie den Code.



2.1. Schritt 1: Erstellen Sie ein "Sicherheitsnetz" aus Tests

Bevor Sie etwas ändern, schreiben Sie Tests für den vorhandenen Code. Verwenden Sie Characterization Tests — Tests, die das aktuelle Verhalten des Systems festhalten. Auch wenn der Code schrecklich aussieht, zeigen die Tests, dass Sie die Logik nicht kaputt gemacht haben.

import XCTest@testable import LegacyApp

class LegacyViewControllerTests: XCTestCase { func testViewDidLoad_SetsLabelText() { let sut = LegacyViewController() sut.loadViewIfNeeded() // Prüfen, dass label nicht nil ist und Text enthält XCTAssertNotNil(sut.label.text) }}

Dieser Test mag nicht perfekt sein, aber er hält den aktuellen Zustand fest. Nach dem Refactoring muss der Test bestehen.



2.2. Schritt

Blogs

Buchempfehlungen