„Festnageln“ und „Hardcoden“ sind umgangssprachliche Begriffe, die das feste Einbetten von Werten direkt in den Programmcode bedeuten, anstatt sie in Einstellungen oder Konfigurationen auszulagern. Hardcode ist einer der bekanntesten Antipatterns in der Entwicklung, da er die Flexibilität und Wiederverwendbarkeit von Code verringert. Laut Refactoring Guru erschwert Hardcode das Testen, die Wartung und die Anpassung der Anwendung an verschiedene Umgebungen. Die bewusste Verwendung von Konstanten anstelle von Hardcode ist ein Zeichen für eine ausgereifte Architektur.
Das Wichtigste
Hardcoden (festnageln) — einen bestimmten Wert so in den Programmcode einbetten, dass für seine Änderung der Quellcode bearbeitet und die Anwendung neu kompiliert werden muss. Die Metapher „festnageln“ spiegelt das Wesen genau wider: Der Wert ist dauerhaft fixiert und kann nur mit Mühe vom Code gelöst werden.
Ein Beispiel für Hardcode ist eine Server-URL, die als Zeichenkette direkt im Funktionsrumpf steht. Wenn der Server auf eine andere Adresse umzieht, muss der Entwickler die Zeichenkette im Code finden, ändern, die Anwendung neu erstellen und ein Release ausrollen. In einer Anwendung mit richtiger Architektur wäre diese URL in eine Konfigurationsdatei, eine Umgebungsvariable oder einen Konfigurationsdienst ausgelagert.
Der Begriff „festnageln“ ist emotionaler aufgeladen: Er betont, dass der Wert dauerhaft eingefügt wurde und nicht schnell ausgetauscht werden kann. Im russischsprachigen Umfeld werden beide Ausdrücke als vollständige Synonyme mit negativer Konnotation verwendet. Manchmal wird Hardcode ironisch als „Konstante, die in eine separate Konstante aus einer Konstante extrahiert wurde“ bezeichnet.
Hardcode ist ein Antipattern, weil er die Prinzipien der Wartbarkeit, Testbarkeit und Erweiterbarkeit des Codes verletzt. In Code, wo Werte „festgenagelt“ sind, erfordert jede Änderung der Umgebung, des Designs oder der Logik manuelles Suchen und Ersetzen in den Quellen. Dies erhöht das Risiko von Fehlern und verlangsamt die Entwicklung.
Betrachten wir die konkreten Folgen von Hardcode am Beispiel einer typischen mobilen Anwendung. Wenn der Abstand aller Schaltflächen durch eine Zahl im Code festgelegt ist, nicht durch eine Ressource — erfordert eine Designänderung das Auffinden und Ersetzen aller Vorkommen. Wenn die Endpunkt-URL fest codiert ist — ist ein Wechsel zwischen Umgebungen (dev, stage, prod) ohne Neukompilierung unmöglich.
| Folge | Beschreibung | Kritikalitätsgrad |
|---|---|---|
| Wartungskomplexität | Änderung erfordert Suche im gesamten Code | Hoch |
| Fehler beim Kopieren | Nicht alle Vorkommen werden gefunden und ersetzt | Hoch |
| Testunmöglichkeit | Testdaten können nicht eingesetzt werden | Mittel |
| Lokalisierungsprobleme | Texte im Code werden nicht übersetzt | Mittel |
| Code-Review-Komplexität | Prüfer muss alle Kontexte kennen | Niedrig |
Eine Funktion, die magische Zahlen und fest codierte Zeichenketten verwendet, ist ein klassisches Beispiel für Hardcode. Nach einem Monat erinnert sich der Autor nicht mehr, was 18, 0.07 und 2.5 bedeuten. Nach einem Jahr — wagt niemand im Team, diese Zahlen zu ändern, aus Angst, die Logik zu brechen. Das Auslagern von Werten in benannte Konstanten macht den Code selbstdokumentierend.
// Schlecht: magische Zahlen und Zeichenketten
fun calculatePrice(base: Double): Double {
val tax = base * 0.07
val tip = base * 0.15
val discount = if (base > 100) 10 else 0
return base + tax + tip - discount
}
Eine hartcodierte Datenbank-URL erlaubt es nicht, Tests auf einer lokalen In-Memory-Datenbank auszuführen. Der Entwickler muss einen vollwertigen Server hochfahren oder den Code vor dem Testen bearbeiten. Das Auslagern der Konfiguration aus dem Code löst das Problem: Tests verwenden Testparameter, die Produktion verwendet echte Parameter, und der Code bleibt unverändert.
Hardcode ist ein Antipattern, aber es gibt legitime Ausnahmen, bei denen ein fest codierter Wert nicht nur akzeptabel, sondern sogar vorzuziehen ist. Die Grenze verläuft entlang der Änderbarkeit: Wenn sich der Wert im Lebenszyklus der Anwendung nie oder fast nie ändert, kann er hartcodiert werden. Wenn er sich potenziell ändern kann — lagern Sie ihn in die Konfiguration aus.
Mathematische und physikalische Konstanten — Pi, Erdbeschleunigung, Anzahl Millisekunden pro Sekunde — sind für Hardcode sicher. Sie sind von Natur oder Standards definiert und ändern sich nicht. Größen von Konstanten-Arrays, die durch Spezifikationen definiert sind, können ebenfalls fest codiert werden, jedoch mit einem Kommentar zur Herkunft der Zahl.
Die Anzahl der Millisekunden pro Sekunde ist eine stabile Konstante, die durch den Zeitstandard definiert ist. Es ergibt keinen Sinn, sie in ein Config auszulagern, da sie sich nie ändern wird. Allerdings sollten auch solche Konstanten mit einem aussagekräftigen Namen deklariert werden, damit der Code keine „magischen Zahlen“ enthält: Statt 1000 schreiben Sie MILLISECONDS_IN_SECOND.
// Gerechtfertigter Hardcode: stabile Konstanten
private const val MILLIS_IN_SECOND = 1000
private const val LOGIN_TIMEOUT_SECONDS = 30
fun formatDuration(ms: Long): String {
val seconds = ms / MILLIS_IN_SECOND
return "${seconds} sec."
}
Es gibt mehrere bewährte Möglichkeiten, Hardcode zu vermeiden, die jeweils für ihren Wertetyp geeignet sind. Die Wahl der Alternative hängt davon ab, wie oft sich der Wert ändert und wer ihn ändert: Entwickler, DevOps oder Endbenutzer.
Für Server-URLs, API-Schlüssel und Feature-Flags verwenden Sie Konfigurationsdateien in den Formaten JSON, YAML oder TOML. Auf Android ist dies build.gradle mit buildConfigField oder res/values/config.xml. Auf iOS — Info.plist oder xcconfig. Konfigs werden mit der Anwendung gebaut, können aber für verschiedene Build-Schemata unterschiedlich sein.
Für Geheimnisse (Tokens, Passwörter) und Umgebungsparameter verwenden Sie Umgebungsvariablen. Sie gelangen nicht ins Repository und können auf dev-, stage- und prod-Servern unterschiedlich sein. In der mobilen Entwicklung werden Umgebungsvariablen oft durch Xcode-Build-Schemata oder Build-Flavors in Gradle emuliert.
Zeichenketten, Farben, Größen, Bilder sollten in Ressourcendateien ausgelagert werden: strings.xml auf Android, Localizable.strings auf iOS, ARB-Dateien in Flutter. Dies vereinfacht die Lokalisierung, Anpassung an verschiedene Bildschirme und das dunkle Thema. Das Ändern einer Zeichenkette in den Ressourcen erfordert kein Umschreiben des Codes.
<!-- Android: res/values/strings.xml -->
<resources>
<string name="app_name">MyApp</string>
<string name="api_base_url">https://api.example.com</string>
</resources>
Für Dienste und Anbieter verwenden Sie Dependency Injection mit Dagger, Hilt oder Koin auf Android, Swinject auf iOS. DI-Frameworks ermöglichen es, Implementierungen im laufenden Betrieb auszutauschen — für Tests, für verschiedene Umgebungen, für verschiedene Benutzer. Dies ist die höchste Abstraktionsebene, bei der die „Festgenageltheit“ des Werts durch externe Injektion ersetzt wird.
Refactoring von Hardcode ist der Prozess des Auslagerns fest codierter Werte in die Konfiguration oder Ressourcen. Es ist eine der sichersten Refactoring-Operationen, wenn sie methodisch durchgeführt wird. Die unten beschriebene Reihenfolge ist für jede Sprache und Plattform geeignet.
Die Suche kann über die IDE (Search in Project) oder ein Skript erfolgen. Suchen Sie nach Zeichenketten, URLs, numerischen Literalen, Größen, Timeouts. Besondere Aufmerksamkeit — sich wiederholenden Werten: Wenn dieselbe Zahl an fünf Stellen vorkommt, ist sie ein Kandidat für eine Konstante. Verwenden Sie grep oder die integrierte Suche von IDEA / Xcode.
Erstellen Sie für jeden gefundenen Wert eine Konstante mit einem aussagekräftigen Namen. Gruppieren Sie Konstanten nach Modulen oder Klassen. Der Name sollte erklären, was der Wert bedeutet, nicht wie er verwendet wird: API_TIMEOUT, nicht TIMEOUT_30. Nach dem Ersetzen sollte keine Zahl im Code ohne Erklärung bleiben.
// Vorher: magische Zahl 0.4
let cardHeight = screenHeight * 0.4
// Nachher: benannte Konstante
private let cardHeightRatio: CGFloat = 0.4
let cardHeight = screenHeight * cardHeightRatio
Wenn der Wert zwischen Builds oder Umgebungen variieren kann — lagern Sie ihn in eine Konfigurationsdatei oder Anwendungsressourcen aus. Für Zeichenketten verwenden Sie Lokalisierungsdateien. Für URLs — build config oder xcconfig. Für Größen — Ressourcendateien (dimens.xml auf Android). Prüfen Sie, dass die Anwendung nach dem Auslagern korrekt gebaut wird und funktioniert.
Schreiben Sie nach dem Refactoring einen Test, der prüft, ob die Konfiguration korrekt geladen wird und die Werte den Erwartungen entsprechen. Wenn in Zukunft jemand das Config ändert, zeigt der Test die Abweichung an. Ein Test für die Konfiguration ist eine schnelle und zuverlässige Methode, um Regression zu verhindern.
Nach dem Auslagern in das Config prüfen Sie, ob alle Stellen, die den alten Wert verwendet haben, auf die einzige Quelle verweisen. Entfernen Sie auskommentierten Code und alte Konstanten, die nicht mehr verwendet werden. Schließen Sie das Refactoring mit einem Commit ab, dessen Nachricht beschreibt, welche Werte wohin ausgelagert wurden.
Häufig gestellte Fragen
Hardcoden — einen Wert direkt im Quellcode festlegen, anstatt ihn in die Konfiguration oder Ressourcen auszulagern. Dies macht den Code weniger flexibel und schwieriger zu warten.
Hardcode erschwert die Änderung des Anwendungsverhaltens, behindert Tests, erzeugt Duplizierung und erhöht das Risiko von Fehlern beim Kopieren. Die Änderung eines hartcodierten Werts erfordert Neukompilierung und Neuveröffentlichung der Anwendung.
Akzeptabel für mathematische Konstanten, stabile Werte, die sich im Lebenszyklus der Anwendung nicht ändern, und für temporäre Prototypen. In der Produktion sollten selbst Konstanten in benannte Variablen ausgelagert werden.
Finden Sie alle magischen Zahlen durch Suche, ersetzen Sie sie durch benannte Konstanten oder lagern Sie sie in eine Konfigurationsdatei aus. Schreiben Sie einen Test, der das Laden der Konfiguration überprüft. Entfernen Sie Duplikate und machen Sie einen Commit mit einer Beschreibung der Änderungen.
Konstante — ein benannter Wert im Code, der an einer Stelle geändert werden kann. Hardcode — unbenannte Werte, die im Code verstreut sind. Gute Praxis: Immer benannte Konstanten mit aussagekräftigen Namen verwenden.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch