kirjoitin muutamia ajatuksia ylös Go:n aloittamisesta:
yksinkertaisin esimerkki, tallenna samaan hakemistoon nimellä hello.go
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
nyt:
$ go run hello.go
hello world
voidaan myös kääntää se binääriksi
$ go build
$ ./example
hello world
binääristä tulee senniminen kuin mikä sen sisältävä hakemiston nimi on (huomaat tämän myöhemmin hakemistorakenteesta cmd/binäärinnimi/main.go
käytännöstä)
otetaan vielä mukaan ulkoinen riippuvuus, muuta hello.go
tällaiseksi:
package main
import (
"fmt"
"github.com/function61/gokit/mac"
)
func main() {
fmt.Println(mac.New("secretKey", "message to sign").Sign())
}
nyt haetaan dependenssit (go noutaa github.com/function61/gokit/mac
modulin) ja ajetaan ohjelma:
$ go get -d ./...
$ go run hello.go
da3bd8c77b4df8c6
- jos ei ala jollain domain-osoitteella, niin on standardikirjaston moduleita
- jos alkaa domain-osoitteella (esim. "github.com/function61/gokit"), niin ne on standardikirjaston ulkopuolisia Git repoja
- go:ssa import-polku on kaikki mitä dependenssien hakemiseen tarvitaan. se on siis sekä dependenssin nimi että tieto mistä dependenssi haetaan. sun tarvitsee vain ajaa
$ go get -d ./...
niin Go varmistaa että kaikki import-polkujen dependenssit haetaan automaattisesti
private/public: jos funktion, constin, tyypin, globaalin muuttujan tai structin memberin nimi alkaa isolla alkukirjaimella niin se on public, jos pienellä niin se on private. privatet näkyy ainoastaan modulin sisällä ja publicit näkyy modulin ulkopuolelle.
heti kun alat järjestämään oman projektisi koodia useampiin moduleihin (= hakemistoihin), niin sun pitää ymmärtää kuinka gopath toimii: https://golang.org/doc/code.html
käytännössä meinaa että jos et halua kikkailla ENV-muuttujan kanssa, niin sun pitää koodata projektiasi hakemistossa /go/src/github.com/sunnimi/projektinnimi
että pystyt importoimaan oman projektisi moduleita. relatiiviset importit toimisivat myös, mutta se ei ole idiomaattista Go:ta.
tähän gopathiin on tulossa muutosta (siitä tulee kai vapaaehtoinen go modulesin myötä), koska tää mekanismi on monien mielestä liian sekava.
koodin hakemisto-layout: https://github.com/golang-standards/project-layout
tää on vähän liian pitkälle viety esimerkki, tärkeimmät pointit on:
- binäärit tulee cmd/binäärinnimi/main.go <-- tästä tulee buildin seurauksena binääri nimelle "binäärinnimi"
- jos kirjoitat useampia moduleita, niin ne tulee hakemistoon internal/modulinnimi/xyz.go jos modulia ei tarkoiteta että sitä käytetään sun projektin ulkopuolella
- modulit, jotka tarkoitat että niitä voi importoida muutkin projektit niin tulee vastaavasti hakemistoon pkg/modulinnimi/
mä tosin usein ite pistän kaikki modulit vain pkg/ hakemiston alle, pitäis ehkä internalia käyttää myös rohkeammin. tässä mun esimerkkiprojekti missä olen noudattanut tätä cmd/ ja pkg/ -rakennetta: https://github.com/function61/holepunch-server
tää on aika pelottavan iso dokumentti, mutta siellä on paljon hyviä vinkkejä: https://golang.org/doc/effective_go.html
go:n työkalut osaa hakea dependenssit $ go get -d ./...
komennolla. tämä riittää testiräpellyksiin, mutta ongelmana on se että se hakee master-haaran uusimman, jolloin sun projektis saattaa mennä rikki koska vaan jos joku sun dependenssissä menee rikki tai muuttuu.
tätä ratkaisemaan on tehty uunituore go modules (https://github.com/golang/go/wiki/Modules), mutta itellä on tuotantokäytössä edellinen best practice työkalu go dep (https://github.com/golang/dep), kunnes go modules julistetaan valmiiks tuotantokäyttöä varten
molemmat työkalut rakentuu ton "dependenssit haetaan import-lausekkeiiden perusteella" päälle, mutta ne pinnaa versiot "lukkotiedostoon", jolloin buildit on toistettavia koska dependensseistä haetaan aina samat versiot.
go:n sisäänrakennettu työkalu on vallan riittävä: $ go test ./...
testaa kaikki sun modulit rekursiivisesti (= alihakemistotkin)
docs: https://golang.org/pkg/testing/
esimerkki testauksesta: https://github.com/function61/gokit/blob/master/hashverifyreader/reader_test.go
go:n sisäänrakennettu format-työkalu muotoilee go-koodin automaattisesti, jolloin kaikki go-koodi näyttää muotoilun puolesta samalta (hyvä asia), eikä tarvi kiistellä muotoilukäytännöistä koska jokaisella olis kuitenkin oma mielipide
aja vain $ go fmt ./...
kts. lisää: https://golang.org/doc/effective_go.html#formatting
go:ssa on pirusti järeitä työkaluja sisäänrakennettuna. $ go vet ./...
ajaa staattisen analyysin ja löytää paljon virheitä.
löytyy myös sisäänrakennettu benchmarkkaus https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
race detector https://blog.golang.org/race-detector
go:n työkaluista käytännössä video: https://www.youtube.com/watch?v=uBjoTxosSys (tällä kaverilla on superisti muitakin Go-opetusvideoita)
profilointi suorituskykypullonkaulojen etsimiseen:
- https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/
- https://blog.golang.org/profiling-go-programs
- https://youtu.be/uBjoTxosSys?t=2167 (makee esimerkki flame graafeista mitä pproffilla saa ulos)
staattiseen analyysiin löytyy "meta linter" joka bundlaa sisään monta hyväksihavaittua ulkopuolista lintteriä https://github.com/alecthomas/gometalinter
godoc.org on palvelu, joka osaa automaattisesti näyttää minkä tahansa julkisen go-projektin rajapintadokumentaation. tietyllä formaatilla kun liität koodikommentit funktioihin niin ne näkyy silloin tuossa godoc-palvelussakin.
jos haluat katsella dokumentaatiota projektille https://github.com/spf13/cobra, niin vastaava hakusana dokumentaation löytämiseen on "godoc spf13/cobra", jolloin löydät: https://godoc.org/github.com/spf13/cobra
Go-maailmassa tuut törmäämään asioita Googlatessa Dave Cheneyn ( https://dave.cheney.net/category/golang ) kirjoituksiin, niitä kannattaa lukea koska sillä on paljon hyvää tietoa
https://github.com/avelino/awesome-go (täällä on muun muassa machine learning kategoria)