Temos uma solução com cerca de 100+ projetos, a maioria deles C #. Naturalmente, leva muito tempo para abrir e construir, então estou procurando as melhores práticas para essas feras. Ao longo das linhas de perguntas que espero obter respostas, são:
- como você lida melhor com referências entre projetos
- deve "copiar local" estar ativado ou desativado?
cada projeto deve ser compilado em sua própria pasta, ou todos devem ser compilados na mesma pasta de saída (todos fazem parte do mesmo aplicativo)
As pastas de soluções são uma boa maneira de organizar as coisas?
Eu sei que dividir a solução em várias soluções menores é uma opção, mas isso vem com seu próprio conjunto de refatoração e dores de cabeça de construção, então talvez possamos guardar isso para um thread separado :-)
Respostas:
Você pode se interessar por estes dois artigos do MSBuild que escrevi.
MSBuild: práticas recomendadas para criar compilações confiáveis, parte 1
MSBuild: Melhores práticas para criar compilações confiáveis, parte 2
Especificamente na Parte 2, há uma seção Construindo grandes árvores de origem que você pode querer dar uma olhada.
Para responder brevemente às suas perguntas aqui:
Sayed Ibrahim Hashimi
My Book: Inside the Microsoft Build Engine: Usando MSBuild e Team Foundation Build
fonte
1 para poupar o uso de pastas de solução para ajudar a organizar as coisas.
+1 para a construção do projeto em sua própria pasta. Inicialmente, tentamos uma pasta de saída comum e isso pode levar a referências sutis e difíceis de encontrar desatualizadas.
FWIW, usamos referências de projeto para soluções e, embora nuget seja provavelmente a melhor escolha hoje em dia, descobrimos que o svn: externals funciona bem para montagens internas de terceiros e (tipo de estrutura). Apenas adquira o hábito de usar um número de revisão específico em vez de HEAD ao fazer referência a svn: externals (culpado conforme cobrado :)
fonte
Descarregue projetos que você não usa com frequência e compre um SSD. Um SSD não melhora o tempo de compilação, mas o Visual Studio se torna duas vezes mais rápido para abrir / fechar / compilar.
fonte
Temos um problema semelhante, pois temos 109 projetos separados para lidar. Para responder às perguntas originais com base em nossas experiências:
1. Como você lida melhor com referências entre projetos
Usamos a opção de menu de contexto 'adicionar referência'. Se 'projeto' for selecionado, a dependência será adicionada ao nosso único arquivo de solução global por padrão.
2. Deve "copiar local" estar ativado ou desativado?
Fora de nossa experiência. A cópia extra apenas aumenta os tempos de construção.
3. Cada projeto deve ser compilado em sua própria pasta ou devem ser compilados na mesma pasta de saída (todos fazem parte do mesmo aplicativo)
Toda a nossa saída é colocada em uma única pasta chamada 'bin'. A ideia é que esta pasta seja a mesma de quando o software é implantado. Isso ajuda a evitar problemas que ocorrem quando a configuração do desenvolvedor é diferente da configuração de implantação.
4. As pastas de soluções são uma boa maneira de organizar as coisas?
Não em nossa experiência. A estrutura de pastas de uma pessoa é o pesadelo de outra. Pastas profundamente aninhadas apenas aumentam o tempo necessário para encontrar qualquer coisa. Temos uma estrutura completamente plana, mas nomeamos nossos arquivos de projeto, assemblies e namespaces da mesma forma.
Nossa forma de estruturar projetos conta com um único arquivo de solução. Construir isso leva muito tempo, mesmo que os próprios projetos não tenham mudado. Para ajudar com isso, geralmente criamos outro arquivo de solução de 'conjunto de trabalho atual'. Todos os projetos em que estamos trabalhando são adicionados a isso. Os tempos de compilação foram amplamente aprimorados, embora um problema que vimos é que o Intellisense falha para tipos definidos em projetos que não estão no conjunto atual.
Um exemplo parcial de nosso layout de solução:
\bin OurStuff.SLN OurStuff.App.Administrator OurStuff.App.Common OurStuff.App.Installer.Database OurStuff.App.MediaPlayer OurStuff.App.Operator OurStuff.App.Service.Gateway OurStuff.App.Service.CollectionStation OurStuff.App.ServiceLocalLauncher OurStuff.App.StackTester OurStuff.Auditing OurStuff.Data OurStuff.Database OurStuff.Database.Constants OurStuff.Database.ObjectModel OurStuff.Device OurStuff.Device.Messaging OurStuff.Diagnostics ... [etc]
fonte
Trabalhamos em um grande projeto semelhante aqui. As pastas de solução provaram ser uma boa maneira de organizar as coisas, e tendemos a apenas deixar o conjunto local de cópia como verdadeiro. Cada projeto é compilado em sua própria pasta e, então, sabemos que, para cada projeto implantável, temos o subconjunto correto dos binários no local.
Quanto à abertura e construção do tempo, isso será difícil de consertar sem quebrar em soluções menores. Você pode investigar a paralelização da compilação (google "Parallel MS Build" para obter uma maneira de fazer isso e integrar à IU) para melhorar a velocidade aqui. Além disso, observe o design e veja se refatorar alguns de seus projetos para resultar em menos no geral pode ajudar.
fonte
Em termos de aliviar a dor de construção, você pode usar a opção "Configuration Manager ..." para construções para habilitar ou desabilitar a construção de projetos específicos. Você pode ter um "Projeto [n] Build" que pode excluir determinados projetos e usá-lo quando estiver almejando projetos específicos.
No que diz respeito aos mais de 100 projetos, sei que você não quer se preocupar com os benefícios de reduzir o tamanho da solução, mas acho que você não tem outra opção quando se trata de acelerar o tempo de carregamento (e uso de memória) de devenv.
fonte
O que normalmente faço com isso depende um pouco de como o processo de "depuração" realmente acontece. Normalmente, embora eu NÃO defina a cópia local como verdadeira. Eu configurei o diretório de compilação para cada projeto para produzir tudo no ponto final desejado.
Portanto, após cada compilação, tenho uma pasta preenchida com todas as dll e qualquer aplicativo do Windows / Web e todos os itens estão no local adequado. Não foi necessário copiar localmente, pois a dll acabou no lugar certo.
Nota
O que está acima funciona para minhas soluções, que normalmente são aplicativos da web e não tive problemas com referências, mas pode ser possível!
fonte
Temos um problema semelhante. Nós resolvemos isso usando soluções menores. Temos uma solução master que abre tudo. Mas perf. sobre isso é ruim. Portanto, segmentamos soluções menores por tipo de desenvolvedor. Portanto, os desenvolvedores de banco de dados têm uma solução que carrega os projetos com os quais eles se importam, desenvolvedores de serviços e desenvolvedores de IU a mesma coisa. É raro quando alguém precisa abrir toda a solução para fazer o que precisa no dia a dia. Não é uma panacéia - tem suas vantagens e desvantagens. Consulte "modelo de várias soluções" neste artigo (ignore a parte sobre o uso de VSS :)
fonte
Acho que com soluções tão grandes, a melhor prática deve ser separá-las. Você pode pensar na "solução" como um lugar para reunir os projetos necessários e talvez outras peças para trabalhar na solução de um problema. Ao dividir os mais de 100 projetos em várias soluções especializadas para desenvolver soluções para apenas uma parte do problema geral, você pode lidar com menos em um determinado momento, agilizando suas interações com os projetos necessários e simplificando o domínio do problema.
Cada solução produziria a saída pela qual é responsável. Essa saída deve ter informações de versão que podem ser definidas em um processo automatizado. Quando a saída é estável, você pode atualizar as referências em projetos e soluções dependentes com a distribuição interna mais recente. Se você ainda deseja entrar no código e acessar a fonte, pode realmente fazer isso com o servidor de símbolos da Microsoft, que o Visual Studio pode usar para permitir que você entre em assemblies referenciados e até mesmo busque o código-fonte.
O desenvolvimento simultâneo pode ser feito especificando interfaces antecipadamente e simulando os assemblies em desenvolvimento enquanto você espera por dependências que não estão completas, mas você deseja desenvolver contra elas.
Acho que esta é a melhor prática porque não há limite para o quão complexo o esforço geral pode se tornar quando você o quebra fisicamente dessa maneira. Colocar todos os projetos em uma única solução acabará atingindo um limite superior.
Espero que esta informação ajude.
fonte
Temos cerca de 60+ projetos e não usamos arquivos de solução. Temos uma mistura de projetos C # e VB.Net. O desempenho sempre foi um problema. Não trabalhamos em todos os projetos ao mesmo tempo. Cada desenvolvedor cria seus próprios arquivos de solução com base nos projetos em que está trabalhando. Os arquivos de solução não são verificados em nosso controle de origem.
Todos os projetos de biblioteca de classes seriam construídos em uma pasta CommonBin na raiz do diretório de origem. Projetos Executáveis / da Web são compilados em suas pastas individuais.
Não usamos referências de projeto, em vez disso, referência baseada em arquivo da pasta CommonBin. Eu escrevi uma tarefa MSBuild personalizada que inspecionaria os projetos e determinaria a ordem de construção.
Temos usado isso há alguns anos e não temos queixas.
fonte
Tudo tem a ver com sua definição e visão do que são uma solução e um projeto. Na minha opinião, uma solução é apenas isso, um agrupamento lógico de projetos que resolvem um requisito muito específico. Desenvolvemos um grande aplicativo de intranet. Cada aplicação dentro daquela Intranet possui sua própria solução, que também pode conter projetos para exes ou serviços windows. E então temos uma estrutura centralizada com coisas como classes básicas e auxiliares e módulos httphandlers / http. A estrutura básica é bastante grande e é usada por todos os aplicativos. Ao dividir as várias soluções dessa forma, você reduz a quantidade de projetos exigidos por uma solução, já que a maioria deles não tem nada a ver um com o outro.
Ter tantos projetos em uma solução é simplesmente um design ruim. Não deveria haver razão para ter tantos projetos sob uma solução. O outro problema que vejo é com as referências de projeto, elas podem realmente bagunçar você eventualmente, especialmente se você quiser dividir sua solução em outras menores.
Meu conselho é fazer isso e desenvolver uma estrutura centralizada (sua própria implementação da Biblioteca Corporativa, se preferir). Você pode usar o GAC para compartilhar ou fazer referência direta ao local do arquivo para ter um armazenamento central. Você também pode usar a mesma tática para objetos de negócios centralizados.
Se você quiser fazer referência direta à DLL, deverá fazer referência a ela em seu projeto com cópia local false (em algum lugar como c: \ minhaempresa \ bin \ minhaempresa.dll). Em tempo de execução, você precisará adicionar algumas configurações ao app.config ou web.config para fazer referência a um arquivo que não está no GAC ou no bin de tempo de execução. Na verdade, não importa se é uma cópia local ou não, ou se a dll vai parar no bin ou até mesmo no GAC, porque a configuração irá sobrescrever ambos. Eu acho que é uma má prática copiar localmente e ter um sistema bagunçado. Você provavelmente terá que copiar localmente temporariamente se precisar depurar em um desses assemblies.
Você pode ler meu artigo sobre como usar uma DLL globalmente sem o GAC. Eu realmente não gosto do GAC principalmente porque ele impede a implantação de xcopy e não dispara uma reinicialização automática nos aplicativos.
http://nbaked.wordpress.com/2010/03/28/gac-alternative/
fonte
Definir CopyLocal = false reduzirá o tempo de construção, mas pode causar diversos problemas durante o tempo de implantação.
Existem muitos cenários, quando você precisa deixar Copy Local 'para True, por exemplo, projetos de nível superior, dependências de segundo nível, DLLs chamados por reflexão.
Minha experiência com a configuração de CopyLocal = false não foi bem-sucedida. Veja o resumo dos prós e contras em minha postagem do blog "NÃO Mude as referências de projeto" Copiar Local "para falsas, a menos que entenda as subsequências."
fonte