Como devo organizar minha árvore de fontes?

89

Eu sou um desenvolvedor individual trabalhando, em grande parte, em projetos web (W / LAMP) e, às vezes, em projetos C / C ++ (não GUI) de escala média.

Geralmente luto com a estruturação da minha árvore de código-fonte. De fato, normalmente, eu não concluo um projeto sem despejar a árvore inteira e reorganizar as peças três a quatro vezes, o que realmente exige muito esforço e, além disso, o resultado final parece um compromisso.

Às vezes, acabo com uma classificação excessiva da fonte - árvore muito longa de pastas e subpastas. Em outros momentos, simplesmente acabo concentrando todos os arquivos em uma pasta específica, com base no propósito maior que eles servem e, assim, levando a pastas 'caóticas' na fonte.

Eu gostaria de perguntar:

  • Existem princípios / lógica / práticas recomendadas que podem me ajudar melhor na estruturação da minha árvore de fontes?
  • Existem técnicas gráficas / diagramáticas (por exemplo: DFD em caso de fluxo de dados) que podem me ajudar a visualizar minha árvore de fontes com base na análise do projeto?
  • Que estratégia adotar para estruturar a árvore de arquivos multimídia associada ao projeto?

Sobre a recompensa : Aprecio as respostas existentes com os membros que compartilham suas próprias práticas. No entanto, gostaria de incentivar respostas (ou recursos) mais gerais e instrutivas e mais respostas dos membros.

check123
fonte
8
Não tenho tempo para uma redação no momento, mas "nomeie as coisas pelo que elas são", "coloque as coisas onde elas pertencem", "mantenha coisas semelhantes próximas umas das outras" e, finalmente, "não se preocupe com isso" , esperamos que você tenha um IDE que o ajude a navegar rapidamente entre partes do código ".
John Saunders
@ John, eu não sou tão bom com IDE (s), geralmente retiro um Notepad ++ ou vi, dependendo do sistema operacional. Isso torna as coisas um pouco mais difíceis. O restante dos pontos é útil, mas, novamente, resume-se a tomar decisões complicadas, como as funções de log (logs de erros etc.), mais próximas da lógica do aplicativo ou do DAL ou do gerenciamento de cache ou dos gerenciadores de exibição. Os erros têm uma probabilidade quase igual de ocorrer em qualquer um deles.
check123
3
Talvez quando você chegar a esse tipo de pergunta, é hora de deixar algumas ferramentas fazerem parte do trabalho para você. E o log é claramente uma preocupação multifuncional, usada por todas as partes do aplicativo (se você estiver usando o tipo de código que precisa de log). Outro pequeno ditado é: "coloque o código acima do código que o utiliza", para que o registro esteja próximo do topo, talvez em \ utilities.
John Saunders
@ John: Muito apreciado. Pode ser que eu deva começar a procurar um IDE. Eclipse parece promissor.
precisa saber é o seguinte
11
@ check123 "... reorganizando as peças três a quatro vezes ..." Prática comum: “A questão da gerência, portanto, não é se deve ser construído um sistema piloto e jogado fora. Você fará isso. A única questão é se planejar com antecedência para construir uma descarga, ou a promessa de entregar o descartável para os clientes “- Frederick P. Brooks Jr., The Man-Month Mythical:. Ensaios sobre Engenharia de Software
shawnhcorey

Respostas:

25

O layout da árvore de origem deve refletir a arquitetura; como corolário, uma arquitetura bem estruturada pode levar a um layout de árvore de origem bem estruturado. Sugiro a leitura do padrão Camadas POSA1 , tentando ajustar sua arquitetura em uma estrutura em camadas, nomeando cada uma das camadas resultantes e usando isso como base para sua hierarquia de origem. Tomando uma arquitetura comum de três camadas como linha de base:

  • presentation / webService (apresente uma interface de serviço da web à nossa lógica de negócios)
  • logic / * (os módulos de lógica de negócios entram aqui)
  • storage / sql (APIs de armazenamento de back-end aqui - isso usa uma interface SQL para armazenar em um banco de dados)
  • util / * (código do utilitário - utilizável por todas as outras camadas, mas que não se refere ao utilitário externo, vai aqui)

Observe que as camadas não contêm código diretamente, mas são estritamente usadas para organizar os módulos.

Dentro de um módulo, eu uso o seguinte tipo de layout:

  • <module> (caminho para o módulo diretamente; define a interface modular)
  • <module>/impl/<implName> (uma implementação específica da interface modular)
  • <module>/doc (Documentação para usar o módulo)
  • <module>/tb (código de teste de unidade para o módulo)

onde <module>está localizado no repositório de acordo com a camada à qual ele pertence.

Aidan Cully
fonte
5
+1: O layout da árvore de origem deve refletir a arquitetura - uma coisa óbvia que eu estava ignorando.
check123
Como você gerencia arquivos seguros - arquivos que apenas usuários autorizados podem acessar após o login?
check123
@ check123 Não sei se entendi a pergunta. Eu me concentrei na organização dos módulos de origem, em vez de oferecer suporte a arquivos para o projeto, e o código-fonte costuma ser acessível a todos. (Há exceções, e eu uso uma dist / diretório acima de tudo código com restrições de uso / modificação não-padrão.)
Aidan Cully
48

Na verdade, não posso dar muitos conselhos relacionados a projetos da Web, mas veja como estruturo minha árvore em um projeto de programação (principalmente da perspectiva do C / C ++):

  • /
    • src - arquivos de origem escritos por mim mesmo
    • ext - Contém bibliotecas de terceiros
      • libname-1.2.8
        • include - Cabeçalhos
        • lib - arquivos lib compilados
        • Donwload.txt - Contém link para baixar a versão usada
    • ide - eu armazeno arquivos de projeto aqui
      • vc10 - Organizo os arquivos do projeto dependendo do IDE
    • bin - Exe compilado vai aqui
    • build - Os arquivos de compilação do compilador
    • doc - Documentação de qualquer tipo
    • LEIA-ME
    • INSTALAR
    • COPIANDO

Algumas notas:

  1. Se estou escrevendo uma biblioteca (e usando C / C ++), organizarei meus arquivos de origem primeiro em duas pastas denominadas "include" e "src" e, em seguida, por módulo. Se for um aplicativo, eu vou organizá-los apenas por módulo (cabeçalhos e fontes vão na mesma pasta).

  2. Os arquivos e diretórios listados acima em itálico não adicionarei ao repositório de códigos.

Paulo
fonte
Qual é a diferença entre ide e build ?
M. Dudley
3
ideé exatamente onde eu armazeno os arquivos do projeto. buildcontém os arquivos de objeto gerados pelo compilador. IDEs diferentes podem usar o mesmo compilador, por isso mantenho os arquivos de projeto do IDE separados dos arquivos de objeto criados pelo compilador.
Paul
Então, construir obj == (o termo usado por muitos outros sistemas)
gbjbaanb
@gbjbaanb Sim, eu acho. Realmente não importa, pois esse diretório não é enviado ao repositório. :) Chamei de 'build' porque era assim que o IDE que eu estava usando att o chamava (Visual Studio).
Paul
E se o seu exe precisar de alguma dll para rodar? Você copia todos os arquivos DLL para o mesmo diretório que exe? Você usa alguns eventos pós-compilação?
Wakan Tanka 13/09/16
14

Embora o Maven Standard Directory Layout seja específico para Java, ele também pode servir como uma boa base para outros tipos de projetos.

Aqui está a estrutura básica (você pode substituir os diretórios 'java' por 'php', 'cpp', etc):

src/main/java       Application/Library sources 
src/main/resources  Application/Library resources  
src/main/filters    Resource filter files 
src/main/assembly   Assembly descriptors 
src/main/config     Configuration files 
src/main/webapp     Web application sources 
src/test/java       Test sources 
src/test/resources  Test resources 
src/test/filters    Test resource filter files 
src/site            Site 
LICENSE.txt         Project's license 
NOTICE.txt          Notices and attributions required by libraries
README.txt          Project's readme

A estrutura é dividida basicamente em 'src / main' e 'src / test' e depois agrupadas por tipo.

Michal Miller
fonte
5

Eu realmente não sei sobre convenções, mas todos os meus principais projetos são feitos usando o Symfony Framework e eu me acostumei a uma estrutura em árvore da seguinte maneira:

raiz/

  • apps
  • nome do aplicativo
    • config (arquivos de configuração específicos do aplicativo)
    • lib (arquivos php específicos do aplicativo)
    • módulos (distribuição modular de funcionalidade)
      • nome do módulo
        • modelos (html)
        • ações (código php)
  • confing (arquivos de configuração do projeto)
  • lib (código php que pode ser usado no projeto do furo)
  • modelo (classes que representam as informações do projeto)
    • base
  • formulário (arquivos php que manipulam formulários, isso pode ser bastante difícil de obter sem o symfony)
    • base (classes de formulário base)
  • rede
  • css
    • imagens
    • file.css
  • js
  • log (arquivos de log que podem ser gerados)
  • data (informações específicas de dados, como patches sql ou qualquer outra coisa)
  • sql
  • plugins (bibliotecas usadas que podem ser mescladas com qualquer aplicativo do projeto)

Se você estiver interessado, leia a documentação do symfony sobre o assunto para obter mais informações ( MVC e Code Organization on Symfony ).

guiman
fonte
Sua pasta CSS está centralizada? Quero dizer, todo o seu CSS (em todo o projeto) está no mesmo diretório?
check123
Não necessariamente, você pode dividi-lo, mas como a maioria dos meus projetos tendem a ter apenas 2 aplicações (frontend e backend), não há que arquivos muito css (plugins sempre tem sua própria pasta web para abstração)
guiman
5

Idealmente, a organização possui um único repositório, cuja estrutura se destina a aumentar o envolvimento entre engenharia e negócios e promover a reutilização.

...\products\
...\products\productName\
...\products\productName\doc\

...\systems\
...\systems\systemName\
...\systems\systemName\doc\
...\systems\systemName\res\
...\systems\systemName\build\
...\systems\systemName\test\

...\library\
...\library\libraryName\
...\library\libraryName\doc\
...\library\libraryName\build\
...\library\libraryName\test\

...\devops\

produtos

Uma pasta por produto; ajuda a comunicar como o software suporta os negócios.

Idealmente, cada "produto" é pouco mais que um arquivo de configuração indicando quais sistemas chamar e como devem ser configurados. A subpasta doc pode conter o resumo de nível superior \ spec e qualquer material promocional etc ...

Ao separar produtos e sistemas, comunicamos o potencial de reutilização ao lado do negócio voltado para o cliente e dividimos os silos por produto. (Isso contrasta com a abordagem "linha de produtos" para o mesmo problema)

sistemas

Uma pasta por sistema; ajuda a comunicar os principais recursos e oportunidades / valor do conteúdo do repositório.

  1. Arquivos de "gerenciamento de configuração" especificando ambientes de criação e implantação.
  2. Configuração de teste no nível do sistema (pode ser uma quantidade significativa).
  3. Lógica e funcionalidade de nível superior; levantamento mais pesado sendo feito pelas funções da biblioteca.

biblioteca

Componentes reutilizáveis ​​invocados por vários sistemas. A maioria das atividades de desenvolvimento é organizada em torno da produção de bibliotecas, e não de sistemas; portanto, a reutilização é incorporada ao processo de desenvolvimento.

devops

Construção, integração contínua e outras funcionalidades da automação de desenvolvimento.

Conclusão

A árvore de fontes é uma peça importante da documentação e molda a abordagem, a estrutura e a psicologia do relacionamento dos negócios com sua tecnologia proprietária.

Os drivers para essa abordagem são explicados um pouco mais profundamente na minha resposta a esta pergunta: https://softwareengineering.stackexchange.com/questions/43733/who-organizes-your-matlab-code/59637#59637

William Payne
fonte
Nota: Pode ser útil nomear pastas de uma maneira que seja compatível com o tipo de hierarquias de produtos discutidas no manual de engenharia de sistemas INCOSE.
William Payne
3

O que estou tentando fazer para cada projeto é semelhante a:

  • src - arquivos de origem, uma pasta para cada namespace / pacote para recuperar facilmente arquivos (mesmo arquivos de cabeçalho para C / C ++)
  • ext - para bibliotecas externas / de terceiros, é simples adicionar externas (como repositórios SVN). Dentro, uma pasta para cada biblioteca (binários e arquivos incluídos)
  • bin - para binários construídos, poderia ser rapidamente exportado para liberação
    • inc - para arquivo de cabeçalhos C / C ++ (copiado por IDE / makefile / etc ...)
  • out - para todos os arquivos gerados temporariamente (.class, .obj etc ...) e pode ser ignorado (por exemplo, por SVN)
  • doc - para qualquer documentação, geralmente gerada com Doxygen
  • res - colocando recursos aqui, é possível separar os arquivos de origem de texto e os recursos binários usados ​​pelo programa. Eu realmente não tenho hierarquia específica dentro.
    • config - para alguns arquivos de configuração
    • drawable - para algumas fotos ou ícones

Todos os arquivos ou makefiles do IDE são salvos diretamente na raiz se você usar apenas um deles.

Ninfomane
fonte
2

Eu faço algo assim. Funciona bem para um jogo de plataforma cruzada que estou fazendo no meu tempo livre. Infelizmente no trabalho, as coisas são muito menos organizadas ...

Output                      <-- Build outputs
Docs
External
   <libname>
      Include
      Lib
Data
<ProjectName>.xcodeproj
<ProjectName>VS2010
Source
Temp                        <-- Intermediate stuff from builds and other tools
Tools
Coronel Panic
fonte
2

Para minhas equipes, tentamos impor uma estrutura padrão entre os projetos para facilitar a localização de coisas, pois a equipe alterna o contexto e evitar a necessidade de reaprender a cada vez. Como nem todos os projetos precisam de todos os sistemas, começamos com o conjunto mínimo.

/ Origem / Componente / Idioma

/ Origem / Componente / Terceiros /

/Documentos necessários

/ Documentação / Design

/ Testes / Automatizado / Unidade

/ Tests / Automated / ToolName

/ Testes / Manual

Isso resulta em alguma duplicação, principalmente no código e nas bibliotecas de terceiros, mas pelo menos nunca esquecemos a resposta para algo como "O que usa o RogueWave Editor?"

Christopher Bibbs
fonte
11
Os componentes do caminho em maiúsculas parecem realmente bobos e inúteis para mim. Por que usar letras minúsculas? É muito mais fácil digitar para humanos (embora as ferramentas não se importem, incluindo gerenciadores de arquivos WIMP ), e lê igualmente bem graças aos separadores de caminho. Uma vitória definitiva para mim.
ulidtko
2

Gosto das idéias apresentadas nesta página www.javapractices.com/topic/TopicAction.do?Id=205 . Basicamente, a recomendação é organizar seu projeto em recursos (ou módulos, componentes). Além dos motivos apresentados:

  1. Menos carga cognitiva quando você pensa sobre o escopo do código em que está trabalhando, pois você tem a garantia de que qualquer código no recurso em que está trabalhando é "particular em recursos".
  2. Há uma sensação adicional de segurança quando você garante que está apenas modificando o código para um determinado recurso. Por exemplo, você não quebrará nada além do recurso em que está trabalhando. Novamente, isso ocorre por causa do "recurso particular".
  3. Menos carga cognitiva simples, porque há menos arquivos que você pode ver para um determinado pacote. Estou certo de que todos viram um pacote que contém mais de 15 arquivos.

Observe que isso está focado nos pacotes Java (também conhecidos como namespaces). Para grandes projetos, recomendo, pelas mesmas razões, dividir o projeto em vários projetos (como em vários projetos independentes) que representam um recurso de negócios. Para projetos espertos, recomendo esta leitura .

Até agora, os projetos em que eu estava / estou envolvido não os seguem. Há muitas razões, mas aqui estão algumas:

  1. O mal-entendido do modificador de acesso padrão Java (o modificador de acesso mais incompreendido de acordo com este livro )
  2. "Argumentum ad populum": cultura predominante de pacote por camada (provavelmente causada pelo motivo 1)

Acho que há uma oportunidade perdida de impedir a complexidade se a organização da fonte do projeto não for levada a sério no início do projeto, como disse o arquiteto Alexander:

"Como qualquer designer dirá, são os primeiros passos de um processo de design que contam para a maioria. Os primeiros traços, que criam a forma, trazem consigo o destino do resto." - Christopher Alexander

Dependendo do tamanho e da complexidade de um projeto, a oportunidade perdida de cortar custos ou ROI pode ser realmente grande. (Estou interessado em ver um estudo para ver os números exatos disso)

terceiro
fonte
2

Minha recomendação é baixar uma variedade de estruturas ou mecanismos e ver como grandes equipes de desenvolvimento lidaram com o layout de suas pastas.

Existem tantas maneiras de organizar arquivos que é melhor escolher um e tentar cumpri-lo em qualquer projeto. Atenha-se a uma convenção específica até a conclusão ou a reformulação para evitar erros e perder tempo desnecessário.

É possível fazer o download das estruturas do Laravel, Symphony ou Codeigniter para projetos da Web para ter um layout de pasta instantâneo que funcione.

Então, tentarei transmitir um layout de pastas comum a qualquer desenvolvimento:

O MVC (Model View Controller) fornece um bom paradigma de organização.

O código-fonte raiz pode ser src (C ++) ou aplicativo (desenvolvimento da web)

Uma estrutura de arquivo que não tem um objetivo claro para as classes que agrupa definitivamente causará confusão. Não se trata apenas de organizar o código; ele pode suportar carregadores automáticos, class factory, agrupar armazenamento local, armazenamento remoto e namespacing.

Essa estrutura de pastas é derivada e simplificada do Laravel Framework . Minha preferência neste post é a nomeação plural, mas uso palavras singulares em meus projetos.


Implementações src / storage (modelos / implementações de armazenamento de arquivos / api / mysql / sql-lite / memcached / redis)

src / repositories (Um invólucro de 'implementações de armazenamento' com alguma lógica de armazenamento, uma interface comum e uma convenção de resultado de retorno.)

src / serviços | lógica | entidades (lógica de negócios do aplicativo)

src / controllers (Usado no desenvolvimento da web para rotear solicitações do servidor para seus serviços)

src / módulos | systems ( Sistemas modulares que ampliam a funcionalidade geral da estrutura. Os serviços podem usar módulos, mas não vice-versa)

src / helpers (classes Helper ou wrapper como, por exemplo, manipulação de strings. Muitas vezes isso pode estar no libs | vendor quando terceiros)

src / types (enumerações nomeadas)

público | construir | saída (web ou c ++)

config (arquivos de instalação. YAML está se tornando popular para arquivos de configuração de plataforma cruzada)

cache

logs

lang (pt-br / es / ru / ...)

bootstrap (inicia a estrutura e o aplicativo)

docs (documentação escrita em formato de remarcação .md)

testes (teste de unidade)

banco de dados / migrações (criar estrutura de banco de dados a partir do zero)

database / seeds (Preenche seu banco de dados com dados fictícios para teste)

libs | vendor (todos os softwares de terceiros. 'libs' em C ++ e 'vendor' geralmente em php)

ativos | recursos (imagens / sons / scripts / json / qualquer mídia)

Heroselohim
fonte
1

Com linguagens orientadas a objetos, você tem a capacidade de criar espaços para nome. Essa divisão lógica usada para separar partes do aplicativo para evitar o acoplamento é a principal fonte de divisão da localização do arquivo lógico. Usar o acoplamento como motivo para separar os espaços para nome é um bom lugar para começar http://en.wikipedia.org/wiki/Software_package_metrics .

Outros já falaram sobre a configuração do projeto em relação à construção, mas uma vez que você entra na própria fonte, é sobre o que faz sentido - basta usar como você divide o código de qualquer maneira.

Travis
fonte