Monorepositório com C#: como organizar o código em projetos .NET
O desenvolvimento moderno em C# e .NET cada vez mais enfrenta a escolha: armazenar todos os projetos relacionados em um único repositório (monorepositório) ou dividi-los em repositórios separados (multirrepositório). Monorepositório é uma abordagem onde o código de vários aplicativos, bibliotecas, testes e configurações é armazenado em um único repositório Git. Para grandes soluções corporativas, microsserviços ou bibliotecas NuGet, essa abordagem pode simplificar significativamente o gerenciamento de dependências, refatoração e implantação.
Neste artigo, vamos analisar como organizar corretamente um monorepositório com C# no ecossistema .NET, abordar a estrutura de pastas, configuração de projetos, CI/CD e melhores práticas.
1. Vantagens e desvantagens do monorepositório no .NET
Antes de nos aprofundarmos nos detalhes técnicos, é importante entender quando o monorepositório é realmente útil e quando pode se tornar um problema.
Vantagens:
- Versão única de dependências. Todos os projetos dentro do repositório usam as mesmas versões de pacotes, eliminando conflitos de versão.
- Refatoração simplificada. A alteração de uma interface comum ou API de biblioteca é imediatamente visível em todos os projetos que a utilizam.
- Integridade dos commits. Commits atômicos que alteram tanto a biblioteca quanto o aplicativo funcionam sem intervalos temporários.
- Configurações compartilhadas. Um único arquivo
Directory.Build.propsdefine configurações de compilação, análise de código e versões para todos os projetos.
Desvantagens:
- Crescimento do tamanho do repositório. Com o tempo, a clonagem e o histórico podem se tornar muito grandes.
- Complexidade do CI/CD. É necessário um sistema de build inteligente para não recompilar tudo a cada commit.
- Permissões de acesso. Em um único repositório, é mais difícil diferenciar o acesso para diferentes equipes.
Para projetos .NET, o monorepositório é especialmente conveniente quando você tem uma biblioteca de classes compartilhada (por exemplo, Domain ou Common), vários microsserviços ou Web APIs que dependem dela.
2. Estrutura do monorepositório para C# (.NET)
Uma estrutura de pastas correta é a base de um monorepositório bem-sucedido. Vamos considerar uma organização típica para uma solução que inclui vários microsserviços, uma biblioteca e testes.
MyApp/├── .github/│ └── workflows/│ └── ci.yml├── src/│ ├── MyApp.Common/ # biblioteca compartilhada│ │ ├── MyApp.Common.csproj│ │ └── ...│ ├── MyApp.Api.Orders/ # microsserviço para pedidos│ │ ├── MyApp.Api.Orders.csproj│ │ └── ...│ └── MyApp.Api.Users/ # microsserviço para usuários│ ├── MyApp.Api.Users.csproj│ └── ...├── tests/│ ├── MyApp.Common.Tests/│ │ ├── MyApp.Common.Tests.csproj│ │ └── ...│ └── MyApp.Api.Orders.Tests/│ ├── MyApp.Api.Orders.Tests.csproj│ └── ...├── Directory.Build.props # configurações compartilhadas para todos os projetos├── MyApp.sln # solução para Visual Studio└── README.mdPontos-chave:
- Todos os projetos estão na pasta
src/, os testes emtests/. Este é o padrão adotado pela comunidade .NET. - O arquivo
Directory.Build.propsdefine propriedades compartilhadas:TargetFramework,Nullable,ImplicitUsings, versões de pacotes, etc. - Um único arquivo SLN simplifica o trabalho na IDE, mas com um grande número de projetos, pode-se dividir em várias soluções.
Exemplo de Directory.Build.props:
<Project> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <TreatW