Jaki jest rozsądny sposób rozmieszczenia projektu w Go [zamknięte]

113

Mam projekt go, który zaczyna być bardziej złożony i chcę rozłożyć system plików w taki sposób, aby zmniejszyć ból.

Czy są jakieś dobre przykłady tego, co ma sens?

aussiegeek
źródło

Odpowiedzi:

132

Aktualizacja maj 2013: oficjalna dokumentacja znajduje się w sekcji „ Organizacja kodu

Kod Go musi być przechowywany w obszarze roboczym .
Obszar roboczy to hierarchia katalogów z trzema katalogami w katalogu głównym:

  • src zawiera pliki źródłowe Go zorganizowane w pakiety (jeden pakiet na katalog),
  • pkg zawiera obiekty pakietu, a
  • bin zawiera polecenia wykonywalne.

go toolBuduje pakiety źródłowe i instaluje wynikających binarnych do pkgi binkatalogów.

srcPodkatalogu zazwyczaj zawiera wiele repozytoriów kontroli wersji (jak Git czy Mercurial), które śledzą rozwój jednego lub więcej pakietów źródłowych.

bin/
    streak                         # command executable
    todo                           # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
        github.com/nf/todo/
            task.a                 # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source

Aktualizacja z lipca 2014 r .: zobacz „ Strukturyzacja aplikacji w ruchuautorstwa Bena Johnsona

Ten artykuł zawiera wskazówki, takie jak:

Oddziel swój plik binarny od aplikacji

połączenie main.gopliku i logiki aplikacji w tym samym pakiecie ma dwie konsekwencje:

  • To sprawia, że ​​moja aplikacja jest bezużyteczna jako biblioteka.
  • Mogę mieć tylko jeden plik binarny aplikacji.

Najlepszym sposobem rozwiązania tego problemu jest po prostu użycie cmdkatalogu „ ” w moim projekcie, w którym każdy z jego podkatalogów jest plikiem binarnym aplikacji.

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

Rozwój oparty na bibliotekach

Przeniesienie main.gopliku z katalogu głównego umożliwia zbudowanie aplikacji z perspektywy biblioteki. Plik binarny aplikacji jest po prostu klientem biblioteki aplikacji.

Czasami możesz chcieć, aby użytkownicy wchodzili w interakcje na wiele sposobów, więc tworzysz wiele plików binarnych.
Na przykład, jeśli masz adderpakiet „ ”, który umożliwia użytkownikom dodawanie razem liczb, możesz chcieć wydać wersję wiersza poleceń, a także wersję internetową.
Możesz to łatwo zrobić, organizując swój projekt w następujący sposób:

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

Użytkownicy mogą instalować pliki binarne aplikacji „adder” za pomocą polecenia „go get”, używając wielokropka:

$ go get github.com/benbjohnson/adder/...

I voila, twój użytkownik ma zainstalowane „ adder” i „ adder-server”!

Nie zwariuj na punkcie podpakietów

Zwykle wszystkie typy moich projektów są bardzo powiązane, więc lepiej pasują z punktu widzenia użyteczności i API.
Te typy mogą również korzystać z wywoływania niewyeksportowanych między nimi, co sprawia, że ​​interfejs API jest mały i przejrzysty.

  1. Grupuj powiązane typy i kod razem w każdym pliku. Jeśli twoje typy i funkcje są dobrze zorganizowane, stwierdzam, że pliki mają zwykle między 200 a 500 SLOC. To może wydawać się dużo, ale nawigacja jest dla mnie łatwa. 1000 SLOC jest zwykle moim górnym limitem dla pojedynczego pliku.
  2. Zorganizuj najważniejszy typ u góry pliku i dodaj typy o malejącej ważności u dołu pliku.
  3. Gdy aplikacja zacznie przekraczać 10 000 SLOC, należy poważnie ocenić, czy można ją podzielić na mniejsze projekty.

Uwaga: ta ostatnia praktyka nie zawsze jest dobra:

Przepraszam, po prostu nie mogę się zgodzić z tą praktyką.
Rozdzielanie typów na pliki ułatwia zarządzanie kodem, czytelność, łatwość konserwacji i testowalność.
Może również zapewnić pojedynczą odpowiedzialność i przestrzeganie zasady otwarte / zamknięte…
Regułą zakazującą zależności cyrkularnej jest wymuszenie jasnej struktury pakietów.


(Alternatywa z lutego 2013 r., Dotyczy srctylko)
Klasyczny układ zilustrowany w „ Układ kodu GitHub ”:

Aplikacja i obie biblioteki są dostępne na Github, każda w swoim własnym repozytorium.
$GOPATHjest katalogiem głównym projektu - każde repozytorium Github zostanie sprawdzone w kilku folderach poniżej $GOPATH.

Twój układ kodu wyglądałby następująco:

$GOPATH/
    src/
        github.com/
            jmcvetta/
                useless/
                    .git/
                    useless.go
                    useless_test.go
                    README.md
                uselessd/
                    .git/
                    uselessd.go
                    uselessd_test.go
                    README.md

Każdy folder poniżej src/github.com/jmcvetta/jest katalogiem głównym oddzielnego wyewidencjonowania git.

To wywołało jednak krytykę na tej stronie reddit :

Zdecydowanie odradzam tworzenie repozytorium w taki sposób, w jaki masz, ponieważ " go get" się zepsuje , co jest jedną z najbardziej przydatnych rzeczy w Go.
O wiele lepiej jest pisać kod dla osób, które znają Go, ponieważ najprawdopodobniej to one go kompilują.
A ci, którzy tego nie robią, przynajmniej poczują język.

Umieść pakiet główny w katalogu głównym repozytorium.
Umieść zasoby w podkatalogu (aby zachować porządek).
Przechowuj treść kodu w podpakiecie (na wypadek, gdyby ktoś chciał użyć go ponownie poza plikiem binarnym).
Dołącz skrypt instalacyjny w katalogu głównym repozytorium, aby był łatwy do znalezienia.

Pobieranie, budowanie, instalowanie i konfigurowanie to wciąż tylko dwuetapowy proces .:

  • go get <your repo path>”: pobiera i instaluje kod go wraz z podkatalogiem dla zasobów
  • $GOPATH/<your repo path>/setup.sh: dystrybuuje zasoby we właściwe miejsce i instaluje usługę
VonC
źródło
15
Jednym (dużym) problemem setup.shjest to, że Go jest w miarę wieloplatformowy, podczas gdy skrypty powłoki POSIX nie.
kostix
Struktura jmcvetta nie zepsuje się go get, ponieważ uselessd importuje bezużyteczne, go get zainstaluje oba z poleceniem go get ... / uselessd. Ale zgadzam się, że jeśli bezużyteczna jest biblioteka stworzona specjalnie dla uselessd, bardziej sensowne jest przechowywanie jej w jednym repozytorium git, jako podfolder lub rodzeństwo.
mna
@PuerkitoBio Zgadzam się. Moje szkolenie w zakresie kontroli wersji i zarządzania opartego na komponentach ( stackoverflow.com/a/933735/6309 ) prowadzi mnie bardziej do jednego komponentu na repozytorium, stąd druga część tej odpowiedzi.
VonC,
7

Zakładam, że „projekt” nie oznacza pakietu Go, ale oprogramowanie, które tworzysz. W przeciwnym razie możesz uzyskać pomoc tutaj i tutaj . Jednak pisanie pakietów dla Go nie różni się tak bardzo: użyj pakietów, utwórz folder dla każdego pakietu i połącz te pakiety w swojej aplikacji.

Aby zbudować sobie opinię, możesz spojrzeć na popularne repozytoria Go na github: https://github.com/trending/go . Wybitne przykłady Cayley i Zeus .

Najpopularniejszym schematem jest prawdopodobnie posiadanie głównego pliku Go oraz wielu modułów i podmodułów w swoich własnych katalogach. Jeśli masz wiele plików meta (dokumentacja, licencja, szablony, ...), możesz umieścić kod źródłowy w podkatalogu. Tak zrobiłem do tej pory.

nemo
źródło
@aussiegeek, nie jestem ekspertem w Go, ale z powodzeniem zastosowałem to, co nemo zaproponował we własnym kodzie - chodzi o to, że możesz mieć moduły w katalogu swojego projektu, wystarczy odwołać się do nich pełnym prefiksem - względnym do $GOPATH/srclub używając ich go getnazw tabel.
kostix
doozerdnie jest dobrym przykładem, nawet jego testy są słabe.
Inanc Gumus
@InancGumus Zachęcam do zaproponowania lepszego przykładu.
nemo
zobacz to i to .
Inanc Gumus
1

Jest zalecane podejście od autorów Golang, które definiuje, jak rozmieścić kod, aby działał najlepiej z narzędziami go i obsługiwał systemy kontroli źródła

FigmentEngine
źródło
1
Tak wygląda układ $GOROOT, a nie kod w src/<project>katalogu.
docwhat