- Der Autor beschreibt die Grenzen und Probleme der Programmiersprache Go, die ihm nach mehreren Jahren Nutzung und dem Wechsel zu Java aufgefallen sind
- Es wird die Perspektive vertreten, dass Gos Eigenschaft als einfache und langweilige (
boring) Sprache kein Vorteil, sondern ein Nachteil sein kann
- Gos Philosophie: Das Go-Designteam bei Google betonte Einfachheit und Begrenzung, doch das führt zu wiederkehrender Arbeit, die Nutzer selbst lösen müssen
1. Dass Go „keinen Spaß macht“, kann ein Nachteil sein
- Behauptung von Russ Cox:
- Es wird betont, dass es ein Vorteil sei, dass Go „langweilig (
boring)“ ist
- Es gibt nur
for als Schleife, und Funktionen wie Filter, Map und Reduce sind nicht eingebaut
- Dass viele fortgeschrittene Features fehlen, die in den meisten anderen Sprachen vorhanden sind, gilt als Teil der Einfachheit
- Meinung eines Reddit-Nutzers:
- Die Grenze zwischen „langweilig“ und „mächtig“ ist unscharf
- Es wird argumentiert, dass Gos fehlende Grundfunktionen irgendwann wahrscheinlich zur Sprache hinzugefügt werden
- Abhängigkeit von Third-Party-Paketen:
- Das häufig genutzte Paket
samber/lo, um fehlende Funktionen auszugleichen:
- Enthält essenzielle Funktionen wie Filter, Map und Suche
- Hat 18.1k Sterne auf GitHub und wird in mehr als 12.6k Projekten verwendet
- Einige Funktionen wurden zwar dem Paket
slices hinzugefügt, funktional reicht das aber weiterhin nicht aus
- Kritik des Autors:
- Man wird gezwungen, immer wieder Schleifen zu schreiben
- Aufgaben wie Filter und Map lassen sich nur schwer kompakt ausdrücken
- Man kann sie zwar in separate Receiver-Methoden auslagern, das schadet aber der Sauberkeit des Codes
- Gos Einfachheit ist oft ein Vorteil, doch das Fehlen grundlegender Komfortfunktionen kann Produktivität und Lesbarkeit des Codes verringern
2. Behindert Clean-Code-Prinzipien
- Problem bei der Fehlerbehandlung:
- In den meisten Fällen enthalten Funktionsrückgaben ein
error:
- Das Muster
if err != nil muss ständig wiederholt werden
- Beim Aufräumen des Codes wird der Code dadurch eher noch komplexer
- Selbst in einfachen Projekten wächst HTTP-Handler-Code dadurch auf mehr als 20 Zeilen an
- Das ursprüngliche Ziel war, ihn bei etwa 4 Zeilen zu halten
- Die Frustration über die Fehlerbehandlung geht so weit, dass sogar
panic() und Recovery-Middleware erwogen werden
- Empfehlung kurzer Namen:
- Für Variablen-, Methoden- und Funktionsnamen werden kurze Namen empfohlen:
- Bei Namen wie
c oder a ist unklar, wofür sie stehen
- Beispiel: Bedeutet
c Command, Controller, Argument oder Amendment?
- Längere Namen könnten klarer sein, aber Gos Philosophie bevorzugt kurze Namen
- Das führt in Team-Code-Reviews zu endlosen Debatten, etwa über Namen von Testmethoden
- Gos Philosophie betont prägnanten und einfachen Code, kann aber am Ende Komplexität und Ineffizienz erzeugen, die Clean-Code-Prinzipien zuwiderlaufen
3. Philosophie einer absichtlich kleinen Sprache und DIY-Kultur
- Fehlende Grundfunktionen:
- Einen einfachen HTTP-Handler zu implementieren ist leicht, aber sobald grundlegende Middleware nötig ist (z. B. exponentielles Backoff, Cross-Site-Konfigurationen usw.), muss man mehrere Pakete durchsuchen
- Bei solchen Paketen ist schwer sicher zu sein, ob sie (1) gepflegt werden und (2) wie erwartet funktionieren
- Mehr Wiederholungsarbeit:
- Gos Designphilosophie, Einfachheit zu bewahren, läuft letztlich darauf hinaus, Entwickler zum „Neuerfinden des Rads“ zu zwingen
- Beispiel: Selbst eine einfache Filterfunktion muss unter Umständen direkt selbst implementiert werden
- Unausgereiftes Paket-Ökosystem:
- Viele GitHub-Projekte sind verwaist oder haben nur sehr wenige Versionen veröffentlicht
- Als relativ junge Sprache ist ein Vergleich mit .NET oder Java vielleicht unfair, praktisch gesehen fehlt Go aber Stabilität und Reife im Paket-Ökosystem
- Grenzen von ORMs:
- Gos wichtigstes ORM-Paket (
Gorm) liegt funktional hinter Hibernate oder Entity Framework zurück
- Es gibt merkwürdiges Verhalten und Defizite in der Dokumentation
- Reaktion aus der Go-Community: „In Go braucht man kein ORM, Do It Yourself!“
- Gos Einfachheit kann je nach Projekt und Team ein Vorteil sein, doch der Mangel an eingebauten Funktionen kann Produktivität und Entwicklungserlebnis negativ beeinflussen
4. In Go gibt es nicht nur einen einzigen Weg
- Missverständnis von Konsistenz und Einheitlichkeit:
- Table Tests
- Einsatz von Test-Suites wie
stretchr/testify (wird in 557k Projekten verwendet)
- Schreiben eigener Subtests innerhalb von Table Tests
- Dadurch entsteht eine Lücke zwischen Gos Philosophie des „einheitlichen Wegs“ und der Realität
- Fördert Konflikte im Team:
- Diskussionen über Teststile und Implementierungsweisen zwischen Teams nehmen eher zu
- Auch Gos Philosophie und selbst das Designteam sind nicht konsequent:
- Beispiel: Uneinigkeit bei der Benennung von Getter-Methoden
- Ablehnung von Features und Paketabhängigkeit:
- Das Go-Team lehnt die Einführung von Assertion-Features ab und wird dafür kritisiert, die Schuld auf Unzulänglichkeiten der Programmierer zu schieben
- Infolgedessen muss man für benötigte Funktionen wieder ein weiteres Paket per
go get installieren
- Go strebt nach Einfachheit und Einheitlichkeit, in der Praxis gibt es aber verschiedene Implementierungsweisen und entsprechende Debatten, wobei die Unschärfe der Sprachphilosophie das Problem verschärft
5. Debugging in Go macht keinen Spaß
- Keine Auswertung von Ausdrücken beim Debugging:
- Während einer Debugging-Session lassen sich keine Ausdrücke auswerten und keine benutzerdefinierte String-Repräsentation von Objekten anzeigen
- Dadurch ist es schwierig, den Zustand von Objekten zur Laufzeit klar zu erfassen
- Unintuitive Stacktraces und Logs:
- Wenn große Testläufe scheitern (z. B. tausende Tests in CI), liefern sie verwirrende Stacktraces und Logs
- Das erschwert das Debugging und senkt die Produktivität
- Debugging-Erlebnis im C-Stil:
- Gos Debugging-Toolchain arbeitet C-basiert:
- Sie bietet ein primitives Debugging-Erlebnis ähnlich wie in C
- Sie ist nicht entwicklerfreundlich
- Vergleich mit Rust:
- Rust verbessert Gos Schwächen:
- Es liefert klare und hilfreiche Fehlermeldungen
- Fehlermeldungen enthalten präzise Vorschläge zur Behebung
- Gos Debugging-Erlebnis basiert auf einer Designphilosophie, die optimierte Binärdateien priorisiert, was jedoch zulasten der Developer Experience geht. In Umgebungen, in denen effizientes Debugging wichtig ist, kann es sinnvoll sein, alternative Sprachen in Betracht zu ziehen
Zusammenfassung: Eignung und Grenzen von Go
- Vorteile der eingebauten Go-Tools:
- Eine grundlegende Toolchain für Paketverwaltung, Tests und Performance-Monitoring ist vorhanden
- Sie ist ohne zusätzliche Konfiguration nutzbar und vereinfacht dadurch das initiale Setup der Entwicklungsumgebung
- Grenzen:
- „Langweiliger Code“ und Wiederholungsarbeit:
- Gos Toolchain ist funktional, zwingt beim Schreiben von Code jedoch zu wiederkehrender Arbeit (
Plumbing Code)
- Beispiel: Monotone Syntax und eingeschränkte Features nehmen der Arbeit ihren Reiz
- „import cycle not allowed“:
- In Tests sind zyklische Abhängigkeiten (
import cycle) nicht erlaubt
- Bei Domain-Driven Design (DDD) erhöht das durch strukturelle Einschränkungen die Komplexität
- Abhängigkeit von
struct-Embedding-Techniken:
- Der seltsame und eingeschränkte Mechanismus von
struct-Embedding verursacht praktische Schmerzen bei der Nutzung
- Geeignete Einsatzbereiche:
- Gut geeignet für Infrastrukturentwicklung:
- Tools auf Systemebene wie Docker, Drone und Hugo sind in Go geschrieben
- Nützlich für leichte Server und CLI-Anwendungen
- Ungeeignete Einsatzbereiche:
- Entwicklung komplexer Enterprise-Anwendungen (z. B. ERP-Systeme):
- Durch die eingeschränkte Sprachphilosophie und die Werkzeuge ist die Verwaltung großer Business-Logik ineffizient
- Go liefert bei bestimmten Aufgaben, insbesondere im Infrastrukturumfeld, hervorragende Effizienz, ist aber für komplexe Anwendungen mit anspruchsvollen Business-Domänen kein geeignetes Werkzeug. Auch wenn ein CTO stark auf den Google-Technologie-Stack ausgerichtet ist, sollte die Technologiewahl mit Bedacht getroffen werden
5 Kommentare
Wenn es nur
?aus Rust gäbe, wäre es nicht schon jetzt deutlich besser gewesen ...Beim Einsatz von Go hatte ich den Eindruck, wie viel implizites Error-Handling ich bisher eigentlich betrieben habe.
Natürlich kann es strukturell sauber wirken, Error-Handling an einer einzigen Stelle zu behandeln, aber ich finde, dass man Code auf diese Weise sicherer schreibt, weil explizit sichtbar wird, dass es sich um eine Operation mit möglicher Fehlerantwort handelt.
if err != nil {}ist ehrlich gesagt schon etwas lästig. Den genannten Nachteilen stimme ich auch zu. Wenn man aber klar versteht, worauf diese Sprache abzielt, und sich überlegt, welche Stärken man besser nutzen kann, lässt sie sich trotz der aufgezeigten Schwächen wohl noch besser einsetzen. Sie ist C ähnlich, hat aber GC, unterstützt zwar eingeschränkt, aber immerhin Generics, und dazu kommt noch Cross-Compilation! So betrachtet ist sie doch wieder eine ziemlich großzügige Sprache, oder?Als ich von Java zu Go gewechselt bin, hatte ich anfangs wohl ein ähnliches Gefühl.
Inzwischen macht mir Go so viel Spaß, dass ich die Zeit, die ich mit Java verbracht habe, fast für verschwendet halte. Dass es für komplexe Business-Applikationen nicht geeignet sei, lässt mich eher denken, dass bei diesen Applikationen nicht gründlich genug darüber nachgedacht wurde, wie man das System vereinfachen kann.
Hacker-News-Meinung
Probleme entstehen, wenn Java-Entwickler Go einen Java-Stil aufzwingen
Viele Entwickler versuchen zu früh zu abstrahieren
Gos Standardbibliothek ist groß, aber nicht groß genug, um alles abzudecken
Es gibt größere Herausforderungen als die Wahl der Programmiersprache
Es ist schwer nachzuvollziehen, warum manche Go mögen
Es ist frustrierend, dass das Kernteam von Go falsche Entscheidungen wieder zurücknimmt
Go hat ähnliche Probleme wie UNIX