Quelle est la manière judicieuse de mettre en page un projet Go [fermé]

113

J'ai un projet go qui commence à devenir plus complexe et je veux disposer le système de fichiers de manière à réduire la douleur.

Y a-t-il de bons exemples de ce qui a du sens?

aussiegeek
la source

Réponses:

132

Mise à jour mai 2013: la documentation officielle se trouve dans la rubrique " Organisation du code "

Le code Go doit être conservé dans un espace de travail .
Un espace de travail est une hiérarchie de répertoires avec trois répertoires à sa racine:

  • src contient des fichiers source Go organisés en packages (un package par répertoire),
  • pkg contient des objets de package, et
  • bin contient des commandes exécutables.

Le go toolcompile les packages sources et installe les binaires résultants dans les répertoires pkget bin.

Le srcsous-répertoire contient généralement plusieurs référentiels de contrôle de version (comme pour Git ou Mercurial) qui suivent le développement d'un ou plusieurs packages sources.

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

Mise à jour de juillet 2014: voir « Structuring Applications in Go » de Ben Johnson

Cet article comprend des conseils tels que:

Séparez votre binaire de votre application

combiner le main.gofichier et ma logique d'application dans le même package a deux conséquences:

  • Cela rend mon application inutilisable en tant que bibliothèque.
  • Je ne peux avoir qu'un seul binaire d'application.

Le meilleur moyen que j'ai trouvé pour résoudre ce problème est d'utiliser simplement un cmdrépertoire « » dans mon projet où chacun de ses sous-répertoires est un binaire d'application.

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

Développement piloté par la bibliothèque

Déplacer le main.gofichier hors de votre racine vous permet de créer votre application du point de vue d'une bibliothèque. Le binaire de votre application est simplement un client de la bibliothèque de votre application.

Parfois, vous pouvez souhaiter que les utilisateurs interagissent de plusieurs manières afin de créer plusieurs binaires.
Par exemple, si vous aviez un adderpackage « » permettant aux utilisateurs d'ajouter des nombres ensemble, vous souhaiterez peut-être publier une version en ligne de commande ainsi qu'une version Web.
Vous pouvez facilement le faire en organisant votre projet comme ceci:

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

Les utilisateurs peuvent installer les fichiers binaires de votre application «additionneur» avec «go get» en utilisant des points de suspension:

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

Et voila, votre utilisateur a " adder" et " adder-server" installés!

Ne devenez pas fou avec les sous-packages

Habituellement, les types de mon projet sont tous très liés, il convient donc mieux du point de vue de la convivialité et de l'API.
Ces types peuvent également tirer parti des appels non exportés entre eux, ce qui maintient l'API petite et claire.

  1. Regroupez les types et le code associés dans chaque fichier. Si vos types et vos fonctions sont bien organisés, je trouve que les fichiers ont tendance à être compris entre 200 et 500 SLOC. Cela peut sembler beaucoup mais je trouve qu'il est facile de naviguer. 1000 SLOC est généralement ma limite supérieure pour un seul fichier.
  2. Organisez le type le plus important en haut du fichier et ajoutez les types en importance décroissante vers le bas du fichier.
  3. Une fois que votre application commence à dépasser 10 000 SLOC, vous devez évaluer sérieusement si elle peut être divisée en projets plus petits.

Remarque: cette dernière pratique n'est pas toujours bonne:

Désolé, je ne suis pas d'accord avec cette pratique.
La séparation du type en fichiers facilite la gestion du code, la lisibilité, la maintenance et la testabilité.
Cela peut aussi assurer une responsabilité unique et le respect du principe ouvert / fermé…
La règle pour ne pas autoriser la dépendance circulaire est de forcer que nous ayons une structure claire des paquets.


(Alternative Février 2013, concernant srcuniquement)
Vous pouvez trouver la mise en page classique illustrée dans " GitHub Code Layout ":

L'application et les deux bibliothèques vivent sur Github, chacune dans son propre référentiel.
$GOPATHest la racine du projet - chacun de vos dépôts Github sera extrait dans plusieurs dossiers ci-dessous $GOPATH.

Votre disposition de code ressemblerait à ceci:

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

Chaque dossier sous src/github.com/jmcvetta/est la racine d'un checkout git séparé.

Cela a cependant suscité quelques critiques dans cette page reddit :

Je recommande fortement de ne pas structurer le dépôt comme vous l'avez fait, il cassera " go get", ce qui est l'une des choses les plus utiles à propos de Go.
Il est préférable d'écrire votre code pour les personnes qui connaissent Go, car ce sont probablement eux qui le compilent.
Et pour ceux qui ne le font pas, ils auront au moins une idée de la langue.

Placez le package principal à la racine du dépôt.
Avoir les actifs dans un sous-répertoire (pour garder les choses en ordre).
Conservez la viande du code dans un sous-paquet (au cas où quelqu'un voudrait le réutiliser en dehors de votre binaire).
Incluez un script d'installation à la racine du dépôt pour qu'il soit facile à trouver.

Il ne s'agit toujours que d'un processus en deux étapes pour télécharger, créer, installer et configurer:

  • " go get <your repo path>": télécharge et installe le code go, avec un sous-répertoire pour les ressources
  • $GOPATH/<your repo path>/setup.sh: distribue les actifs au bon endroit et installe le service
VonC
la source
15
Un (gros) problème avec setup.shest que Go est raisonnablement multiplateforme alors que les scripts shell POSIX ne le sont pas.
kostix le
La structure jmcvetta ne cassera pas go get, puisque les importations inutiles sont inutiles, go get installera les deux avec un go get ... / uselessd. Mais je suis d'accord que si inutile est une bibliothèque spécialement conçue pour inutiled, il est plus logique de la conserver dans un seul dépôt git, en tant que sous-dossier ou frères.
mna
@PuerkitoBio Je suis d'accord. Ma formation au contrôle de version et à la gestion par composants ( stackoverflow.com/a/933735/6309 ) m'amène davantage vers un composant par référentiel, d'où la deuxième partie de cette réponse.
VonC le
7

Je suppose qu'avec «projet», vous ne voulez pas dire un package Go mais un logiciel que vous développez. Sinon, vous pouvez obtenir de l'aide ici et ici . Cependant, ce n'est pas tellement différent d'écrire des packages pour Go: utilisez des packages, créez un dossier pour chaque package et combinez ces packages dans votre application.

Pour vous forger une opinion, vous pouvez consulter les référentiels Go tendance sur github: https://github.com/trending/go . Les exemples notables sont cayley et zeus .

Le schéma le plus populaire est probablement d'avoir un fichier Go principal et de nombreux modules et sous-modules dans leurs propres répertoires. Si vous avez de nombreux méta-fichiers (doc, licence, modèles, ...), vous voudrez peut-être mettre le code source dans un sous-répertoire. C'est ce que j'ai fait jusqu'ici.

nemo
la source
@aussiegeek, je ne suis pas un expert de Go, mais j'ai appliqué avec succès ce que nemo a proposé dans mon propre code - l'idée est que vous pouvez avoir des modules dans le répertoire de votre projet, il vous suffit de vous y référer en utilisant leur préfixe complet - relatif à $GOPATH/srcou d' utiliser leurs go getnoms -Table.
kostix
doozerdn'est pas un bon exemple, même ses tests sont faibles.
Inanc Gumus
@InancGumus Je vous encourage à suggérer un meilleur exemple.
nemo
voir ceci et cela .
Inanc Gumus
1

Il existe une approche recommandée par les auteurs de Golang qui définit comment mettre en page votre code pour qu'il fonctionne au mieux avec les outils go et pour prendre en charge les systèmes de contrôle de source.

FigmentEngine
la source
1
Voilà comment mettre en page $GOROOT, pas le code dans le src/<project>répertoire.
docwhat