Code-Review auf Go: Was man prüfen sollte, damit der Code nicht explodiert

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

Code-Review auf Go: Was man prüfen sollte, damit der Code nicht explodiert

\n\n

Code-Review ist nicht nur ein Häkchen in Jira oder ein Grund, sich mit einem Kollegen in den Kommentaren eines Pull-Requests zu streiten. Es ist wohl der ehrlichste Weg, sich nicht selbst ins Bein zu schießen, wenn es in die Produktion geht. Und wenn es um Go geht – eine Sprache, die für ihre Einfachheit geliebt und dafür gehasst wird, „wo sind hier die Generics?“ (Spoiler: Sie sind bereits da) – wird das Review zur Kunst. In diesem Artikel analysieren wir, worauf man bei einem Code-Review auf Go genau achten sollte, damit Ihr Code nicht nur funktioniert, sondern auch eine Freude fürs Auge ist. Los geht's!

\n\n

1. Fehlerbehandlung: Nicht ignorieren, keine Angst haben

\n\n

In Go gibt es keine Ausnahmen. Hier ist alles ehrlich: Wenn eine Funktion fehlschlagen kann, gibt sie error zurück. Das häufigste Problem bei Anfängern ist das Ignorieren von Fehlern durch einen Unterstrich. Denken Sie daran: „Never ignore an error“ – das ist nicht nur ein Mantra, es ist ein Gesetz.

\n\n

Was im Code prüfen:

\n
    \n
  • Prüfung auf err != nil – sie muss überall dort sein, wo eine Funktion einen Fehler zurückgibt. Selbst wenn Sie sicher sind, dass „hier kein Fehler auftreten wird“.
  • \n
  • Loggen oder Weiterleiten – der Fehler muss entweder mit Kontext geloggt oder nach oben zurückgegeben werden. Ihn zu unterdrücken ist ein No-Go.
  • \n
  • Vergleich mit Sentinel-Fehlern – verwenden Sie errors.Is() und errors.As(), nicht den direkten Vergleich mit ==.
  • \n
\n\n
// Schlecht: Fehler ignorieren\nfile, _ := os.Open("config.yaml")\n\n// Gut: Prüfen und loggen\nfile, err := os.Open("config.yaml")\nif err != nil {\n    log.Printf("Konnte Konfiguration nicht öffnen: %v", err)\n    return err\n}\ndefer file.Close()\n
\n\n

2. Goroutinen und Nebenläufigkeit: Ordnung im Chaos

\n\n

Goroutinen sind die Superkraft von Go. Aber mit großer Kraft kommt große Verantwortung. Beim Review sehen wir oft Goroutinen-Leaks, Datenrennen und Blockaden. Ein Code-Review in Go ohne Prüfung der Nebenläufigkeit ist wie Sportwagenfahren ohne Sicherheitsgurt.

\n\n

Checkliste für Goroutinen:

\n
    \n
  • Starten von Goroutinen – kontrollieren Sie immer die Lebensdauer. Verwenden Sie sync.WaitGroup oder Kontexte.
  • \n
  • Datenrennen – prüfen Sie, ob der Zugriff auf gemeinsame Daten durch einen Mutex oder einen Kanal geschützt ist. Führen Sie go test -race aus.
  • \n
  • Panik in einer Goroutine – wenn eine Goroutine in Panik gerät, stürzt das gesamte Programm ab. Verwenden Sie in Production-Code unbedingt recover.
  • \n
\n\n
// Schlecht: Goroutine ohne Kontrolle\ngo func() {\n    // Kann abstürzen und den gesamten Prozess killen\n    doWork()\n}()\n\n// Gut: Mit WaitGroup und recover\nvar wg sync.WaitGroup\nwg.Add(1)\ngo func() {\n    defer wg.Done()\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf("Goroutine abgestürzt: %v", r)\n        }\n    }()\n    doWork()\n}()\nwg.Wait()\n
\n\n

3. Schnittstellen: Klein und zur Sache

\n\n

In Go sind Schnittstellen Verträge. Aber im Gegensatz zu Java müssen sie nicht riesig sein. In der Go-Community gilt das Prinzip: „Je kleiner die Schnittstelle, desto besser“. Eine Methode – ideal. Zwei – in Ordnung. Drei – bereits verdächtig.

\n\n

Worauf achten:

\n
    \n
  • Größe der Schnittstelle – wenn sie mehr als 3-4 Methoden hat, denken Sie über eine Aufteilung nach.
  • \n
  • Akzeptieren Sie Schnittstellen, geben Sie Strukturen zurück – klassische Go-Weisheit. Sie macht den Code flexibel und testbar.
  • \n
  • Definieren Sie Schnittstellen nicht im Voraus – lassen Sie sie vom Konsumenten erstellen, nicht vom Produzenten.
  • \n
\n\n
// Schlecht: Riesige Schnittstelle\ntype Storage interface {\n    Save(data []byte) error\n    Load(id string) ([]byte, error)\n    Delete(id string) error\n    List() ([]string, error)\n    Connect() error\n    Close() error\n}\n\n// Gut: Kleine Schnittstellen\ntype Saver interface {\n    Save(data []byte) error\n}\ntype Loader interface {\n    Load(id string) ([]byte, error)\n}\n

                
                

Blogs

Buchempfehlungen