Lucas F. Costa Inhimillisiä ajatuksia eksakteista tieteistä

tammi 16, 2022
admin

Hei, kaikki! Kuten olette ehkä huomanneet, olen todella kiinnostunut Go:sta ja koska olen rakastunut tähän kieleen, haluaisin kirjoittaa siitä useammin.

Jos et vielä tunne Go:ta, olen todella sitä mieltä, että sinun pitäisi oppia se. Go on mahtava!

Go on suhteellisen nuori kieli ja mitä tulee vendorointiin ja riippuvuuksien hallintaan, se ei ole vielä todella kypsä. Go-yhteisö on kuitenkin ottanut käyttöön joitakin käytäntöjä ja luonut työkaluja tämän tarpeen tyydyttämiseksi. Tästä aiomme puhua tänään.

Go-ekosysteemin ymmärtäminen

Go pyrkii käyttämään yksinkertaisuutta monimutkaisten tehtävien suorittamiseen ja siten tekemään kielestä hauskemman ja tuottavamman. Kielen alusta lähtien Go:n tiimi valitsi, että he käyttäisivät merkkijonolitteraaleja, jotta tuontisyntaksi olisi mielivaltainen kuvaamaan sitä, mitä tuodaan.

Tämä on kirjoitettu heidän omissa dokumenteissaan:

Gon selkeä tavoite alusta lähtien oli, että Go:n koodia voitaisiin rakentaa käyttämällä vain lähdekoodista itsestään löytyvää informaatiota, eikä tarvitsisi kirjoittaa makefileä tai jotakin monista nykyaikaisista korvikkeista makefilelle. Jos Go olisi tarvinnut konfiguraatiotiedoston selittämään, miten ohjelma rakennetaan, Go olisi epäonnistunut.

Tämän tavoitteen saavuttamiseksi Go tiimi suosii konventioita konfiguraatioiden sijaan. Nämä ovat pakettien hallinnassa omaksutut konventiot:

  1. Tuontipolku johdetaan aina tunnetulla tavalla lähdekoodin URL-osoitteesta. Tämän vuoksi tuontisi näyttävät seuraavanlaisilta: github.com/author/pkgname. Näin saamme myös automaattisesti hallinnoidun nimiavaruuden, koska nämä verkkopalvelut hallinnoivat jo valmiiksi yksilöllisiä polkuja jokaiselle paketille.
  2. Paikka, johon tallennamme paketit tiedostojärjestelmässämme, johdetaan tunnetulla tavalla tuontipolusta. Jos etsit, minne go tallentaa lataamasi paketit, voit yhdistää sen URL-osoitteeseen, josta se on ladattu.
  3. Jokaista lähdepuun hakemistoa vastaa yksi paketti. Tämä helpottaa tiettyjen pakettien lähdekoodin löytämistä ja auttaa sinua järjestämään koodisi standardoidusti. Sitomalla kansiorakenne pakettirakenteeseen meidän ei tarvitse huolehtia molemmista yhtä aikaa, koska tiedostojärjestelmätyökaluista tulee pakettien hallintatyökaluja.
  4. Paketti rakennetaan käyttäen vain lähdekoodin tietoja. Tämä tarkoittaa, että ei makefiles eikä configuration ja vapauttaa sinut siitä, että sinun ei tarvitse ottaa käyttöön erityisiä (ja luultavasti monimutkaisia) työkaluketjuja.

Nyt kun olemme sanoneet tämän, on helppo ymmärtää, miksi go get-komento toimii niin kuin se toimii.

Go-työkalujen komentojen ymmärtäminen

Ennen kuin menemme näihin komentoihin, ymmärtäkäämme, mikä on ”$GOPATH”.

$GOPATH on ympäristömuuttuja, joka osoittaa hakemistoon, jota voidaan pitää työtilan hakemistona. Siinä säilytetään lähdekoodisi, käännetyt paketit ja ajettavat binäärit.

go get

Komento go get on yksinkertainen ja toimii melkein kuin git clone. Argumentti, joka sinun on annettava go get:lle, on yksinkertainen arkiston URL-osoite. Tässä esimerkissä käytämme komentoa: go get https://github.com/golang/oauth2.

Kun suoritat tämän komennon, go yksinkertaisesti hakee paketin antamastasi URL-osoitteesta ja laittaa sen $GOPATH-hakemistoosi. Jos navigoit $GOPATH-kansioosi, näet nyt, että sinulla on src/github.com/golang/oauth2-kansiossa kansio, joka sisältää paketin lähdetiedostot, ja käännetty paketti pkg-hakemistossa (yhdessä sen riippuvuuksien kanssa).

Kun suoritat go get, sinun on hyvä pitää mielessäsi, että kaikki ladatut paketit sijoitetaan hakemistoon, joka vastaa sitä URL-osoitetta, jota käytit sen lataamiseen.

Se on myös käytettävissä joukko muita lipukkeita, kuten -u, joka päivittää paketin, tai -insecure, joka sallii pakettien lataamisen käyttämällä turvattomia järjestelmiä kuten HTTP:tä. Voit lukea lisää go get-komennon ”edistyneestä” käytöstä tästä linkistä.

Käskyn go help gopath mukaan go get-komento päivittää myös hankkimiesi pakettien alamoduulit.

go install

Kun suoritat komennon go install paketin lähdehakemistossa, se kääntää paketin uusimman version ja kaikki sen riippuvuudet hakemistoon pkg.

go build

Go build vastaa pakettien ja niiden riippuvuussuhteiden kääntämisestä, mutta ei asenna tuloksia!

Varastojen hallinnan ymmärtäminen

Kuten olet saattanut huomata tavasta, jolla Go tallentaa riippuvuuksiaan, tähän lähestymistapaan riippuvuuksien hallintaan liittyy muutama ongelma.

Esimerkiksi emme pysty määrittelemään, mitä versiota paketista tarvitsemme, paitsi jos se sijaitsee täysin eri arkistossa, sillä muutoin go get noutaa aina paketin uusimman version. Tämä tarkoittaa sitä, että jos joku tekee rikkovan muutoksen pakettiinsa eikä laita sitä toiseen repoon, sinä ja tiimisi joudutte ongelmiin, koska saatatte päätyä hakemaan eri versioita samasta paketista, mikä johtaa sitten ”toimii minun koneellani” -ongelmiin.

Toinen suuri ongelma on, että koska go get asentaa paketit src-hakemiston juureen, sinulla ei voi olla eri versioita riippuvuussuhteistasi jokaisessa projektissasi. Tämä tarkoittaa sitä, että sinulla ei voi olla projekteja, jotka ovat riippuvaisia saman paketin eri versioista, vaan sinulla on joko yksi tai toinen versio kerrallaan.

Tämän ongelman lieventämiseksi Go 1.5:stä lähtien Go tiimi otti käyttöön vendoring-ominaisuuden. Tämän ominaisuuden avulla voit laittaa paketin riippuvuuden koodin omaan hakemistoonsa, jolloin se saa aina samat versiot kaikkiin buildeihin.

Asetaan, että sinulla on projekti nimeltä awesome-project, joka on riippuvainen popular-package:sta. Varmistaaksesi, että kaikki tiimisi jäsenet käyttävät samaa versiota popular-package:stä, voit laittaa sen lähdekoodin $GOPATH/src/awesome-project/vendor/popular-package:n sisälle. Tämä toimii, koska Go yrittää silloin ratkaista riippuvuuksiesi polun alkaen oman kansionsa vendor-hakemistosta (jos siinä on vähintään yksi .go-tiedosto) eikä $GOPATH/src:stä. Tämä tekee myös rakennuksistasi deterministisiä (toistettavia), koska ne käyttävät aina samaa versiota popular-package.

On myös tärkeää huomata, että komento go get ei laita ladattuja paketteja automaattisesti vendor-kansioon. Tämä on vendoring-työkalujen tehtävä.

Käytettäessä vendoringiä voit käyttää samoja tuontipolkuja kuin jos et käyttäisi, koska Go yrittää aina löytää riippuvuudet lähimmästä vendor-hakemistosta. Tuontipolkujen eteen ei tarvitse lisätä vendor/.

Voidaksemme täysin ymmärtää, miten vendorointi toimii, meidän on ymmärrettävä algoritmi, jota Go käyttää tuontipolkujen ratkaisemiseen, joka on seuraava:

  1. Etsitään tuontia paikallisesta vendor-hakemistosta (jos sellainen on olemassa)
  2. Jos emme löydä tätä pakettia paikallisesta vendor-hakemistosta, siirrymme ylempään vanhempaan kansioon ja yritämme löytää sen sieltä vendor-hakemistosta (jos mitään)
  3. Toistamme vaiheen 2, kunnes saavumme $GOPATH/src
  4. Etsimme tuotua pakettia $GOROOT-kansiosta
  5. Jos emme löydä tätä pakettia $GOROOT-kansiosta, etsimme sitä $GOPATH/src-kansiostamme

Vastaan, tämä tarkoittaa, että jokaisella paketilla voi olla omat riippuvuutensa, jotka on ratkaistu omaan myyjähakemistoonsa. Jos olet riippuvainen esimerkiksi paketista x ja paketista y, ja paketti x on myös riippuvainen paketista y, mutta tarvitsee eri version siitä, voit silti suorittaa koodisi ilman ongelmia, koska x etsii y omasta vendor-kansiostaan, kun taas pakettisi etsii y projektisi vendor-hakemistosta.

Nyt käytännön esimerkki. Oletetaan, että sinulla on tämä kansiorakenne:

$GOPATH src/ github.com/user/package-one/ one.go myproject main.go vendor/ github.com/user/package-one/ one.go client/ client.go vendor/ github.com/user/package-one/ server/ server.go vendor/ github.com/user/package-one/ one.go

Jos tuomme github.com/user/package-one sisältä main.go se ratkeaisi tämän paketin versioon, joka on vendor-hakemistossa samassa kansiossa:

$GOPATH src/ github.com/user/package-one/ one.go myproject main.go <-- Importing package-one from here vendor/ github.com/user/package-one/ <-- resolves to here one.go client/ client.go vendor/ github.com/user/package-one/ server/ server.go vendor/ github.com/user/package-one/ one.go

Nyt jos tuomme saman paketin client.go:ssä, se ratkeaa myös tämän paketin vendor-kansioon omassa hakemistossaan:

$GOPATH src/ github.com/user/package-one/ one.go myproject main.go vendor/ github.com/user/package-one/ one.go client/ client.go <-- Importing package-one from here vendor/ github.com/user/package-one/ <-- resolves to here server/ server.go vendor/ github.com/user/package-one/ one.go

Samoin tapahtuu, kun tuomme tämän paketin server.go:ssä:

$GOPATH src/ github.com/user/package-one/ one.go myproject main.go vendor/ github.com/user/package-one/ one.go client/ client.go vendor/ github.com/user/package-one/ server/ server.go <-- Importing package-one from here vendor/ github.com/user/package-one/ <-- resolves to here one.go

Riippuvuuksien hallinnan ymmärtäminen

Nyt kun olemme oppineet kaikki nämä asiat siitä, miten Go käsittelee tuontia ja myyntiä, on aika vihdoin puhua riippuvuuksien hallinnasta.

Työkalu, jota käytän tällä hetkellä omissa projekteissani riippuvuuksien hallintaan, on nimeltään godep. Se näyttää olevan hyvin suosittu ja se toimii minulla hyvin, joten suosittelen lämpimästi käyttämään myös sitä.

Se on rakennettu vendoring:n toimintatavan ympärille. Kaikki mitä sinun täytyy tehdä aloittaaksesi sen käytön on käyttää komentoa godep save aina kun haluat tallentaa riippuvuuksiasi vendor-kansioon.

Kun suoritat godep save, godep tallentaa luettelon nykyisistä riippuvuuksistasi Godeps/Godeps.json-kansioon ja kopioi sen jälkeen niiden lähdekoodin vendor-kansioon. On myös tärkeää huomata, että sinulla on oltava nämä riippuvuudet asennettuna koneellesi, jotta godep voi kopioida ne.

Nyt voit sitoa vendor-kansion ja sen sisällön varmistaaksesi, että kaikilla on samat versiot samoista paketeista aina, kun suoritat pakettisi.

Toinen mielenkiintoinen komento on godep restore, joka asentaa Godeps/Godeps.json-tiedostossasi määritellyt versiot $GOPATH:iin.

Voidaksesi päivittää riippuvuuden sinun tarvitsee vain päivittää se käyttämällä go get -u (kuten puhuimme aiemmin) ja sitten ajaa godep save, jotta godep päivittää Godeps/Godeps.json-tiedoston ja kopioi tarvittavat tiedostot vendor-hakemistoon.

Muutama ajatus siitä, miten Go käsittelee riippuvuuksia

Tämän blogikirjoituksen loppuun haluaisin lisätä myös oman mielipiteeni siitä, miten Go käsittelee riippuvuuksia.

Mielestäni Go:n valinta käyttää ulkoisia arkistoja pakettien nimiavaruuksien käsittelyyn oli loistava, koska se tekee koko pakettien resoluutiosta paljon yksinkertaisempaa yhdistämällä tiedostojärjestelmäkonseptit nimiavaruuskonsepteihin. Tämä saa myös koko ekosysteemin toimimaan itsenäisesti, koska meillä on nyt hajautettu tapa hakea paketteja.

Hajautetulla pakettien hallinnalla on kuitenkin hintansa, nimittäin se, ettei kaikkia solmuja, jotka ovat osa tätä ”verkkoa”, voida hallita. Jos joku päättää ottaa pakettinsa pois esimerkiksi github:stä, niin sadat, tuhannet tai jopa miljoonat buildit voivat yhtäkkiä alkaa epäonnistua. Myös nimimuutoksilla voisi olla sama vaikutus.

Gon päätavoitteet huomioon ottaen tämä on täysin järkevää ja täysin reilu kompromissi. Go:ssa on kyse konventioista konfiguroinnin sijaan, eikä ole yksinkertaisempaa tapaa käsitellä riippuvuuksia kuin nykyinen tapa.

Tietysti muutamia parannuksia voisi tehdä, kuten git-tagien käyttäminen tiettyjen pakettien versioiden hakemiseen ja käyttäjien antaminen määrittää, mitä versioita heidän pakettinsa käyttävät. Olisi myös siistiä pystyä hakemaan nämä riippuvuudet sen sijaan, että ne tarkistettaisiin lähdekoodinhallinnasta. Näin voisimme välttää likaiset diffit, jotka sisältävät vain muutoksia vendor-hakemistossa olevaan koodiin, ja tehdä koko arkistosta siistimmän ja kevyemmän.

Ota yhteyttä!

Jos sinulla on epäilyksiä, ajatuksia tai jos olet eri mieltä jostain kirjoittamastani, jaa ne kanssani alla olevissa kommenteissa tai tavoittele minua twitterissä osoitteessa @thewizardlucas. Kuuntelisin mielelläni, mitä sinulla on sanottavaa ja tekisin korjauksia, jos olen tehnyt virheitä.

Viimeisenä, mutta ei vähäisimpänä, muista katsoa tämä Wisdom Omuyan mahtava puheenvuoro GopherCon 2016 -tapahtumassa, jossa hän selittää, miten Go Vendoring toimii, ja osoittaa myös joitakin yksityiskohtia sen sisäisestä toiminnasta.

Kiitos, että luit tämän!

Vastaa

Sähköpostiosoitettasi ei julkaista.