3. Go Erfahrung
• Artikel, Buch, Talks, Kolumne rund um Go
seit 2010
• Seit 2011 professionelle Nutzung
• Cloud Provisioning
• Microservices in der Logistik
• Ethereum Messaging
• Kubernetes Cluster Management
• OSS unter dem Label Tideland
5. Kurzeinführung
• Go ist langweilig
• Go folgt keinem klaren Paradigma
• Go bietet keine esoterischen Features
• Go bietet nichts wirklich Neues
• Go ist nicht perfekt
• Go beinhaltet Stolpersteine
6. ABER
• Go ist einfach (Language Specification nur
eine HTML Seite)
• Go bringt eine umfangreiche Bibliothek mit
sich
• Go kompiliert sehr schnell in ein Binary
• Go beherrscht Cross-Compiling
• Go verfügt über Garbage Collection
• Go führt sehr schnell aus
• Go ist pragmatisch
Kurzeinführung
7. ❝
It’s better to have a permanent income than to be
fascinating.
Oscar Wilde
9. Historie
• Start Ende 2007 aus Frust
• FAQ: "One had to choose either efficient
compilation, efficient execution, or ease of
programming; all three were not available in
the same mainstream language."
• Beginn der Entwicklung Mitte 2008
• Erste öffentliche Vorversion im November
2009
• Version 1.0 im März 2012
10. ❝Go aims to combine the safety and performance of a
statically typed compiled language with the
expressiveness and convenience of a dynamically
typed interpreted language.
It also aims to be suitable for modern systems – large
scale – programming.
Rob Pike
11. Das Team
• Rob Pike
• Ken Thompson
• Robert Griesemer
• Russ Cox
• Ian Lance Taylor
• Und weitere ...
12. Keine Unbekannten
• Ken Thompson — Multics, Unix, B, Plan 9,
ed, UTF-8, etc. sowie Turing Award
• Rob Pike — Unix, Plan 9, Inferno, Limbo,
UTF-8, etc.
• Robert Griesemer — Strongtalk, Java
HotSpot VM, V8 JavaScript Engine
13. Fortschritt
• 2014 wurde der der Gopher das Maskottchen
von Go; entworfen von Renée French, der
Ehefrau von Rob Pike
• Alle 6 Monate erscheint ein neues Release
• Aktuell Version 1.14.1
• Versprechen der Sprachkompatibilität
gleicher Hauptversionen
• Go 2 in Diskussion
15. Drei Binaries
• go — Wichtigstes Werkzeug mit vielen
Subcommands
• gofmt — Einheitliche Formatierung der Go
Quellen
• godoc — Generierung von Dokumentation
aus Kommentaren
16. go Subcommands (Auszug)
• build — Compiling der Quellen
• fmt — Formattierung der Quellen
• get — Packages herunterladen und
installieren
• install — Compiling und Installation der
Quellen
• mod — Verwaltung von Modulen
• test — Durchführung der Unit Tests
• vet — Bericht über gängige Fehler
17. go mod Subcommands (Auszug)
• download — Download von Modulen in
lokalen Cache
• init — Initialisierung eines Moduls im
aktuellen Verzeichnis
• tidy — Bereinigung der Abhängigkeiten
• vendor — Vendorize von Abhängigkeiten
• why — Erläuterung von Abhängigkeiten
19. Orientierung in Packages
• Code immer in Packages
• Ein oder mehrere Dateien pro Package in
einem Verzeichnis
• Sonderrollen
• main wird zu ausführbarem Programm
• <name>_test wird zu Unit Test von
Package <name>
• Packages lassen sich hierarchisch schachteln
20. Package main
!// main wird zu Programm mit dem Namen des Verzeichnisses
!// oder einem per Argument bestimmten Namen.
package main
!// Einstieg in das Programm.
func main() {
println("Hello, World!")
}
21. Import von Packages
• Import direkt nach dem Package Statement
• Externe Packages mit Domain und Pfad
• Eigene Domains mit Code auf z.B. GitHub
sind via Meta Tags in einem lokalen HTML-
Dokument ebenfalls möglich
• Package-Name als Präfix für Namensräume
• Aliase bei Namensgleichheit möglich
• Export durch Großschreibung, sonst package
private
23. Funktionen
• Schlüsselwort func
• Mit Namen, anonym oder als Methode
eigener Typen
• Beliebige Anzahl Parameter, letzter kann
variadisch sein
• Beliebige Anzahl Rückgabewerte ohne und
mit Namen
• Rückgabe mit Schlüsselwort return
24. Definition einer einfachen Funktion
!// Mul multipliziert f mit einer beliebigen Anzahl
!// Integer.
func Mul(f int, vs !!...int) int {
r !:= f
for _, v !:= range vs {
r *= v
}
return r
}
25. Funktion mit Ergebnis und Fehler
!// Div dividiert f ganzzahlig durch eine beliebige Anzahl
!// Integer.
func Div(f int, vs !!...int) (int, error) {
r !:= f
for _, v !:= range vs {
if v !== 0 {
return 0, errors.New("division by zero")
}
r !/= v
}
return r, nil
}
26. Optionen als Funktionen 1/3
!// Server ist ein Typ mit privaten Feldern.
type Server struct {
port int
!!...
}
!// Option ist eine Funktion, die auf einem Server operiert.
type Option func(s *Server)
27. Optionen als Funktionen 2/3
!// Port liefert eine Option zum Setzen des Felds port
!// zurück.
func Port(port int) Option {
return func(s *Server) {
s.port = port
}
}
28. Optionen als Funktionen 3/3
!// New erzeugt einen Server. Optionen sind !!... optional. ;)
func New(opts !!...Option) *Server {
s !:= &Server{
port: 12345, !// Standardwert.
!!...
}
for _, opt !:= range opts {
opt(s)
}
return s
}
32. Methoden und Interfaces
type StringProducer func() []string
func (sp StringProducer) Len() int {
return len(sp())
}
!// Sizer definiert in meinem Package, was ich von einem
!// Typ benötige.
type Sizer interface {
Len() int
}
func SizePrinter(sizer Sizer) { !!... }
33. Einbetten von Typen
type Honker interface {
Honk() string
}
!// Car bettet Honker ein, geht mit Structs und Interfaces.
type Car struct {
Honker
motor *Motor
!!...
}
myCar.Honk()
34. Flexibilität durch Interfaces
!// Handler in Package net/http definiert einen Handler für
!// Web Requests.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
!// ListenAndServe startet den Server mit einem Handler.
func ListenAndServe(addr string, handler Handler) error
35. Funktionstypen erlauben Methoden
!// HandlerFunc vereinfach den Handler zu nur einer Funktion.
type HandlerFunc func(ResponseWriter, *Request)
!// ServeHTTP implementiert den Handler und führt nur die
!// Handler-Funktion aus.
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
36. Weitere Implementierungen
!// ServeMux verteilt auf Handler nach Pfaden.
type ServeMux struct {
!!...
}
func (mux *ServeMux) Handle(pattern string, handler Handler) {
!!...
}
!// ServeHTTP implementiert Handler.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
!!...
}
37. Vom einfachem Interface zu Lösungen
• Multiplexer für HTTP Methoden
• Multiplexer für Schachtelung bei RESTful
APIs
• Schachtelung für Trennung von
Authentisierung/Autorisierung via JSON Web
Tokens o.ä.
38. Variablen explizit und implizit
• Mit Deklaration via var oder mit Zuweisung
durch :=
• Typisierung explizit oder implizit
• var kennt beides, := ist immer implizit
• Zuweisung mit =
39. Unterschiedliche Zuweisungen
var s1 string !// Deklaration
s1 = "Hello" !// Zuweisung
var s2 string = "World" !// Explizit mit Zuweisung
var s3 = s1 + ", " + s2 !// Implizit mit Zuweisung
s4 ":= s3 + "!" !// Deklaration implizit mit
!// Zuweisung
41. Bedingungen
• Mit if oder switch für logische Bedingungen
• Mit select für Channel
• switch und select kennen default an
beliebiger Stelle
• break nicht notwendig
• switch verfügt über fallthrough für die
Ausführung der Folgebedingung
42. Verzweigung mit if
if x > y {
x, y = y, x
}
if myFunctionReturnsTrue() {
fmt.Println("Juchu!")
} else {
fmt.Println("Schade")
}
43. Verzweigung mit switch
switch x {
case 1, 2, 3:
fmt.Println("1 bis 3")
!// Verpönte Weiterverarbeitung!
fallthrough
case 4, 5, 6:
fmt.Println("4 bis 6")
default:
fmt.Println("Keine Ahnung")
}
44. Verzweigung mit Bedingungen
!// Abarbeitung von oben nach unten, aber default immer nur
!// wenn nichts passt.
switch {
case x < 0:
fmt.Println("Kleiner als 0")
default:
fmt.Println("Ha! Genau 0")
case x > 0:
fmt.Println("Größer als 0")
}
45. Channel-Verzweigung mit select
select {
case !<-ctx.Done()
return ctx.Err()
case job !:= !<-jobs:
if err !:= job(); err !!= nil {
log.Printf("job failed: %v", err)
}
case !<-time.Tick(5 * time.Second):
log.Printf("I'm waiting !!...")
}
46. Schleifen
• Schlüsselwort for
• Verschiedene Formen der Bedingungen
• Vorzeitige Fortsetzung über continue
• Vorzeitiges Verlassen über break
• Label für geschachtelte Schleifen
• Arrays, Slices, Maps und Channel können mit
range iteriert werden
48. Schleifen 2/2
for i !:= 0; i < 2019; i!++ {
if i % 2 !== 0 {
continue
}
!!...
}
visitors !:= visitorsByWebinar("Devs@Home")
for i, visitor !:= range visitors {
fmt.Printf("Besucher %d ist %sn", i, visitor.Name)
}
50. Nebenläufigkeit
• Leichtgewichtige Funktionen (Goroutinen) im
Thread Pool
• Schnelle Kontextwechsel
• Kommunikation über typisierte Channel
• Abfrage mehrerer Channel gleichzeitig über
select
• Start mit Schlüsselwort go
• Gibt keine Instanz oder ID zurück
51. ❝In programming, concurrency is the composition of
independently executing processes, while parallelism
is the simultaneous execution of (possibly related)
computations.
Concurrency is about dealing with lots of things at
once. Parallelism is about doing lots of things at once.
Rob Pike
53. Typische Varianten von Goroutinen
• „Mach mal.“
• „Mach mal und bring mir dann das Ergebnis.“
• „Kümmere dich um alle meine Aufträge.“
• „Sei mein schlauer Kollege.“
61. Einfacher Taschenrechner
type Op func()
!// Calc ist ein Taschenrechner mit einem Wert als Zustand.
type Calc struct {
cancel context.CancelFunc
ops chan Op
value float64
}
62. Konstruktion des Rechners
func New(ctx cancel.Context) *Calc {
c !:= &Calc{
ops: make(chan Op, 1),
value: 0.0,
}
ctx, c.cancel = context.WithCancel(ctx)
go c.backend(ctx)
return c
}
69. Volle Kanäle 2/5
• Nicht wie bei OOP überschneidender Zugriff
• Serialisierung eingehender Nachrichten
• Synchrone Zugriffe werden blockiert, Queues
laufen voll und blockieren ebenso
70. Volle Kanäle 3/5
• Last möglichst beim Aufrufer belassen
• Zentrale Goroutine zur Datenverwaltung
• Weitere Last und Daten auf Arbeits-
Goroutinen verteilen
• Mutex / RWMutex in Go können helfen
71. Volle Kanäle 4/5
Client Server
DoThis()
Data()
API
return data
SetData()
Work()
Client Goroutine
74. Race Conditions 2/4
• Überlagerndes Lesen und Setzen
• Update durch Delta mit Rückgabe des neuen
Wertes
• Alternativ Rückgabe des Wertes mit Handle
für Aktualisierung
78. Nicht-atomare Veränderungen 2/3
• Auslöser sind zu granuläre Nachrichten und
nicht eingehaltene Protokolle
• Zusammenhängende Daten gleichzeitig
ändern beziehungsweise auslesen
80. Blockaden durch Cycles 1/3
Goroutine A Goroutine B
Goroutine C
Foo()
Bar()
Yadda()
return
return
81. Blockaden durch Cycles 2/3
• Auslöser sind synchrone Abfragen
• Timeouts zeigen Blockaden auf, vermeiden
jedoch nicht den Fehler
• Bei zwingender Abhängigkeit Design auf
Basis asynchroner Kommunikation
• Zustandsänderungen in den Prozessen
müssen dies berücksichtigen
82. Blockaden durch Cycles 3/3
Goroutine A Goroutine B
Goroutine C
Foo(1)
Bar(1)
Yadda(1)
SetBar(1)
SetFoo(1)
SetYadda(1)
84. Aufschieben
• Funktionen können im Ablauf mit defer
gestapelt werden
• Werden rückwärts beim Verlassen der
umgebenden Funktion ausgeführt
• Praktisch für Aufräumarbeiten, zum Beispiel
Schließen geöffneter Dateien
85. Mehrere gestapelte Aufräumer
file, err !:= ioutil.TempFile("/tmp", "webinar-*")
if err !!= nil {
return fmt.Errorf("failed to open temp file: %v", err)
}
defer file.Close()
writer !:= bufio.NewWriter(file)
defer writer.Flush()
writer.WriteString("Webinar Devs@Homen")
writer.WriteString("Einführung in Gon")
86. Fehlerbehandlung
• Keine Exceptions
• Fehlertyp error als letzter Rückgabewert
• Interface mit Methode Error() string
• Helfer im Package errors
• panic() für echte Ausnahmesituationen
• Kann mit recover() aufgefangen werden
87. Paniken auffangen
func CanBreakHard(x int) (err error) {
defer func() {
if r !:= recover(); r !!= nil {
err = fmt.Errorf("panic: %v", r)
}
}()
!!...
if veryBadCondition {
panic("have a very, yes, very, very bad condition")
}
return nil
}
94. Fast wie Scripting
• Einfache Syntax
• Leichtgewichtiges Typenmodell
• Wenige Schlüsselworte
• Schnelle Kompilation erlaubt schnelle Tests
• Aber: Manchmal mehrere Lösungswege
möglich
• Nutzung etablierter Konventionen hilft
95. Einfache Nebenläufigkeit
• Prinzipiell nur Funktionen
• Flexible Kommunikation
• Weitere Hilfen zur Synchronisation
• Aber: Kein Schutz vor gleichzeitigem Zugriff
auf Variablen
• Aber: Kein Schutz vor Locks und Races
• Tools helfen, ansonsten Verantwortung des
Entwicklers