Organisation d'un projet Go standard

Cet article est une traduction du dépôt Github Standard Go Project Layout

Introduction

Ce dépôt est une architecture basique pour des projets d'applications en Go. Il ne représente pas un standard officiel défini par l'équipe de développement principale de Go. C'est néanmoins un ensemble de modèles d'architecture que l'on peut retrouver autant sur des projets historiques que plus récents dans l'écosystème Go. Certains patterns sont plus populaires que d'autres. Il comporte également nombre d'améliorations mineures ainsi que plusieurs répertoires communs à beaucoup d'applications existantes de taille importante.

Si vous commencez à apprendre Go, ou si vous souhaitez développer un petit side-project pour vous-même, cette architecture n'est pas du tout adaptée. Commencez par quelque chose de très simple (un unique fichier main.go est largement suffisant). Au fur et à mesure que votre projet évolue, il est important de garder à l'esprit que votre code doit être bien structuré sinon vous finirez rapidement avec un code difficile à maintenir, comprenant beaucoup de dépendances cachées et un state global. Plus il y aura de gens qui travailleront sur le projet, plus il sera important d'avoir une structure solide. C'est pourquoi il est important d'introduire une façon identique pour tout le monde de gérer les bibliothèques et les packages. Lorsque vous maintenez un projet open source ou que vous savez que d'autres projets importent votre code depuis votre dépôt, il est important d'avoir des packages et du code privé (aka internal). Clonez le dépôt, gardez ce dont vous avez besoin et supprimez tout le reste ! Ce n'est pas parce que des dossiers existent que vous devez impérativement tous les utiliser. Tous ces patterns ne sont pas tout le temps utilisés dans tous les projets. Même le pattern vendor n'est pas universel.

Depuis la sortie de Go 1.14 les Go Modules sont enfin prêts à être utilisés en production. Utilisez les Go Modules par défaut sauf si vous avez une raison bien spécifique de ne pas les utiliser. Lorsque vous les utilisez, vous n'avez pas besoin de vous embêter avec le $GOPATH ou de définir le dossier dans lequel vous allez mettre votre projet. Le fichier go.mod part du principe que votre dépôt est hébergé sur Github, mais ce n'est pas une obligation. Le chemin du module peut être n'importe quoi, mais il faut savoir que le premier composant du chemin devrait toujours avoir un point dans son nom (la version actuelle de Go ne l'impose plus, mais si vous utilisez des versions un peu plus anciennes ne soyez pas surpris que votre build échoue s'il n'y a pas de point). Allez voir les tickets 37554 et 32819 si vous souhaitez en savoir plus.

L'architecture de ce projet est générique de manière intentionelle et elle n'essaie pas d'imposer une structure de paquet Go spécifique.

Ce projet est un effort communautaire. Ouvrez un ticket si vous découvrez un nouveau pattern ou si vous pensez qu'un des patterns existants devrait être mis à jour.

Si vous avez besoin d'aide pour le nommage, le formattage ou le style, commencez par lancer gofmt et golint. Prenez également le temps de parcourir ces lignes directrices et recommandations :

Lisez l'article Go Project Layout pour avoir des informations additionnelles.

Plus d'infos sur le nommage et l'organisation des packages, ainsi que quelques recommandations sur la structuration du code :

Un article en Chinois sur les guidelines du design orienté package et la couche Architecture :

Les répertoires Go

/cmd

Les applications principales de ce projet.

Le nom de répertoire de chaque application doit correspondre au nom de l'exécutable que vous souhaitez avoir (p. ex., /cmd/myapp).

Ne mettez pas trop de code dans le répertoire de votre application. Si vous pensez que le code peut être importé et réutilisé dans d'autres projets, déplacez le dans le dossier /pkg. Si le code n'est pas réutilisable, ou si vous ne souhaitez pas que d'autres personnes l'utilisent, placez le dans le dossier /internal. Soyez explicite quant à vos intentions, vous seriez surpris de l'utilisation que d'autres développeurs pourraient faire de votre code !

Il est habituel d'avoir une petite fonction main qui importe et appelle du code contenu dans les dossiers /internal et /pkg, et rien de plus.

Voir le dossier /cmd pour des exemples.

/internal

Applications privées et bibliothèques de code. C'est le code que vous ne souhaitez pas voir importé dans d'autres applications ou bibliothèques. Notez que ce pattern est imposé par le compilateur Go lui-même (voir les release notes de Go 1.4 pour plus de détails). Vous n'êtes pas limité à un seul dossier internal de haut niveau, mais vous pouvez en avoir plusieurs à n'importe quel niveau de l'arborescence de votre projet.

Vous pouvez également ajouter un peu de structure dans vos packages internes pour séparer le code partagé et non partagé. Ce n'est pas du tout obligatoire (surtout pour les petits projets), mais il est intéressant d'avoir des indices visuels indiquant l'utilisation prévue d'un package. Le code de votre application peut aller dans un dossier /internal/app (p. ex., /internal/app/myapp) tandis que le code partagé par les applications peut se retrouver dans un dossier /internal/pkg (p. ex., /internal/pkg/myprivlib).

/pkg

Placez-y le code qui peut être réutilisé par les applications externes (p. ex., /pkg/mypubliclib). D'autres projets peuvent importer ces bibliothèques et s'attendent donc à ce qu'elles soient fonctionnelles, pensez y donc à deux fois avant de mettre du code dans ce dossier :-) Utiliser le dossier internal est une manière plus adéquate de garder vos packages privés et non importables car c'est intégré au compilateur Go. Le dossier /pkg est nénanmoins une bonne manière d'indiquer que le code contenu dans ce dossier peut être utilisé par les autres utilisateurs sans problème. L'article de blog de Travis Jeffery I'll take pkg over internal explique plus en détail les différences entre les dossier pkg et internal et quand il fait sens de les utiliser.

C'est également une manière de regrouper tout votre code Go au même endroit lorsque votre dossier racine comporte de nombreux composants et dossiers non-Go, permettant plus facilement de lancer les différents outils Go, tel que mentionné dans les conférences suivantes : Best Practices for Industrial Programming lors de GopherCon EU 2018, GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps et GoLab 2018 - Massimiliano Pippi - Project layout patterns in Go).

Voir le dossier /pkg pour découvrir quels projets Go populaires utilisent cette architecture de projet. C'est un pattern plutôt commun, mais qui n'est pas accepté de manière universelle, et certaines personnes de la communauté Go ne le recommandent pas.

Vous n'êtes pas obligés de l'utiliser si votre projet est petit et si l'ajout d'un niveau de plus n'ajoute pas vraiment de valeur (sauf si vous y tenez vraiment :-)). Il est temps d'y penser lorsque votre projet commence à prendre de l'ampleur et que votre dossier racine est encombré (surtout si vous avez beaucoup de composants non-Go)

/vendor

Les dépendances de votre application (gérées manuellement ou via votre gestionnaire de dépendances favori tel que la fonctionnalité incluse dans les Go Modules). La commande go mod vendor créera un dossier /vendor pour vous. Notez que vous devrez peut-être utiliser le flag -mod=vendor avec votre commande go build si vous n'utilisez pas Go 1.14 qui le définit par défaut.

Ne commitez pas vos dépendances si vous développez une bibliothèque.

Depuis sa version 1.13, Go active la fonctionnalité de proxy de module (en utilisant https://proxy.golang.org comme serveur de proxy par défaut). Plus d'infos ici afin de définir si cela correspond à votre obligations et contraintes. Si c'est le cas, vous n'aurez pas besoin du dossier vendor.

Les répertoires d'application de services

/api

Spécifications OpenAPI/Swagger, fichiers de schémas JSON, fichiers de définitions de protocoles.

Voir le dossier /api pour des examples.

Les répertoires d'application web

/web

Les composants spécifiques aux applications web : assets statiques, templates serveurs et SPAs.

Les répertoire communs aux applications

/configs

Templates de fichiers de configuration ou configurations par défaut.

Ajoutez vos templates confd ou consul-template dans ce répertoire.

/init

Initialisation du système (systemd, upstart, sysv) et configurations des administrateurs/superviseurs de process (runit, supervisord).

/scripts

Scripts permettant différentes opérations telles que le build, l'installation, des analyses, ...

Ces scripts permettent de garder le Makefile du dossier racine réduit et simple (p. ex., https://github.com/hashicorp/terraform/blob/master/Makefile).

Voir le dossier /scripts pour des exemples.

/build

Packaging et Intégration Continue.

Ajoutez vos scripts et configurations de cloud (AMI), conteneur (Docker), OS (deb, rpm, pkg) et package dans le dossier /build/package.

Placez vos scripts et configurations de CI (travis, circle, drone) dans le dossier /build/ci. Prenez garde au fait que certains outils de CI (p. ex., Travis CI) sont très contraignants vis à vis de l'emplacement de leurs fichiers de configuration. Essayez donc, lorsque c'est possible, de créer des liens entre le dossier /build/ci et les endroits où les outils de CI s'attendent à trouver ces fichiers.

/deployments

Templates et configurations pour les IaaS, PaaS, système et l'orchestration de conteneurs (docker-compose, kubernetes/helm, mesos, terraform, bosh). Sur certains projets (principalement les applications déployées via Kubernetes) ce dossier s'appelle /deploy.

/test

Applications et données de tests externes additionnels. Vous pouvez structurer le dossier /test de la façon qui vous convient le mieux. Pour des projets plus importants, il fait sens d'utiliser un sous-dossier data. Vous pouvez par exemple utiliser /test/data ou /test/testdata si vous souhaitez que Go ignore ce dossier. Go ignore également les dossiers ou fichiers commençant par "." ou "_", ce qui vous donne plus de flexibilité en terme de nommage de votre dossier de données de test.

Voir le dossier /test pour des exemples

Autres répertoires

/docs

Documents utilisateurs et design (en plus de votre documentation générée GoDoc)

Voir le dossier /docs pour des exemples

/tools

Outils de support du projet. Ces scripts peuvent importer du code des dossier /pkg et /internal

Voir le dossier /tools pour des exemples

/examples

Exemples de vos applications et/ou de vos bibliothèques publiques

Voir le dossier /examples pour des exemples

/third_party

Outils d'aide externe, code forké et autres utilitaires tierces (p. ex., Swagger UI).

/githooks

Hooks Git.

/assets

D'autres assets qui sont utilisés dans votre dépôt (images, logos, etc).

/website

C'est là que vous placez les données du site de votre projet si vous n'utilisez pas GitHub pages.

Voir le dossier /website pour des exemples

Les répertoires que vous ne devriez pas avoir

/src

Certains projets Go comportent un dossier src mais cela arrive en général lorsque les développeurs viennent du monde de Java où c'est une pratique habituelle. Faites tout votre possible pour ne pas adopter ce pattern Java. Vous n'avez vraiment pas envie que votre code Go ou vos projets Go ressemblent à du Java :-)

Ne confondez pas le répertoire /src à la racine avec le répertoire /src utilisé par Go pour gérer ses espaces de travail comme décrit dans How to Write Go Code. La variable d'environnement $GOPATH pointe vers votre espace de travail courant (par défault il pointe vers $HOME/go sur les systèmes non-Windows). Cet espace de travail inclut les dossiers /pkg, /bin et /src. Votre projet en lui-même va se retrouver dans un sous-dossier de /src, donc si vous avez un dossier /src dans votre projet le chemin vers celui-ci ressemblera à ceci : /some/path/to/workspace/src/your_project/src/your_code.go. Notez qu'à partir de Go 1.11 il est possible d'avoir votre projet en dehors de votre GOPATH mais cela ne veut toujours pas dire que c'est une bonne idée d'utiliser le dossier /src

Badges

Go Report Card Go Doc Release

Notes

Un template de projet moins générique avec du code, des script et des configs réutilisables est en cours de réalisation.