Monorepo mit Swift: Code-Organisation in der Praxis

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

Monorepository mit Swift: Code-Organisation in der Praxis



In der modernen iOS- und macOS-Entwicklung ist die Wahl der Strategie zur Code-Verwaltung einer der Schlüsselfaktoren, die sich auf Skalierbarkeit, Liefergeschwindigkeit und Produktqualität auswirken. Traditionell verwendeten Entwickler Multi-Repositories (Polyrepo), bei denen jedes Modul oder jeder Dienst in einem eigenen Git-Repository lebt. Mit dem Wachstum von Projekten und Teams stellt sich jedoch immer häufiger die Frage: Wie organisiert man Code so, dass er ganzheitlich, wiederverwendbar und leicht wartbar bleibt? Die Antwort ist ein Monorepository (Monorepo) mit Swift. In diesem Artikel werden wir untersuchen, was ein Monorepository ist, warum es für Swift-Projekte geeignet ist und wie man es in der Praxis mit dem Swift Package Manager (SPM) organisiert.



Was ist ein Monorepository und warum wird es in Swift benötigt?



Ein Monorepository ist ein Ansatz, bei dem der gesamte Code eines Projekts (oder mehrerer verwandter Projekte) in einem einzigen Repository gespeichert wird. Im Gegensatz zu Polyrepo, bei dem jede Komponente isoliert ist, vereint Monorepo Bibliotheken, Anwendungen, Tests, Konfigurationen und Dokumentation unter einer einzigen Versionskontrolle.



Für Swift-Entwickler ist das Monorepository aus mehreren Gründen besonders relevant:

  • Einheitliche Version von Abhängigkeiten: Sie vermeiden die Desynchronisation von Bibliotheksversionen zwischen verschiedenen Anwendungen.
  • Vereinfachtes Refactoring: Änderungen an einem gemeinsamen Modul sind sofort für alle Konsumenten innerhalb des Repositorys sichtbar.
  • Schnelle Integration: Neue Funktionen können in einem einzigen Pull-Request getestet und veröffentlicht werden.
  • Kompatibilität mit SPM: Der Swift Package Manager eignet sich ideal für Monorepositories, da er lokale Pakete und relative Pfade unterstützt.


Struktur eines Monorepositorys für ein Swift-Projekt



Betrachten wir ein praktisches Beispiel. Angenommen, wir haben eine Anwendung für iOS (mit SwiftUI) und macOS (mit AppKit), die gemeinsame Module verwenden: eine Netzwerkschicht, eine Authentifizierungslogik und UI-Komponenten. Wir organisieren das Monorepository wie folgt:



MyMonorepo/├── Package.swift├── Sources/│   ├── AppiOS/│   │   └── main.swift│   ├── AppMacOS/│   │   └── main.swift│   ├── CoreNetworking/│   │   ├── Sources/│   │   │   └── HTTPClient.swift│   │   └── Tests/│   ├── CoreAuth/│   │   ├── Sources/│   │   │   └── AuthService.swift│   │   └── Tests/│   └── UIComponents/│       ├── Sources/│       │   └── CustomButton.swift│       └── Tests/├── Tests/│   ├── AppiOSTests/│   └── AppMacOSTests/├── .gitignore└── README.md


Die Schlüsseldatei ist Package.swift. Sie beschreibt alle Module und ihre Abhängigkeiten. Ein Beispiel für eine solche Datei:



// swift-tools-version:5.9import PackageDescription

let package = Package( name: "MyMonorepo", platforms: [ .iOS(.v17), .macOS(.v14) ], products: [ .executable(name: "AppiOS", targets: ["AppiOS"]), .executable(name: "AppMacOS", targets: ["AppMacOS"]), .library(name: "CoreNetworking", targets: ["CoreNetworking"]), .library(name: "CoreAuth", targets: ["CoreAuth"]), .library(name: "UIComponents", targets: ["UIComponents"]) ], dependencies: [ // Externe Abhängigkeiten, falls benötigt // .package(url: "https://github.com/...", from: "1.0.0") ], targets: [ .executableTarget( name: "AppiOS", dependencies: ["CoreNetworking", "CoreAuth", "UIComponents"], path: "Sources/AppiOS" ), .executableTarget( name: "AppMacOS", dependencies: ["CoreNetworking", "CoreAuth", "UIComponents"], path: "Sources/AppMacOS" ), .target( name: "CoreNetworking", dependencies: [], path: "Sources/CoreNetworking/Sources" ), .target( name: "CoreAuth",

Blogs

Buchempfehlungen