Qual é uma maneira sensata de fazer o layout de um projeto Go [fechado]

113

Eu tenho um projeto que está começando a se tornar mais complexo e quero organizar o sistema de arquivos de forma a reduzir a dor.

Existem bons exemplos do que faz sentido?

aussiegeek
fonte

Respostas:

132

Atualização de maio de 2013: a documentação oficial está na seção " Organização do código "

O código Go deve ser mantido dentro de um espaço de trabalho .
Um espaço de trabalho é uma hierarquia de diretórios com três diretórios em sua raiz:

  • src contém arquivos de origem Go organizados em pacotes (um pacote por diretório),
  • pkg contém objetos de pacote e
  • bin contém comandos executáveis.

O go toolcria pacotes de origem e instala os binários resultantes nos diretórios pkge bin.

O srcsubdiretório normalmente contém vários repositórios de controle de versão (como para Git ou Mercurial) que rastreiam o desenvolvimento de um ou mais pacotes de origem.

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

Atualização de julho de 2014: consulte " Estruturação de aplicativos em Go " de Ben Johnson

Esse artigo inclui dicas como:

Separe seu binário de seu aplicativo

combinar o main.goarquivo e a lógica do meu aplicativo no mesmo pacote tem duas consequências:

  • Isso torna meu aplicativo inutilizável como biblioteca.
  • Só posso ter um binário de aplicativo.

A melhor maneira que encontrei de corrigir isso é simplesmente usar um cmddiretório “ ” em meu projeto, onde cada um de seus subdiretórios é um binário de aplicativo.

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

Desenvolvimento dirigido por biblioteca

Mover o main.goarquivo para fora de sua raiz permite que você construa seu aplicativo da perspectiva de uma biblioteca. O binário do seu aplicativo é simplesmente um cliente da biblioteca do seu aplicativo.

Às vezes, você pode querer que os usuários interajam de várias maneiras, para criar vários binários.
Por exemplo, se você tiver um adderpacote “ ” que permite aos usuários somar números, pode desejar lançar uma versão de linha de comando, bem como uma versão da web.
Você pode fazer isso facilmente organizando seu projeto desta forma:

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

Os usuários podem instalar os binários do seu aplicativo “adicionador” com “go get” usando reticências:

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

E pronto, seu usuário tem “ adder” e “ adder-server” instalados!

Não enlouqueça com subpacotes

Normalmente os tipos do meu projeto são todos muito relacionados, então ele se encaixa melhor do ponto de vista de usabilidade e API.
Esses tipos também podem tirar vantagem da chamada não exportada entre eles, o que mantém a API pequena e clara.

  1. Agrupe tipos e códigos relacionados em cada arquivo. Se seus tipos e funções forem bem organizados, acho que os arquivos tendem a ter entre 200 e 500 SLOC. Pode parecer muito, mas acho fácil navegar. 1000 SLOC geralmente é meu limite superior para um único arquivo.
  2. Organize o tipo mais importante na parte superior do arquivo e adicione tipos de importância decrescente na parte inferior do arquivo.
  3. Assim que seu aplicativo começar a ultrapassar 10.000 SLOC, você deve avaliar seriamente se ele pode ser dividido em projetos menores.

Nota: essa última prática nem sempre é boa:

Desculpe, não posso concordar com esta prática.
A separação do tipo em arquivos ajuda no gerenciamento, legibilidade, manutenção e testabilidade do código.
Pode também garantir a responsabilidade única e o seguimento do princípio aberto / fechado…
A regra para não permitir a dependência circular é forçar que tenhamos uma estrutura clara dos pacotes.


(Alternativa de fevereiro de 2013, srcapenas referente )
Você pode encontrar o layout clássico ilustrado em " Layout de código do GitHub ":

O aplicativo e as duas bibliotecas estão no Github, cada um em seu próprio repositório.
$GOPATHé a raiz do projeto - cada um de seus repositórios Github será verificado em várias pastas abaixo $GOPATH.

O layout do seu código ficaria assim:

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

Cada pasta abaixo src/github.com/jmcvetta/é a raiz de um checkout git separado.

Isso atraiu algumas críticas, porém, nesta página do reddit :

Eu recomendo fortemente não estruturar o repo da maneira que você fez, ele quebrará " go get", que é uma das coisas mais úteis sobre Go.
É muito melhor escrever seu código para pessoas que conhecem Go, já que provavelmente serão elas que o compilarão.
E para quem não conhece, pelo menos sentirá o idioma.

Coloque o pacote principal na raiz do repo.
Tenha os ativos em um subdiretório (para manter as coisas organizadas).
Mantenha a parte essencial do código em um subpacote (caso alguém queira reutilizá-lo fora do seu binário).
Inclua um script de configuração na raiz do repo para que seja fácil de encontrar.

O processo de download, compilação, instalação e configuração ainda é um processo de duas etapas:

  • " go get <your repo path>": baixa e instala o código go, com um subdiretório para os recursos
  • $GOPATH/<your repo path>/setup.sh: distribui os ativos no lugar certo e instala o serviço
VonC
fonte
15
Um (grande) problema com setup.shé que Go é razoavelmente multiplataforma, enquanto os scripts de shell POSIX não são.
kostix
A estrutura jmcvetta não irá quebrar go get, visto que uselessd importa inúteis, go get instalará ambos com go get ... / uselessd. Mas eu concordo que se inútil for uma biblioteca feita especificamente para uselessd, faz mais sentido mantê-la em um único repositório git, como uma subpasta ou irmãos.
mna de
@PuerkitoBio eu concordo. Meu treinamento em controle de versão e em gerenciamento baseado em componente ( stackoverflow.com/a/933735/6309 ) me leva mais para um componente por repo, daí a segunda parte desta resposta.
VonC de
7

Presumo que com 'projeto' você não quer dizer um pacote Go, mas um software que você desenvolve. Caso contrário, você pode obter ajuda aqui e aqui . No entanto, não é muito diferente de escrever pacotes para Go: use pacotes, crie uma pasta para cada pacote e combine esses pacotes em seu aplicativo.

Para construir uma opinião, você pode olhar os repositórios de tendências Go no github: https://github.com/trending/go . Exemplos notáveis ​​são cayley e zeus .

O esquema mais popular provavelmente é ter um arquivo Go principal e muitos módulos e submódulos em seus próprios diretórios. No caso de você ter muitos arquivos meta (doc, licença, modelos, ...) você pode querer colocar o código-fonte em um subdiretório. Foi o que fiz até agora.

nemo
fonte
@aussiegeek, não sou um especialista em Go, mas apliquei com sucesso o que nemo propôs em meu próprio código - a ideia é que você pode ter módulos sob o diretório do seu projeto, você só precisa se referir a eles usando seu prefixo completo - relativo para $GOPATH/srcou usando seus go getnomes -table.
kostix
doozerdnão é um bom exemplo, mesmo seus testes são fracos.
Inanc Gumus de
@InancGumus eu encorajo você a sugerir um exemplo melhor.
nemo
veja isso e isso .
Inanc Gumus
1

Há uma abordagem recomendada dos autores de Golang que define como fazer o layout de seu código para funcionar melhor com as ferramentas go e para oferecer suporte aos sistemas de controle de origem

FigmentEngine
fonte
1
É assim que se faz o layout $GOROOT, não o código dentro do src/<project>diretório.
docwhat