golang rockt!
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 84 | |
Author | ||
License | CC Attribution 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/32428 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
FrOSCon 201656 / 84
2
4
5
7
11
16
25
26
27
28
29
30
31
32
34
36
37
40
41
43
46
47
48
49
50
52
55
56
58
59
62
63
64
65
66
67
68
69
70
71
72
73
75
76
77
79
82
83
84
00:00
Programming languageState of matterCodeXMLUMLLecture/Conference
01:35
Moment (mathematics)Order of magnitudeState of matterMemory managementDirection (geometry)TypsystemHöheGoogleComputer animationLecture/Conference
02:57
Overhead (computing)ZugriffMemory managementSoftware developerSearch engine (computing)Web browserInternetdienstProxy serverProgrammer (hardware)Lecture/Conference
04:34
Smart cardBeat (acoustics)Programming languageCodeLecture/Conference
05:43
Programmer (hardware)Lecture/Conference
07:19
Liste <Informatik>SoftwareLaufzeitSupremumProgramming languageSource codeStack (abstract data type)Web serviceJavaScriptLösung <Mathematik>Lecture/Conference
10:50
Variable (mathematics)OperatorInferenceFunction (mathematics)French braidHidden surface determinationProgramming language
12:02
Variable (mathematics)Function (mathematics)TypsystemLoop (music)Data typeDepictionAliasingComputer multitaskingLecture/Conference
13:57
Variable (mathematics)InferenceComputer fileMetreHighlight <Programm>Scripting languageRegular expressionString (computer science)IndexSlide ruleMilitary rankParameter (computer programming)EditorLecture/Conference
16:58
TOUR <Programm>CodeWeb browserVariable (mathematics)Parameter (computer programming)Programming languageSource codeSoftware repositorySequenceCalculationLaufzeitExplosionswelleSimilarity (geometry)Scripting languageCompilerIP addressSoftware testingJUnitThread (computing)Computer fileMoment (mathematics)Lecture/Conference
26:44
Content (media)Function (mathematics)Revision controlVersion <Informatik>ZugriffRoute of administrationAustauschformatMechanism designProcess (computing)Electronic signatureComputer fileSource codeOpen sourceC-CompilerMassCodeScripting languageServer (computing)Field extensionCache (computing)Software repositoryLecture/Conference
36:31
Function (mathematics)Hidden surface determinationElectronic signatureString (computer science)Mover <Programm>Logical constantObjektorientierungKennzahlDebuggerData typeTracing (software)LaufzeitBenchmarkOverhead (computing)Object-oriented programmingObject (grammar)ProviderGDB <Programm>Computer programmingSoftware developerIndexInternetIntelSmart cardApple <Marke>Strich <Typographie>HierarchyTOUR <Programm>Lecture/Conference
46:17
Set (mathematics)Order (biology)Order of magnitudeFunction (mathematics)CoroutineSocial classWeb serviceUbuntu <Programm>Multitier architectureManual of StyleGRADEAlgebraic closureTOUR <Programm>Computer fileSchaleOnline chatContent (media)Channel <Internet>Hidden surface determinationSlide ruleError messageString (computer science)Error detection and correctionCodeThread (computing)StatisticsEquivalence relationCommon-LISP object systemREDUCE <Programm>Level (video gaming)Electronic signatureAndroid (robot)Variable (mathematics)Physical quantityLecture/Conference
56:03
Programming languageIndexComputing platformUniform resource locatorHigh availabilityTOUR <Programm>C-CompilerHeuristicGit <Software>APISoftware repositoryInformationEmacsRoundingWINDOWS <Programm>Eigenvalues and eigenvectorsLecture/Conference
01:05:50
Computer animation
Transcript: German(auto-generated)
00:08
Jo, ist viertel vor, denke ich. Also wenn das mit dem Video tut, perfekt, super, dann können wir, denke ich, starten. Cool, dass so viele da sind. Ich hatte so ein bisschen Bammel, letzter Vortrag am Sonntagabend. Wer kommt dann da überhaupt noch? Aber das Thema ist ja durchaus ein schönes, interessantes.
00:24
Wer hat denn hier schon mal was von oder schon mal ein bisschen was mit Gula gemacht oder schon mal was reingeguckt? Ah, super. Hab ich mir gedacht, das hat auch einige sind, die schon interessiert sind und sich das eigentlich noch mal anhören, weil es alles so schön ist. Ganz gerne könnt ihr auch ruhig da, wo ich irgendwie Sachen sage oder sowas und
00:43
denke, ah, hier habe ich auch noch was zu sagen oder das finde ich cool. Also mir geht es um ein bisschen Stimmung rüber zu bringen, warum das so eine coole Sprache ist. Ich habe recht trocken viel Code vorbereitet. Also wenn ihr irgendwo sagt, ah, hier, das ist übrigens noch ein super Aspekt, oder was gerne dazwischengrätschen und so ein bisschen Stimmung machen dafür, dass das eine schöne Programmiersprache ist.
01:01
Ich habe relativ viel Code auch wirklich drauf getan, weil ich wollte eine Programmiersprache vorstellen. Das geht nicht ohne, dass man Code sieht, denke ich. Ich habe kein Gefühl dafür, ob es zu viel ist oder ob es passt. Wenn ich irgendwie zu schnell bin, dann könnte ich einfach Stopp sagen. Andererseits sind die Sachen auch alle natürlich online, könnte also auch hinterher reinschauen. Soll nicht jede Sache voll verstanden werden, sondern einfach ein kleiner Einblick sein, dass ihr eine Idee kriegt, wie das sich anfühlt insgesamt.
01:27
Also Golang ist eine relativ neue Programmiersprache, aber Gosang auch noch relativ neu. Das heißt, es ist auch schon sehr, sehr, also schon abgehangen genug, um es wirklich voll zu benutzen. Go 1.0 habe ich mir angeschaut, ist in 2012 rausgekommen. Im Moment sind wir bei Go 1.7, was jetzt irgendwie drei Wochen alt ist.
01:45
Und ich gucke immer regelmäßig, auch um das in der Firma so ein bisschen zu argumentieren, dass es wirklich jetzt irgendwie zwar noch nicht ganz so bekannt ist, aber durchaus Sinn macht auch, da drauf zu setzen und nicht morgen wieder weg ist. Jetzt gucke ich mir mal die Google Trends an, die doch zunehmend irgendwo Höhe zeigen.
02:02
Wenn man das so mit Java vergleicht, dann ist zwar die Größenordnung ganz, ganz andere, die man bei Java erreicht bei Google Trends. Dafür ist es ein ganz, ganz anderer Trend in die andere Richtung. Golang ist unter BSD-Lizenz, wurde von Leuten bei Google erfunden und maintained und immer noch ganz stark von dort getrieben. Es ist eine statisch typisierte Sprache, sehr, sehr strenges Typsystem dahinter,
02:29
einen Garbage-Collector dahinter, das heißt, man hat irgendwo mit Low-Level-Speicherverwaltung nichts zu tun, wenn man das nicht will. Und es produziert statisch gelingte Binaries. Insgesamt ist es so, sage ich mal ein bisschen, wenn man sich so ein Dreieck von Sprachen,
02:44
also vielleicht C, Python und Java anschaut, liegt es da so in der Mitte von dem, was an Sprache ist. Ich komme aus der Java-Ecke, habe lange Jahre viel Java gemacht und mir gefällt Golang so gut, weil es ist direkt da, ich habe den ganzen Overhead nicht, es ist nicht so bloated und trotzdem vermisse ich irgendwo nichts.
03:02
Das heißt irgendwie, es ist eine Sprache, in der ich trotzdem allen Komfort habe. Das heißt, mir fliegt nicht bei einem Nullpointer Zugriff plötzlich das ganze System gnadenlos weg oder ich habe jetzt nicht dauernd Probleme mit Speicherverwaltung, weil es so kompliziert ist. Das heißt also, man hat die Direktheit wie bei C vielleicht, ich bin kein C-Programmierer,
03:21
aber man hat die Nähe zum Programm, man weiß so ein bisschen, was der Speicher macht, ohne dass man die Komfortfunktion vermissen muss. Haupteinsatzzweck ist ganz klar serverseitig. Es gibt so ein paar Bestrebungen, das auch irgendwo im Browser laufen zu lassen, Transcompiled oder auch GUI-Bibliotheken ein paar, aber das sind irgendwie ganz starke Ausnahmen.
03:43
Ich meine mal, so ein paar Experimente wird nicht wirklich in der Breite verwendet. Das heißt ganz klar, Einsatzzweck, wofür es heutzutage verwendet wird, sind serverseitige Programme, Web-Server, Reverse-Proxys gerne. Das heißt vor allem in den Microservice-Architekturen, wo die Dienste immer kleiner werden, sieht man sehr, sehr viel Go. Und das schlägt sich auch in den populären Projekten, die in Go geschrieben sind, nieder.
04:05
Also vielleicht noch Go und Golang. Mir hat schon mal einer gesagt, ach, Golang ist schon lange out, bald kommt Go raus oder bald gehen alle auf Go. Go und Golang sind einfach zwei Synonyme, da kann man einfach das eine oder das andere verwenden. Go selbst ist eine Suchmaschine relativ schwer zu finden.
04:21
Das heißt, wenn man nach Go googelt, wird man sehr, sehr schnell das Wort Golang verwenden, aber im Sprechen ist halt Go trotzdem einfacher. So der ein bisschen Zufluss hat Go ganz klar durch Docker bekommen. Docker ist in Go geschrieben und damit auch sehr, sehr viel vom Ökosystem drum herum. Es gibt aber auch einige andere Projekte und viel von dem, was irgendwie jetzt neu kommt, merkt man wirklich.
04:42
Neue Projekte von den Cutting-Edge-Firmen. Da wird sehr, sehr viel gerade in Go angefangen. Ich habe jetzt mir diese Elastic Beats oder wie die heißen, die Log-Stages ein bisschen ablösen, gerade eben angeschaut von Elastic. Auch nicht mehr in Java geschrieben, sondern in Go. Und irgendwie ist der Trend schon ziemlich deutlich dabei.
05:03
Warum verwende ich so gerne Go? Hat für mich so ein paar ganz einfache Gründe. Ich bin jetzt 36, das war noch nicht so alt, aber ich bin nicht mehr ganz so jung. Ich habe keine Lust mehr, mir dauernd irgendwie zu komplexe Sachen zu merken. Das heißt, ich will irgendwo ein sehr, sehr einfaches Werkzeug haben, weil die Probleme, die ich jeden Tag lösen muss, sind mir schon komplex genug.
05:21
Deswegen möchte ich ein Tool haben, was einfach zu verstehen ist, was ich wirklich verstehen kann und beherrschen kann. Und das Gefühl habe ich da. Das heißt, das ist nicht das allerschönste Tool teilweise. Also Go versucht nicht, die allerhübscheste Programmiersprache zu sein. Also irgendwelche DSLs oder skala-mäßig oder ich weiß nicht was, kann ich in Go ein bisschen vergessen.
05:40
Aber es ist eine Programmiersprache, in der ich sehr, sehr einfach verständlichen Code produzieren kann, den anderen verstehen, den ich selbst verstehen kann. Das heißt, es ist nicht unbedingt das allerschönste, aber es ist sehr, sehr gut. Und da liegt halt auch in dieser Einfachheit auch dann doch wieder eine Schönheit drin. Ich habe gemerkt, ich war drei Wochen in Norwegen, so gar nichts mit IT, drei Wochen an dem Computer, nicht dabei gehabt, aber nicht angemacht.
06:01
Das Schöne ist, ich kam zurück und ich konnte mich noch an alles in Go erinnern. Und das ist mir bei Java nach dem Urlaub schon manchmal anders gegangen. Ich mache auch manchmal diesen Bierdeckeltest. In Go bin ich in der Lage, auf einem Bierdeckel vielleicht nahezu auswendig aufzuschreiben, wie ich einen HTTP-Server programmieren muss, die paar Zeilen, den zu starten. Nach 15 Jahren Java-Entwicklung bin ich nicht in der Lage, auf einem Bierdeckel aufzuschreiben,
06:24
wie ich einen HTTP-Server in Java mit der Standard-Bibliothek starten würde. Ich glaube, sogar in der Java-Standard-Bibliothek gibt es auch mittlerweile ein paar ganz einfache Methoden, aber man weiß es einfach nicht, weil alles ist groß, es gibt 5.000 Wege, was zu machen.
06:40
Und es ist halt irgendwo auch nicht mehr idiomatisch, das Java. Ich habe so ein paar Sachen mal zusammengefasst über die Vorbereitung, wo ich sage, okay, was macht Go für mich auf, so ein paar Charaktereigenschaften. Ja klar, skalierbar, das ist so, sage ich mal, das, womit es am meisten daherkommt. Aber das Schöne ist, das skalierbar, das merke ich jetzt wirklich, das sind zwei Aspekte.
07:00
Das eine ist, es ist skalierbar aus dem technischen Aspekt, das heißt, man kann wirklich skalierbare Programme machen. Es ist aber auch in der Organisation und prozessual skalierbar. Das heißt, man kann mit mehreren Leuten daran arbeiten, verschiedenste Leute verstehen das. Auch jemand, der gerade seine Ausbildung bei uns fertig gemacht hat, kann das einsetzen. Und man kann es an andere Teams verteilen. Das heißt, es skaliert also nicht nur im technischen Sinne, die Software dahinter,
07:22
sondern auch als Sprache und als Werkzeug skaliert es sehr, sehr gut. Ganz klar, sehr produktiv, das heißt, es ist ein Getting Things Done-Mentalität. Also, die Sachen sind sehr, sehr einfach. Es ist sehr, sehr schnell. Also, vor allem so, sage ich mal, die Ausführungsgeschwindigkeit. Ich vergleiche jetzt immer mit Java, ich würde kein Java-Bashing machen.
07:40
Man kann auch immer noch D.O.F.M. gut verwenden. Aber, und D.O.F.M. ist ja auch sehr, sehr schnell, wenn ich zur Laufzeit Sachen habe. Aber wenn ich so sehe, Spring Boot-Applikation heutzutage, wenn man die schnell macht, dann braucht die sieben Sekunden oder so, bis die gestartet ist und bis die mal eine Http-Anfrage beantworten kann. Ich habe es bei Goni gemessen, aber es ist irgendwie ein Bereich von 100 Millisekunden oder so, bis der Prozess gestartet ist und ein Listener oben hat.
08:03
Das ist sehr, sehr schön, wenn ich gerade Microservice-Architekturen habe, wo ich schnell einen Service wegschmeißen, durchstarten möchte oder so was. Das ist einfach super. Es ist simpel, es ist lesbar, es bietet keine unnötigen Abstraktionsschichten. Das heißt, wenn ich ein Problem habe, dann kann ich direkt in meiner IDE
08:24
in den Quellcode zur Standard-Bibliothek reinspringen, sehe, wie die Sachen gemacht sind und kann eigentlich ziemlich klar durchschauen, was irgendwo in dem Lösungs-Stack, den ich gerade verwende, drin steckt. Wenn ich da irgendwo, keine Ahnung, Life-Ray auf JBoy sind so meine schlimmsten Erfahrungen, wo zu viele Stacks einfach dazwischen sind oder GWT oder so was,
08:43
da ist man halt sehr, sehr weit von dem entfernt, was wirklich passiert. Und irgendwo finde ich zunehmend wichtiger, diese ganzen Schichten wieder rauszunehmen und wegzukriegen und das bietet halt Go, ohne dass man das Gefühl hat, man vermisst irgendwie Komfort.
09:01
Idiomatisch, das ist eigentlich fast noch, glaube ich, das wichtigste Wort da drin für mich. Also idiomatisch ist eine Programmiersprache dann, wenn sie ein Stück weit vorgibt oder wenn die Community und es einen ComeSense gibt, wie eine Lösung in der Programmiersprache aussehen sollte. Ja, war zu Beginn auch mal idiomatisch. Ja, was gibt es?
09:20
Das unidiomatischste, was es gibt, das heißt, es ist nur so ein Tool und man kann damit dann machen, was man möchte. Super flexible Sprache, aber es ist sehr, sehr schwer in dem Ökosystem Schritt zu halten, zu wissen, wie es verwendet wird. Und das ist halt, oder bei Pearl hatte ich das auch damals irgendwie vor 20 Jahren zurück. In Pearl gab es zig Wege, irgendeine Kleinigkeit zu machen
09:42
und ich habe es nie geschafft, das von einem an, also, könnt ihr euch alle vorstellen, wie es aussieht. Bei Go ist das anders, das heißt eigentlich, zwei Go-Entwickler haben für das selbe Problem sehr, sehr häufig eine sehr, sehr ähnliche Art und Weise, das runterzuschreiben, weil dieses minimalistische Toolset und die idiomatische Denke dabei
10:01
ein Stück weit vorgibt, wie man das Ganze machen sollte. Da kann man sagen, okay, da fehlt ein bisschen die Vielfalt, aber das Schöne ist halt, ich kann mir Go-Code anschauen von jemand anderem, kann den lesen und komme sehr, sehr schnell rein, weil halt doch die Denke ziemlich schnell zusammenrutscht. Ganz großes Zeichen davon ist, dass halt die Formatierung beispielsweise bei Go
10:22
direkt mit dem Standard-Tooling ausgeliefert wird. Ein Standard-Formatter ist festgelegt, wie Go-Code auszusehen hat und formatiert wird und ich habe nicht, von vornherein nicht die Diskussion, wie ich es formatieren soll, weil es eh egal ist. Die Syntax ist im Prinzip an die C-Syntax, die wir alle wahrscheinlich kennen,
10:43
grundsätzlich angelegt, aber doch sehr, sehr reduziert und das ist das Schöne an Go als neue Programmiersprache. Es ist halt im Vergleich zu anderen Programmiersprachen sehr, sehr jung. Das heißt, es hat zwar die Anlehnung an eine C-Syntax, aber hat ganz, ganz viele Zöpfe abgeschnitten und viele kleine Veränderungen, Verbesserungen aus meiner Sicht reingebracht,
11:04
die die Syntax viel benutzbarer machen. Es ist sparsamer, es hat keine Klammern beispielsweise, wo man sie nicht braucht. Das sind Statements beispielsweise oder kein abschließendes Semikolon. Es hat viel oder nicht viel, aber teilweise Konventionen,
11:20
sodass man beispielsweise keine Public-Private-Modifier braucht, sondern einfach es gibt zwei Sichtbarkeiten innerhalb eines Packages. Kleingeschriebene Bezeichner sind innerhalb des Packages sichtbar, groß beschriebene Bezeichner bei Funktionen oder auch bei Variablen werden exportiert, sind außerhalb des Packages nutzbar. Die Sprache ist ja an sich sehr, sehr stark und streng typisiert,
11:42
also noch deutlich strenger als Java typisiert. Macht es aber trotzdem beim Schreiben einfach, weil es gibt so einen schönen Operator Doppelpunkt gleich für Zuweisungen und der macht dann eine Inferenz automatisch auf den Typ, den der zugewiesene Wert hat und kann damit recht gut automatisch bestimmen, von was für einem Typ eine Variable sein muss,
12:01
sodass man sich letztendlich trotz der strengen Typisierung nicht so viel Syntax drumherum schreiben muss. Es gibt einen sehr, sehr mächtigen For-Loop, also einen Loop nur, es gibt nicht einen While oder was weiß ich nicht alles, sondern es gibt halt einfach nur einen Konstrukt für Loop, das ist ein For, das kann man auf verschiedene Art und Weise verwenden.
12:20
Das If sehen wir gleich noch, ist zweiteilig ein bisschen mächtiger gemacht worden und eine der schönsten Funktionen haben wieder, wie es früher manchmal war, mehrere Rückgabewerte. Das heißt, ich bin nicht auf einen Rückgabewert limitiert, ich kann halt einfach einer Funktion mehrere Rückgabewerte zurückgeben. Das Typsystem, dachte ich, ist schon sehr, sehr streng typisiert.
12:42
Das heißt, man kann wirklich eine Variable, die einen Typ hat, nur eine andere Variable mit genau demselben Typ zu ordnen, also es gibt keine Ersetzbarkeit, wie das sonst bei einer Ableitungsherachie oder was in Java der Fall wäre, sondern halt nur exakte Zuweisungen. Manchmal nervt das ein bisschen, aber es bringt halt auch sehr, sehr viel Sicherheit.
13:04
Es gibt gute Build-ins, also primitive Datentypen, Maps und Slices, die man wirklich verwenden kann zu Arrays. Arrays sage ich jetzt mal nichts, also Slices sind so was ähnliches wie Arrays, Arrays sind nur ein Schickchen anders vom Konzept her. Und es gibt Interfaces, die auch direkt wieder einen Typ darstellen.
13:21
Komme ich aber gleich noch zu. Hier mal so zwei Typdefinitionen. Man kann Typ als Alias Typ definieren, also hier ist zum Beispiel ein Punkt. Jetzt habe ich sogar hier den Array als Beispiel genommen. Ein Punkt ist ein von mir vergebener Typ, der in dem Fall dasselbe ist wie ein zweielementiges Array als Typ.
13:41
Das heißt, ich kann einfach selbst Typen vergeben, die auf anderen Typen aufbauen. Oder hier beispielsweise ein Struct-Typ, im Prinzip wie eine Struktur. Ein einfach Struct-Typ, mit dem ich den Namen User gebe, mit zwei Feldern, Username und Nickname. Hier kann ich noch Annotationen dazu geben, die für andere Tools auf dir darauf arbeiten.
14:03
So kann ich dann beispielsweise einen Struct erstellen und zuweisen. Das heißt, ich habe eine Variable User und der weise ich ein neues Struct vom Typ User zu und übergebe hier direkt die initialen Werte an der Stelle.
14:20
User ist jetzt auch streng typisiert, hat also ganz klar diesen Typ, den ich hier angebe, was automatisch durch diese Inferenz hier abgeleitet wird aus dem, was ich zuweise. Das heißt, Doppelpunkt gleich, macht eine neue Variable User und weist direkt den Wert zu. Hier mal ein einfaches kleines Group-Programm, um so eine Idee für die Syntax zu bekommen.
14:43
Ich habe in meinen Slides leider kein Highlighting mehr reingefummelt bekommen. Ich kann aber auch, kurz die Sachen im Editor öffnen, das ist vielleicht etwas angenehmer, oder? Besser?
15:01
Also alles, was ich habe, jede Datei gehört zu einem Package, wie die Datei heißt dabei, ist go lang egal. Ich habe Imports von anderen Packages, hier jetzt für das Beispiel ein Regular Expression Package, was ich reinziehe. Einspunktpunkt für jedes Programm ist die Function Main im Package Main. Die wird halt einfach als erstes ausgeführt.
15:21
Die hat anders als in den meisten Sprachen keine Argumente. Die nimmt sich einfach aus einer Library das, was sie braucht, wenn sie auf Parameter zugreifen möchte. Wird ausgeführt. Hier lege ich einen Slice, also einfach eine Liste von Strings an, wo ich mal drei Werte reinpacke. Ja, war es fun. Und dann iteriere ich einfach da drüber.
15:42
Man sieht jetzt von diesem For Loop, ich werde nicht alle Sachen erklären, ich will halt einen Eindruck geben und deswegen würde ich nicht im Detail drauf gehen, aber vom For Loop gibt es verschiedene Varianten. Der eine ist, der ist so ein iterator Gedanke, da kann ich mit dem Range-Ausdruck über eine Liste, also über einen Slice drüber iterieren. Range gibt mir als Rückgabe zwei Werte.
16:01
Das erste wäre der Index, also 0, 1, 2, bin ich nicht daran interessiert, deswegen verwerfe ich das mit dem Unterstrich. Und das zweite ist der Value, den ich beim iterieren kriege, den habe ich halt beim iterieren dann in der Value Variable. Hier kompiliere ich mir einen regulären Ausdruck. Stimmt, das hätte ich auch außerhalb des For Loops machen können.
16:22
Muss ich nicht jedes Mal neu machen. Und dann, einfach nur um ein Beispiel zu haben, mache ich mit dem regulären Ausdruck ein Replace auf dem Value und ersetze damit Java durch Golang und printe das Ganze aus. Also einfach nur ein sinnloses Beispiel um zu zeigen, wie das Ganze läuft.
16:42
Das Schöne ist, ich brauche jetzt, also Go ist ja eigentlich eine kompilierte Sprache, Static Binary kommt draus, aber es gibt auch einfach einen Go-Run, mit dem ich einfache Skripte sage ich jetzt mal ausführen kann, damit es im Hintergrund ein Binary herausstellt und deshalb wird halt direkt ausgeführt. Das heißt, mit Go-Run kann ich das direkt laufen lassen.
17:01
Hier sieht man auch schon direkt, dass es doch relativ schnell ist. Das heißt, obwohl das jetzt kompiliert und ausführt, ist es ja kein Skript oder sowas, sondern der baut ein Binary und fützt aus, funktioniert das auch schon sehr sehr gut. Also ich schätze jetzt etwa ein Megabyte oder sowas.
17:20
Statisch gelingt, alles drin. Also so eine, ich möchte jetzt nicht reingucken in die Sachen, sonst habe ich zu wenig Zeit da. Ich habe so die normalen, also wenn ich so ein bisschen Web-Server mit ein, zwei Libraries drin habe, dann bin ich meistens so bei 6, 7 MB oder sowas. Da ist halt alles drin. Im Prinzip ist es halt auch deutlich mehr, wenn ich das mit einem C-Programm vergleiche als ein C-Programm,
17:42
weil ich habe ja auch einen Garbage-Collector drin. Ich habe eine Runtime, die macht noch zur Laufzeit, macht Range-Checks und Typ-Checks und sowas. Im Prinzip habe ich einen ähnlichen Runtime-Komfort, wie so ein JVM, ein bisschen vom Gefühl her. Ich finde, das fühlt sich relativ ähnlich an. Das heißt, das muss natürlich auch alles mit ins Binary reingepackt werden.
18:05
Hier mal ein einfacher HTP-Server. Kann ich auch kurz? Wollte ich gar nicht. Einfach HTP-Server, den ich jetzt genommen habe, um eine Slice zu erstellen beispielsweise.
18:22
Ich habe immer, also es gibt ja auch 100 Varianten, aber ich habe gedacht, okay meine Slice werden irgendwie generiert, brauche ich einen HTP-Server, der auf dem aktuellen Verzeichnis einfach ausliefert. Habe ich gedacht, ja, schreibe ich gerade mit ein Go. Kann man schön in Go als Einzeiler schreiben. HTP Listen and Surf. Damit erstelle ich einen neuen HTP-Server.
18:42
Übergibt den Port, auf dem ich lauschen möchte bzw. die Adresse. Und hier habe ich einen direkt in Go vorhandenen HTP-Händler kreiert, der auf dem aktuellen Verzeichnis irgendwo die Dateien dann ausliefert.
19:04
Das ist jetzt aus der Standardbibliothek. Die ist recht umfangreich. Also man kommt darauf an, womit man es vergleicht. Aber es ist eine recht gute Standardbibliothek, die sich, sage ich mal, auf allen IOT-Themen, HTP-Encoding-Geschichten, Jason oder sowas, das alles drin hat. Das heißt, so sage ich mal, für die ganzen sehr technischen Sachen
19:22
sind dort alle Sachen drin und man hat die direkt. Ja, jetzt zu Threads komme ich gleich noch. So Go lang hat im Prinzip intern nicht das Konzept von Threads, sondern von Go-Routinen. Aber das sage ich später noch etwas dazu.
19:46
Ein Process, so viele Threads, wie ich CPUs habe. Aber es gibt so Go-Routinen, zu denen ich gleich noch komme. Das sind virtuelle Threads, das kann man sich vorstellen. Ich schedule da drauf und davon habe ich fast beliebig viele. Davon kann ich da auch 100.000 Stück oder sowas auf der Maschine einfach abfahren.
20:02
Also sehr, sehr viel. Also Parallelität ist da ziemlich gut unterstützt in den HTTPS-Arbeiten. Go lang hat so die Idee, Batteries included. Das heißt, ich habe jetzt nicht eine Programmiersprache, eine Standard-Library
20:22
und der ganze Rest, den sollte ich die Community irgendwann mal bauen. Dann haben wir 1.000 verschiedene Varianten. Sondern ich habe direkt im Tool-Link drin auch schon so die essentiellen Sachen, wo man gemerkt hat, dass eigentlich jede Programmiersprache die Geschichten braucht. Die verbergen sich alle hinter dem Go-Kommando. Das heißt, ich habe einen Go-Fed für eine statische Fehleranalyse,
20:43
so ein bisschen Find-Bugs mäßig. Der sucht mir typische Fehler raus. Also wenn ich in Printf beispielsweise die Prozentplatzhalter und die Argumente nicht zueinander passen, so Geschichten, die ich sonst eigentlich nur während der Laufzeit merken würde, sucht er dann statisch raus, wenn er da einen Verdacht hat.
21:03
Das Go-Format, was letztendlich alle IDEs dann auch verwenden für die Code-Formatierung. Das ist super praktisch, muss ich sagen, weil seitdem habe ich keine Lust mehr irgendwo, ich kann ja mal irgendwie hier einen Konsens rausmachen,
21:21
seitdem formatiere ich gar nicht mehr von Hand, sondern, okay, den hat er jetzt natürlich nicht gemacht, aber wenn ich jetzt, also ich könnte jetzt auch eine Demikola dran machen, das macht er mir direkt weg, oder halt allen Unsinn, den ich bei Formatierung mache, oder was, den rückt er mir, macht er passend und rückt auch direkt ein,
21:41
also zum Beispiel beim Struct, dass alles schön untereinander steht und so. Das ist halt cool, weil alle IDEs verwenden, oder fast alle verwenden dieses Format-Tool auch wirklich, dadurch ist es halt wirklich möglich, Go-Code im Team zu schreiben, auch einen größeren Team, den formatiert zu haben und bei allen gleich formatiert zu haben, so dass man Autoformatter verwenden kann,
22:02
ohne dass der eine Kollege dem anderen ständig die Sachen wieder hin und her wegformatiert. Go-Doc ist ein Doku-Generator und Doku-Browser. Go-Generate kann Source-Code erstellen, das heißt, kann dann statisch übers Projekt gehen, kann dann verschiedene Annotationen auslesen
22:22
und dann Code generieren, wenn man das möchte. Und Go-Test ist, das finde ich das Coolste an den Tools noch, ist direkt ein eingebauten Test-Runner, also sowas wie JUnit oder dergleichen, ist halt direkt im Tooling drin, das heißt, ich habe einen Standardweg, da zeige ich gleich noch, wie man einen Test schreibt. Die Tests sind direkt Teil des Projektes und direkt im Standard-Tooling ist halt der Test-Runner drin,
22:41
so dass man von vornherein in Go ein Tooling nur hat, um Test zu schreiben, was alle gleichheitlich verwenden. Ich sage gleich etwas zu, nachdem ich insgesamt Dependency-Management vorgestellt habe,
23:01
das habe ich vergessen, ich komme noch mal da drauf. Genau, schon die nächste Folie direkt. Go hat, also ich sage jetzt bei manchen Sachen, das ist für mich das Allerkulte, der größte Knaller, aber es ist halt alles geil. Go hat als einzige Sprache, die ich so kenne,
23:21
immer außer pure Script-Sprachen, hat halt als Dependencies nur Quellcode-Dependencies. Das heißt, erst mal denkt man, oh, das ist ja doof, das ist ja weniger, das heißt, es gibt kein Konzept von Libraries oder Shared Libraries oder Packages oder sowas. Stimmt nicht, dass das gar nicht gibt. Es gibt auch noch eine Möglichkeit, das zu verwenden, macht aber keiner.
23:42
Ist auch nur für Extremfälle gedacht. Der Dependency, den Go-Projekt hat, referenziert direkt auf ein Quellcode-Projekt. Klar, ich will auch ein statisches Banner hinten rauskriegen und ich erzeugt keine Libraries oder sowas. Das macht auch Sinn, direkt auf den Quellcode zu referenzieren, weil ich halt dieses Library-Konzept ja gar nicht habe.
24:02
Dadurch referenziere ich halt direkt in meinem Projekt, ein Repository von jemand anderem beispielsweise, und die Sachen werden direkt von dem Tooling aufgelöst und integriert. Das hat den super coolen Effekt, dass wenn ich halt mehrere Projekte habe oder auch mehrere Open-Source-Projekte habe, die verknüpft sind und miteinander arbeiten, dass halt eine direkte Integration von mehreren Projekten möglich ist.
24:23
An manchen Stellen hat es auch die eine oder andere Schwierigkeit da drin, aber die sind aus meiner Sicht mittlerweile seit Go 1.6 eigentlich alle gelöst. Ich zeige es jetzt einfach mal. Ein Package hat einen Package-Pfad
24:40
und den kann ich voll qualifizieren über eine Quelle. Also ich habe beispielsweise diesen HTTP-Server, den ich hier gezeigt habe, den habe ich auch vorher auf GitHub gepackt.
25:04
Es ist nicht viel hier drin, es ist einfach nur im Prinzip eine Main. Das habe ich jetzt noch eine Zeit dazu geschrieben, aber im Prinzip der selbe Code von dem HTTP-Server, den habe ich auf GitHub direkt draufgepackt. Wenn ich den jetzt runterladen, kompilieren und installieren möchte, geht das relativ einfach.
25:27
Ich setze erst auf irgendeinem Verzeichnis meinen Go Pass, das muss ich machen, das ist ein bisschen nervig. Solltet ihr auch, wenn ihr euch dafür interessiert, einmal richtig miteinander setzen, dass ihr es direkt von Anfang an versteht. Ich gehe mal ins Demo-Verzeichnis und dann setze ich meinen Go Pass auf das aktuelle Verzeichnis.
25:45
Und dann gehe ich hin und rufe einfach Go Get auf, auf diesem Package-Pfad. Ja, bitte. Nee, kann man nicht, das ist die Frage auch von ihm. Da sage ich gleich etwas dazu, was da der Workaround ist.
26:06
Dieses Go Get, also im Moment geht alles nur auf den Master, ist doof sozusagen, wenn es professionell macht, aber ist auch erstmal cool, weil ich kann damit direkt arbeiten, kann Sachen integrieren und kann halt sofort loslegen. Das Go Get hat jetzt dafür gesorgt, dass ich zwei Verzeichnisse angelegt bekommen habe.
26:21
Das eine ist das Source. Okay, da sind jetzt natürlich die Git-Verzeichnisse drin. Das Source sieht man jetzt, ist einfach runtergeladen unter der Package-Struktur und da liegt halt genau das, was ich vorher hatte. Und das Bin-Verzeichnis, wo jetzt schon direkt vom Go Get das runtergeladene Programm übersetzt drin liegt.
26:40
Das heißt, ich kann jetzt einfach Go Get aufrufen, die Sources wurden runtergeladen, das Ganze wird komponiert und ich kann jetzt direkt hier Bin, Surf Local, den HTP Server starten. Mal gucken, ob ich auch die Wahrheit erzähle. Ach, nee, war 1, 2, 3, 4, glaube ich, genau.
27:00
Wird halt einfach das lokale Verzeichnis ausgeliefert. Das war jetzt ja nur das eine Projekt, aber das Ganze geht halt auch transitiv. Um das zu beweisen, gehe ich nochmal hin und gucke mir die Main an, damit ich nicht zu viel Live-Typing reinmachen will. Also genau, hier wurde jetzt von dem Server nichts ausgegeben, wenn ich darauf zugegriffen habe.
27:23
Die Idee wäre, ich packe jetzt von irgendeiner Library, ich will Log-Statements für die Zugriffe ausgeben. Deswegen hole ich mir irgendeine Library raus aus dem Gorilla-Framework, die so HTP-Händler beinhaltet, mit denen ich einfach einen anderen Händler chanen kann. Dann wird erst der obere HTP-Händler aufgerufen, der kann was machen,
27:43
danach wird der nächste HTP-Händler aufgerufen. Das heißt, ich mache jetzt einen Import von dem Handlers-Package. Gehe jetzt nochmal raus, rufe nochmal das Go-Get auf. Das sorgt jetzt dafür, dass auch die transitiven Dependencies runtergeladen werden.
28:06
Der meckert hier, weil ich habe die Library importiert, aber nicht verwendet. Das ist klar, ich habe noch keinen Code dazu geschrieben. Jetzt sehe ich aber, unterm Source-Git-Hub gibt es jetzt auch das Gorilla-Package und da sind die Händler drin. Jetzt kann ich den Händler benutzen.
28:25
Wo ich den alten Händler definiert hatte, kann ich einfach hingehen. Händler wird jetzt nochmal ein Handlers-Combined-Logging-Händler outgehen.
28:50
Nach dem Loggen an den oben drüber definierten Händler delegieren. Jetzt kann ich nochmal Go-Get aufrufen, aber ich mache einen anderen Befehl.
29:00
Go-Install, weil ich nichts neu runterladen muss. Der installiert jetzt die Sachen, das heißt, wenn ich jetzt global starte, ist da jetzt der zusätzliche Händler integriert, den ich als Library verwendet habe. Das heißt, wenn ich noch zugreife, also ich, jetzt habe ich auch Log-Ausgaben dazu. Ja, bitte.
29:24
Nichts, das heißt, du brauchst hierfür, für den einfachen Fall brauchst du keinerlei Pompfals. Weil ich referenziere den Master des anderen. Ich habe in der Versionsverwaltung nichts von dem anderen. Das heißt, ich würde jetzt nur mein eigenes Projekt einchecken. Da ist die Referenz auf das Package des anderen drauf. Und jedes Mal, wenn ich das baue, mit Go-Get ziehe, würden die Sourcen des anderen vom Master gezogen.
29:46
Das ist natürlich für ein professionelles Projekt nicht so sinnvoll. Das ist gut, um schnell was zu entwickeln. Das ist auch gut, um in der CI beispielsweise ein Master gegen einen anderen Master laufen zu haben, schnell zu integrieren oder zwei Open-Source-Projekte, die gegeneinander grün laufen sollen
30:00
und direkt zu sehen, wenn sich was verändert. Und dafür zu nehmen, wenn ich natürlich irgendwo reproduzierbare Bilder haben möchte, reicht das nicht aus. Das war lange Zeit ein bisschen ungelöst. In Go 1.6 wurde dann ein Wendor-Verzeichnis eingeführt. Das heißt, ich kann ein Wendor-Unterverzeichnis anlegen, wo ich die Libraries komplett einchecke.
30:22
Und dann werden die nicht gezogen. Und ich habe im Prinzip die Library meiner Dependency mit drin. Weil das natürlich von Hand nicht gut zu managen ist, gibt es ein paar Tools, Go-Wendor oder Go-Dap oder sowas, mit dem ich mir dann auch wieder so ein File wie ein Pomp-File oder so eine Package-Station oder sowas machen kann, wo ich die Dependencies mit genauen Versionen, mit Branchen, sowas referenziere
30:42
und der dann diesen Prozess, das in das Wendor-Verzeichnis zu packen, für mich automatisiert, womit ich das pflegen kann. Das heißt, also meistens startet man auf diesen naiven Weg, den ich jetzt gemacht habe oder für einfache Skripte oder Beispielgeschichten arbeitet man auf jahrteinweise. Und je nachdem, wie weit man im Entwicklungszyklus ist, geht man dann hin, dass man die Sachen irgendwo entweder mit ins Repository eincheckt
31:02
oder halt über Tools, die die Versionen dann festbinden. Mit Sicherheit, die ganzen Gründe der Designverscheidung bei Go auch super dokumentiert, an der Stelle kann ich es aber nicht genau sagen.
31:23
Genau, das finde ich das Schöne. Erstmal ist es dann viel einfacher Sachen als Quellcode einzubinden. Das heißt, ich habe, selbst bei Open-Source-Libraries habe ich ja teilweise ansonsten Quellcode gar nicht so direkt enden aber zur Verfügung, weil mir der Prozess viel zu schwierig ist. Das ist ja anders. Ich kann direkt reinsteppen, was ändern und Pull-Request im anderen Repository fallen.
31:40
Das ist super praktisch. Das heißt, der Open-Source-Gedanke ist so, sage ich mal, als primärer Denker dahinter. Es gibt auch eine Erweiterung. Das war das, was ich schon meinte, mit dem, als ich sagte, dass es gar keine Library-Konzept gibt. Das stimmt nicht wirklich. Es gibt auch eine Möglichkeit, in dem ich binäre Packages machen kann. Das heißt, wenn ich jetzt hier mein Verzeichnis sehe,
32:01
sehe ich, hier ist ein Unterverzeichnis PKG entstanden. Und da sehe ich jetzt einfach binäre Artifakte, die zwischendrin im Compile-Prozess erstellt wurden, einfach so als Caching. Und im Prinzip, auf dem Weg mehr oder weniger, kann ich letztendlich auch binäre Packages nehmen
32:23
und an andere Leute verteilen. Die sind jetzt versionsspätig. Das hat sich auch zwischen 1.6 und 1.7 etwas verändert. Ich glaube, es gibt mittlerweile auch da eine Standardisierung von einem Austauschformat.
32:40
Aber das Schöne ist, das macht eigentlich quasi keiner. Das heißt also, Go als Library, die ohne Sourcen ausgeliefert, habe ich bisher noch nirgendwo gesehen in der echten Wildbahn. Weiß ich nicht. Kommerziell und Open Source, widerspricht sich ja Gott sei Dank. Ich stelle mir sicher, dass ich am Ende des Binary irgendwie weiß,
33:05
welches Exakt von allen Library-Einwanderungen ist. Das ist ja so ein Security-Thema. Irgendwie kann man abdecken auf einer Library, die ist schon gebacken. Welche Binary muss ich neu bauen? Das hast du natürlich immer, dass du in deinem Binary
33:22
erst mal gar nicht mehr so richtig weißt, was da, wenn du nur das Binary nimmst, was da genau drin ist. Ich habe jetzt hier beispielsweise im Source von dem anderen Projekt, wie dann bei dem Gorilla, das echte Git-Repository drin. Das heißt, ich habe wirklich das Git-Repository ausgescheckt. Wenn ich mit diesem Vendoring-Mechanismus arbeite,
33:41
dann kann ich ja die Version genau festpinnen. Dann weiß ich das ganz exakt natürlich in meinem Versionsverwaltungssystem, was ich drin hatte. Klar, das verlierst du hier. Du hast statisch kompiliert, du hast die Sachen drin. Das heißt, wenn du LibSSL oder sowas hast, kannst du nicht auf dem System austauschen.
34:05
Genau, statisch gelingt. Das kommt halt auf einen Einsatzzweck drauf an. Wenn du dann eine ganze Distri oder sowas erstellen möchtest, ist das vielleicht nicht ganz so schlau. Wenn du die Sachen in deine Docker-Containerchen reinpackst, die du sowieso eigentlich gar nicht veränderst,
34:22
wo du auch drin eh nichts austauschst, sondern die du eher, wenn du was nicht veränderst, Immutable-Infrastructure-mäßig wegschmeißt, wenn du alles neu baust und neu publizierst und alles durch deine Bildchain schiebst, dann ist dir das völlig egal. Also das ist durchaus...
34:42
Ja, ja, ja, das ist durchaus ein Thema. Jetzt, wenn ich einem bestehenden Programm eine HENCO-Weinregung geben möchte, gibt es da eine Möglichkeit, auf einen anderen Programm hier zu warten, der in Geiserexportierungen ist, der umgehen kann, und nicht mehr als die 2.5 hat?
35:03
Also Go hat eine sehr, sehr gute C-Integration. Ich kann direkt im Prinzip einen Import machen und dann kann ich direkt inline in meinem Go-Programm C-Code aufrufen. Ich bin kein C-Programmierer, deswegen mache ich das nie wirklich, sozusagen, aber ich kann direkt in meinem C-Programm, in meiner Go-Datei
35:21
Funktionen in C definieren, die ich von unten calle, weil letztendlich geht das hier eher durch einen C-Compiler durch, das heißt, das ist im Prinzip eine Welt und die geht sehr, sehr gut. Ok, Testing, hier mal ein Testbeispiel. Das Testen ist halt direkt bei Go schön integriert,
35:41
was ich super finde, weil dadurch schreibe ich nicht erst meine 20-Zeilen-Code und dann meine 40-Zeilen-Code, und dann denke ich, oh, jetzt ziehe ich einen Test-Dependency rein, sondern ich habe es halt direkt drin und für mich dadurch der Einstieg ist es sofort bei den ersten Zeilen mit Test und so zu arbeiten deutlich leichter geworden. Außerdem ist es halt cool, weil man jetzt nicht in jedem Projekt über nachdenken muss,
36:01
welchen Testrunner der jetzt hier verwendet, sondern halt alles schön einfach ist. Ich kann einfach in mein Projekt hinein Dateien legen, die unterstrich-test.go heißen und da drin sind Tests, die ausgeführt werden können. In einer solchen Datei wird alles ausgeführt, was diese Signatur
36:21
hat, das heißt, alle Funktionen, die mit Test-Unterstrich anfangen und so einen Testing-Context übergeben bekommen, werden dann automatisch ausgeführt. Da drin kann ich dann auf dem Testing-Objekt verschiedene Sachen machen, das ist ein bisschen reduziert, da gibt es keine schönen Assertions oder sowas, es gibt aber natürlich ein paar Libraries, die mir das Leben hier auch noch ein bisschen erleichtern und das ganz so schön machen.
36:44
Ja, also ich habe direkt auch hier eine Benchmark-Funktion, das heißt, ich könnte hier auch statt Test auch einen Benchmark hinterlegen, dann wird hier ein Benchmark ausgeführt, und da habe ich dann so Convenience-Methoden wie ich schreibe den Test eigentlich einmal hin und dann wird der Toolset mehrmals in verschiedenen Iterationsgrößen, also
37:01
10x, 100x, 1000x ausgeführt, um irgendwo die Ergebnisse dann rauszugeben. Ich kann damit Messpunkte setzen und sowas. Das ist, sage ich mal, als Benchmarking interessant. Und was ich bei dem Tooling gerade eben geschlappert hatte, es gibt halt auch direkt so ein Tracing und Profiling für das Profiling zur Laufzeit im Prozess gibt es auch direkt integriert.
37:22
Da kann ich halt was setzen, entweder im Programm oder beim Aufruf, und dann kann ich über den Endpunkt mir Profiling, also zum einen Laufzeit, zum anderen auch Memory-Profiling-Daten ausgeben lassen und so ein bisschen daran analysieren. Genau, kann mir das auch noch grafen und sehe so ein bisschen die
37:41
akumulierten Geschichten. Lässt ein bisschen zu wünschen übrig, ist jetzt nicht so, dass ich sagen würde, klicke mausi bunti, alles toll, man sieht, der ist total übersichtlich, aber die wesentlichen Kennzahlen kann man schon rausbekommen. Vielleicht an der Stelle auch noch, ein Debugger war lange ein Thema, dass es keinen guten
38:02
Debugger wirklich gab. Mittlerweile gibt es den DELV, der ein bisschen besser ist. Ich weiß jetzt nicht wirklich, wie die IDE-Integration ist, also im EMAX funktioniert es nicht in eine IDE integriert, ich glaube sogar in Intellij, das ist auch so eine IDE-Integration, aber sonst hat er auch wie so ein GDB eine recht gute Textkonsole, so dass man damit
38:22
jetzt auch ganz anständig debuggen kann und nicht mehr so ein Printf-Debugging machen muss, was ja doch ein bisschen nervig ist. Ist aber auch an der Stelle noch nicht auf dem Level, wo ich mir einen Debugger eigentlich wünschen würde oder wo andere Sprachen da sind. Das ist vom Komfort nicht ganz so weit. Sieht man halt einfach, dass es nicht ganz so alt ist,
38:41
dass es halt noch keine 15 Jahre auf dem Buckel hat wie andere Sprachen mittlerweile. Objektorientierte Programmierung. Golang schreibt einem, ist an der Stelle nicht idiomatisch, schreibt einem nicht vor, ob man objektorientiert programmieren soll oder einfach nur prozedural mit Funktionen.
39:02
Es kann beides, das heißt, man kann auch die ganzen Libraries eigentlich weitestgehend ohne Objektorientierung verwenden oder seine Sachen schreiben, man kann aber auch sehr, sehr gut objektorientiert programmieren da drin. Wobei objektorientiert etwas anders ist, als hat man das teilweise gewohnt. Das ist ein deutlich besserer Ansatz.
39:22
Es ist die Frage, ob es objektorientiert ist. Golang spricht eigentlich auch nicht von Objekten, sondern Golang hat einfach nur Typen und auf Typen kann ich halt auch Methoden definieren oder für eine Funktion, die einen Typ als Receivertyp haben. Damit kann ich beispielsweise hingehen und habe einen Item, das ist einfach
39:40
wieder ein Struct, also ein von mir definierter Typ und dann kann ich einer Funktion einfach sagen, dass sie auf dem Item definiert ist. Und danach, ich habe jetzt kein Nutzungsbeispiel hier drin, danach kann ich halt einfach ganz normal, wenn ich mir ein Item mache, Item Punkt Move To oder so etwas aufrufen, also wie ich das gewohnt bin.
40:01
Hier beispielsweise habe ich dem Item noch eine String Methode gegeben, wo man dann einfach die Werte ausgibt. Innerhalb des Objektes sage ich jetzt mal, innerhalb des Types gibt es dann kein Vis, sondern ich habe halt bei dem Receivertyp, den ich hier angegeben habe, einen Variablenamen, in dem Fall ein Item und ich kann dann die Membervariablen einfach darüber referenzieren.
40:21
Also mein Struct Item hat dann eine Variablename, deswegen kann ich ja nicht auf mein Receiver Klein Item, Item Punkt Name da drin aufrufen. Also jeder Bezeichner ist packageweit nur und
40:41
ein Receivertyp unterscheidet sich voneinander, das heißt, ich kann Move To, könnte ich jetzt dann noch eine Funktion ohne Receiver dazu tun, dann wäre es eine einfache Funktion im selben Package, oder ich könnte die Move To auch noch auf einem anderen Typ definieren im selben Package. Und durch den Receivertyp ist dann eindeutig, also gehört halt einfach der Receivertyp zu Signaturen zu, sondern zwei unterschiedliche Dinge die Move To.
41:04
Ja, das war das, was ich vorhin einmal kurz gesagt hatte per Konvention. Hier habe ich jetzt Großbuchstaben verwendet, dadurch sind die außerhalb des Packages sichtbar. Wenn ich jetzt hier einen kleinen Buchstaben verwendet hätte, dann wäre es nur innerhalb des Packages sichtbar.
41:21
Genau. Doch, du kannst jetzt Package, also ich habe jetzt hier keinen Package angegeben, einfach dem Kurzschnitzel. Du kannst erst Package importieren und dann kannst du mit dem Package als Präfix auf alle Symbole innerhalb des Packages zugreifen. Was es nicht gibt, ist sowas wie Static Import
41:41
oder sowas bei Java, wo du sagst, gib mir mal folgende Geschichten in meinen globalen Namespace rein. Sondern alle Sachen, die du verwendest, verwendest du immer unter dem Präfix. Also im Prinzip ist es dasselbe wie ein Byte Array, nur ein anderer Typname für einen...
42:02
Ach ja klar, also ich ins Mikro. Und die Frage war, wie in Golang Strings definiert sind und was das ist. Das ist im Prinzip einfach ein Byte Array, in dem dann aber UTF-8 Character drin sind. Das heißt, wenn ich jetzt über den String beidweise iteriere, dann habe ich auch
42:21
Byte Salat unter Umständen, muss ich halt wissen. Und ich habe einen Package, wo ich halt auch UTF-8 Funktionen habe, wo ich dann runenweise oder sowas mir zum runen Array auch machen kann und dann runenweise drüber iterieren kann, wenn ich das möchte. Also eine sehr, sehr ziemlich straight forward, ohne viel drüber nachzudenken, aber man hat auch die Möglichkeit, sowohl das eine oder das andere
42:41
präzise zu machen. Und kein Overhead finde ich dabei. Bei Objektorientierung sind die besonderen Sachen, dass es bewusst keine Vererbung gibt. sozusagen ist es halt auch, deswegen habe ich das Objektorientierung auch nur in Anführungsstriche gesetzt. Um dann damit Sachen
43:01
zu modellieren, gibt es aber Interfaces und es gibt ein Konzept von Embedding mit Delegation. Und das ist ja auch, sage ich mal, in einer OO-Welt schon länger bewusst, dass eigentlich diese Vererbungs-Hierarchien meistens eher zu Problemen in der Applikation führen und man eher dazu kommen sollte, dass Objekte andere
43:21
einbetten und dahin delegieren. Die Interfaces sind dabei finde ich super cool, viel, viel besser als in die meisten anderen Sprachen realisiert. Da ist nämlich die Beziehung der Abhängigkeit umgedreht. Es gibt diese, also das nennt sich Duck-Typing,
43:41
es gibt diesen Ansatz, dass ein Interface oder dass ein Typ, ein Interface dadurch implementiert, dass er einfach die Signatur des Interfaces unterstützt, also durch das Protokoll einfach unterstützt. Nicht dadurch, dass der Typ das implementiert, irgendwo deklariert, welches Interface, von welchem Namen
44:01
er verwendet. Damit ist im Prinzip alles automatisch kompatibel, was dieselben Signaturen hat. Erstmal komisch zu denken, weil im Prinzip diese Interface-Beziehung dadurch anders wird. Die riesen Vorteile sind aber halt, dass Consumer und Provider von den Interfaces gar nichts voneinander wissen müssen. Das heißt, man kann
44:21
zwei Sachen haben, die kompatibel sind, ohne, dass sie eine Dependency voneinander wissen muss man wahrscheinlich schon, damit man die Signaturen explizit genau so baut. Aber man muss vor allem keine technische Dependency von dem einen auf den anderen haben. Außerdem führt es dazu, weil man diese Interfaces dort, wo man sie implementiert, nicht explizit deklarieren muss, sondern nur dort, wo man sie verwendet,
44:41
dass die Interfaces häufig sehr viel kleiner werden, weil der Consumer meistens einen kleinen Ausschnitt aus dem Interface braucht. Das heißt, der Consumer selbst kann dann, wenn er was verwendet, das Interface definieren, von den Sachen, die er erwartet und dabei halt nur die Sachen ins Interface aufnehmen, die er wirklich braucht, die ihn wirklich interessieren. Mal ein Beispiel,
45:02
ich hoffe, man kann das hier nachvollziehen. Ich habe ein Interface gemacht, das habe ich printable genannt. Interface ist auch wieder ein richtiger Typ, also type printable ist ein Interface. Und das Interface legt einfach nur fest, dass alles, was dem Interface genügen soll, die Signatur
45:20
String hat. Also eine Funktion oder eine Methode String, die dann einen String zurückliefert. So was ähnliches wie das ToString in Java. Jetzt kann ich beispielsweise hingehen und einen Typ von Integer ableiten, nämlich MyInt. Und dem spendiere ich eine solche String Methode.
45:42
Der Typ MyInt weiß aber nichts davon. Genauso hatte ich hier vorher in dem Beispiel ein Item gemacht, was auch so eine String Methode hat. Da habe ich nicht dran geschrieben, das Item printable implementiert, sondern es hat halt einfach diese String Methode. Bei der Verwendung kann ich jetzt hingehen und mir eine Liste von printables machen.
46:01
Und da kann ich sowohl mein Item reintun, als auch mein MyInt. Als auch hier so ein ganz komisches Konstrukt, das sind irgendwie aus einem OS Package irgendwelche Konstanten zum Öffnen von Files. Im Prinzip ist da irgendwie ein Integer als Bitmaske oder sowas glaube ich drin. Aber auch die implementieren die String Methode.
46:23
Sodass ich jetzt all diese Geschichten unter diesem Interface, das wirklich nur dieser Konsument hier kennt und definiert hat, was auch nur in diesem Package hätte das jetzt auch kleinschreiben können, dann wäre es nur in diesem Package sichtbar. Das nur in dem Package eigentlich existiert. Alle, die implementieren das, sodass ich jetzt einfach darüber intervieren kann und auf allen die String Methode auflösen kann.
46:41
Also sehr, sehr einfache Verwendung der Interface. Heute Morgen in so einem Clojure Vortrag kam so ein Antibalspiel von Objektionierung in Java, wo irgendwie eine Uri-Klasse in Android und eine Uri-Klasse in einer Java-Standard-Bibliothek irgendwie unterschiedliche Klassen sind. Eigentlich mehr oder weniger dasselbe
47:01
oder vielleicht sogar dieselbe Signatur drin oder sowas, aber sie sind halt einfach unterschiedlich benannt. Also sie haben einfach sie haben kein gemeinsames Interface. Das würde eigentlich bei Go nicht passieren, weil ich kann an der Stelle mir ein Interface definieren und kann ihn einfach verwenden. Fragen zur Objektionierung?
47:24
Oder dem, was so ähnlich ist wie Objektionierung? Aber ich muss mich ein bisschen sputmerkig. Zu Funktionen sage ich nicht so viel. Es gibt Funktionen als First-Order-Typ. Das heißt, ich kann also auch eine Funktion in Variabel stecken,
47:42
danach typisieren und alles. Trotzdem ist Go leider kein bisschen funktional. Das vermisse ich manchmal ein bisschen daran. Aber dadurch, dass es halt es gibt auch keinen Generics-Konzept. Und durch diese strenge Typisierung kriege ich leider so Sachen wie Map and Reduce oder Filter oder sowas nicht schon implementiert. Das ist so mit einer Sprache das
48:01
einzige, was mich ein bisschen gestört. Noch so ein cooles kleines Konstrukt. Defer sorgt dafür, dass ich Ressourcen immer ordentlich aufgeräumt bekomme. Ich habe hier in meiner Main gehe ich hin und öffne die Datei, prüfe dann, ob das auch funktioniert hat und direkt danach schließe ich
48:21
die Datei. Aber als Defer-Statement. Defer sichert mir zu, dass das, was ich damit mache, am Ende der Funktion ausgeführt wird, ähnlich wie so ein Finally-Block. Ich kann das also schön dort sicherstellen, dass ich die Ressource wieder freigebe, wo ich die Ressource erstelle.
48:40
Dann schreibe ich etwas da rein und halt nach diesem Reinschreiben wird am Ende der Methode umgekehrt als Close. Fehlerbehandlung hat man auf der einen oder anderen Stelle schon gesehen. Geht halt über Rückgabewerte meistens. Das heißt, ich habe eine Methode, die was tut, habe mehrere Rückgabewerte
49:01
und der letzte Rückgabewert ist per Funktion meistens eine Variabel von Typ Error. Die kann ich dann abfragen. Das If ist ein zusammengesetztes. Hier ist Initialisierung. Und hier ist die Auswertung des Bündchen-Ausdruckes. So ein bisschen ähnlich, wie man das von einem C vorkennt. Also das ist quasi bei einem Vorwärter sozusagen der erste Teil
49:21
und das halt der mittlere Teil. Und da kann ich dann direkt in dem If auf die Variablen zugreifen bzw. den Fehler handhaben. Das führt manchmal zu etwas hässlicher Code, wenn man halt an jeder Zeile wieder das Error checkt oder Error checkt, aber hat den großen Vorteil, dass man dieses Checking des Errors einfach explizit macht. Klar ist das hässlich, ist
49:41
langweilig, aber man macht sich über jeden Error halt Gedanken, wie man den händeln muss. Genau. Manchmal kann man das schon schön vereinfachen.
50:02
Es gibt auch so eine ich sag mal Äquivalenz zu Exceptions, was aber halt nicht so verwendet wird so häufig, aber im Prinzip kann man das selber damit abbilden. Das heißt, überall wo ein Panic aufgerufen wird, kann man das auch recovern und kann das fangen, auch weiter oben fangen und damit im Prinzip ähnlich wie auf Exceptions reagieren. Sollte dabei halt nur ein Ausnahmen verwendet werden.
50:23
Und jetzt so sag ich mal der coolste Teil. Kam mir vorhin schon die Frage bei dem Web-Server, was ist das dann? Forkt der irgendwas raus oder was macht der? Go hat das Konzept von Go-Routinen. Das sind kleine Co-Routinen. Also kleine Code-Blöcke,
50:41
die auf einen internen Thread-Pool verteilt werden. Das heißt, die Go- runtime, die macht einstellbar viele Threads auf und man nutzt aber keine Threads in der Sprache. Man hat gar nicht zur Verfügung, um die Threads explizit zu nutzen, sondern man schreibt halt kleine Go-Routinen oder gibt an, dass halt eine Funktion als Go-Routine
51:01
verwenden, ausgeführt werden soll, parallel oder nebenläufig vielmehr und dann schedule die Go runtime diese kleinen Code-Schnipsel in dem internen Thread-Pool. Selbiges machen, auch moderne Libraries in Java oder in anderen Sprachen, wo man halt letztendlich heutzutage auch nicht mehr beliebiges Stats verwendet, sondern
51:21
einfach Code macht, der dort gescheduled wird und sich verteilt. Die Syntax ist so, ich gebe mit Go eine Funktion an, dass das als Go-Routine ausgeführt werden soll, dann läuft das schon im Hintergrund. Ich kann das auch inline definieren, die Function-Closer direkt irgendwo inline, was dann auch funktioniert. Ich habe mal so einen Test gemacht
51:41
hier auf dem Notebook. Ist jetzt unfair, weil ich vergleiche jetzt Äpfel und Birnen, also ich will jetzt kein Java-Bashing machen. Wenn ich in eine Go echte Threads aufmachen würde, wäre das genauso langsam. Aber ich habe einfach mal eine Million Threads aufgemacht in Java. Das braucht halt 30 Sekunden, wenn ich Threads aufmache, die quasi nichts tun und direkt zurückkommen, eine Million davon.
52:01
Wenn ich hingegen eine Million Go-Routinen aufrufe und direkt wieder zurückkehre, schaffe ich das in 1,3 Sekunden. Also ein sehr vielleicht gewichtiges Ding, sodass ich halt wirklich, wenn ich das möchte, Größen in Ordnung 50 oder 100.000 oder 120.000, 150.000 Go-Routinen im Programm verwenden möchte, wenn ich das tun will. Das heißt, ich kann also auch bei einem HTTP-Server,
52:22
wenn ich da nicht ein Connection-Problem kriege, muss ich mir halt Gedanken machen natürlich um HTTP-Connections mit Max-Open-Files und so was, aber rein von der Threading-Geschichte kann ich halt jeder Anfrage einfach in einer eigenen Go-Routine beantworten. Um zwischen Go-Routinen zu kommunizieren, gibt es das Konzept der Channels.
52:41
Das heißt, ich kann einfach einen Channel machen und da kann ich Daten drüber schicken. Mit einem Spezial-Syntax kann ich Daten in den Channel reintun oder Daten aus dem Channel rausholen. Kleines Beispiel, ich mach den Channel, asynchron in einer Go-Funktion schreibe ich Daten rein und hier printe ich die Daten,
53:01
die ich aus dem Channel rauslese, wieder aus. Wie läuft das ab? Die Zeile wird ausgeführt, das hier wird gescheduled, also nur vorgemerkt, dann läuft das Ganze hier weiter, blockt auf dem Channel, weil dort noch nichts vorliegt, dann
53:21
merkt das Scheduler, okay, ich hab noch was anderes zu tun, führt hier die Sachen aus, packt das erste in den Channel rein, dann wird wieder die Main-Routine ausgeführt, die vierte gibt das aus, dann wird hier wieder geblockt, das zweite kommt rein und wird dann ausgeführt. Die Channels sind halt sehr, sehr und ich hab da noch machen kann, die laufen
53:40
unabhängig voneinander und kann da einfach Daten hin und her senden und habe damit wenig Schwierigkeiten auf Speicher und so zu greifen, den von hand synchronisieren zu müssen. Ich hätt jetzt noch ein bisschen mehr, aber die Zeit ist schon ziemlich fortgeschritten. Die Sachen sind natürlich online und ich hab auch Beispiele
54:01
online, grad auch zu dem Parallelität und dem ja, sag ich mal, schnell parallelisieren. Also ich habe ein Beispiel von einem HTTP-Server noch hier drin, der mit 500 Threads parallel irgendwo auf einen HTTP-Server zuzugreifen. Da kriegt man locker irgendwo 30.000 Fliegquests pro Sekunde mit beantwortet.
54:23
Ihr könnt euch, wenn ihr das habt, Nachgaben anschauen. Also gute Doku findet man direkt im Upstream-Projekt. Gibt es eine Doku-Seite, die ist ziemlich gut. Es gibt dieses Tour of Go, wo man direkt so mit Playground durchgehen kann.
54:40
Eigentlich ein sehr, sehr gutes Tutorial, um das nachzuvollziehen. Ich habe mal eine Schulung bei uns in der Firma gehalten über sechs oder sieben Workshop-Blöcke. Die Sachen sind auch online, könnt ihr euch anschauen. Fehlt so ein bisschen der Subtext dazwischen, aber die ganzen Beispiele sind da und die ganzen Essentials. Und das ist das Buch. Ich weiß nicht, ob es bessere Bücher gibt, aber das Buch habe ich mal gelesen
55:02
und war eigentlich zufrieden damit. Es gibt mittlerweile auch noch zwei oder drei andere. Und die Slides selbst sind online unter meinem GitHub-Account. Entweder direkt als Slides hier oder auch als Markdown mit den Beispielen noch dran. Jetzt haben wir, glaube ich, noch ein paar Minuten Zeit für Fragen, so fünf etwa.
55:37
Also unter Ubuntu beispielsweise, das WI ist aber unter Ubuntu standardmäßig vorhanden.
55:44
Ich glaube, ein Sechser ist aktuell in Ubuntu drin. Kann man gut mitarbeiten. Kann man also einfach app.get.install, dann hat man es drauf. Und man kann aber auch sehr, sehr einfach sich die Distri als TGZ runterladen, wenn man möchte. Ich habe jetzt beispielsweise noch das 17er, was ganz frisch ist, einfach daneben gelegt und kann halt auch einfach damit arbeiten.
56:02
Also als Binary in Fahrt und schon läuft es. Es gibt, glaube ich, einen sehr, sehr guten Windows-Support, wenn man das so liest. Also das Go wird auch unter Windows redlich verwendet. Und da es im Prinzip ein GCC als Backend hat, ist die Architekturfrage ziemlich einfach.
56:22
Also das im Prinzip kann das fast überall hin kompilieren, noch cross-kompilieren. Ja, da hinten. Entschuldigung, jetzt hat er es in der Hälfte hintereinander direkt.
56:41
Ja?
57:02
Also die Frage war, ob man als Import-URL auch im Prinzip eigene oder neue Import-URLs andere als GitHub verwenden kann. Ja, kann man. Du kannst auch einfach dein eigenes Git Repository dort referenzieren und muss halt ein auflösbarer Name an der Stelle sein. Schwierigkeiten bekommst du, wenn du auf nicht-typischen Ports bist oder so was.
57:24
Wenn du irgendwie einen Git Repository auf irgendwelche komischen Ports hast, dann funktioniert das nicht ganz so easy, aber gibt es auch Work-Rounds. Das heißt, du kannst das also auch in geschlossener Infrastruktur mit eigenen Repositories wunderbar verwenden. Es gibt eine Heuristik nach der, der auf diesem Pfad abklappert, was er dort vielleicht findet.
57:42
Und da sind, ich habe mich außer geht nicht dollernd beschäftigt, aber es gibt irgendwie drei, vier, fünf Varianten von Versionsverwaltungssystemen oder auch per HTTP, glaube ich, geht sogar im NPEG auch. Ja, also wenn irgendwas ganz Neues auf...
58:01
Okay, ja. Hier bitte. Also das Schöne ist eigentlich bei uns, die Fragen, die mit Kunden heutzutage, wo es so viele Technologien gibt und die eigentlich fast nicht mehr durchblicken, die meisten, gar nicht mehr, in welcher Technologie wir das machen.
58:20
Das heißt, dort, wo wir eine Realisierungshoheit haben, können wir das sehr, sehr stark selber wählen. Ich habe bisher noch nicht erlebt, dass ein Kunde explizit nach Go gefragt hat. Ich glaube, das kommt vielleicht in ein, zwei Jahren, aber so weit ist es noch nicht. Das Schöne ist, sage ich mal, von der Verfügbarkeit der Entwickler ist es so, dass halt Go sehr, sehr leicht erlernbar ist. Das heißt, es eignet sich sehr, sehr gut dazu,
58:42
man kriegt nicht so einen Scala-Entwickler oder Closure-Entwickler-Problem, es eignet sich sehr, sehr gut dazu, Leuten, die man hat, einfach gerade Go beizubringen und dann könnt ihr recht schnell Robust darin realisieren.
59:02
Also, es ist so, dass das Projekt tatsächlich, bei dem man erst einmal an die Basis-Förderung verhindert, dann wird sich der S-Anfrage gestellt, und ich kann dann einen Wettbewerber modifizieren, der mir dann den Hintertext quasi, was ich eigentlich rauskriege. War noch eine Frage irgendwo, oder?
59:31
Ich dachte nicht. Du warst ja weit entgegangen. Wie schnell passt auch Go darauf?
59:41
Also, die Frage ist, wie schnell Go erlernbar ist. Kommt natürlich immer darauf an, also man braucht ja schon... Also, wie tief man in etwas drin sein will. Also, ich habe jetzt mit verschiedenen Leuten, ich habe ja welche geschult, und wir haben jetzt so ein 15-Personen-Projekt gemacht mit 50%-Go. Ich habe halt gemerkt, dass man, wenn man Java-Entwickler, ohne ihnen viele zu erklären...
01:00:00
zunimmt einfach und im Team macht er dann, soll er plötzlich ab morgen einfach Go machen, dass er halt so innerhalb von zwei Wochen oder so was mitläuft und dann ganz gut zurechtkommt. Natürlich ist es schon so, es wäre gelogen zu sagen, du kannst in kurzer Zeit komplett alles über Go wissen. Man muss natürlich eine Plattform wissen, man muss ein bisschen Libraries dann doch auch kennen oder ein paar speziellere Geschichten.
01:00:21
Also ich hatte das Gefühl, nachdem ich neben dem Beruf, also so ab 8 Uhr abends, sag ich mal, habe ich ein halbes Jahr lang mich mit Go beschäftigt. Und nach einem halben Jahr hatte ich selbst das Gefühl, dass ich sicherer in Go wäre, ein halbes bis dreiviertel Jahr, als ein Jahr war, was ich 15 Jahre vorher gemacht habe. Also ein halbes, dreiviertel Jahr intensive Beschäftigung, dann hat man,
01:00:42
aus meiner Sicht, die Einarbeitung, dass man es richtig in der Tiefe verstehen kann. Ja, bitte? Weiß ich nicht. Ich bin kein Linker-Experte.
01:01:03
Also in Go selbst Libraries dynamisch zu linken, wüsste ich nicht, dass das geht. Manche Sachen, die halt reingelinkt sind, weil hinterher auch ein Linker-Prozess einfach hängt, sind halt auch dynamisch reingelinkt. Das heißt, wenn du jetzt nichts Besonderes angibst, dadurch, dass du halt im Prinzip einen C-Compiler drunter hast, sind halt auch teilweise Libraries dynamisch reingelinkt.
01:01:21
Aber genau, das weiß vielleicht jemand besser als ich. Eher nicht, aber vielleicht hast du noch?
01:02:39
Emacs. Aber das ist eher Glaubensfrage.
01:02:44
Nein. Lang antwort, ich bin froh, dass ich endlich wieder eine Programmiersprache unter Emacs entwickeln kann und auch Autovervollständigung habe und Autoformatierung, was ich in anderen Sprachen an Emacs halt doch nicht wirklich habe. Das heißt, weil das Tooling so einfach zu bauen ist, ist das ja gut unterstützt.
01:03:00
Aber die Kollegen haben halt größtenteils IntelliJ. Ja, letzte Frage würde ich sagen. Und dann, weil es schon so spät ist, schließen wir die Runde.
01:03:39
Wer noch Interesse hat, kann ja noch nach vorne kommen.
01:04:00
Also die Idee ist, von den Packages, oder die Frage war, inwieweit die Packages, wie ausgereift sie sind, wie viel davon mitkommt.
01:04:07
Also, Gord, das Konzept Battery is included. Das heißt, du hast das, was du brauchst, gerade für diesen serverseitigen Einsatz, hast du eigentlich da drin. Und es ist im Vergleich zu anderen Sachen, ist es ein bisschen weniger, auch etwas weniger Komfort drin.
01:04:21
Aber gut darauf geachtet, dass die Sachen wirklich funktionieren und wirklich ausgereift sind, sodass du dann auch wirklich einen ganz akzeptablen HTTP-Server drin hast oder sowas und die Libraries wirklich verwenden kannst und nicht eine Library hast, die zwar, wo alles mögliche drin ist, aber du dich doch dauernd aus Partylibraries irgendwo bedienst. Aber ganz klar ist da drin, der Einsatz ist so auf diesen, also wenn du einen Web-Server schreibst,
01:04:43
wenn du irgendwas schreibst, was mit Datenzugriffen geht oder sowas, dann hast du den wesentlichen Teil schon drin für UI-Geschichten. Also es ist jetzt nicht wie eine Java-Bibliothek.
01:05:05
... dokumentiert oder darüber den IBs, die schmeißen darauf Fehler aus, wenn man das Doku vergessen hat oder den Teil reingeschrieben hat. Und du sagst also, da ist halt auch sehr viel Spaß, einfach sich auf den Kunden anderen einfach anzugucken und durchzulesen.
01:05:24
Genau, so häufig lese ich Doku nicht, wenn ich irgendwie eine API habe, aber bei Go ist das anders, weil da halt wirklich wertvoll Informationen drin stehen zu Constraints, wie das benutzen oder nicht benutzen solltest oder was. Also das ist schon wirklich sehr wertvoll. Okay, wir haben Sonntag Abend. Ich bedanke mich für eure gute Aufmerksamkeit.
01:05:40
Wer noch Lust hat zu Fragen zu stellen oder zu diskutieren, kann nach vorne kommen.