- Mehrere Entscheidungen im Sprachdesign von Go wurden unnötig getroffen oder unter Ignorieren bestehender Erfahrungen gefällt
- Das Problem der Verwaltung des Gültigkeitsbereichs von Fehler-Variablen erschwert die Lesbarkeit des Codes und das Auffinden von Bugs
- In mehreren Bereichen wie der Doppelnatur von
nil, Speicherverbrauch und Code-Portabilität zeigt sich ein unintuitives Design, das nicht zur Praxis passt
- Die Grenzen der
defer-Anweisung und die Art der Ausnahmebehandlung in der Standardbibliothek erschweren es, Exception-Sicherheit zu gewährleisten
- Aufgestaute Probleme wie mangelhafte Speicherverwaltung und UTF-8-Verarbeitung wirken sich langfristig negativ auf die Qualität von Go-Codebasen aus
Langfristige Kritik an der Go-Sprache
- Wie ich bereits in früheren Beiträgen (Why Go is not my favourite language, Go programs are not portable) dargelegt habe, weise ich seit mehr als zehn Jahren auf verschiedene Probleme der Go-Sprache hin
- Besonders bedauerlich wirkt, dass unnötige Designentscheidungen, die bekannte Good Practices ignorieren, immer stärker ins Gewicht fallen
Die Unintuitivität des Gültigkeitsbereichs von Fehler-Variablen
- Die Go-Syntax erweitert den Gültigkeitsbereich der Fehler-Variable (
err) unnötig und erhöht damit die Wahrscheinlichkeit von Fehlern
- Im Beispielcode lebt die Variable
err über die gesamte Funktion hinweg weiter und wird wiederverwendet, was Lesbarkeit und Wartbarkeit des Codes verschlechtert
- Selbst erfahrene Entwickler erleben durch solche Scope-Probleme Missverständnisse und Zeitverlust bei der Fehlersuche
- Eine Möglichkeit, Variablen angemessen lokal zu begrenzen, wird von der Syntax nicht zugelassen
Zwei Formen von nil
- In Go gibt es die verwirrende Situation, dass
nil bei Interface-Typen und Pointer-Typen unterschiedlich funktioniert
- Wie im folgenden Beispiel führen Zuweisungen von
nil an s (Pointer) und i (Interface) zu inkonsistentem Verhalten, etwa weil s==i unterschiedlich ausgewertet wird
- Das ist ein Problem, das man bei der Behandlung von null-Werten normalerweise vermeiden möchte, und wirkt wie das Ergebnis unzureichender Überlegungen im Design
Grenzen der Portabilität von Code
- Die Verwendung von Kommentaren für bedingte Kompilierung ist im Hinblick auf Wartbarkeit und Portabilität deutlich ineffizient
- Wer tatsächlich schon portable Software gebaut hat, weiß, dass dieser Ansatz umständlich und fehleranfällig ist
- Historisch gewachsene Erfahrungen zu Code-Portabilität und praktischen Fällen werden ignoriert
- Siehe dazu Go programs are not portable
Unklare Besitzverhältnisse bei append
- Die Beziehung zwischen der Funktion
append und dem Besitz von Slices ist nicht klar, wodurch sich Code schwer vorhersagen lässt
- Anhand eines Beispiels wird gezeigt, dass sich vorab schwer erkennen lässt, welchen Einfluss ein
append auf einen Slice in der Funktion foo tatsächlich auf das Original hat
- Dadurch nimmt die Zahl sprachlicher „quirks“ zu, die man kennen muss, und das führt zu Fehlern
Unzureichendes Design der defer-Anweisung
- Es gibt keine klare Unterstützung für das Freigeben von Ressourcen nach dem RAII-Prinzip (Resource Acquisition Is Initialization)
- Im Vergleich zu strukturierten Resource-Management-Konstrukten in Java und Python ist in Go nicht klar erkennbar, welche Ressourcen mit
defer freigegeben werden sollten
- Wie das Beispiel mit Dateiverarbeitung zeigt, muss man sogar Probleme wie Double-Close selbst behandeln, und die richtige Reihenfolge sowie Art der Freigabe bleiben unklar
Ausnahmebehandlung in der Standardbibliothek
- Go ist strukturell so angelegt, dass es keine expliziten Exceptions unterstützt, dennoch treten Ausnahmefälle wie
panic weiterhin auf
- In manchen Situationen beendet
panic das Programm nicht vollständig, sondern wird gewissermaßen verschluckt
- In der Standardbibliothek (
fmt.Print, HTTP-Server usw.) existieren Muster, in denen Ausnahmen ignoriert werden, sodass echte Exception-Sicherheit nicht garantiert werden kann
- Am Ende ist exception-sicherer Code zwar zwingend nötig, aber Exceptions selbst lassen sich nicht direkt verwenden
UTF-8-Verarbeitung und Strings
- Selbst wenn man beliebige Binärdaten in den Typ
string steckt, arbeitet Go ohne besondere Validierung weiter
- Dadurch kann es vorkommen, dass Dateinamen aus der Zeit vor UTF-8 stillschweigend ausgelassen werden
- Bei Backups und ähnlichen Szenarien können wichtige Daten verloren gehen; der Ansatz ist zu simpel und spiegelt reale Anforderungen nicht wider
Grenzen der Speicherverwaltung
- Eine direkte Kontrolle über den RAM-Verbrauch ist schwierig, und auch die Zuverlässigkeit des GC (Garbage Collector) hat Grenzen
- Der Speicherverbrauch von Go wächst, was langfristig zu Kosten- und Performance-Problemen führt
- In Umgebungen mit mehreren Instanzen oder Containern treten Kosten- und Skalierungsprobleme tatsächlich auf
Fazit: Es hätte einen besseren Weg gegeben
- Obwohl es bereits wirksam erprobte Sprachdesigns gab, ignoriert Go sie in vielen Punkten
- Anders als bei den Problemen früher Java-Entwürfe gab es zum Zeitpunkt der Veröffentlichung von Go bereits bessere Ansätze
Referenzen
Noch keine Kommentare.