Hlavní navigace

Nástroje pro kontrolu kvality zdrojových kódů psaných v Go

Pro ekosystém vytvořený okolo Go vzniklo mnoho nástrojů kontrolujících kvalitu kódů, ať se to týká existence komentářů, kontroly chybových stavů, tak i například výpočtu cyklomatické složitosti funkcí a metod.
Pavel Tišnovský 10. 3. 2020
Doba čtení: 45 minut

Sdílet

11. Nástroj gocyclo

12. Příklady problémů zachycených nástrojem gocyclo

13. Nástroj ineffassign

14. Příklady problémů zachycených nástrojem ineffassign

15. Zobrazení výsledků kontrol přímo v repositáři

16. Služba Go Report Card

17. Služba Codecov

18. Obsah následujícího článku

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Nástroje pro kontrolu kvality zdrojových kódů psaných v Go

Samotný programovací jazyk Go je navržen velmi konzervativně, což bylo ostatně patrné i z předchozího článku o (ne)používaní generických datových typů, funkcí a metod. To pochopitelně některým vývojářům nemusí vyhovovat, na čemž ale ve skutečnosti nemusí být nic špatného – ideální univerzálně přijímaný programovací jazyk neexistuje a pravděpodobně ani nikdy existovat nebude, protože některé vlastnosti jazyků jsou protichůdné. Ovšem samotný programovací jazyk je jen jednou (i když pochopitelně velmi důležitou) součástí celého ekosystému, který kromě překladače (někdy interpretru) obsahuje i vývojová prostředí a ladicí nástroje, ale i další pomocné nástroje a utility. Mezi tyto nástroje patří i utility určené pro kontrolu kvality zdrojových kódů, odhalování různých chyb nerozpoznaných překladačem, potenciálních chyb, špatně strukturovaného kódu, nedodržování zavedených idiomů atd. A právě těmito mnohdy velmi užitečnými nástroji se budeme zabývat v dnešním článku.

Samostatnou kapitolu tvoří nástroje sloužící k odhalení potenciálních bezpečnostních problémů. I těchto nástrojů existuje relativně velké množství a budeme se jimi zabývat v navazujícím článku.

Poznámka: již na úvod je nutné poznamenat, že z hlediska kontroly kvality a ustálených pravidel je na tom ekosystém programovacího jazyka Go velmi dobře (i v porovnání s přímou konkurencí) a většina projektů s otevřeným zdrojovým kódem, které jsou v Go psány, se snaží dodržovat většinu zavedených praktik, k čemuž pomáhají i dále zmíněné služby, které k projektům dokážou přidat odznaky/visačky (badge) a demonstrovat tak kvalitu či nekvalitu produktu (alespoň z pohledu těchto nástrojů). To je velmi dobrá filozofie, která se u některých dalších jazyků prosazuje teprve postupně

2. Nástroj gofmt

Jednou z poměrně častých otázek mnoha programátorů, kteří na programovací jazyk Go přechází z jiných jazyků, je, jakým způsobem je možné zkontrolovat syntaxi zdrojových kódů bez provedení jejich překladu či dokonce spuštění. Takový nástroj nabízí například jazyk Ruby, Perl či Python:

$ ruby -c test.rb
$ perl -c test.pl
$ python -m py_compile test.py

V sadě základních nástrojů jazyka Go se nachází i nástroj gofmt, jehož primárním úkolem je naformátování zdrojových kódů podle poměrně striktních pravidel, která jsou testována například tímto testem. Ovšem gofmt, na rozdíl od mnoha dalších formátovačů, pracuje s kódem reprezentovaným AST (abstraktním syntaktickým stromem). To mj. znamená, že kód je zapotřebí parsovat a převést do AST, takže i gofmt dokáže provádět kontrolu syntaxe.

Program bez uvedení balíčku:

func main() {
}

Odhalená chyba:

01_missing_package.go:1:1: expected 'package', found 'func

Špatně umístěná otevírací bloková závorka:

package main
 
func main()
{
}

Příklad problematického zdrojového kódu, v němž nejsou použity blokové (složené) závorky na stejném řádku s programovým kódem:

package main
 
func classify_char(c rune) string {
        if c >= 'a' && c <= 'z'
        {
                return "male pismeno"
        }
        else if c >= 'A' && c <= 'Z' {
                return "velke pismeno"
        }
        else
        {
                return "neco jineho"
        }
}
 
func main() {
        println(classify_char('a'))
        println(classify_char('Z'))
        println(classify_char('?'))
}

Většina těchto chyb je odhalena:

bad_syntax.go:13:25: unexpected newline, expecting { after if clause
bad_syntax.go:17:2: expected statement, found 'else'
bad_syntax.go:20:2: expected statement, found 'else'
bad_syntax.go:24:1: expected declaration, found '}'

Kromě toho dokáže gofmt provádět i zjednodušení některých výrazů:

Původní podoba Zjednodušená podoba
[]T{T{}, T{}} []T{{}, {}}
s[a:len(s)] s[a:]
for x, _ = range v {…} for x = range v {…}
for _ = range v {…} for range v {…}

Navíc je možné specifikovat i vlastní transformace či zjednodušování. Následující příklad je převzat z reálných zdrojových kódů:

package main
 
import "fmt"
import "bytes"
 
func main() {
        a := []byte{1, 2, 3}
        b := []byte{3, 4, 5}
 
        c := bytes.Compare(a, b) == 0
        fmt.Println(c)
 
        c = bytes.Compare(a, a) == 0
        fmt.Println(c)
}

Tento zdrojový kód lze příkazem:

$ gofmt -r 'bytes.Compare(a, b) == 0 -> bytes.Equal(a, b)'

Transformovat na:

package main
 
import "fmt"
import "bytes"
 
func main() {
        a := []byte{1, 2, 3}
        b := []byte{3, 4, 5}
 
        c := bytes.Equal(a, b)
        fmt.Println(c)
 
        c = bytes.Equal(a, a)
        fmt.Println(c)
}

3. Překladač programovacího jazyka Go

The boy is smoking and leaving smoke rings into the air. The girl gets irritated with the smoke and says to her lover: „Can't you see the warning written on the cigarettes packet, smoking is injurious to health!“ The boy replies back: „Darling, I am a programmer. We don't worry about warnings, we only worry about errors.“

I když se to možná bude zdát překvapivé, na druhém místě v seznamu nástrojů pro kontrolu kvality stojí přímo překladač programovacího jazyka Go. Ten se vyznačuje mj. i tím, že při parsování, kontrole a překladu zdrojových kódů nikdy negeneruje varování – zdrojový kód je buď přeložen bez dalších doplňujících zpráv nebo se vypíšou nalezené chyby (resp. přesněji řečeno několik prvních chyb, aby nebyl vývojář polekán a nemusel scrollovat o několik obrazovek). Navíc není možné kontrolu chyb ani vypnout ani naopak zapínat obdobu režimu „pedantic“, kterou můžeme znát například z céčka (ve skutečnosti vlastně překladač Go vždy pracuje právě v režimu „pedantic“). Díky těmto vlastnostem je samotný překladač skutečně prvním nástrojem, který dokáže odhalit poměrně značné množství různých potenciálních chyb. Kromě běžných problémů typu chybějící závorka, špatně zapsané klíčové slovo, nekorektní programová konstrukce lze odhalit například i:

  1. prakticky všechny prohřešky vůči typovému systému jazyka Go (typový systém je striktnější, než například v případě C či Javy)
  2. nepoužívané importované balíčky
  3. cyklická závislost mezi balíčky
  4. deklarované proměnné, které nejsou použity
  5. chybějící příkaz return ve všech větvích funkce či metody
  6. použití operátoru = namísto == v podmínkách, a to ve všech případech, protože taková konstrukce není v programovacím jazyce Go povolena (v C, C++ i Javě je tato chyba odhalena jen někdy – viz příklad pod tímto seznamem)
  7. kontrola, zda typ předávané hodnoty implementuje očekávané rozhraní
  8. kontrola, zda je skok realizovaný pomocí goto proveden na korektní místo či nikoli
  9. cyklická závislost rozhraní
  10. nesprávné použití parametrů ve variadických funkcích
  11. kontrola konstant používaných u bitových posunů
  12. kontrola, zda jsou příkazy ++ a – skutečně použity jako příkazy a nikoli jako operátory (to Go z mnoha dobrých důvodů neumožňuje)
class BooleanAssign {
    void foobar() {
        boolean a=true;
        boolean b=false;
        if (a=b) {
        }
        if (a==b) {
        }
    }
}
Poznámka: díky typovému systému programovacího jazyka Go a poměrně omezených možností práce s ukazateli se potenciální množství chyb v programech dosti razantním způsobem zmenšuje, už jen z toho důvodu, že překladač má nad kódem větší kontrolu (může tvořit CFG atd.). Navíc se díky automatickému správci paměti zamezí problémům typu „vrácení ukazatele na lokální proměnnou alokovanou na zásobníku“ apod.

Uveďme si nyní příklady některých striktnějších kontrol prováděných překladačem jazyka Go.

Konstanty, jejichž hodnoty neodpovídají typům proměnných, do kterých jsou přiřazovány:

package main
 
import "fmt"
 
func main() {
        var a int8 = -1000
        var b int16 = -100000
        var c int32 = -10000000000
        var d int32 = -10000000000000000
 
        fmt.Println(a)
        fmt.Println(b)
        fmt.Println(c)
        fmt.Println(d)
}

Chybová hlášení:

./integer_signed_types_checks.go:15:15: constant -1000 overflows int8
./integer_signed_types_checks.go:16:16: constant -100000 overflows int16
./integer_signed_types_checks.go:17:16: constant -10000000000 overflows int32
./integer_signed_types_checks.go:18:16: constant -10000000000000000 overflows int32

Striktní typové kontroly (silnější, než v mnoha dalších jazycích):

package main
 
import "fmt"
 
func main() {
        var a uint8 = 255
        var b uint16 = a
 
        fmt.Println(a)
        fmt.Println(b)
}

Chybové hlášení:

./05_improper_conversion.go:16:6: cannot use a (type uint8) as type uint16 in assignment

Podobné typové kontroly, ovšem u typů s plovoucí řádovou čárkou:

package main
 
func main() {
        var c float32 = 1e300
        var d float32 = -1e300
 
        var g float64 = 1e3000
        var h float64 = -1e3000
}

Chybová hlášení:

./fp_types_checks.go:13:18: constant 1e+300 overflows float32
./fp_types_checks.go:14:18: constant -1e+300 overflows float32
./fp_types_checks.go:16:18: constant 1e+3000 overflows float64
./fp_types_checks.go:17:18: constant -1e+3000 overflows float64

4. Jaké potenciální problémy překladač Go nenalezne?

Na druhou stranu je však nutné upozornit na to, že některé typické a často se vyskytující chyby samotný překladač neodhalí, což může způsobit problémy. Jen pro příklad:

  1. kontrola chybových stavů
  2. práce s neinicializovanou mapou
  3. přístup přes ukazatel obsahující nil
  4. zda jsou deklarovány všechny větve v příkazu switch
  5. kontrola parametrů funkce fmt.Printf atd.

Některé z těchto problémů dokážou odhalit nástroje popsané v navazujících kapitolách.

Pro zajímavost si ukažme dvě chyby, které nejsou překladačem odhaleny. Prvním z problémů je přístup do neinicializované mapy, což je chyba, kterou udělal snad každý programátor, který ke Go přešel z jiného jazyka, v němž mapy (asociativní pole) existují:

package main
 
func main() {
        var m map[string]string
        m["foo"] = "bar"
}

Tento problém je odhalen až za běhu aplikace:

panic: assignment to entry in nil map
 
goroutine 1 [running]:
main.main()
        /home/tester/m.go:5 +0x4b
exit status 2

Ve druhém chybném příkladu se pracuje s ukazatelem nastaveným na nulovou hodnotu, tedy na nil:

package main
 
import "fmt"
import "math"
 
type Vector struct {
        X, Y float64
}
 
func (v *Vector) Length() float64 {
        return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
 
func main() {
        var v *Vector
        fmt.Println(v.Length())
}

I tato chyba je objevena až po spuštění programu:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x484bb3]
 
goroutine 1 [running]:
main.(*Vector).Length(...)
        /home/tester/p.go:11
main.main()
        /home/tester/p.go:16 +0x23
exit status 2

5. Standardní nástroj go vet

Dalším (dnes již posledním jmenovaným) standardním nástrojem dodávaným v instalaci programovacího jazyka Go je nástroj nazvaný vet, který je z příkazové řádky volán následovně:

$ go vet parametry

Tento nástroj slouží k odhalení dalších typů potenciálních chyb a problémů, například:

  • kontrola typů parametrů funkce fmt.Pritnf na základě formátovacího řetězce
  • dtto u podobných funkcí (fmt.Sprintf apod.)
  • bitové posuny prováděné mimo rozsah daného datového typu (8 bitů u uint8 atd.)
  • kontrola signatur metod u nejpoužívanějších rozhraní (tj. zda uživatelem definované metody mají shodné signaturami s metodami předepsanými ve standardních rozhraních – ukážeme si na demonstračním příkladu)
  • kontrola, zda kód psaný v assembleru odpovídá deklaracím v jazyku Go
  • nepotřebná přiřazení
  • problémy s použitím atomických operací
  • nepoužité výsledky (vracené hodnoty) volaných funkcí
  • nedostupný kód
Poznámka: možnosti nástroje vet se postupně zvětšují, což znamená, že je do něj zahrnováno větší množství potenciálně chybných programových konstrukcí.

Jak jsme si již řekli v předchozím odstavci, je go vet součástí základních nástrojů programovacího jazyka Go, takže by měl být vždy dostupný:

$ go help vet
 
usage: go vet [-n] [-x] [build flags] [vet flags] [packages]
 
Vet runs the Go vet command on the packages named by the import paths.
 
For more about vet and its flags, see 'go doc cmd/vet'.
For more about specifying packages, see 'go help packages'.
 
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
 
The build flags supported by go vet are those that control package resolution
and execution, such as -n, -x, -v, -tags, and -toolexec.
For more about these flags, see 'go help build'.
 
See also: go fmt, go fix.
Poznámka: pokud se v adresáři nachází soubor s chybou a použijete příkaz go vet *.go, bude tento nástroj ukončen již u první chyby. To je ostatně i případ našeho repositáře obsahujícího chybné soubory. Řešením může být smyčka naprogramovaná v BASHi, která postupně projde všemi soubory a na každý samostatně go get zavolá.

6. Příklady problémů zachycených nástrojem go vet

Podívejme se nyní na některé problémy, které odhalí právě nástroj go vet, ovšem nikoli překladač programovacího jazyka Go.

V prvním příkladu se nachází příkazy za konstrukcí return. K těmto příkazům není pochopitelně možné se žádným způsobem dostat:

package main
 
import "fmt"
 
func main() {
        return
        i := 10
        fmt.Println(i)
}

Chybová hlášení nástroje go vet:

./t.go:7: unreachable code

Ve druhém příkladu se pokoušíme o bitový posun proměnné typu int (32bitová či 64bitová) o 70 bitů doleva:

package main
 
import "fmt"
 
func main() {
        i := 1
        i <<= 70
        fmt.Println(i)
}

Chybová hlášení nástroje go vet:

./t.go:7: i (64 bits) too small for shift of 70

V příkladu třetím je kontrolováno, jaké parametry se předávají funkci fmt.Printf a zda tyto parametry odpovídají formátovacímu řetězci:

package main
 
import "fmt"
 
func main() {
        fmt.Printf("foo")
        fmt.Printf("foo", "bar")
        fmt.Printf("%d", "bar")
        fmt.Printf("%s %s", "bar")
        fmt.Printf("%d", 3.14)
        fmt.Printf("%p", nil)
}

Chybová hlášení nástroje go vet odhalí většinu problémů s funkcí fmt.Printf:

./t.go:7: Printf call has arguments but no formatting directives
./t.go:8: Printf format %d has arg "bar" of wrong type string
./t.go:9: Printf format %s reads arg #2, but call has 1 arg
./t.go:10: Printf format %d has arg 3.14 of wrong type float64
./t.go:11: Printf format %p has arg nil of wrong type untyped nil

Existuje i podobná funkce fmt.Sprintf, která ovšem vrací hodnotu (naformátovaný řetězec), který kvůli chybě programátora ignorujeme:

package main
 
import "fmt"
 
func main() {
        fmt.Sprintf("foo")
        fmt.Sprintf("foo", "bar")
        fmt.Sprintf("%d", "bar")
        fmt.Sprintf("%s %s", "bar")
        fmt.Sprintf("%d", 3.14)
        fmt.Sprintf("%p", nil)
}

Z chybových hlášení je patrné, že go vet i tyto problémy korektně odhalil, zatímco překladač tento kód bez problémů přeložil:

./s.go:6: result of fmt.Sprintf call not used
./s.go:7: result of fmt.Sprintf call not used
./s.go:7: Sprintf call has arguments but no formatting directives
./s.go:8: result of fmt.Sprintf call not used
./s.go:8: Sprintf format %d has arg "bar" of wrong type string
./s.go:9: result of fmt.Sprintf call not used
./s.go:9: Sprintf format %s reads arg #2, but call has 1 arg
./s.go:10: result of fmt.Sprintf call not used
./s.go:10: Sprintf format %d has arg 3.14 of wrong type float64
./s.go:11: result of fmt.Sprintf call not used
./s.go:11: Sprintf format %p has arg nil of wrong type untyped nil

Konečně kontrola, jestli metody nazvané ReadByte odpovídají signatuře metody předepsané v rozhraní Reader:

package main
 
type X struct {
}
 
type Y struct {
}
 
type Z struct {
}
 
func (x X) ReadByte() (byte, error) {
        return 0, nil
}
 
func (y Y) ReadByte() error {
        return nil
}
 
func (z Z) ReadByte() byte {
        return 0
}
 
func main() {
}
./t.go:16: method ReadByte() error should have signature ReadByte() (byte, error)
./t.go:20: method ReadByte() byte should have signature ReadByte() (byte, error)

7. Nástroj errcheck

Nyní si pojďme popsat některé užitečné nástroje, které nejsou (alespoň prozatím) součástí standardní instalace nástrojů programovacího jazyka Go. První z těchto nástrojů se jmenuje jednoduše errcheck a jak již název této utility napovídá, jedná se o nástroj provádějící kontrolu, zda se zpracovávají všechny chybové kódy vrácené různými funkcemi. Vychází se přitom z předpokladu, že jakmile je chybový kód uložen do lokální proměnné, je nutné s ním dále pracovat, protože jazyk Go neumožňuje vytvořit proměnnou bez jejího dalšího použití (ovšem tento předpoklad ne vždy platí, což si ostatně ukážeme na příkladech v navazující kapitole).

Instalace tohoto nástroje se provede příkazem:

$ go get -u github.com/kisielk/errcheck

Vlastní kontrolu (v rámci celého projektu) zajistí příkaz:

$ errcheck ./...

8. Příklady problémů zachycených nástrojem errcheck

Úloha nástroje errcheck je tedy jednoznačná – detekovat, ve kterých místech zdrojového kódu ignorujeme návratovou hodnotu s informací o chybě. Ukažme si tedy, jak a kde se tyto problémy mohou nalézt.

Prvním příkladem je implementace jednoduchého serveru reagujícího na zprávy přicházející na port 1234. Zdánlivě ošetřujeme všechny chybové stavy:

package main
 
import (
        "fmt"
        "net"
)
 
func main() {
        l, err := net.Listen("tcp", "localhost:1234")
        if err != nil {
                println("Can't open the port!")
        }
        defer l.Close()
        for {
                conn, err := l.Accept()
                if err != nil {
                        println("Connection refused!")
                }
                go func(c net.Conn) {
                        fmt.Fprintf(c, "Holla\n")
                        c.Close()
                }(conn)
        }
}

Nástroj errcheck ukáže, které chyby ignorujeme:

$ errcheck 16_simple_server.go 
 
16_simple_server.go:13:15:      defer l.Close()
16_simple_server.go:20:15:      fmt.Fprintf(c, "Holla\n")
16_simple_server.go:21:11:      c.Close()

Ve druhém příkladu vytváříme rastrový obrázek ve formátu PNG:

package main
 
import (
        "image"
        "image/color"
        "image/png"
        "os"
)
 
const width = 256
const height = 256
 
func main() {
        img := image.NewRGBA(image.Rect(0, 0, width, height))
        for x := 0; x < width; x++ {
                for y := 0; y < height; y++ {
                        var red uint8 = uint8(x)
                        var green uint8 = uint8((x + y) >> 1)
                        var blue uint8 = uint8(y)
                        c := color.RGBA{red, green, blue, 255}
                        img.SetRGBA(x, y, c)
                }
        }
 
        outfile, err := os.Create("test.png")
        if err != nil {
                panic(err)
        }
        defer outfile.Close()
        png.Encode(outfile, img)
}

Opět se podívejme na ignorované chyby:

$ errcheck 17_png_output.go 
 
17_png_output.go:29:21: defer outfile.Close()
17_png_output.go:30:12: png.Encode(outfile, img)

9. Nástroj golint

Druhým nástrojem, který je zapotřebí explicitně nainstalovat (není tedy součástí standardního toolingu), je nástroj pojmenovaný golint. Jedná se o nástroj, který dokáže vyhledávat problémy související se stylem zápisu zdrojových kódů (coding style), což je odlišný typ problémů, než který vyhledává například go vet či výše zmíněný nástroj errcheck. Typické problémy, které lze odhalit, jsou – špatné názvy proměnných, použití „tečkového“ importu, exportování symbolu bez dokumentačního řetězce, zbytečné větve else apod. Tento potenciálně velmi užitečný nástroj nainstalujeme příkazem:

$ go get -u golang.org/x/lint/golint

10. Příklady problémů zachycených nástrojem golint

Kód s exportovanými symboly bez dokumentačních řetězců:

type StringHeap []string
 
func (h StringHeap) Len() int {
        return len(h)
}
 
func (h StringHeap) Less(i, j int) bool {
        return h[i] < h[j]
}
 
func (h StringHeap) Swap(i, j int) {
        h[i], h[j] = h[j], h[i]
}
 
func (h *StringHeap) Push(x interface{}) {
        *h = append(*h, x.(string))
}

Špatné dokumentační řetězce:

// Encode
func (ge *GobEncoder) Encode(subject string, v interface{}) ([]byte, error) {
        b := new(bytes.Buffer)
        enc := gob.NewEncoder(b)
        if err := enc.Encode(v); err != nil {
                return nil, err
        }
        return b.Bytes(), nil
}
 
// This function encodes...
func (ge *GobEncoder) Encode(subject string, v interface{}) ([]byte, error) {
        b := new(bytes.Buffer)
        enc := gob.NewEncoder(b)
        if err := enc.Encode(v); err != nil {
                return nil, err
        }
        return b.Bytes(), nil
}

Zbytečné použití else:

if _, cur := nc.currentServer(); cur == nil {
        return ErrNoServers
} else {
        return SomethingElse
}
Poznámka: obecně je možné říci, že v Go se else používá pouze minimálně.

11. Nástroj gocyclo

Při vývoji nových aplikací, popř. při analýze již existujících aplikací je možné sledovat různé metriky popisující kvalitu celé aplikace. Kromě klasických metrik, které jsou zaměřeny spíše na výsledný produkt a na jeho chování při běhu (výkonnost, doba odezvy, střední doba selhání, …) či na procesy související s vývojem a údržbou produktu (cena, produktivita, …) se v některých případech používají i metriky, které se nějakým způsobem snaží popsat složitost zdrojových kódů a tím pádem i pracnost opravy chyb či přidávání nových vlastností. Z hlediska implementace je jednou z nejjednodušších metrik tohoto typu takzvaná cyklomatická složitost neboli cyclomatic complexity. Zjednodušeně řešeno se jedná o číslo, kterým se snažíme vyjádřit složitost programu nebo jednotlivých logických bloků, typicky funkcí, tříd a metod (popř. celých balíků). Obecně platí, že čím větší je cyklomatická složitost daného bloku (například funkce), tím více jednotkových testů je zapotřebí vytvořit a tím složitější jsou případné další úpravy kódu (či jen jeho prosté pochopení).

Ve vybrané části programu se cyklomatická složitost počítá pomocí grafu toku řízení toho programu: uzly grafu odpovídají neoddělitelným skupinám v programu (například tělu cyklu, podmínky). Orientované hrany odpovídají tomu, v jakém pořadí se skupiny příkazů budou provádět. Cyklomatickou složitost je možné aplikovat individuálně na vybrané funkce, moduly, metody nebo třídy [1].

Implementace měření cyklomatické složitosti je relativně snadná díky tomu, že se pouze zjišťuje počet možných cest ve zdrojovém kódu, tj. provádí se statická analýza, která nevyžaduje měření prováděné v běžící aplikaci. Typicky se nástroje pro měření cyklomatické složitosti zaměřují na zjišťování počtu rozhodovacích konstrukcí (if-then, if-then-else, switch) a programových smyček (for. Tyto informace lze velmi snadno zjistit z abstraktního syntaktického stromu (AST – Abstract Syntax Tree), což je i případ nástroje nazvaného gocyclo.

Tento nástroj se nainstaluje příkazem:

$ go get github.com/fzipp/gocyclo

A zavolá se (v adresáři s projektem):

$ gocyclo parametry

Existují i některé parametry, které lze nastavit:

$ gocyclo -top 10 src/
 
$ gocyclo -over 25 docker
 
$ gocyclo -avg .

12. Příklady problémů zachycených nástrojem gocyclo

Následující programový kód obsahuje mnoho podmínek v jediné funkci a proto bude mít relativně vysokou cyklomatickou komplexitu (ostatně sami se zamyslete, kolik jednotkových testů bude nutné napsat, aby se prošlo všemi větvemi):

package main
 
import (
        "fmt"
        "log"
        "os"
        "runtime/pprof"
        "strconv"
)
 
func main() {
        f, err := os.Create("mandelbrot2.prof")
        if err != nil {
                log.Fatalf("failed to create profiler output file: %v", err)
        }
        defer func() {
                if err := f.Close(); err != nil {
                        log.Fatalf("failed to close profiler file: %v", err)
                }
        }()
 
        if err := pprof.StartCPUProfile(f); err != nil {
                log.Fatalf("failed to start profle: %v", err)
        }
        defer pprof.StopCPUProfile()
 
        if len(os.Args) < 4 {
                println("usage: ./mandelbrot width height maxiter")
                os.Exit(1)
        }
 
        width, err := strconv.Atoi(os.Args[1])
        if err != nil {
                fmt.Printf("Improper width parameter: '%s'\n", os.Args[1])
                os.Exit(1)
        }
 
        height, err := strconv.Atoi(os.Args[2])
        if err != nil {
                fmt.Printf("Improper height parameter: '%s'\n", os.Args[2])
                os.Exit(1)
        }
 
        maxiter, err := strconv.Atoi(os.Args[3])
        if err != nil {
                fmt.Printf("Improper maxiter parameter: '%s'\n", os.Args[3])
                os.Exit(1)
        }
 
        renderer.Start(width, height, maxiter)
}

Spočtená cyklomatická komplexita:

8 main main 18_cyclomatic_complexity.go:11:1

Ve druhém kódu je deklarováno několik funkcí a cyklomatická komplexita bude spočtena a vypsána pro všechny tyto funkce:

package renderer
 
import (
        "image"
        "image/png"
        "log"
        "os"
)
 
func writeImage(width uint, height uint, pixels []byte) {
        img := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
        pixel := 0
 
        for y := 0; y < int(height); y++ {
                offset := img.PixOffset(0, y)
                for x := uint(0); x < width; x++ {
                        img.Pix[offset] = pixels[pixel]
                        img.Pix[offset+1] = pixels[pixel+1]
                        img.Pix[offset+2] = pixels[pixel+2]
                        img.Pix[offset+3] = 0xff
                        pixel += 3
                        offset += 4
                }
        }
 
        outputFile, err := os.Create("mandelbrot.png")
        if err != nil {
                log.Fatal(err)
        }
        defer outputFile.Close()
 
        png.Encode(outputFile, img)
}
 
func iterCount(cx float64, cy float64, maxiter uint) uint {
        var zx float64 = 0.0
        var zy float64 = 0.0
        var i uint = 0
        for i < maxiter {
                zx2 := zx * zx
                zy2 := zy * zy
                if zx2+zy2 > 4.0 {
                        break
                }
                zy = 2.0*zx*zy + cy
                zx = zx2 - zy2 + cx
                i++
        }
        return i
}
 
func calcMandelbrot(width uint, height uint, maxiter uint, palette [][3]byte, image []byte, cy float64, done chan bool) {
        var cx float64 = -2.0
        for x := uint(0); x < width; x++ {
                i := iterCount(cx, cy, maxiter)
                color := palette[i]
                image[3*x] = color[0]
                image[3*x+1] = color[1]
                image[3*x+2] = color[2]
                cx += 3.0 / float64(width)
        }
        done <- true
}
 
func Start(width int, height int, maxiter int) {
        done := make(chan bool, height)
 
        pixels := make([]byte, width*height*3)
        offset := 0
        delta := width * 3
 
        var cy float64 = -1.5
        for y := 0; y < height; y++ {
                go calcMandelbrot(uint(width), uint(height), uint(maxiter), mandmap[:], pixels[offset:offset+delta], cy, done)
                offset += delta
                cy += 3.0 / float64(height)
        }
        for i := 0; i < height; i++ {
                <-done
        }
        writeImage(uint(width), uint(height), pixels)
}

Vypočtené a zobrazené výsledky:

4 renderer writeImage 19_cyclomatic_complexity.go:10:1
3 renderer Start 19_cyclomatic_complexity.go:65:1
3 renderer iterCount 19_cyclomatic_complexity.go:35:1
2 renderer calcMandelbrot 19_cyclomatic_complexity.go:52:1

Reálná funkce s velkou cyklomatickou složitostí: https://github.com/gordon­klaus/ineffassign/blob/mas­ter/ineffassign.go#L126 nebo https://github.com/minio/mi­nio/blob/master/cmd/gatewa­y/gcs/gateway-gcs.go#L556.

Další příklad s příliš velkou cyklomatickou komplexitou:

package main

func main() {
        for x := 1; x < 10; x++ {
                for y := 1; y < 10; y++ {
                        for z := 1; z < 10; z++ {
                                if x > 5 && x < 8 && y > 5 && y < 8 && z > 5 && z < 8 {
                                        break
                                }
                        }
                }
        }
        for u := 1; u < 10; u++ {
                for v := 1; v < 10; v++ {
                        for w := 1; w < 10; w++ {
                                if u > 5 && u < 8 && v > 5 && v < 8 && w > 5 && w < 8 {
                                        break
                                }
                        }
                }
        }
}

13. Nástroj ineffassign

Další nástroj nese název ineffassign a slouží je zjišťování neefektivních přiřazení, tj. přiřazení nulové hodnoty (první příklad) nebo dvojí (popř. vícenásobné) přiřazení do stejné proměnné bez čtení přiřazené hodnoty (druhý příklad). Tyto problémy sice samy o sobě nemusí nutně znamenat pády aplikace, ale mohou značit problémy vzniklé například refaktoringem apod.:

d := dch
select {
case d <- time.Now():
default:
        d = nil
}
err := encoder.Encode(&a)
decoder := gob.NewDecoder(&buffer)
err = decoder.Decode(&x)
if err != nil {
        fmt.Println(err)
        return
}

14. Příklady problémů zachycených nástrojem ineffassign

Pravděpodobně všechny problémy, které jsou detekovatelné nástrojem ineffassign, naleznete přímo v testovacích datech tohoto nástroje na adrese https://github.com/gordon­klaus/ineffassign/blob/mas­ter/testdata/testdata.go, například:

func _() {
        var x int
        x = 0
        _ = x
}
 
func _() {
        var x int
        x = 0
        if b {
                _ = x
        }
}
 
func _() {
        var x int
        _ = x
        x = 0 //x
}
 
func _() {
        var x int
        for x = range []int{} {
                _ = x
                x = 0
                if b {
                        continue
                } else {
                        break
                }
        }
        _ = x
}
 
func _() {
        var x int
        for {
                if b {
                        x = 0 //x
                        break
                }
                _ = x
        }
}
 
func _() {
        var x int
        if b {
                x = 0
        } else if b {
                x = 0
        }
        _ = x
}

15. Zobrazení výsledků kontrol přímo v repositáři

Poměrně velké množství projektů vytvořených v programovacím jazyce Go (ale ostatně i v mnoha dalších programovacích jazycích) obsahuje přímo ve svém souboru README.md odkazy na takzvané odznaky/visačky (badge), což jsou většinou malé obrázky (reprezentované buď ve vektorové nebo v rastrové podobě), které reprezentují nějakou metriku vztaženou k projektu. Může se například jednat o výsledky jednotkových testů, pokrytí kódu testy (vyjadřované v procentech), výsledky překladu projektu atd. Tyto visačky jsou většinou přímo poskytovány k tomu určenými službami, například Codecov.io (viz navazující kapitoly), Travis CI, Go Report Card atd. atd. V navazující kapitole se zmíníme o poslední jmenované službě, tedy Go Report Card, jejíž výhodou je, že není nutné se registrovat, pouze postačuje znát URL s repositářem obsahujícím zdrojové kódy aplikace.

16. Služba Go Report Card

Pro aplikace vytvářené v programovacím jazyku Go existuje online služba nazvaná Go Report Card. Tato služba nejenom zkontroluje zvolený repositář několika nástroji, z nichž většinu jsme si popsali v předchozích kapitolách, ale dokáže vygenerovat visačku (badge) s celkovým ohodnocením kvality zdrojových kódů projektu. Odkaz na tuto visačku lze vložit přímo do souboru README.md, který je viditelný při procházení repositáře se zdrojovými kódy. Jen pro zajímavost se podívejme na některé příklady:

# Projekt Stručný popis
1 Minio projekt Minio popsaný zde
2 NATS message broker NATS popsaný zde
3 Kubernetes jedna z nejdůležitějších platforem naprogramovaná v Go
4 go-root repositář s příklady používanými v seriálu o Go
Poznámka: některé zdrojové kódy z posledního repositáře obsahují chyby naschvál, takže se v tomto případě nulového počtu problémů nedosáhne.
Poznámka2: povšimněte si, že v dnešním repositáři kupodivu nebyly nalezeny chyby nástrojem go vet; pravděpodobně se stále používá jeho stará verze.

17. Služba Codecov

Druhou službou, o níž se v dnešním článku alespoň ve stručnosti zmíníme, je poměrně známá služba Codecov.io (či zkráceně jen Codecov). Tato služba umožňuje sbírat informace o pokrytí zdrojového kódu jednotkovými testy s tím, že tyto informace jsou následně zobrazeny v grafické podobě, v tabulkové podobě (po balíčcích i souborech) a dokonce i pro jednotlivé pull requesty. Repositář se zdrojovými kódy je nejdříve nutné do této služby zaregistrovat (což je pro open source projekty zdarma) a následně využít vygenerované UID pro posílání informací o pokrytí kódu jednotkovými testy, což se typicky provádí na CI (například v Jenkinsu, na Travis CI atd.). A naopak – Codecov může posílat informace o pokrytí zpět do GitLabu či GitHubu a zobrazit tak změnu v pokrytí testy přímo u daného pull requestu.

MIF obecny

Poznámka: existují i další podobné projekty, například Coveralls.io apod.

18. Obsah následujícího článku

V navazujícím článku se seznámíme s některými projekty, které se zaměřují na nalezení potenciálních bezpečnostních chyb. I tyto projekty bývají založeny na analýze zdrojového kódu převedeného do AST.

19. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/wccode (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 01_missing_package.go nekorektní zdrojový kód, v němž chybí deklarace balíčku https://github.com/tisnik/wcco­de/blob/master/01_missing_pac­kage.go
2 02_parenthesis.go chybně umístěná otevírací bloková závorka https://github.com/tisnik/wcco­de/blob/master/02_parenthe­sis.go
3 03_bad_syntax.go chybně umístěné otevírací i uzavírací blokové závorky https://github.com/tisnik/wcco­de/blob/master/03_bad_syn­tax.go
4 04_before_transform.go zdrojový kód před transformací nástrojem gofmt https://github.com/tisnik/wcco­de/blob/master/04_before_tran­sform.go
5 05_after_transform.go zdrojový kód po transformaci nástrojem gofmt https://github.com/tisnik/wcco­de/blob/master/05_after_tran­sform.go
       
6 06_integer_signed_types_checks.go kontrola celočíselných konstant překladačem https://github.com/tisnik/wcco­de/blob/master/06_integer_sig­ned_types_checks.go
7 07_improper_conversion.go kontrola prováděná při typových konverzích (celočíselné datové typy) https://github.com/tisnik/wcco­de/blob/master/07_improper_con­version.go
8 08_fp_types_checks.go kontrola prováděná při typových konverzích (typy s plovoucí řádovou čárkou) https://github.com/tisnik/wcco­de/blob/master/08_fp_types_chec­ks.go
       
9 09_nil_map.go pokus o zápis do takzvané nulové mapy (nil map) https://github.com/tisnik/wcco­de/blob/master/09_nil_map­.go
10 10_nil_pointer.go pokus o přístup do struktury přes nulový ukazatel (nil pointer) https://github.com/tisnik/wcco­de/blob/master/10_nil_poin­ter.go
       
11 11_unreachable_code.go zdrojový kód, jehož části nejsou dosažitelné https://github.com/tisnik/wcco­de/blob/master/11_unreacha­ble_code.go
12 12_shift.go použití bitového posunu o 70 bitů v 64bitové proměnné https://github.com/tisnik/wcco­de/blob/master/12_shift.go
13 13_printf_checks.go kontrola parametrů funkce fmt.Printf https://github.com/tisnik/wcco­de/blob/master/13_printf_chec­ks.go
14 14_sprintf_checks.go kontrola parametrů funkce fmt.Sprintf i její návratové hodnoty https://github.com/tisnik/wcco­de/blob/master/14_sprintf_chec­ks.go
15 15_read_byte_methods.go kontrola signatury metody ze známého rozhraní https://github.com/tisnik/wcco­de/blob/master/15_read_by­te_methods.go
       
16 16_simple_server.go jednoduchý HTTP server, ne všechny chybové kódy jsou ošetřeny https://github.com/tisnik/wcco­de/blob/master/16_simple_ser­ver.go
17 17_png_output.go zápis do PNG, opět ne všechny chybové kódy jsou ošetřeny https://github.com/tisnik/wcco­de/blob/master/17_png_output­.go
       
18 18_cyclomatic_complexity.go kód pro měření cyklomatické složitosti https://github.com/tisnik/wcco­de/blob/master/18_cycloma­tic_complexity.go
19 19_cyclomatic_complexity.go kód pro měření cyklomatické složitosti https://github.com/tisnik/wcco­de/blob/master/19_cycloma­tic_complexity.go
Poznámka: tyto příklady nebyly zařazeny do repositáře používaného pro příklady z tohoto seriálu, a to mj. i z toho důvodu, aby omylem neposloužily ke studijním účelům :-)

20. Odkazy na Internetu

  1. Go Data Structures: Binary Search Tree
    https://flaviocopes.com/golang-data-structure-binary-search-tree/
  2. Gobs of data
    https://blog.golang.org/gobs-of-data
  3. Formát BSON
    http://bsonspec.org/
  4. Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
    https://blog.intelligentbe­e.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/
  5. Tvorba univerzálních projevů
    http://www.kyblsoft.cz/projevy
  6. Repositář projektu Gift
    https://github.com/disinte­gration/gift
  7. Dokumentace k projektu Gift
    https://godoc.org/github.com/di­sintegration/gift
  8. Online x86 / x64 Assembler and Disassembler
    https://defuse.ca/online-x86-assembler.htm#disassembly2
  9. The Design of the Go Assembler
    https://talks.golang.org/2016/as­m.slide#1
  10. A Quick Guide to Go's Assembler
    https://golang.org/doc/asm
  11. AssemblyPolicy
    https://github.com/golang/go/wi­ki/AssemblyPolicy
  12. Geohash in Golang Assembly
    https://mmcloughlin.com/posts/geohash-assembly
  13. Command objdump
    https://golang.org/cmd/objdump/
  14. Assembly
    https://goroutines.com/asm
  15. Go & Assembly
    http://www.doxsey.net/blog/go-and-assembly
  16. A Foray Into Go Assembly Programming
    https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/
  17. Golang Capturing log.Println And fmt.Println Output
    https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4
  18. Stránka projektu plotly
    https://plot.ly/
  19. Plotly JavaScript Open Source Graphing Library
    https://plot.ly/javascript/
  20. Domain coloring
    https://en.wikipedia.org/wi­ki/Domain_coloring
  21. Michael Fogleman's projects
    https://www.michaelfogleman­.com/projects/tagged/grap­hics/
  22. Color Graphs of Complex Functions
    https://web.archive.org/web/20120511021419/htt­p://w.american.edu/cas/mat­hstat/lcrone/ComplexPlot.html
  23. A Gallery of Complex Functions
    http://wismuth.com/complex/ga­llery.html
  24. package glot
    https://godoc.org/github.com/A­rafatk/glot
  25. Gnuplotting: Output terminals
    http://www.gnuplotting.org/output-terminals/
  26. Introducing Glot the plotting library for Golang
    https://medium.com/@Arafat­./introducing-glot-the-plotting-library-for-golang-3133399948a1
  27. Introducing Glot the plotting library for Golang
    https://blog.gopheracademy.com/advent-2018/introducing-glot/
  28. Glot is a plotting library for Golang built on top of gnuplot
    https://github.com/Arafatk/glot
  29. Example plots (gonum/plot)
    https://github.com/gonum/plot/wi­ki/Example-plots
  30. A repository for plotting and visualizing data (gonum/plot)
    https://github.com/gonum/plot
  31. golang library to make https://chartjs.org/ plots
    https://github.com/brentp/go-chartjs
  32. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  33. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  34. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  35. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  36. gonum
    https://github.com/gonum
  37. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  38. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  39. Gonum Numerical Packages
    https://www.gonum.org/
  40. Stránky projektu MinIO
    https://min.io/
  41. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  42. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  43. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  44. Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
    https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/
  45. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  46. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  47. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  48. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  49. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  50. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  51. Ginkgo
    http://onsi.github.io/ginkgo/
  52. Gomega
    https://onsi.github.io/gomega/
  53. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  54. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  55. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  56. Balíček goexpect
    https://github.com/google/goexpect
  57. Balíček go-expect
    https://github.com/Netflix/go-expect
  58. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  59. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  60. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  61. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  62. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  63. goblin na GitHubu
    https://github.com/franela/goblin
  64. Mocha framework
    https://mochajs.org/
  65. frisby na GitHubu
    https://github.com/verdverm/frisby
  66. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  67. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  68. Cucumber for golang
    https://github.com/DATA-DOG/godog
  69. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  70. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  71. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  72. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  73. xml.org
    http://www.xml.org/
  74. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  75. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  76. JSON to YAML
    https://www.json2yaml.com/
  77. Data Format Converter
    https://toolkit.site/format.html
  78. Viper na GitHubu
    https://github.com/spf13/viper
  79. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  80. The fantastic ORM library for Golang
    http://gorm.io/
  81. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  82. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  83. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  84. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  85. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  86. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  87. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  88. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  89. Sémantické verzování
    https://semver.org/
  90. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  91. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  92. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  93. Modules
    https://github.com/golang/go/wi­ki/Modules
  94. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  95. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  96. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  97. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  98. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  99. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  100. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  101. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  102. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  103. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  104. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  105. gopls
    https://github.com/golang/go/wi­ki/gopls
  106. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  107. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  108. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  109. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  110. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  111. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  112. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  113. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  114. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  115. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  116. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  117. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  118. Package trace
    https://golang.org/pkg/runtime/trace/
  119. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  120. Command trace
    https://golang.org/cmd/trace/
  121. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  122. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  123. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  124. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  125. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  126. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  127. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  128. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  129. Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/
  130. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  131. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  132. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  133. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  134. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  135. The LLDB Debugger
    http://lldb.llvm.org/
  136. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  137. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  138. Go is on a Trajectory to Become the Next Enterprise Programming Language
    https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e
  139. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  140. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  141. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  142. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  143. 10 tools written in Go that every developer needs to know
    https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/
  144. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  145. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  146. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  147. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  148. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  149. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  150. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  151. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  152. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  153. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  154. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  155. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  156. go-cron
    https://github.com/rk/go-cron
  157. gocron
    https://github.com/jasonlvhit/gocron
  158. clockwork
    https://github.com/whiteShtef/cloc­kwork
  159. clockwerk
    https://github.com/onatm/clockwerk
  160. JobRunner
    https://github.com/bamzi/jobrunner
  161. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  162. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  163. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  164. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  165. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  166. go-prompt
    https://github.com/c-bata/go-prompt
  167. readline
    https://github.com/chzyer/readline
  168. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  169. go-readline
    https://github.com/fiorix/go-readline
  170. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  171. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  172. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  173. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  174. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  175. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  176. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  177. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  178. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  179. Editline Library (libedit)
    http://thrysoee.dk/editline/
  180. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  181. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  182. WinEditLine
    http://mingweditline.sourceforge.net/
  183. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  184. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  185. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  186. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  187. history(3) – Linux man page
    https://linux.die.net/man/3/history
  188. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  189. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  190. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  191. Balíček ogletest
    https://github.com/jacobsa/ogletest
  192. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  193. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  194. package testing
    https://golang.org/pkg/testing/
  195. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  196. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  197. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  198. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  199. GoConvey
    http://goconvey.co/
  200. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  201. 5 simple tips and tricks for writing unit tests in #golang
    https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
  202. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  203. package gg
    https://godoc.org/github.com/fo­gleman/gg
  204. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  205. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  206. The Go image package
    https://blog.golang.org/go-image-package
  207. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  208. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  209. YAML
    https://yaml.org/
  210. edn
    https://github.com/edn-format/edn
  211. Smile
    https://github.com/FasterXML/smile-format-specification
  212. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  213. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  214. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  215. Introducing JSON
    http://json.org/
  216. Package json
    https://golang.org/pkg/encoding/json/
  217. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  218. Go by Example: JSON
    https://gobyexample.com/json
  219. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  220. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  221. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  222. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  223. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  224. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  225. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  226. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  227. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  228. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  229. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  230. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  231. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  232. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  233. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  234. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  235. Algorithms to Go
    https://yourbasic.org/
  236. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  237. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/
  238. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  239. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  240. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  241. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  242. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  243. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  244. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  245. The Go Programming Language (home page)
    https://golang.org/
  246. GoDoc
    https://godoc.org/
  247. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  248. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  249. The Go Programming Language Specification
    https://golang.org/ref/spec
  250. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  251. Package builtin
    https://golang.org/pkg/builtin/
  252. Package fmt
    https://golang.org/pkg/fmt/
  253. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  254. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  255. Learning Go
    https://www.miek.nl/go/
  256. Go Bootcamp
    http://www.golangbootcamp.com/
  257. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  258. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  259. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  260. The Go Blog
    https://blog.golang.org/
  261. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  262. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  263. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  264. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  265. How the Go runtime implements maps efficiently (without generics)
    https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics
  266. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  267. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  268. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  269. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  270. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  271. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  272. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  273. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  274. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  275. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  276. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  277. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  278. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  279. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  280. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  281. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  282. Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
    https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/
  283. 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
    https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd
  284. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  285. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  286. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  287. Go vs. Python
    https://www.peterbe.com/plog/govspy
  288. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  289. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  290. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  291. Go by Example: Slices
    https://gobyexample.com/slices
  292. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  293. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  294. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  295. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  296. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  297. nils In Go
    https://go101.org/article/nil.html
  298. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  299. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  300. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  301. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  302. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  303. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  304. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  305. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  306. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  307. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  308. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  309. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  310. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  311. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  312. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  313. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  314. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  315. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  316. Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
    https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06
  317. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  318. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  319. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  320. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  321. Selectors
    https://golang.org/ref/spec#Selectors
  322. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  323. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  324. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  325. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  326. Part 21: Goroutines
    https://golangbot.com/goroutines/
  327. Part 22: Channels
    https://golangbot.com/channels/
  328. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  329. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  330. Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
    https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  331. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  332. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  333. Control Structures
    https://www.golang-book.com/books/intro/5
  334. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  335. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  336. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  337. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  338. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  339. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  340. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  341. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  342. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  343. Effective Go
    https://golang.org/doc/ef­fective_go.html
  344. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  345. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  346. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  347. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  348. Nils in Go
    https://www.doxsey.net/blog/nils-in-go