Go – nicht nur eine modische Sprache, sondern ein Werkzeug für schnelle Entwicklung
\n\nGo (oder Golang) hat sich in den letzten Jahren von einer exotischen Sprache zum Industriestandard für Backend, Microservices und Cloud-Anwendungen entwickelt. Seine Schöpfer (Rob Pike, Ken Thompson) haben die Sprache bewusst einfach gehalten, aber der Teufel steckt, wie immer, im Detail. Viele Anfänger bleiben in der Phase „Ich habe Hello World geschrieben, was nun?“ stecken.
\n\nIn diesem Artikel habe ich Tipps von Senior-Entwicklern gesammelt, die Ihnen helfen, nicht nur die Syntax von Go zu lernen, sondern das Lernen von Go zu beschleunigen und produktionsreifen Code zu schreiben. Wir werden reale Fälle analysieren, typische Fehler besprechen und konkrete Handlungsempfehlungen geben. Los geht's!
\n\n1. Vergessen Sie „OOP aus Java“ – denken Sie in Komposition
\n\nDer häufigste Fehler von Anfängern ist der Versuch, klassische OOP (Vererbung, Klassenpolymorphismus) auf Go zu übertragen. Go hat keine Klassen und keine Vererbung. Stattdessen gibt es Strukturen und Interfaces.
\n\nSenior-Entwickler raten: Lernen Sie Go durch Komposition. Betten Sie eine Struktur in eine andere ein, verwenden Sie Interfaces zur Abstraktion.
\n\nBeispiel: Wie man es NICHT macht
\n// Schlecht: Versuch einer "Vererbung" durch Einbettung mit Methodenüberschreibung\ntype Animal struct {\n Name string\n}\nfunc (a Animal) Speak() string {\n return "I am an animal"\n}\n\ntype Dog struct {\n Animal\n}\nfunc (d Dog) Speak() string {\n return "Woof!"\n}\n\n\nBeispiel: Wie man es richtig macht (Komposition + Interfaces)
\n// Gut: Verwenden von Interface und Komposition\ntype Speaker interface {\n Speak() string\n}\n\ntype Dog struct {\n Name string\n}\n\nfunc (d Dog) Speak() string {\n return "Woof! I'm " + d.Name\n}\n\nfunc MakeSound(s Speaker) {\n fmt.Println(s.Speak())\n}\n\nfunc main() {\n dog := Dog{Name: "Rex"}\n MakeSound(dog) // Funktioniert mit jedem Speaker\n}\n\n\nTipp vom Senior: „Beginnen Sie mit interface{} – das ist das leere Interface. Verstehen Sie, wie Go Typen durch Type Assertion prüft. Das spart Ihnen Wochen.“
2. Goroutinen sind nicht einfach nur „go func()“
\n\nGoroutinen sind die Killer-Funktion von Go. Aber Anfänger schreiben oft:
\ngo myFunc()\n// ... und vergessen die Synchronisation\n\n\nDas führt zu Datenrennen (data races). Senior-Entwickler raten, immer sync.WaitGroup oder Channels zur Synchronisation zu verwenden.
Das richtige Pattern: Worker Pool
\npackage main\n\nimport (\n "fmt"\n "sync"\n "time"\n)\n\nfunc worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {\n defer wg.Done()\n for j := range jobs {\n fmt.Printf("Worker %d processing job %d\\n", id, j)\n time.Sleep(time.Second) // Arbeitsimulation\n results <- j * 2\n }\n}\n\nfunc main() {\n const numJobs = 5\n jobs := make(chan int, numJobs)\n results := make(chan int, numJobs)\n var wg sync.WaitGroup\n\n // Starte 3 Worker\n for w := 1; w <= 3; w++ {\n wg.Add(1)\n go worker(w, jobs, results, &wg)\n }\n\n // Sende Aufgaben\n for j := 1; j <= numJobs; j++ {\n jobs <- j\n }\n close(jobs)\n\n // Warte auf alle Worker\n wg.Wait()\n close(results)\n\n // Sammle Ergebnisse\n for r := range results {\n fmt.Println("Result:", r)\n }\n}\n\n\nWarum beschleunigt das das Lernen von Go? Sie lernen sofort, sicher mit Goroutinen zu arbeiten, ohne Lecks und Paniken.
\n\n3. Fehler sind Werte (errors are values)
\n\nGo hat keine Ausnahmen (try-catch). Fehler sind einfach Werte, die behandelt werden müssen. Senior-Entwickler hämmern das bei den ersten Code-Reviews ein.
\n\nTypischer Anfängerfehler:
\nresult, _ := doSomething() // Fehler ignorieren\n\n\nWie es richtig geht:
\nresult, err := doSomething()\nif err != nil {\n // Loggen, zurückgeben, panic (aber n