XFXamlCValidateOnly

No ano de 2019 o grande foco da equipe do Xamarin foi melhorar a experiência de desenvolvimento na plataforma Xamarin, isso incluiu melhorias em tempo de build, ferramentas de produtividade, como o hot reload, diminuição no tamanho do app, tempo de startup, etc. Acompanhando o blog da Xamarin dá pra perceber que vários posts estão focados nessas melhorias, mas uma delas, mais recente, não teve post, e com ela é possível diminuir ainda mais o tempo de build de aplicações feitas com Xamarin.Forms, usando apenas um atributo novo, o XFXamlCValidateOnly.

Em Agosto de 2019 a equipe da Xamarin lançou um Challenge para que as pessoas perdessem o medo e se aventurassem nas várias melhorias feitas na plataforma, principalmente para Android, em troca de testar e compartilhar como foi a experiência, a Microsoft enviava alguns adesivos.

Seguindo as instruções para ativar todas as otimizações possíveis em cada modo (Debug e Release devem ter opções diferentes habilitadas), eu consegui ter melhorias, sendo que a maior delas foi no build incremental com mudanças apenas em XAML, o que é bom, dado que é o caso mais comum que faço diariamente no código.

Se você ainda não aplicou essas melhorias no seu projeto, sugiro testar o quanto antes, pois as melhoras podem ser significativas. Na minha experiência a única que me causou alguma adaptação no código foi habilitar o r8 como shrinker, mas isso já era esperado dado o propósito dessa ferramenta, e não foi difícil ajustar o app para voltar a funcionar com ela.

Mais melhorias

Conversando com o Jonathan Peppers no Twitter, uma das coisas que detectamos foi que o tempo levado na task de XamlCompilation é o que estava causando uma grande diferença nos resultados do meu app comparado ao app utilizado por ele nos testes, devido ao fato de que o meu app era um app em produção com muito mais arquivos XAML do que o testado por ele.

Uma das sugestões dada por ele foi desabilitar a compilação do XAML, mas achei que a validação do XAML era importante demais para trocar por um tempo de build um pouco mais rápido. Foi daí que surgiu uma ideia do Jonathan Peppers de implementar uma forma de apenas validar o XAML, sem fazer passos extras que só são necessários na compilação do XAML para Release. Dessa forma eu poderia ter a vantagem da validação do XAML sem precisar de fato ter o XAML compilado, o que seria bem útil em modo Debug.

O PR dessa ideia foi aprovado e integrado já tem algum tempo, disponível desde a versão 4.3 do Xamarin.Forms, mas só agora resolvi testar para entender quanto meu projeto teria de benefício com essa nova opção.

Diminuindo o tempo de build

Para permitir que o XAML seja apenas validado, sem a compilação, foi implementado um atributo que indica ao MSBuild o que ele deve fazer.

O atributo é o XFXamlCValidateOnly, e ativá-lo é bem simples, é só editar o arquivo csproj e adicionar esta opção para que o MSBuild faça a mágica.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  <!-- outras propriedades -->
  <XFXamlCValidateOnly>True</XFXamlCValidateOnly>
</PropertyGroup>

Atenção para adicionar a opção apenas na configuração de Build desejada, no meu caso, eu quero que em Debug o XAML seja apenas validado, mas em Release ele seja validado e compilado, por isso adicionei a condição de Debug.

Lembrando que este atributo pode ser usado em conjunto com as melhorias descritas no Challenge citado acima para ter o menor tempo de build possível.

Medindo os resultados

Medi os resultados no meu aplicativo em 2 situações: um build completo (com clean), e um build incremental (com alteração apenas no XAML), e tive resultados similares.

A média de tempo no build completo, sem o atributo, foi de 5 segundos no projeto Xamarin.Forms (compilando apenas o projeto Core que contém minhas telas em XAML). Adicionando o atributo o tempo de build completo caiu para a média de 4,5 segundos. É uma queda de 10%. É ótimo que eu possa diminuir mais ainda o tempo de build apenas adicionando uma linha no meu csproj.

Mais interessante foi ver nos logs que a task de XamlC foi realmente a maior responsável pela melhoria, cortando 350 ms por si só:

Antes:

2686 ms  XamlCTask                                  1 calls

Depois:

2339 ms  XamlCTask                                  1 calls

Dá pra validar se o seu build está utilizando o atributo corretamente ativando o modo verboso de log de build e procurando por essa linha:

ValidateOnly=True. Skipping writing assembly.

Uma das preocupações no PR era que isso podia aumentar o tempo de startup do app, mas nos meus testes a diferença foi desprezível, portanto, compensou bem mais manter o XFXamlCValidateOnly sempre ativado para Debug.

Conclusão

Todas essas melhorias de tempo de build, startup e tamanho do app já podem ser aproveitadas nos seus projetos também, sendo que a maioria exige apenas alterar algo nas propriedades do projeto. Claro que seus resultados vão ser diferentes, no projeto usado no PR, por exemplo, a melhora é bem mais significativa: mais de 50% de melhora na task de compilação do XAML!

Esses valores se dão por conta de diferenças no tamanho do projeto, na quantidade de referências, na quantidade de telas escritas em XAML, etc., mas recomendo fortemente que você teste todas elas, adotando as que te trouxerem melhorias, pois essas tarefas são repetidas dezenas ou até centenas de vezes no dia enquanto estamos codando, todo segundo de diferença conta!

(Cross-post de: http://high5devs.com/2020/01/xfxamlcvalidateonly-diminuindo-mais-ainda-o-tempo-de-build-em-apps-xamarin-forms/)

Mahmoud Ali

Desenvolvedor de Software na Lambda3, Microsoft MVP, amante de um bom café ☕️ e uma boa cerveja 🍺.