Heutzutage besitzt ein gut organisiertes Entwicklerteam Coding Guidelines, um das Code-Bild im Team kontinuierlich hoch und gleich zu halten. Ohne Coding Guidelines kann es dazu führen, dass durch unterschiedliche Konventionen und Stile sowie Erfahrungsniveaus der Entwickler eine Anwendung sehr schwer zu debuggen ist. Für neue Entwickler, die einem Team beitreten, kann es auch deshalb sehr schwer sein den Code zu verstehen.
Mit Coding Guidelines erzeugt das Team einen gut organisierten Code der wartbar und zugleich performant ist. Damit diese Coding Guidelines fortwährend von allen Teammit-gliedern eingehalten werden, gibt es Hilfsmittel wie zum Beispiel Code Reviews. Hier kann dann ggf. auf die Nichteinhaltung hingewiesen werden. Im Eifer des Gefechts passiert es dennoch häufig, dass den Coding Guidelines zu wenig Beachtung geschenkt wird. Bei einem Code Review kann dies zu Spannungen führen.
Besser ist es dann doch, wenn bereits dann auf die Nichteinhaltung der Coding Guidelines hingewiesen wird, wenn der Fehler gerade passiert. In der JavaScript Welt werden zu diesem Zweck bereits seit einigen Jahren Linter eingesetzt. Die deutsche Übersetzung für das Wort lint ist Fussel. Somit „entfusselt“ der Linter den Code. Auch für Swift gibt es solche Linter, die mit Unterstützung von Xcode auf die Nichteinhaltung von Coding Guidelines zur Entwicklungszeit hinweise.
In diesem Blogbeitrag möchte ich SwiftLint vorstellen und zeigen, wie es in ein Swift-Projekt eingebunden werden kann. Anhand von Beispielen in einer SwiftLint Konfigurationsdatei möchte ich zeigen, wie vordefinierte Regeln deaktiviert bzw. aktiviert werden können. Außerdem, wie man eigene Regeln, die für das Team wichtig sind, erstellt. Auch möchte ich kurz darauf eingehen, wie sinnvoll es ist, SwiftLint in bereits bestehenden Swift-Projekten zu verwenden und was man dabei beachten sollte.
SwiftLint ist ein Werkzeug mit dessen Hilfe die Swift-Styles, Swift-Konventionen und API Design Guidelines eingehalten werden sollen. SwiftLint kommt mit vordefinierten Regeln, die sich bereits an die genannten Guidelines halten. Hinter SwiftLint steht das Unternehmen Realm Inc welches auch andere OpenSource-Projekte unterstützt. Zum Zeitpunkt der Veröffentlichung des Blogbeitrages existiert bereits eine Sammlung von 183 Regeln, welche fortlaufendergänzt werden. Es gibt drei Arten von Regeln:
SwiftLint kann auf verschiedenen Wegen installiert werden:
Über den Swift Package Manager steht aktuell SwiftLint noch nicht zur Verfügung.
In diesem Blogbeitrag verwende ich CocoaPods, da die meisten Swift-Projekte bereits über ein Podfile verfügen und mit einem Eintrag leicht zum Projekt hinzugefügt werden könne
pod 'SwiftLint'
Nachdem die Zeile in dem Podfile hinzugefügt wurde muss mit dem Pod-Befehl „pod install“ SwiftLint installiert werden.
Damit SwiftLint uns zum Entwicklungszeitpunkt unterstützt, und bei der Code-Erstellung auf Regelverstöße in der IDE hinweist, muss im Target unter „Build Phase“ ein „Run Script“ hinzugefügt werden:
"${PODS_ROOT}/SwiftLint/swiftlint"
Der oben gezeigte „Run Script“ ist nur in Verbindung mit CocoaPods zu verwenden! Für die anderen Installationsvarianten muss folgender „Run Script“ verwendet werden:
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
Damit ist die Installation abgeschlossen und SwiftLint unterstützt uns nun dabei, mit jedem Build (Shortcut: CMD + B) die in SwiftLint bereits standardisiert aktivierten Regeln zu beachten.
Schauen wir uns jetzt die Konfiguration von SwiftLint an. Um den Linter zu konfigurieren, benötigen wir im Projektverzeichnis eine Konfigurationsdatei mit dem Namen „.swiftlint.yml“. In dieser Datei können wir folgende Konfigurationen durchführen:
Hier ein Beispiel wie eine SwiftLint Konfigurationsdatei aussehen kann:
disabled_rules:
- colon
- comma
- control_statement
opt_in_rules:
- empty_count
included:
- Source
excluded:
- Carthage
- Pods
- Source/ExcludedFolder
- Source/ExcludedFile.swift
- Source/*/ExcludedFile.swift
analyzer_rules:
- explicit_self
...
ANMERKUNG: In der SwiftLint Konfigurationsdatei kann auf Xcode Umgebungsvariablen folgendermaßen zugegriffen werden:
${SOME_VARIABLE}.
Die SwiftLint Regeln können an die Teambedürfnisse angepasst werden. Was genau bei einer Regel angepasst werden kann, findet man in der Dokumentation der einzelnen Regeln.
In der Dokumentation gibt es zu jeder Regel Beispiele, wann eine Warnung bzw. ein Fehler ausgegeben wird. Die Dokumentation ist sehr ausführlich und es empfiehlt sich, jede einzelne Regel anzuschauen.
Nachfolgend zeige ich einige Beispiele wie die Regeln angepasst werden können:
...
force_cast: warning # Die Regel nur als Warnung markieren
force_try:
severity: warning # Die Regel nur als Warnung markieren
line_length: 110
type_body_length:
warning: 300 # Mehr als 300 Zeilen für eine Typ-Definition -> Warnung angezeigen
error: 400 # Mehr als 400 Zeilen für eine Typ-Definition -> Fehler anzeigen
file_length:
warning: 500
error: 1200
type_name:
min_length:
warning: 4
max_length:
warning: 40
error: 50
excluded: iPhone
allowed_symbols: ["_"] # Liste der Zeichen die in einem Typ-Bezeichner verwendet werden dürfen
identifier_name:
min_length:
error: 4
excluded:
- id # Die Regel gilt nicht für Bezeichner
- URL # Die Regel gilt nicht für URL's
...
Die Custom Rules werden ebenfalls in der SwiftLint Konfigurationsdatei definiert. Die Regeln werden Regex-basiert beschrieben:
...
custom_rules: #1
swift_beat_objC: #2
included: ".*\\.swift" #3
excluded: ".*Test\\.swift" #4
name: "Swift Beat ObjC" #5
regex: "([o,O]bj[c,C])" #6
match_kinds: #7
- comment
- identifier
message: "Swift are better than ObjC." #8
severity: error #9
...
Was genau die einzelnen Zeilen bedeuten, möchte ich hier einmal beschreiben:
Das Verhalten der im oben gezeigte Custmer Rule sieht in Xcode an einem Code-Beispiel so aus:
Wie oben bereits im „Run Script“ zu sehen, wird der Linter über die Kommandozeile ausgeführt. Eine Liste von möglichen Befehlen kann wie üblich über den folgenden Befehl ausgegeben werden:
$ swiftlint help
Available commands:
analyze [Experimental] Run analysis rules
autocorrect Automatically correct warnings and errors
generate-docs Generates markdown documentation for all rules
help Display general or command-specific help
lint Print lint warnings and errors (default command)
rules Display the list of rules and their identifiers
version Display the current version of SwiftLint
SwiftLint unterstützt auch die Autokorrektur, bei der der Code automatisch korrigiert wird. Aber Vorsicht! Ich empfehle beimSchreiben von Code auf die Autokorrektur zu verzichten, da die Korrekturen direkt in der Datei auf der Festplatte und nicht in Xcode durchgeführt werden. Dadurch wird der Code unwiderruflich überschrieben und kann nicht mehr rückgängig gemacht werden. Es ist besser, die Korrekturen in Xcode manuell durchzuführen, damit die Änderungen ggf. in der IDE rückgängig gemacht werden können.
Sinnvoll ist die Autokorrektur bei bestehenden Swift-Projekten, bei denen das Tool zum Einsatz kommen soll. Oft besteht der bereits existierende Code die Coding Guidelines nicht, wodurch die entsprechenden Code-Stellen vom Linter automatisch korrigiert werden. Das manuelle Korrigieren ist bei größeren Projekten sehr aufwendig und kostenintensiv. Aber auch hier sollte man vorher sicherstellen, dass eine Sicherheitskopie der Dateien, zum Beispiel in einem Git-Repository, vorhanden ist, bevor die Autokorrektur verwendet wird.
Um sicherzustellen, dass der von allen Teammitgliedern geschriebene Code den Coding Guidelines entspricht, sollte SwiftLint zusätzlich in den Continuous Integration Prozess eingebunden werden. Dadurch wird kontinuierlich der eingereichte Code auf das Einhalten der festgelegten Coding Guidelines geprüft und ggf. als Warnung oder Fehler ausgegeben. Auch lässt sich SwiftLint durch die Kommando-Befehle in fastlane integrieren:
swiftlint(
# SwiftLint mode: :lint (default) or :autocorrect
mode: :lint,
# Specify path to lint (optional)
path: "/path/to/lint",
# The path of the output file (optional)
output_file: "swiftlint.result.json",
# The path of the configuration file (optional)
config_file: ".swiftlint-ci.yml",
# List of files to process (optional)
files: [
"AppDelegate.swift",
"path/to/project/Model.swift"
],
# Allow fastlane to raise an error if swiftlint fails
raise_if_swiftlint_error: true,
# Allow fastlane to continue even if SwiftLint returns a non-zero exit status
ignore_exit_status: true
)
Durch die Verwendung von SwiftLint kann kontinuierlich und automatisch überprüft werden, ob der Code den im Team bestehenden Coding Guidelines entspricht. Ggf. werden dann Warnungen bzw. Fehler direkt in der IDE angezeigt oder im Continuous Integration Prozess ausgegeben. Ein Team kann sich an bereits existierenden Coding Guidelines bedienen oder eigene Regeln in der SwiftLint Konfigurationsdatei definieren. Einige namhafte Unternehmen haben ihre Rapid-Code-Style-Guidesfür die freie Verwendung in anderen Projekten bereitgestellt, an denen man sich orientieren kann:
Inzwischen habe ich SwiftLint in mehrere Projekte eingebunden. Das ist durch die einfache Installation und der Möglichkeit der individuellen Anpassung der Regeln in SwiftLint sehr einfach und macht dieses Werkzeug sehr flexibel. Zudem können teameigene Regeln zu den Bestehenden hinzugefügt werden.
Das Feedback im Team zu SwiftLint ist durchweg positiv. Das Lesen des Codes in einem Code Review ist nun einfacher und macht nun auch Spaß. Jedes Teammitglied, egal mit welchem Erfahrungsniveau, erzeugt mit Hilfe des Linters einen gut organisierten Code, der wartbar und zugleich performant ist.