Quando separar um projeto em vários subprojetos

30

Gostaria de saber se faz sentido dividir o projeto no qual estou trabalhando em dois repositórios, em vez de um.

Pelo que posso dizer:

  • O frontend será escrito em html + js
  • Back-end em .net
  • O back-end não depende do front-end e o front-end não depende do back-end
  • O front-end usará uma API repousante implementada no back-end.
  • O front-end pode estar hospedado em qualquer servidor http estático.

A partir de agora, o repositório tem esta estrutura:

raiz:

  • a parte dianteira/*
  • back-end / *

Eu acho que é um erro manter os dois projetos no mesmo repositório. Como os dois projetos não têm dependências entre si, eles devem pertencer a repositórios individuais e, se necessário, a um repositório pai que possua submódulos.

Foi-me dito que é inútil e que não obteremos nenhum benefício em fazer isso.

Aqui estão alguns dos meus argumentos:

  • Temos dois módulos que não dependem entre si.
  • Ter o histórico de origem de ambos os projetos a longo prazo pode complicar as coisas (tente pesquisar no histórico por algo no front-end enquanto você tiver metade dos commits que não têm nenhuma relação com o bug que está procurando)
  • Conflito e fusão (isso não deve acontecer, mas ter alguém empurrando para o back-end forçará outro desenvolvedor a puxar alterações de back-end para empurrar alterações de front-end).
  • Um desenvolvedor pode trabalhar apenas no back-end, mas sempre precisará puxar o front-end ou o contrário.
  • A longo prazo, quando será a hora de implantar. De alguma forma, o front-end pode ser implantado em vários servidores estáticos enquanto você possui um servidor de back-end. Em todos os casos, as pessoas serão forçadas a clonar o back-end inteiro ou a criar scripts personalizados para enviar a todos os servidores apenas o front-end ou remover o back-end. É mais fácil empurrar / puxar apenas o front-end ou back-end do que ambos, se apenas um for necessário.
  • Contra-argumento (uma pessoa pode trabalhar nos dois projetos), Crie um terceiro repositório com o submódulo e desenvolva-o. O histórico é mantido separado em módulos individuais e você sempre pode criar tags nas quais a versão do back-end / front-end realmente funciona em sincronia. Ter o front-end / back-end juntos em um repo não significa que eles trabalharão juntos. É apenas mesclar a história em um grande repositório.
  • Ter front-end / back-end como submódulos facilitará as coisas se você quiser adicionar um freelancer ao projeto. Em alguns casos, você realmente não deseja dar acesso total à base de código. Ter um grande módulo tornará as coisas mais difíceis se você quiser restringir o que os "estranhos" podem ver / editar.
  • Introdução e correção de bugs, inseri um novo bug no frontend. Então alguém corrige um bug no back-end. Com um repositório, a reversão antes do novo bug também reverterá o back-end, o que pode dificultar a correção. Eu precisaria clonar o back-end em uma pasta diferente para que o back-end funcionasse enquanto corrigia o bug no front-end ... depois tentava refazer as coisas ... Ter dois repositórios será indolor porque mover o HEAD de um repo ganhou mude o outro. E testar contra versões diferentes do back-end será indolor.

Alguém pode me dar mais argumentos para convencê-los ou pelo menos me dizer por que não faz sentido (mais complicado) dividir o projeto em dois submódulos. O projeto é novo e a base de código tem alguns dias, portanto não é muito cedo para corrigir.

Loïc Faure-Lacroix
fonte

Respostas:

23

Na minha empresa, usamos um repositório SVN separado para cada componente do sistema. Posso dizer que fica extremamente frustrante. Nosso processo de compilação tem muitas camadas de abstração.

Fazemos isso com Java, portanto, temos um processo de compilação pesado com compilação javac, compilação de ligação JibX, validação XML, etc.

Para o seu site, pode não ser um grande problema se você realmente não o "constrói" (como o baunilha PHP).

Desvantagens de dividir um produto em vários repositórios

  1. Gerenciamento de build - Não posso apenas fazer o checkout do código, executar um script de build independente e ter um produto executável / instalável / implementável. Preciso de um sistema de compilação externo que saia para vários repositórios, execute vários scripts de compilação internos e monta os artefatos.
  2. Acompanhamento de alterações - Como ver quem mudou o que, quando e por quê. Se uma correção de bug no front-end exigir uma alteração no back-end, agora existem 2 caminhos divergentes para que eu me refira posteriormente.
  3. Administração - você realmente deseja dobrar o número de contas de usuário, políticas de senha etc. que precisam ser gerenciadas?
  4. Mesclando - É provável que novos recursos alterem muito código. Ao dividir seu projeto em vários repositórios, você está multiplicando o número de mesclagens necessárias.
  5. Criação de ramificação - Mesmo acordo com ramificação, para criar uma ramificação, agora você precisa criar uma ramificação em cada repositório.
  6. Marcação - após um teste bem-sucedido do seu código, você deseja marcar uma versão para lançamento. Agora você tem várias tags para criar, uma em cada repositório.
  7. Difícil de encontrar algo - Talvez o front-end / back-end seja direto, mas se torne uma ladeira escorregadia. Se você se dividir em módulos suficientes, os desenvolvedores talvez precisem investigar onde um pedaço de código reside no controle de origem.

Meu caso é um pouco extremo, pois nosso produto é dividido em 14 repositórios diferentes e cada repositório é dividido em 4-8 módulos. Se bem me lembro, temos algo em torno de 80 ou alguns "pacotes" que precisam ser verificados individualmente e montados.

Seu caso com apenas back-end / front-end pode ser menos complicado, mas ainda não o aconselho.

Exemplos extremos podem ser argumentos convincentes a favor ou contra praticamente qualquer coisa :)

Critérios que eu usaria para decidir

Eu consideraria dividir um produto em vários repositórios de código-fonte depois de considerar os seguintes fatores:

  1. Construção - Os resultados da construção de cada componente se fundem para formar um produto? Como combinar arquivos .class de vários componentes em uma série de arquivos .jar ou .war.
  2. Implantação - Você acaba com os componentes implantados juntos como uma unidade ou unidades diferentes que vão para servidores diferentes? Por exemplo, os scripts do banco de dados acessam o servidor do banco de dados, enquanto o javascript acessa o servidor da web.
  3. Co-mudança - Eles tendem a mudar com frequência ou juntos? No seu caso, eles podem mudar separadamente, mas ainda com frequência.
  4. Frequência de ramificação / mesclagem - se todos fizerem check-in no tronco e os galhos são raros, você poderá se safar. Se você freqüentemente ramifica e mescla, isso pode se transformar em um pesadelo.
  5. Agilidade - se você precisar desenvolver, testar, liberar e implantar uma alteração a qualquer momento (provavelmente com SaaS), poderá fazê-lo sem gastar um tempo precioso fazendo malabarismos com repositórios e repositórios?

Seus argumentos

Também não concordo com a maioria dos seus argumentos para essa divisão. Não vou contestar todos, porque essa resposta longa ficará ainda mais longa, mas algumas que se destacam:

Temos dois módulos que não dependem entre si.

Absurdo. Se você retirar seu back-end, seu front-end funcionará? Isso foi o que eu pensei.

Ter o histórico de origem de ambos os projetos a longo prazo pode complicar as coisas (tente pesquisar no histórico por algo no front-end enquanto você tiver metade dos commits que não têm nenhuma relação com o bug que está procurando)

Se a raiz do seu projeto for dividida em front-end / e back-end /, você poderá examinar o histórico dessas hierarquias de forma independente.

Conflito e mesclagem (Isso não deve acontecer, mas ter alguém empurrando para o back-end forçará outro desenvolvedor a puxar alterações de back-end para empurrar alterações de front-end.) por aí.

Dividir seu projeto em diferentes repositórios não resolve isso. Um conflito de front-end e de back-end ainda deixa você com 2 conflitos, seja um repositório vezes 2 conflitos ou 2 repositórios vezes 1 conflito. Alguém ainda precisa resolvê-los.

Se a preocupação é que 2 repositórios significam que um desenvolvedor de front-end pode mesclar o código de front-end enquanto um desenvolvedor de back-end mescla o código de back-end, você ainda pode fazer isso com um único repositório usando o SVN. SVN pode mesclar em qualquer nível. Talvez seja uma limitação git ou mercurial (você marcou os dois, então não tem certeza de qual SCM usa)?

Por outro lado

Com tudo isso dito, vi casos em que a divisão de um projeto em vários módulos ou repositórios funciona. Até defendi isso uma vez em um projeto específico em que integramos o Solr ao nosso produto. É claro que o Solr é executado em servidores separados, apenas muda quando um conjunto de alterações está relacionado à pesquisa (nosso produto faz muito mais que a pesquisa), possui um processo de construção separado e não há artefatos de código ou artefatos de construção compartilhados.

Brandon
fonte
Moderação em todas as coisas, como minha mãe costumava dizer ...
William Payne
No momento da minha escrita, estou escrevendo o frontend sem backend. Eu emulo o back-end com arquivos json e provavelmente poderia até emular completamente com o indexedDB no navegador. Então, sim, o back-end é apenas um servidor que serve json. Pode ser substituído por qualquer coisa, desde que os dados recebidos estejam em conformidade com a API. Ambos os projetos usam um sistema de compilação diferente. Em resumo, é como ter um site e um aplicativo para celular para Android. Adicionando o aplicativo móvel ao repositório do servidor da web.
precisa saber é o seguinte
Além disso, se não estiver claro, o back-end e o front-end não são interfaces de usuário / administrador. Mas o frontend é apenas uma interface ajax e o backend serve json. Usuários e funções são tratados de maneira diferente e a interface do administrador estará no frontend. A idéia é manter as duas partes isoladas e impedir que o html gerado pelo javascript carregue o html gerado pelo servidor. O servidor deve servir apenas json ou xml.
precisa
11
Então você não tem problemas de compilação ou implantação, o que pode ser bom. Mas, novamente, se você fizer uma grande alteração, pode ser necessário alterar a API, que afeta o front-end e o back-end e, portanto, você estará ramificando duas vezes, mesclando duas vezes, marcando duas vezes etc. Mas enquanto permanecer apenas duas vezes e não se transforme em 3 ... 4 ... 12 ... 20, provavelmente não é uma má idéia.
Brandon
Mesmo se a API mudar, com o versionamento adequado, poderá ser possível criar versões de ramificação para cada front-end que suporte uma versão da API. O back-end deve ter alguma compatibilidade "com versões anteriores" e manter a API antiga funcionando o maior tempo possível.
Loïc Faure-Lacroix
3

Alguns de seus argumentos são válidos e outros não.

Temos dois módulos que não dependem entre si.

Na verdade, isso não é inteiramente verdade. Para poder se comunicar, o front-end e o back-end precisam ter uma interface comum (descrição). Isso o torna um argumento fraco em favor de ter os dois em um repositório comum. Mas apenas um argumento fraco, pois não faz muita diferença.

Ter o histórico de origem de ambos os projetos a longo prazo pode complicar as coisas (tente pesquisar no histórico por algo no front-end enquanto você tiver metade dos commits que não têm nenhuma relação com o bug que está procurando)

Este é um argumento falso. Se você deseja verificar como um bug específico foi corrigido, procure no rastreador de erros para o qual o commit contém a correção. E se você quiser saber como um determinado código evoluiu, analise o histórico de um único arquivo (ou, no máximo, um punhado). Em qualquer um dos casos, ter outros arquivos, possivelmente de outros módulos, no repositório não deve complicar as coisas de forma alguma.

Conflito e fusão (isso não deve acontecer, mas ter alguém empurrando para o back-end forçará outro desenvolvedor a puxar alterações de back-end para empurrar alterações de front-end).

Este é um argumento falso. Não conheço nenhum VCS (meio decente) em que você precise sincronizar todo o repositório antes de confirmar / enviar suas alterações. No máximo, você precisa sincronizar as pastas que contêm os arquivos alterados (e geralmente apenas os próprios arquivos).

Um desenvolvedor pode trabalhar apenas no back-end, mas sempre precisará puxá-lo ou vice-versa.

Este é o mesmo argumento falso que o anterior.

A longo prazo, quando será a hora de implantar. De alguma forma, o front-end pode ser implantado em vários servidores estáticos enquanto você possui um servidor de back-end. Em todos os casos, as pessoas serão forçadas a clonar o back-end inteiro ou a criar scripts personalizados para enviar a todos os servidores apenas o front-end ou remover o back-end. É mais fácil empurrar / puxar apenas o front-end ou back-end do que ambos, se apenas um for necessário.

Dependendo de como as pessoas imaginam que a implantação será feita, esse pode ser um argumento válido. Se a implantação for feita descompactando um arquivo zip / tarbal no servidor, não importa como seus repositórios estão organizados. Se a implantação for feita através do check-out (parte de) de um repositório no servidor, pode ser uma boa ideia usar repositórios separados para módulos implantados separadamente.

Contra-argumento (uma pessoa pode trabalhar nos dois projetos), Crie um terceiro repositório com o submódulo e desenvolva-o. O histórico é mantido separado em módulos individuais e você sempre pode criar tags nas quais a versão do back-end / front-end realmente funciona em sincronia. Ter o front-end / back-end juntos em um repo não significa que eles trabalharão juntos. É apenas mesclar a história em um grande repositório.

Este é um argumento válido, mas não é tão forte.

Ter front-end / back-end como submódulos facilitará as coisas se você quiser adicionar um freelancer ao projeto. Em alguns casos, você realmente não deseja dar acesso total à base de código. Ter um grande módulo tornará as coisas mais difíceis se você quiser restringir o que os "estranhos" podem ver / editar.

Este é um argumento válido.

Introdução e correção de bugs, inseri um novo bug no frontend. Então alguém corrige um bug no back-end. Com um repositório, a reversão antes do novo bug também reverterá o back-end, o que pode dificultar a correção.

Esse é um argumento falso, porque significaria que, após duas correções de bug em um módulo, você não seria capaz de reverter o primeiro. Qualquer VCS meio decente permitirá reverter praticamente qualquer confirmação antiga (embora muitas vezes signifique que você faça uma nova confirmação que reverta essas alterações, às vezes até para o topo da HEAD).

Eu precisaria clonar o back-end em uma pasta diferente para que o back-end funcionasse enquanto corrigia o bug no front-end ... depois tentava refazer as coisas ... Ter dois repositórios será indolor porque mover o HEAD de um repo ganhou mude o outro. E testar contra versões diferentes do back-end será indolor.

Este é realmente um bom argumento. A existência de dois repositórios facilita o teste dos cenários em que os front-ends e back-ends implantados podem ficar (ligeiramente) fora de sincronia.

Bart van Ingen Schenau
fonte
Para ser sincero, a maioria dos argumentos falsos pode ser resolvida com ramificações. Ramificar para front-end e ramificar para back-end. Mestre para sincronização. Mas, de alguma forma, lidar com ramificações como essa está tornando as coisas mais complicadas do que ter dois repositórios.
Loïc Faure-Lacroix
11
@ Sybiam: Na verdade, eles são argumentos falsos, porque não destacam um problema que possa existir com o uso de um único repositório, mesmo que todas as alterações sejam feitas apenas no tronco / principal.
Bart van Ingen Schenau
Eu acho que suas críticas são válidas. Eu simplesmente não acho que esse era o ponto da questão.
Sylvanaar
2

Este post é um pouco antigo, mas eu gostaria de contribuir. Embora seu back-end realmente não saiba sobre o front-end, ele precisa ter solicitações correspondentes à API do back-end. Se você considerar seu back-end como uma API REST, poderá definir um arquivo de interface como uma interface YAML swagger. Agora, existem realmente três projetos, que você pode dividir individualmente em diferentes repositórios, como achar melhor:

  • Definição de API
  • Back-end
  • A parte dianteira

A definição da API é uma dependência nos outros dois projetos, digamos que você estava usando o maven como uma ferramenta de injeção de dependência. Depois, depende de quão estritamente você deseja fazer o controle de versão. Você pode aumentar a versão do projeto de definição de API sempre que fizer uma alteração para garantir que os projetos estejam sempre em um estado compatível, mas exija mais sobrecarga, ou use algo como SNAPSHOTS no maven e faça o versionamento apenas depois de está satisfeito com a interface, que é menos sobrecarga, mas muitas vezes você pode ter incompatibilidades. Mas, desde que você aplique a definição da API em seu front e back-end, você poderá dividir os projetos em diferentes repositórios.

Esses problemas são mais sobre o gerenciamento de dependências. Mesmo que os projetos não estejam divididos e estejam no mesmo repositório, é muito fácil para o site ser colocado em um estado em que o front-end e o back-end estejam fora de sincronia. Realmente, a única maneira de impedir isso é realmente definir o contrato entre os dois, mas você deseja fazê-lo de uma maneira que não acoplar as implementações do front e back-end, da mesma forma que codificaria para uma interface. de uma implementação na programação OO.

Também para lidar preventivamente com as críticas de que isso cria uma sobrecarga na manutenção desse arquivo de interface, o swagger, por exemplo, pode até produzir stubs de código para diferentes linguagens de programação e estruturas, como JAX-RS. Portanto, você pode produzir uma interface com a tecnologia escolhida e implementar essa interface. Também adiciona uma documentação muito boa ao seu back-end, facilitando o trabalho dos desenvolvedores de front-end.

Snickers3192
fonte