Scrum e Entity Framework 6: Tudo a Ver

No capítulo 1 do primeiro módulo do meu curso de ASP.NET MVC, discuto com os alunos estratégias para desenvolvimento e construção rápida do banco de dados utilizando Entity Framework. Nas consultorias que faço, é bastante comum encontrar a configuração do Entity Framework sendo usada de maneira a complicar o fluxo de trabalho do time de desenvolvimento, e este artigo busca discutir algumas dessas configurações e orientar o time para aquilo que é o mais adequado.

Para este artigo, estou supondo uma configuração de time Scrum como a de um capítulo, como é descrito no vídeo do Spotify sobre a cultura deles, de até 8 pessoas. Também estou supondo uso do framework ASP.NET MVC5 juntamente com a versão mais recente do Entity Framework 6 (na época deste artigo, 6.1.3).

Para todos os lugares em que fiz consultoria até hoje, a melhor configuração para incremento do banco de dados é a que usa Migrations automáticas e perda de dados. E por que? Porque, no desenvolvimento, é comum (e saudável) construir e destruir a base de dados de amostra várias vezes. Defeitos e problemas de design costumam aparecer nesta etapa. Também é corriqueiro cada desenvolvedor trabalhar numa funcionalidade diferente e implementar todo um novo conjunto de dados, sem precisar depender dos demais. Perder os dados em desenvolvimento não é exatamente um problema. Havendo um bom procedimento de semeadura de dados configurado, a perda de dados de teste em desenvolvimento passa a ser detalhe.

internal sealed class Configuration : DbMigrationsConfiguration<SeuSistema.Models.ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }

    ...
}

E para unir os códigos? A famosa etapa de merge? O que acontece nela? Bom, considerando a configuração, nada.

Com a configuração de migrações automáticas, a execução do comando Update-Database faz o Entity Framework calcular a variação do banco de dados e montar automaticamente um script personalizado para cada situação de banco de dados, ou seja, para cada desenvolvedor.

Uma prática bastante comum em times pequenos desenvolvendo sistemas é configurar Migrations manuais. Ao final do dia (ou da semana, ou do sprint), um dos programadores fica responsável por destruir as Migrations dos demais colegas e gerar uma versão que seria a união de todo o código, para então publicar a versão em um ambiente de homologação e produção.

A abordagem não é incorreta, mas não faz sentido se o sistema está exclusivamente em desenvolvimento. Não é preciso manter histórico incremental de bases de dados que sequer estão em produção. Para estes casos, a simples configuração automática resolve.

Mas, e se estamos falando de um sistema já em homologação, por exemplo? Neste caso, podemos usar uma abordagem mista. Mantemos a configuração de migrações automáticas ligada, mas usando os seguintes procedimentos:

  • Ao final do sprint, um desenvolvedor fica encarregado de sincronizar a base incrementada automaticamente com o último esforço de migração manual. Antes disso, é necessário reverter o banco de dados local para a última versão de migração manual. Isto pode ser feito facilmente através do comando:

    PM> Update-Database -TargetMigration:NomeDoArquivoDaMigration
    
  • Logo após, o desenvolvedor deve gerar a nova migração de sprint utilizando o roteiro tradicional de geração de migração:

    PM> Add-Migration SprintNumero123
    
  • Os demais desenvolvedores podem reverter seus bancos de dados locais usando o mesmo procedimento explicado acima ou simplesmente apagar o banco de dados e criá-lo novamente. O efeito será o mesmo.

  • Os demais sprints trabalham normalmente em cima de migrações automáticas.

Por fim, para produção, toda e qualquer configuração de migração automática ou perda de dados deve ser removida:

    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        AutomaticMigrationDataLossAllowed = false;
    }