/go-workshops

Go language basic workshops for devz

Primary LanguageGo

Goland Training

Dlaczego Go?

Kto jest głównym pomysłodawcą języka

  • Rob Pike (Unix, UTF-8)
  • Ken Thompson (Unix author, UTF-8, B lang)
  • Robert Griesemer (V8, Java Hotspot (Oracle Java), GFS)

lista kontrybutorów https://golang.org/AUTHORS

Dlaczego go zostało stworzone przez Google? Chcieli rozzwiązać problemy z DUŻYMI aplikacjami które mieli napisane w Google:

  • przyspieszyć development
  • multicore systems

źródła:

Charakterystyka Go

  • Statycznie kompilowany (jedna binarka ze wszystkimi zależnościami)
  • Garbage Collected
  • Silnie typowany
  • Funkcyjno - Pseudo obiektowa hybryda

Dlaczego jest warte uwagi?

  • łatwy deploy aplikacji (kod nie ma zależności - jenda binarka) + statics
  • brak wojny o code style gofmt
  • zintegrowany package manager go get
  • zintegrowane sprawdzanie poprawności kodu go vet także golint (github.com/golang/lint)
  • gocode serwer do intellisense - nie musisz miec IDE aby ci podpowiadało możesz pisać w swoim ulubionym edytorze (Sublime, Atom, Vim)
  • szybkie budowanie binarek
  • ciekawa standardowa biblioteka template/html, performant www servers, json, xml streams, io, buffers, first class citizen concurrency
  • kompilacja na wiele maszyn (cross-compilation)
  • łatwy i przyjemny setup środowiska (edytory, ide, code completition server)
  • wbudowane testy
  • bardzo niski próg wejścia aby zacząć pisać
  • hype w internetach, jeden z większych wzrostów w trendach na githubie oraz google trends (Tiobe kłamie!)

Dlaczego jest niefajne?

  • brak zarządzania wersjami w package managerze (go get only honors URLs?) 3rd party - godep
  • w go 1.5 została dodana flaga która pozwoli na ładowanie w podobny sposób jak godep to robi (istnieje co prawda zarządzanie na poziomie pkg server przykład mongo "gopkg.in/mgo.v2/bson") zmieniamy API podbijamy wersję, API kompatybilne
  • często jeszcze młode biblioteki przykład gin i skopany cache w contrib repo

Init

go get github.com/exu/go-workshops
cd $GOPATH/exu/go-workshops

Porównanie z PHP

Architektura web aplikacji

  • PHP: Reqest - response app
  • Go: Serwery aplikacyjne (a'la NodeJs, Ruby, Python)

Typ

  • PHP: Skryptowy (z OPCache)
  • Go: Kompilowany

Typowanie

  • PHP: Dynamiczne (static z dupy w PHP7)
  • Go: Statyczne

Zaprojektowany jako:

  • PHP: HTML generator
  • Go: Łatwo zarządzalny następca C dla większych projektów

Entry level

  • PHP: Trochę trzeba się naumieć aby przykrywać niekompetencje frameworków innymi design patternami
  • Go: niski dla podstawowych, trzeba zrozumieć concurrency i kilka dziwnych rozwiązań (np: err handling)

Główny paradygmat

  • PHP: Pseudo Java OO
  • Go: Pseudo-funkcyjny / Pseudo-Obiektowość da się zamodelować na struct'ach

RPSy

  • PHP: Req-Response boli, zamodelowanie Event-loop'a kopnie cie w tylek
  • Go: "Concurrency as CORE feature" WWW serwer może być wystarczająco szybki

Użycie w świecie:

  • PHP: Tu wygrywa bardzo dużo softu, mało ciekawych projektów
  • Go: Jak już coś wychodzi o czym słychać to z reguły jest fajne :)

Github style struktura projektu

w Go projekty są uporządkowane zgodnie z "github style" - częścią ścieżki jest adres serwera na którym hostowane jest projekt / biblioteka

src/
    github.com
        exu
            mysuperproject
    ioki.com.pl
            mnmel
                 nmelinium
bin/
    superappbinary
pkg/
    compiled packages

Zmienna środowiskowa $GOPATH decyduje gdzie się znajdują te katalogi w twoim systemie.

Go Tools

Included

IDEs

Auto reload

  • BRA

Testing

  • Unit
  • Http
  • Bdd tools
  • Blackbox testing
  • Benchmarking
  • Chromedriver example

Assertion libs

Go nie posiada wbudowanej biblioteki do asercji, istnieje za to wiele projektów open source:

Database drivers

Storages:

  • Mongo

  • RethinkDB

  • Redis

  • MySQL?

  • Cassandra?

Biblioteki

workflow

Web frameworks

  • echo (MUX)
  • gin (MUX)
  • beego (większy z ORMem)

Stress testing

  • vegeta

Go debugging

Expvar i expvarmon

live app monitoring

W dokumentacji jest integracja z GDB

ale to jest trochę słabe

##3 Delve

Filmik autora z Gophercona: https://www.youtube.com/watch?v=InG72scKPd4

Profiling

https://github.com/bradfitz/talk-yapc-asia-2015/blob/master/talk.md

Github style struktura projektu BASICS IMPORTING CODE

w Go projekty są uporządkowane zgodnie z "github style" - częścią ścieżki jest adres serwera na którym hostowane jest projekt / biblioteka

src/
    github.com
        exu
            mysuperproject
    ioki.com.pl
            mnmel
                 nmelinium
bin/
    superappbinary
pkg/
    compiled packages

Zmienna środowiskowa $GOPATH decyduje gdzie się znajdują te katalogi w twoim systemie.

Importowanie i packages

W go package jest zbiorem plików z dyrektywą package nazwa Package default'owo jest importowany po pełnej ścieżce ścieżce

import "github.com/exu/go-workshops/010-basics-importing/sub"

W go zmienne nie muszą mieć z góry określonego typu, możemy przypisać zmienną w postaci a := 1 kompilator będzie wiedział że ma doczynienia z typem int.

Obsługa standardowa, fajna rzecz iota (taki autoincrement)

Funkcje w go to "First class citizen".

W go istnieje tylko jedna pętla: for. Wykorzystywana jest jednak w różnych wariantach, często używana ze słowem kluczowym range

Inicjalzacja package'u BASICS INIT CODE

func init() {} odpowiada za zainicjowanie paczki, jest wykonywana tylko przy pierwszym imporcie paczki.

Tablice w Go to niskopoziomowa struktura danych, najczęściej z nich nie korzystasz zamiast tego wykorzystujemy slice'y nakładkę na typy tablicowe znacznie ułatwiającą pracę z nimi

Slice to "nakładka" na tablicę, trzyma do niej referencję jak przypiszesz slice do slice'a to będą wskazywać na tą samą tablicę.

źródła:

Mapy są statycznie typowane jak inne struktury w go, jeżeli potrzebujesz przechowywać różne typy w jednej mapie możesz uzyć interface{} oznaczjącego dowolny typ

Struktury to podstawowy typ danych w go, większość driverów do storage'u pozwala kodować i dekodować do struktur. są bardzo użyteczne, dzięki nim możemy zamodelować pseudo-obiektowość, często używane do kompzycji oprogramowania.

Struktury - Kompoozycja BASICS STRUCT COMPOSITION CODE

Kompozycja taki pattern chyba znacie ?

Tagi - annotacje BASICS STRUCT TAGS CODE

Struktury w go posiadają możliwość opisywania pól dodatkowymi "tagami" które następnie możemy wykorzystać programistycznie wykorzystywane często przy enkodowaniu i dekodowaniu z formatów danych (JSON, yml) jak i z różnych silników baz danych.

Go posiada tzw "implicit interfaces", oznacza to że jeżeli dana struktura implementuje metody z interfejsu automatycznie staje się obikektem o typie równym typie intefejsu.

Zarządzanie błędami BASICS ERRORS CODE

W go nie ma exceptionów, błędy są zwracane poprzez wielokrotne wartości lub agregowane w obiektach jeżeli zachodzi taka potrzeba. Preferuje się podejście jak najszybszej obsługi błędów. W Go błąd jest wartością na którą masz reagować.

Źródła:

  • Używamy gdy chcemy zatrzymać program.
  • Możemy podpiąć sprawdzenie do "defer chain" czy panic wystąpił

Podstawowa struktura danych w większości problemów programistycznych tu też jest i ma wszystko czego potrzebujesz.

Concurrency. Goroutine to lekki "wątek" uruchamiany wewnątrz programu Goroutines są bardzo lekkie więc uruchomienie równolegle wielu tysięcy nie kosztuje nas zbyt wiele zasobów.

Używanie tzw 3rd parties BASICS 3RD PARTY PACKAGES CODE

Go posiada zintegrowany package manager (bez wersjonowania jeszcze niestety) go get pozwala nam w łatwy sposób ściągnąć paczki oraz je uruchamiać. dzięki powyższej komendzie zostaną ściągnięte wszystkie zależności związane z packagem main

Example project structure BASICS PROJECT STRUCTURE CODE

Streams - Przykłady STDLIB STREAMS CODE

Readers

implementują io.Reader

Writers

implementują io.Writer.

koniec.

Podstawowe operacje na IO, Bufory STDLIB IO CODE

Przykład z bufio

Directory traversal

Łączenie plików za pomocą buforów

Uruchom

cd docker/mysql
docker-compose start
mysql -uroot -proot -P7701 -h127.0.0.1 < init.sql
mysql -uroot -proot -P7701 -h127.0.0.1

Przykłady MongoDB DATABASES MONGODB CODE

Jedną z ciekawych funkcjonalności RethinkDB jest możliwość monitorowania zmian na kolekcji

Dockerizing

Uruchom rethinka jako kontener

docker run --name some-rethink -v "$PWD:/data" -d rethinkdb

mozemy również zmapować porty do lokalnej maszynki

docker run --name rethink -p 28015:28015 -v "$PWD/data:/data" -d rethinkdb

wtedy instacja kontenera będzie widoczna pod adresem localhost:28015

Zlinkuj go w swojej aplikacji

docker run --name some-app --link some-rethink:rdb -d application-that-uses-rdb

go readline implementation LIBS READLINE CODE

https://github.com/chzyer/readline

Caddy webserver LIBS CADDY CODE

Profilowanie PROFILING CODE

Command

Profilowanie standardowego programu

import (
	"runtime/pprof"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func init() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
	}
}

func main() {
	defer pprof.StopCPUProfile()

Następnie budujemy binarkę i odpalamy ją z flagą cpuprofile

go build command.go && ./command -cpuprofile=data.prof

po czym możemy włączyć nasz profiler

go tool pprof command data.prof

Możemy do naszego programu dodać memory profile

var memprofile = flag.String("memprofile", "", "write memory profile to this file")


func memProfile() {
	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}
}

informacje o pamięci zbierane są zbierane na końcu więc dorzucamy do defer list

func main() {
    defer memProfile()

Teraz możemy zbierać informacje o obu profilach

go build command.go && ./command -cpuprofile=cpu.prof -memprofile=mem.prof

go tool pprof command cpu.prof

go tool pprof command mem.prof

Web

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
)

func handler(w http.ResponseWriter, r *http.Request) {
	for i := 0; i < 100000000; i++ {
		w.Write([]byte(fmt.Sprintf("%d - %d, ", i, i)))
	}
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

run in shell:

go tool pprof http://localhost:8080/debug/pprof/profile