Aus Linux-Magazin 04/2015

Programmieren mit Go

© vvvita, 123RF.com

2009 legte die von Google initiierte Programmiersprache Go einen wilden Start hin. Spätestens seit 2012, dem Erscheinungsjahr von Version 1.0, gilt Go als stabil. Sie bringt recht erbauliche Features mit, die Entwicklern lästige Routinearbeiten abnehmen. Ist Go inzwischen im Mainstream angekommen?

Mit Go kam 2009 eine auf den ersten Blick simple Sprache zur Welt [1], die wie ein modernes C wirkte. Neben ihrem Markenzeichen CSP (Communicating Sequential Processes, [2]) als Lösung für Nebenläufigkeit, schlugen auch Einflüsse von Limbo [3] und Inferno [4] durch. Die Entwicklung fing damals gerade erst an und Änderungen im Wochenrhythmus führten mitunter dazu, dass sich eben noch lauffähiger Code nicht mehr kompilieren ließ.

Erst 2012 wurde Go 1.0 mit dem Versprechen veröffentlicht, dass der geschriebene Code auch mit zukünftigen Versionen der 1.x-Reihe funktioniert. Seitdem liegt der Fokus der Go-Entwickler auf den Tools, Compilern und der Runtime.

Das Buildsystem

Im Jahr 2009 brachte Go noch kein eigenes Buildsystem mit. Vielmehr mussten Entwickler die Compiler und Linker manuell aufrufen oder für größere Projekte Makefiles schreiben, ähnlich wie in C. Da Go es jedoch erleichtern sollte, komplexe und verteilte Projekte zu entwickeln, musste eine bessere Lösung her. Das »go« -Tool lieferte ein einfach zu bedienendes Buildsystem ohne Konfiguration. Mit Hilfe seiner diversen Funktionen lassen sich Projekte bauen und mit diesen arbeiten. Die wichtigsten Funktionen zählt Tabelle 1 auf.

Tabelle 1

Wichtige Go-Tool-Funktionen

Funktion

Effekt

go build

Damit kann ein Entwickler Pakete bauen, um zu schauen, ob der Compiler zufrieden ist (für die Bibliotheken), oder um schlicht ausführbare Dateien zu erzeugen.

go install

Verhält sich ähnlich wie »go build« , speichert aber das Ergebnis auch für Bibliotheken, damit spätere Kompiliervorgänge schneller ablaufen.

go get

Der Befehl lädt sowohl die Abhängigkeiten des aktuellen Projekts als auch allgemein Pakete aus dem Internet herunter.

Wie erwähnt brauchen all diese Funktionen keine Konfiguration, ein Entwickler muss also weder Makefiles schreiben noch Abhängigkeiten explizit auflisten, noch auf den Quelltext verlinken. Das ermöglichen im Kern zwei simple Prinzipien: Die »GOPATH« -Umgebungsvariable (Abbildung 1), die sich ähnlich wie »PATH« verhält und einen oder mehrere Workspaces angibt sowie die Paketpfade. »GOPATH« ist ein wichtiges Konzept. Die Variable bestimmt, wo Go die Quellen eines Pakets findet und wo es Objektdateien speichert. Jeder Workspace besteht dabei aus drei Ordnern:

Abbildung 1: Die »GOPATH«-Variable und ihre Pfade in einem Beispielprojekt.

Abbildung 1: Die »GOPATH«-Variable und ihre Pfade in einem Beispielprojekt.

  • »src/« speichert Quellcode
  • »pkg/« speichert Objektdateien
  • »bin/« speichert kompilierte, ausführbare Dateien

Führt der Entwickler also »go build« aus, sucht das Buildskript die Quelltexte in »$GOPATH/src/« , und »go install« schreibt Dateien nach »$GOPATH/pkg/« sowie »GOPATH/bin/« .

Alle Quelltexte sind in Pakete unterteilt. Jeder Ordner und Unterordner in »$GOPATH/src/« stellt ein einzelnes Paket dar, jeder Quelltext muss sich in einem solchen Paket befinden, damit Go ihn findet. Aber anders als zum Beispiel Workspaces in Java bezieht sich ein Workspace in Go nicht ausschließlich auf ein einzelnes Projekt. Vielmehr referenziert es eine Sammlung von Go-Paketen und -Projekten, sozusagen die eigene Kopie eines Teils des Go-Universums. Daher finden sich meist verschiedene Projekte in einem einzelnen Workspace.

Jedes Paket lässt sich über einen individuellen Pfad erreichen. Während Pakete in der Standardbibliothek nur sehr kurze Pfadnamen tragen, etwa »fmt« oder »net/http« , sollten eigene Pakete eindeutige Namen besitzen, die nicht mit den Namen der Pakete anderer Entwickler kollidieren. Daher verwenden Programmierer häufig den Pfad, über den sie das Paket im Internet erreichen, etwa auf Github [5]. Ein Pfad heißt dann zum Beispiel »github.com/Benutzer/example« . Dieser Pfad ist eindeutig, da niemand anderes den Benutzernamen verwenden kann. Zugleich erlaubt es diese Art der Benennung später, die Pakete automatisch aus dem Internet zu beziehen.

In Aktion

Die folgenden Listings verdeutlichen die Dateistruktur und zeigen die Tools in Aktion. Nach Vorbild von Listing 1 erstellt ein Entwickler die Grundstruktur für ein Paket. Der Pfad lautet »github.com/Benutzer/hallo« , in der Annahme, dass das Paket dereinst auf Github gehostet werden wird. Listing 2 zeigt den Quelltext des eigentlichen Programms, das, weil es in der Datei »$GOPATH/src/github.com/Benutzer/hallo« steckt, den Namen »hallo.go« trägt. Es könnte aber auch anders heißen, etwa »main.go« .

Listing 2

hallo.go

01 package main
02
03 import "fmt"
04
05 func main() {
06   fmt.Println("Hallo, Benutzer.")
07 }

Listing 1

Pfad anlegen

01 $ export GOPATH=~/go/
02 $ mkdir -p $GOPATH/src/github.com/Benutzer/hallo

Listing 3 kompiliert das Projekt. Hierzu übergibt der Entwickler den Pfad zum Paket und erhält als Dank eine ausführbare Datei im aktuellen Verzeichnis. Die heißt nach dem Ordner mit dem Quelltext, in diesem Fall also »hallo« . Wer das Programm ausführt, den begrüßt es auf etwas steife Art und Weise.

Listing 3

go build

01 $ go build github.com/Benutzer/hallo
02 $ ./hallo
03 Hallo, Benutzer.

Auch Listing 4 kompiliert das Projekt, allerdings über »go install« und nicht »go build« . Das Endresultat landet im selbst festgelegten Ordner »$GOPATH/bin/« . Davon abgesehen verhält sich das Programm identisch.

Listing 4

go install

01 $ go install github.com/Benutzer/hallo
02 $ $GOPATH/bin/hallo
03 Hallo, Benutzer.

Listing 5 zeigt eine etwas veränderte Version des Programms, die eine externe Bibliothek verwendet, um Parameter auf der Kommandozeile zu übergeben. Go bringt hierzu zwar auch das Paket »flag« in der Standardbibliothek mit, dieses implementiert aber die Flag-Regeln von Plan 9, nicht die von Gnu. Der Versuch, es zu kompilieren, schlägt fehl, wie Listing 6 veranschaulicht.

Listing 6

Vergessene Abhängigkeiten

01 $ go build github.com/user/hallo
02 github.com/user/hallo/main.go:5:3: cannot find package "github.com/ogier/pflag" in any of:
03         /usr/lib/go/src/github.com/ogier/pflag (from $GOROOT)
04         /home/dominikh/go/src/github.com/ogier/pflag (from $GOPATH)

Listing 5

hallo.go (Version 2)

01 package main
02
03 import (
04   "fmt"
05   "github.com/ogier/pflag"
06 )
07
08 func main() {
09   name := pflag.String("name", "Unbekannt", "Dein Name")
10   pflag.Parse()
11   fmt.Println("Hallo,", *name)
12 }

Das liegt daran, dass der Nutzer das Paket »pflag« einfach noch nicht heruntergeladen hat. Bei dieser Aufgabe hilft »go get« . Es holt Pakete aus dem Netz und installiert sie, was rekursiv geschieht, wodurch es auch alle Abhängigkeiten einspielt. Ruft der Entwickler, wie es Listing 7 zeigt, zuerst »go get« für das eigene Paket auf, beschafft er auch alle Abhängigkeiten, im konkreten Fall »pflag« .

Listing 7

go get

01 $ go get github.com/Benutzer/hallo
02 $ go build github.com/Benutzer/hallo
03 dominikh-pc ./junk/src $ ./hallo
04 Hallo, Unbekannt
05 dominikh-pc ./junk/src $ ./hallo --name="lieber Leser"
06 Hallo, lieber Leser
07

Dieser Ablauf skaliert problemlos für Hunderte von Paketen und Abhängigkeiten. Der Entwickler muss nie sagen, wie genau der Buildprozess ablaufen soll, welches Versionskontrollsystem er verwendet oder wie er Abhängigkeiten herunterladen möchte.

Nie mehr Streitereien

So banal es auch klingt: Im Arbeitsalltag vergeuden Programmierer unvorstellbar viel Zeit damit, sich über richtige Codeformatierungen zu streiten. Leerzeichen oder Tabs? Wie viele Leerzeichen? Wohin kommen die geschweiften Klammern? Jeder Entwickler hat hier eigene Vorlieben, in Teams mit mehreren Programmierern kommt es darüber nicht selten zu Streit. Weil das so ist, gilt es, für jedes neue Projekt oder jeden neuen Job neue Richtlinien auswendig zu lernen – auch das braucht Zeit.

Go kennt dieses Problem nicht. Es bringt ein Tool namens »gofmt« mit, das den Code für Entwickler formatiert, und zwar auf die einzig richtige Art und Weise (Abbildung 2). Es bietet keine Optionen an, die das Ergebnis beeinflussen, und jeder neue Go-Entwickler wird aufgefordert »gofmt« zu benutzen. Somit fallen die Diskussionen zu Codeformatierungen weg, wird der Code weltweit einheitlich gestaltet. Das spart zugleich Zeit beim Lesen von Code, da zumindest das Aussehen bekannt ist.

Abbildung 2: Das Tool »gofmt« formatiert den Go-Code automatisch, was Diskussionen und Zeit spart.

Abbildung 2: Das Tool »gofmt« formatiert den Go-Code automatisch, was Diskussionen und Zeit spart.

Tools, Tools und nochmals Tools

Inspiriert durch die offiziellen Tools, zum Beispiel das Buildsystem und »gofmt« , programmieren viele Entwickler ihre eigenen Werkzeuge. Prominent sind Tools wie Autocompletion, Refactoring und Linter, doch es gibt auch viele andere Helfer, die kleine, wiederkehrende Aufgaben erledigen.

Das klappt vor allem, weil die Standardbibliotheken von Go einen Parser für die Sprache selbst an Bord haben. Außerdem folgt Go dem Unix-Prinzip “Write programs that do one thing and do it well”, weswegen solche Tools nicht Teil einer riesigen IDE sind. Stattdessen arbeiten sie meist auf der Kommandozeile und lassen sich mit jedem beliebigen Editor kombinieren.

Eine Community auf Go

Eine Programmiersprache kann so gut sein, wie sie will, ohne Community hebt sie nicht ab. Go hat so eine Community. Neben Google gehört eine lange Liste bekannter Firmen [6] zu den Go-Nutzern, darunter etwa die BBC, Canonical und Dropbox.

Das Ziel von Go bestand von Anfang an darin, das Entwickeln von Serveranwendungen zu vereinfachen, genau das tut es heute. Etwa im Fall von Docker [7], die Containervirtualisierung ist komplett in Go geschrieben. Auch Ubuntu-Hersteller Canonical setzt auf Go, sowohl für Juju [8] als auch für LXD [9]. Disqus nutzt es für sein Kommentarsystem – die Aufzählung ließe sich fortsetzen.

Eine Fülle von Usergroups, Meet-ups und Konferenzen stärkt die Community zusätzlich. Allein im vorigen Jahr gab es drei gut besuchte Veranstaltungen nur für Go: die Gophercon [10], Dot Go [11] und die Gocon Tokyo. Nicht zuletzt finden auf der Fosdem regelmäßig ausgebuchte Veranstaltungen zu Go statt. Es scheint also tatsächlich, als sei die Sprache im Mainstream angekommen und werde vorerst auch dort bleiben.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 3 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben