Android Coden
Android 6 min lesen

Refactoring-Grundlagen

Refactoring verbessert Android-Code, ohne das sichtbare Verhalten zu ändern. Du lernst, wie Tests und kleine Schritte dabei helfen.

Refactoring ist eine Kernfähigkeit, sobald du nicht mehr nur neue Funktionen baust, sondern bestehenden Android-Code langfristig wartbar halten musst. Du räumst Code auf, verbesserst Namen, trennst Verantwortlichkeiten und entfernst Duplikate, ohne dass Nutzer danach eine andere App erleben. Genau dieser Verhaltenserhalt macht Refactoring anspruchsvoll: Die Oberfläche soll gleich bleiben, aber die innere Struktur soll klarer, robuster und leichter testbar werden.

Was ist das?

Refactoring bedeutet, vorhandenen Code so umzubauen, dass seine Struktur besser wird, während sein beobachtbares Verhalten gleich bleibt. Beobachtbar heißt im Android-Kontext: dieselben UI-Zustände, dieselben Navigationseffekte, dieselben Daten, dieselben Fehlermeldungen und dieselben Nebenwirkungen wie vorher. Wenn du dabei absichtlich eine neue Funktion einbaust oder einen fachlichen Ablauf änderst, ist das kein reines Refactoring mehr.

Das Problem, das Refactoring löst, kennst du aus echten Projekten schnell: Eine Compose-Funktion wird zu lang, ein ViewModel enthält Formatierung, Netzwerklogik und UI-Zustand zugleich, oder dieselbe Validierung steht in drei Screens leicht unterschiedlich. Solcher Code funktioniert oft noch, aber jede Änderung wird riskanter. Du brauchst länger, um ihn zu verstehen, und kleine Anpassungen lösen unerwartete Fehler aus.

Das mentale Modell ist deshalb: Refactoring ist keine Verschönerung aus Prinzip, sondern Risikoreduktion. Du kaufst dir bessere Änderbarkeit. In modernem Android betrifft das besonders Kotlin-Code, Jetpack Compose, ViewModels, Repositorys, Coroutines, Flow und Tests. Du verschiebst Logik an passendere Stellen, benennst Dinge präziser oder extrahierst Funktionen, damit fachliche Entscheidungen lesbar bleiben.

Wichtig ist die Grenze zur Architekturarbeit. Wenn du ein komplettes Projekt von einer Architektur in eine andere überführst, kann das viele Refactorings enthalten. Für den Lernweg ist aber zuerst die kleine Einheit entscheidend: eine konkrete Verbesserung, ein klarer Zweck, ein überprüfbares Verhalten.

Wie funktioniert es?

Sicheres Refactoring folgt einem einfachen Ablauf: Verhalten verstehen, Schutz schaffen, kleine Änderung machen, prüfen. Bevor du Code bewegst, musst du wissen, welches Verhalten erhalten bleiben soll. Bei Android kann das ein Text im Screen sein, ein Ladezustand, eine Fehlermeldung, eine Navigation oder ein gespeicherter Wert.

Schutz entsteht durch Tests und durch manuelle Kontrolle. Unit-Tests eignen sich gut für reine Kotlin-Logik, etwa Validatoren, Mapper oder ViewModel-Zustände. Instrumentierte Tests und UI-Tests helfen, wenn Android-Framework, Compose oder echte Geräteumgebung beteiligt sind. Die Android-Testgrundlagen betonen genau diesen Punkt: Tests geben dir Rückmeldung, ob dein Code weiterhin das tut, was du erwartest. Refactoring ohne irgendeine Form von Prüfung ist möglich, aber deutlich riskanter.

Typische Refactoring-Techniken sind klein: Funktion extrahieren, Variable umbenennen, Klasse aufteilen, Duplikat entfernen, Parameterobjekt einführen oder eine Bedingung lesbarer machen. In Kotlin helfen dir dabei der Compiler, die IDE und starke Typen. Wenn du etwa eine Funktion umbenennst, kann Android Studio Referenzen aktualisieren. Wenn du Logik aus einer Compose-Funktion in eine reine Kotlin-Funktion ziehst, kannst du diese Logik unabhängig von der UI testen.

In Compose ist eine häufige Regel: UI beschreibt Zustand, fachliche Entscheidung gehört nicht tief in verschachtelte UI-Blöcke. Eine Composable darf natürlich kleine Darstellungsentscheidungen enthalten. Wenn dort aber Berechnungen, Validierungen oder Mapping von Domain-Daten wachsen, wird der Screen schwer testbar. Dann ist ein Refactoring sinnvoll: Zustand im ViewModel vorbereiten, reine Hilfsfunktionen nutzen oder UI-Modelle einführen.

Der wichtigste Unterschied zu normaler Feature-Arbeit ist die Reihenfolge. Bei einem Feature fragst du: Was soll neu passieren? Beim Refactoring fragst du: Was darf sich nicht ändern? Du machst die Struktur besser, aber du hältst die Wirkung stabil. Deshalb solltest du Refactoring und fachliche Änderung möglichst nicht im selben Commit vermischen. In Code-Reviews ist sonst kaum erkennbar, ob ein Unterschied beabsichtigt oder ein Versehen ist.

In der Praxis

Nimm an, du hast eine kleine Preislogik direkt im ViewModel. Sie funktioniert, aber sie ist unübersichtlich und wird später an mehreren Stellen gebraucht.

data class CartItem(
    val name: String,
    val priceCents: Int,
    val quantity: Int
)

class CartViewModel : ViewModel() {
    fun totalLabel(items: List<CartItem>): String {
        var total = 0
        for (item in items) {
            total += item.priceCents * item.quantity
        }
        val euros = total / 100
        val cents = total % 100
        return "$euros,${cents.toString().padStart(2, '0')} €"
    }
}

Ein kleines Refactoring wäre, Berechnung und Formatierung zu trennen. Das sichtbare Ergebnis bleibt gleich, aber du kannst die Teile gezielter testen.

fun calculateTotalCents(items: List<CartItem>): Int =
    items.sumOf { item -> item.priceCents * item.quantity }

fun formatEuroLabel(totalCents: Int): String {
    val euros = totalCents / 100
    val cents = totalCents % 100
    return "$euros,${cents.toString().padStart(2, '0')} €"
}

class CartViewModel : ViewModel() {
    fun totalLabel(items: List<CartItem>): String =
        formatEuroLabel(calculateTotalCents(items))
}

Dazu passt ein kleiner Test, der das Verhalten absichert:

class CartPriceTest {
    @Test
    fun totalLabel_formatsSumInEuro() {
        val items = listOf(
            CartItem("Kabel", 1299, 2),
            CartItem("Adapter", 350, 1)
        )

        val label = formatEuroLabel(calculateTotalCents(items))

        assertEquals("29,48 €", label)
    }
}

Die Entscheidungsregel lautet: Refactore zuerst dort, wo du das Verhalten klar beschreiben kannst. Wenn du nicht sagen kannst, was gleich bleiben soll, fehlt dir die Prüfbasis. Dann beobachte die App, schreibe einen kleinen Test oder notiere im Review, welche Zustände du verglichen hast.

Eine typische Stolperfalle ist das „nebenbei verbessern“. Du extrahierst eine Funktion, änderst dabei aber auch Rundung, Sortierung oder Fehlerbehandlung. Das fühlt sich effizient an, macht die Änderung aber schwer prüfbar. Besser ist: Erst Struktur ändern, Tests laufen lassen, dann fachliche Änderung separat umsetzen. So sieht dein Team im Code-Review, welche Änderung welches Ziel hat.

Eine zweite Stolperfalle betrifft Compose: Wenn du beim Aufräumen Zustände an eine andere Stelle verschiebst, kann sich Recomposition-Verhalten ändern. Das ist nicht automatisch falsch, aber du solltest prüfen, ob Eingaben erhalten bleiben, Ladezustände stabil sind und keine unnötigen Nebeneffekte in Composables entstehen. Besonders bei LaunchedEffect, remember und Flow-Collection im UI-Bereich lohnt sich vorsichtige Kontrolle.

Für den Alltag reicht oft ein kurzer Refactoring-Workflow: Schreibe oder finde einen Test, führe ihn aus, ändere nur eine Sache, führe ihn wieder aus. Danach prüfst du die betroffene UI kurz manuell. Bei größeren Änderungen ergänzt du ein Code-Review mit der Aussage, welches Verhalten unverändert bleiben soll. Das macht Qualität sichtbar und passt zur Android-Praxis, in der stabile Releases wichtiger sind als elegante Umbauten ohne Nachweis.

Fazit

Refactoring ist die Fähigkeit, Android-Code gezielt aufzuräumen, ohne die Nutzererfahrung zu verändern. Du verbesserst Namen, Struktur und Verantwortlichkeiten, aber du schützt das vorhandene Verhalten durch Tests, Debugger, manuelle Prüfung und klare Reviews. Übe das an kleinen Stellen: Extrahiere eine Funktion aus einem ViewModel, schreibe einen Test für das bisherige Ergebnis und prüfe danach, ob der Screen gleich reagiert. Wenn du diese Disziplin beherrschst, werden spätere Architektur- und Qualitätsentscheidungen deutlich verlässlicher.

Quellen (2)
Redaktion

Geschrieben von

Redaktion

Das Redaktionsteam recherchiert und schreibt Artikel zu aktuellen Themen rund um Tech, Lifestyle und Ratgeber.