Was ist ein sinnvoller Weg, um ein Go-Projekt zu gestalten? [Geschlossen]


113

Ich habe ein Go-Projekt, das zunehmend komplexer wird, und möchte das Dateisystem so gestalten, dass die Schmerzen gelindert werden.

Gibt es einige gute Beispiele dafür, was Sinn macht?

Antworten:


132

Update Mai 2013: Die offizielle Dokumentation befindet sich im Abschnitt " Code Organisation "

Der Go-Code muss in einem Arbeitsbereich aufbewahrt werden .
Ein Arbeitsbereich ist eine Verzeichnishierarchie mit drei Verzeichnissen im Stammverzeichnis:

  • src enthält in Paketen organisierte Go-Quelldateien (ein Paket pro Verzeichnis),
  • pkg enthält Paketobjekte und
  • bin enthält ausführbare Befehle.

Das erstellt go toolQuellpakete und installiert die resultierenden Binärdateien in den Verzeichnissen pkgund bin.

Das srcUnterverzeichnis enthält normalerweise mehrere Versionskontroll-Repositorys (z. B. für Git oder Mercurial), die die Entwicklung eines oder mehrerer Quellpakete verfolgen.

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

Update Juli 2014: siehe " Strukturieren von Anwendungen in Go " von Ben Johnson

Dieser Artikel enthält Tipps wie:

Trennen Sie Ihre Binärdatei von Ihrer Anwendung

Das Kombinieren der main.goDatei und meiner Anwendungslogik in demselben Paket hat zwei Konsequenzen:

  • Dadurch wird meine Anwendung als Bibliothek unbrauchbar.
  • Ich kann nur eine Anwendungsbinärdatei haben.

Der beste Weg, dies zu beheben, besteht darin, einfach ein " cmd" Verzeichnis in meinem Projekt zu verwenden, in dem jedes seiner Unterverzeichnisse eine Anwendungsbinärdatei ist.

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

Bibliotheksgetriebene Entwicklung

Durch Verschieben der main.goDatei aus Ihrem Stammverzeichnis können Sie Ihre Anwendung aus der Perspektive einer Bibliothek erstellen. Ihre Anwendungsbinärdatei ist einfach ein Client der Anwendungsbibliothek.

Manchmal möchten Sie möglicherweise, dass Benutzer auf mehrere Arten interagieren, sodass Sie mehrere Binärdateien erstellen.
Wenn Sie beispielsweise ein " adder" -Paket hatten, mit dem Benutzer Zahlen addieren können, möchten Sie möglicherweise sowohl eine Befehlszeilenversion als auch eine Webversion veröffentlichen.
Sie können dies einfach tun, indem Sie Ihr Projekt folgendermaßen organisieren:

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

Benutzer können Ihre "Addierer" -Anwendungsbinärdateien mit "go get" mithilfe eines Auslassungszeichens installieren:

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

Und voila, dein Benutzer hat " adder" und " adder-server" installiert!

Sei nicht verrückt nach Unterpaketen

Normalerweise sind die Typen meines Projekts alle sehr verwandt, sodass es vom Standpunkt der Benutzerfreundlichkeit und der API aus besser passt.
Diese Typen können auch den Vorteil nutzen, dass sie nicht exportiert werden, wodurch die API klein und übersichtlich bleibt.

  1. Gruppieren Sie verwandte Typen und Code in jeder Datei. Wenn Ihre Typen und Funktionen gut organisiert sind, liegen die Dateien in der Regel zwischen 200 und 500 SLOC. Das klingt vielleicht nach viel, aber ich finde es einfach zu navigieren. 1000 SLOC ist normalerweise meine Obergrenze für eine einzelne Datei.
  2. Organisieren Sie den wichtigsten Typ oben in der Datei und fügen Sie unten in der Datei abnehmende Typen hinzu.
  3. Sobald Ihre Anwendung mehr als 10.000 SLOC erreicht, sollten Sie ernsthaft prüfen, ob sie in kleinere Projekte unterteilt werden kann.

Hinweis: Das letzte Training ist nicht immer gut:

Entschuldigung, ich kann dieser Praxis einfach nicht zustimmen.
Das Trennen des Typs in Dateien hilft bei der Codeverwaltung, der Lesbarkeit, der Wartbarkeit und der Testbarkeit.
Es kann auch die Einzelverantwortung und die Befolgung des Open / Closed-Prinzips sicherstellen.
Die Regel, um eine zirkuläre Abhängigkeit nicht zuzulassen, besteht darin, eine klare Struktur der Pakete zu erzwingen.


(Alternative nur für Februar 2013 src)
Das klassische Layout finden Sie unter " GitHub-Code-Layout ":

Die App und beide Bibliotheken leben auf Github, jede in ihrem eigenen Repository.
$GOPATHist die Wurzel des Projekts - jedes Ihrer Github-Repos wird in mehreren Ordnern unten ausgecheckt $GOPATH.

Ihr Code-Layout würde folgendermaßen aussehen:

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

Jeder Ordner unter src/github.com/jmcvetta/ist das Stammverzeichnis einer separaten Git-Kasse.

Das hat jedoch auf dieser reddit-Seite einige Kritikpunkte hervorgerufen :

Ich empfehle dringend, das Repo nicht so zu strukturieren, wie Sie es haben. Es wird " go get" brechen , was eines der nützlichsten Dinge bei Go ist.
Es ist weitaus besser, Ihren Code für Leute zu schreiben, die Go kennen, da sie höchstwahrscheinlich diejenigen sind, die ihn kompilieren.
Und für Leute, die dies nicht tun, werden sie zumindest ein Gefühl für die Sprache bekommen.

Legen Sie das Hauptpaket in die Wurzel des Repos.
Haben Sie die Assets in einem Unterverzeichnis (um die Dinge ordentlich zu halten).
Bewahren Sie das Fleisch des Codes in einem Unterpaket auf (falls jemand es außerhalb Ihrer Binärdatei wiederverwenden möchte).
Fügen Sie ein Setup-Skript in das Stammverzeichnis des Repos ein, damit es leicht zu finden ist.

Das Herunterladen, Erstellen, Installieren und Einrichten dauert immer noch nur zwei Schritte:

  • " go get <your repo path>": Lädt den Go-Code herunter und installiert ihn mit einem Unterverzeichnis für die Assets
  • $GOPATH/<your repo path>/setup.sh: verteilt die Assets an den richtigen Ort und installiert den Service

15
Ein (großes) Problem dabei setup.shist, dass Go einigermaßen plattformübergreifend ist, POSIX-Shell-Skripte jedoch nicht.
Kostix

Die jmcvetta-Struktur wird nicht kaputt gehen, da nutzlos importiert nutzlos importiert, wird go beides mit einem go get ... / nutzlos installieren. Aber ich stimme zu, dass wenn nutzlos eine Bibliothek ist, die speziell für nutzlos gemacht wurde, es sinnvoller ist, sie als Unterordner oder Geschwister in einem einzigen Git-Repo zu behalten.
Mna

@PuerkitoBio Ich stimme zu. Meine Ausbildung in Versionskontrolle und in komponentenbasiertem Management ( stackoverflow.com/a/933735/6309 ) führt mich mehr zu einer Komponente pro Repo, daher der zweite Teil dieser Antwort.
VonC

7

Ich gehe davon aus, dass Sie mit "Projekt" kein Go-Paket meinen, sondern eine Software, die Sie entwickeln. Ansonsten können Sie hier und hier Hilfe bekommen . Es unterscheidet sich jedoch nicht so sehr vom Schreiben von Paketen für Go: Verwenden Sie Pakete, erstellen Sie einen Ordner für jedes Paket und kombinieren Sie diese Pakete in Ihrer Anwendung.

Um sich eine Meinung zu bilden, können Sie sich die Trend-Go-Repositories auf github ansehen: https://github.com/trending/go . Bemerkenswerte Beispiele sind Cayley und Zeus .

Das beliebteste Schema besteht wahrscheinlich darin, eine Go-Hauptdatei und viele Module und Submodule in ihren eigenen Verzeichnissen zu haben. Wenn Sie viele Metadateien (Dokument, Lizenz, Vorlagen, ...) haben, möchten Sie den Quellcode möglicherweise in ein Unterverzeichnis einfügen. Das habe ich bisher gemacht.


@aussiegeek, ich bin kein Go-Experte, aber ich habe erfolgreich angewendet, was nemo in meinem eigenen Code vorgeschlagen hat - die Idee ist, dass Sie Module in Ihrem Projektverzeichnis haben können, Sie müssen nur mit ihrem vollständigen Präfix auf sie verweisen - relativ zu $GOPATH/srcoder unter Verwendung ihrer go getTabellennamen.
Kostix

doozerdist kein gutes Beispiel, auch die Tests sind schwach.
Inanc Gumus

@InancGumus Ich ermutige Sie, ein besseres Beispiel vorzuschlagen.
Nemo

sieh das und das .
Inanc Gumus

1

Von den Autoren von Golang wird ein Ansatz empfohlen, der definiert, wie Ihr Code so gestaltet wird, dass er am besten mit den go-Tools funktioniert und Quellcodeverwaltungssysteme unterstützt


1
So wird das Layout erstellt $GOROOT, nicht der Code im src/<project>Verzeichnis.
docwhat

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.