Automatizando builds no TFS: além do Team Build

Pensando fora da caixa - indo além do Team BuildRecentemente o amigo e ex-Lambda3 Osmar Landin iniciou uma série de posts sobre o Jenkins. Apesar de ele normalmente escrever sobre TFS, essa nova série de posts teve uma motivação mais do que justa:

Nem todo mundo pode (ou quer) usar o TFS. Às vezes a melhor (ou a única) solução é partir para um stack open-source. Nesses casos, o que usar para automação de build?

A resposta dele a essa pergunta foi “Jenkins”. Se você se identificou com essa situação, deve ler sua série de posts. Por outro lado, apesar de eu ter me inspirado nos posts dele, minha motivação foi um pouquinho diferente. O que eu quero discutir é:

Eu uso TFS como meu repositório de controle de versão e estou mais que satisfeito. Agora, quero automatizar meus builds. O que faço?

Continue lendo “Automatizando builds no TFS: além do Team Build”

Porque você definitivamente precisa de testes de unidade

(AVISO: Este post é uma tradução livre do excelente post originalmente publicado por Colin Dembovski, também MVP de Visual Studio ALM, em http://www.colinsalmcorner.com/2013/07/why-you-absolutely-need-to-unit-test.html. Thanks, Colin!)


Porque você definitivamente precisa de testes de unidade

Eu escrevi sobre porque builds são absolutamente essenciais no desenvolvimento moderno de aplicações (parte 1) e por que o Team Build é um grande mecanismo de build (parte 2). No entanto, se você não inclui testes de unidade em suas builds, é como escovasse os dentes sem creme dental – há muito movimento, mas não é a maneira mais eficaz de se fazer as coisas. Neste post, quero propor algumas reflexões sobre por que você definitivamente precisa usar testes de unidade.

Aqui vão alguns destaques:

  1. Codificar com testes de unidade em mente obriga-o a pensar sobre o design e a arquitetura de seu código – o que faz com que ele se torne um código melhor
  2. Testes de unidade fornecem feedback imediato – todas as alterações no código são testadas (pelo menos em parte) à medida que você codifica.
  3. Um pequeno investimento agora leva a uma enorme economia mais tarde – bugs em produção custam muito mais do que bugs em desenvolvimento
  4. Testes de unidade fornecem métricas para a qualidade do seu código
  5. Testes de unidade trazem qualidade inerente às suas implantações (releases)

Vamos analisar cada um desses pontos.

Desenvolvimento guiado pelo pensar

Você provavelmente já ouviu falar de termos como “test-driven development (TDD)” (desenvolvimento guiado por testes) ou “behavior-driven development (BDD)” (desenvolvimento guiado por comportamento). Adoraria cunhar mais um termo – desenvolvimento guiado pelo pensar. Eu venho de um histórico de desenvolvimento – e como eu amo codificação (como a maioria dos desenvolvedores), sofro da síndrome de “deixe-os-detalhes-para-lá-quero-apenas-começar-a-codar”. A maioria dos desenvolvedores que conheço também. Espero que você nunca perca esta paixão – mas há muito a ser dito para tomarmos fôlego e pensarmos primeiro.

Se você apenas pular no código e não tiver testes, você provavelmente vai criar algo que funcionará de imediato para algumas situações (geralmente com a ressalva do “funciona na minha máquina!?!”). No entanto, isso não é sustentável já que leva ao que um  professor universitário meu costumava chamar de “código espaguete” (o que foi especialmente engraçado já que ele é italiano). Você escreve algum código e o implanta. Algo quebra. Você faz um remendo e reimplanta. Agora você quebrou alguma outra coisa. Então você põe um pouco de fita adesiva (metaforicamente, é claro). Eventualmente você chega ao ponto do chiclete e da folha de alumínio, e as coisas vão de mal a pior.

Se você começa a escrever testes (ou pelo menos começa a escrever seu código com testes em mente), é mais provável que você escreva um código melhor. Se você alguma vez tentou escrever testes de unidade para código legado, vai entender o que quero dizer. Se você não codificar com testes em mente, seu código (como seria de se esperar) acaba não-testável (ou pelo menos muito difícil de testar com testes de unidade). Escrever código testável o obriga a pensar em boa decomposição, boas interfaces, boa separação de preocupações (SoC, separation of concerns), inversão de controle (IoC, inversion of control) e injeção de dependências (DI, dependency injection) e um montão de outros princípios que todos nós aprendemos, mas de alguma forma esquecemos de usar em nossa rotina diária.

Então comece com seus testes. Isto o obriga a usar todas as coisas boas (não são chamadas de boas práticas por acaso). O pouco de pensamento necessário no início vai te poupar muita dor ao longo do tempo (para não falar da diminuição da quantidade de chiclete que você vai encontrar no seu repositório de fontes).

Feedback imediato

Deixe-me fazer uma pergunta – quão longo é o ciclo de feedback entre o momento em que você escreve algum código e quando você obtém feedback sobre a validade desse código? Ou formulado de outra maneira, pense sobre o último bug que você consertou. Qual é a duração do tempo entre a escrita do código e o relatório do bug? Um dia? Uma semana? Um ano?

O fato é que quanto mais cedo depois de escrever o código que você encontrar um bug, mais barato será para conserta-lo. Vamos considerar duas extremidades do espectro: tempo de codificação e em produção.

Quando existe um bug em produção, pode levar algum tempo para encontra-lo. Em seguida, é relatado para o suporte técnico. Eles investigam. Eles então escalam para o suporte de segundo nível. Eles investigam. Eles então escalam para os desenvolvedores, que tem que investigar e reproduzir. Em outras palavras, um longo tempo.

E quando você está codificando? Você escreve algum código e executa os testes de unidade. O teste falha. Você investiga e corrige. Em outras palavras, muito pouco tempo.

Quanto mais rápido você receber feedback (e quanto mais vezes você obtiver feedback), mais eficiente e eficaz você será. Numa larga escala, essa é em geral a razão para metodologias Ágeis – a iteração rápida aumenta a frequência do ciclo de feedback. Isso funciona no nível de gerenciamento de projeto, e também funciona no nível de codificação.

Eis com o que isso se parece em um gráfico:

clip_image001
350

Quanto mais cedo você encontrar seus bugs, tão menos tempo que você vai gastar encontrando-os e mais barato será para corrigi-los. Se você não tem testes de unidade, você já vai mudar sua primeira oportunidade de feedback para a terceira zona (teste manual). Se você não fizer o teste manual, você está empurrando de novo ainda mais para fora em direção aos testes de aceitação do usuário (UAT, user acceptance test). Se você não fizer isso, então o primeiro feedback que você vai conseguir é da produção – que é o mais demorado e o mais caro.

Obter feedback imediato enquanto você está codificando é ótimo quando você está fazendo projetos “greenfield” (projetos que nunca foram implantados antes). Ele realmente começa a brilhar quando você volta depois de 6 meses (ou 12 ou 18) para adicionar recursos – você ainda tem sua suíte de testes para garantir que você não está quebrando nada com o seu novo código.

Gastar um pouco agora – economizar muito lá na frente

Quase nunca falha: os times que não têm testes de unidade alegam que “não têm tempo para teste de unidade”. Defendo que na grande maioria dos casos, é exatamente porque não se investe em testes de unidade que você não tem tempo para codificar corretamente. Sempre que você implanta código não-testado, você aumenta sua dívida técnica. O fato triste é que a dívida técnica tende a crescer exponencialmente.

Olhe novamente para o gráfico acima. Onde você acha que você vai gastar mais tempo para encontrar e corrigir bugs? Obviamente, quanto mais “à direita” você está, mais tempo você precisa para corrigir um bug. Então invista um pouco “agora” enquanto você está codificando, de modo que você não tem que gastar muito tempo mais tarde lidando com problemas em produção!

Métricas de qualidade

Como se mede a qualidade do seu código? Erros na produção por período de tempo? Tempo médio de reparo (MTTR, Mean Time To Resolve)? A maioria dessas medições é útil em algum grau, mas como são estatísticas de “tempo de produção”, o feedback vem muito tarde no ciclo.

Os time com que trabalho que tem métricas invariavelmente têm métricas de teste de unidade – taxas pass/fail e estatísticas de cobertura de código. Os times que não têm métricas quase sempre não têm testes unitários. Testes unitários fornecem uma medida objetiva da qualidade do seu código. Como você pode melhorar se você não sabe onde você está atualmente?

Qual cobertura que você deve estar almejando? Isto é discutível, mas eu sempre recomendo que você prefira se concentrar em suas tendências – certifique-se que cada implantação é melhor que a última. Dessa forma, o número absoluto realmente não importa. Mas a única maneira que você pode fazer qualquer tipo de análise de tendências é se você realmente está coletando as métricas. É por isso que adoro testes de unidade (com cobertura de código) no TFS Team Build, uma vez que as métricas são agrupadas dentro do data warehouse e é realmente fácil de fazer relatórios de tendências. Mostrar à área de negócios um gráfico com uma constante melhoria da qualidade é uma das melhores coisas que você pode fazer como um desenvolvedor!

Qualidade inerente

Todas estas práticas levam à qualidade inerente – uma qualidade que faz parte intrínseca do que você está fazendo do dia-a-dia, ao invés de algo que você coloca no final de uma iteração (ou rapidamente antes do lançamento). Se você incluir qualidade inerente em seus processos e práticas, você pode dormir tranquilamente na noite da grande implantação. Se não o fizer, você vai ter que manter o telefone por perto para todas aquelas chamadas inevitáveis de “Socorro, o sistema está quebrado…”

Código legado

Na minha empresa anterior, tivemos grandes quantidades de código “legado” – que estava em produção, que nós mantínhamos constantemente, e que não tinham testes. Quando comecei a direcionar para testes de unidade e cobertura, inevitavelmente chegamos ao momento embaraçoso onde alguém deixou escapar, “Mas tem muito código para começar a testar agora!”. Argumentei que 1 teste era melhor do que 0 testes. E 2 testes são melhores que 1 teste e assim por diante.

Então criamos uma política em que qualquer código em que você trabalhou (sejam novos recursos ou correções) precisava ter testes de unidade. Isto nos colocou no caminho para a construção de nossa suíte de testes abrangentes. Também definimos uma política de que a cobertura de código tinha que ser maior nessa implantação do que na implantação anterior para que a entrada em produção fosse aprovada. No começo, nossa cobertura foi 1,5 ou 2%. Depois de apenas 6 meses, estávamos perto dos 40% de cobertura. E o número de problemas de produção em que estávamos trabalhando diminuiu dramaticamente.

Conclusão

Assim como você não pode deixar de fazer builds automatizadas, você realmente não pode se dar ao luxo de não fazer testes de unidade. O investimento agora proporcionará benefícios enormes ao longo do ciclo de vida do seu aplicativo – não só para você e seu time, mas também para o seu negócio e as partes interessadas também.

Para ler mais, Martin Hinshelwood escreveu um ótimo post sobre o test-first que eu recomendo.

Feliz Testes!

Private Builds e Gated Check-ins

Caixa de diálog de Gated Check-inSe você leu meu último post sobre Private Builds, deve ter notado uma semelhança com a funcionalidade de Gated Check-in.

Para aqueles que não sabem o que é um Gated Check-in, vai aí um resumo de um post que fiz sobre o assunto:

O problema da solução apresentada acima [NA: Uso de Integração Contínua], baseada apenas no servidor de build, é que o check-in precisa ser feito antes de ser validado. Ou seja, em caso de problemas eu necessariamente terei que desfazer manualmente as alterações que quebraram o build. O ideal seria que eu pudesse disparar o buid antes do check-in, só efetivando a alteração no controle de versão se tudo corresse bem. É justamente disso que trata o conceito de gated check-in: As operações de check-in são interceptadas (geralmente usando shelvesets) e redirecionadas para um servidor de build especial. Esse servidor combina o código-fonte que já existe no TFS com as alterações que acabaram de vir do desenvolvedor. Se tudo correr bem, só então é que o check-in será consumado.

Reparou na parte que diz que o TFS “combina o código-fonte que já existe no TFS com as alterações que acabaram de vir do desenvolvedor”? É exatamente isso que faz o Private Build, certo?

Logo, podemos dizer que Private Build e Gated Check-in são a mesma coisa? Bem, quase. Smile

Private Build e Gated Check-in são baseados na mesma infraestrutura que permite a execução de builds baseados em shelvesets. A diferença é o gatilho: enquanto o Private Build é opcional e disparado sob demanda pelo desenvolvedor, o Gated Check-in é obrigatório e disparado no check-in.

Qual é o melhor? Private Build ou Gated Check-in?

Não sei se dá para ser tão simplista assim. Neste caso não há melhor ou pior.

Temos clientes que preferem a segurança do Gated Check-in. Ele reduz drasticamente o risco de quebras no build. Entretanto, ele torna o processo de check-in mais burocrático e lento. Times mais maduros acabam sendo “atrapalhados” pelo Gated Check-in.

Minha opinião pessoal? Use Gated Check-in na branch de desenvolvimento APENAS SE O TIME AINDA NÃO FOR MADURO. Em todos os outros casos, confie no bom-senso do time. Eles usarão o Private Build sempre que necessário.

 

Um abraço,
  Igor

Use Private Builds – e pare de passar vergonha!

TFS Build Wall - painel com status de builds mostrando builds quebrados
184

Integração contínua é uma ferramenta importante para garantia de qualidade do código produzido pelo time, certo?

Seu time usa TFS? E usa o Team Build para fazer integração contínua? Legal!

Só tem uma coisa que não é muito legal: ser a pessoa que quebrou o build. Principalmente se, em sua empresa, o status dos builds fica na parede, à vista de todos. Esta foto à direita é do ambiente de desenvolvimento de um de nossos clientes. Temos times mistos (desenvolvedores da Lambda3 e do cliente) trabalhando em projetos hospedados no TFS do cliente. E, acredite: assim que um build é quebrado, TODO MUNDO saca o smartphone do bolso e tira fotos da TV. Provavelmente a “vítima” que quebrou o build vai pagar o almoço e ainda vai ser “trolada” por um tempinho! Smile

Evitar a quebra  do build é fácil, não? Basta compilar o código no seu computador e rodar todos os testes. Só então, se estiver tudo OK, você pode fazer o check-in com a certeza de que o build não será quebrado. Pena que nem sempre as coisas são tão simples assim…

Tem alguns cenários em que nem sempre é viável (ou possível) garantir a integridade do código antes do checkin. Por exemplo: se você está mexendo numa classe de uma biblioteca, que é consumida em várias partes de um grande sistema, você provavelmente precisaria executar novamente todos os seus testes. Não apenas os de unidade (esses são obrigatórios; você deveria executar sempre!) mas também os de integração. E é aí que as coisas começam a ficar mais complicadas.

Testes de integração são, por natureza, como elefantes: grandes, lentos e pesados. Ou seja, muitas vezes não dá para rodar testes de integração da máquina do desenvolvedor – principalmente se há dependência de complexos ambientes de testes que dificilmente poderiam ser reconstruídos no ambiente do desenvolvedor.

Caímos então no dilema: há testes que são inviáveis de se reproduzir no computador do desenvolvedor, por serem muito lentos ou por dependerem de um ambiente caro de se recriar para cada uma das pessoas no time. Nesses casos, o uso do servidor de automação de build é a melhor saída. E nesses casos eu corro o risco de fazer commit de código defeituoso, que quebraria o build e, eventualmente, atrapalharia o trabalho de outros membros do time. Como resolver?

Entra aí o conceito de Private Build: já pensou que legal seria poder rodar um build só seu, usando toda a infraestrutura já montada para a Integração Contínua (CI)? Com esse build você poderia validar o código usando o servidor de build mas, diferente do que acontece em builds de CI, você não precisaria fazer o commit/check-in para disparar o build. Você forneceria seu código ao TFS sem fazer check-in e, portanto, sem atrapalhar os outros! Dessa forma você poderia testar várias vezes seu código, até que estivesse OK. Só então você faria o check-in e dispararia o processo normal de CI.

Vamos ver como fazer isso?

Partiremos da premissa que você tem um ambiente de integração contínua já montado, capaz de rodar todos os seus testes (representado na figura abaixo pela definição de build “CI”).

Exemplo de definições de build. Usaremos a build CI

Agora, faça suas alterações na sua aplicação. Eu espero Smile.

Pronto? Então vamos testar essas alterações!

Clique com o botão direito na definição de build CI e selecione “Queue new build…”:

Menu "Queue new build..."
240

O “pulo do gato” vem a seguir: em “What do you want to build?”, selecione “Latest sources with shelveset” e, depois, em “Create”:

Caixa de diálogo Queue new build com a opção "What do you want to build?"
244

Vamos, agora, criar um shelveset com nossas alterações. Esse shelveset será usado para a execução do build. Vamos chamar nosso shelveset de PB (de Private Build; poderia ter chamado de qualquer outra coisa). Aí é só clicar em Queue!

Caixa de diálogo de criação de shelveset
181

Agora vamos ver o que aconteceu: quando você agenda um build privado, o TFS baixa a última versão do código-fonte no controle de versão para o agente de build e depois aplica o shelveset sobre a última versão do código. É como se você tivesse feito check-in do seu código! Entretanto, o TFS distingue builds privados daqueles que são agendados pelas vias comuns. Repare na mensagem indicando que seu shelveset está sendo validado e que, por padrão, o resultado do seu build não é copiado para a drop location:

Janela de status do build indicando a execução do build privado
91

Em caso de erro você pode corrigir seu código e reagendar um novo build privado – sem atrapalhar ninguém no time!

Viu como é simples usar builds privados? Agora você só quebra build se quiser!

 

Um abraço,
  Igor

Economize espaço em disco ao usar Coded UI Test, Team Build e Vídeo

Gráfico de uso de espaço em disco (exemplo)
269

Você sabia que os testes criados com o Microsoft Test Manager (parte da família Visual Studio 2010) podem ser configurados para capturar, automaticamente, vídeos da tela do computador durante a execução dos testes?

Ah, já sabia? Bom, confesso que realmente não esperava que isso fosse uma grande novidade… Smile

O que talvez seja novidade para alguns é que mesmo testes do tipo Coded UI (testes de automação de interface de usuário, recurso exclusivo do Visual Studio 2010 Premium/Ultimate) que são executados pelo Team Build, durante o processo de build automatizado, podem gerar vídeos.

A vantagem disso é que em caso de problemas o desenvolvedor consegue assistir ao vídeo da execução do teste e pode identificar mais facilmente eventuais problemas. A desvantagem é que o consumo de espaço em disco do banco de dados do TFS pode crescer muito rápido – afinal, testes automatizados são criados para serem executados repetidas vezes!

A dica, portanto, é manter no TFS apenas os vídeos dos testes que falharem! Afinal, se o teste foi bem-sucedido é pouco provável que você precise do vídeo…

Para isso:

  1. Abra a solução que contém seu projeto de testes;
  2. Localize o arquivo .testsettings que está associado ao seu processo de build (no meu exemplo, é o arquivo BVT.testsettings):
    Localização do arquivo BVT.testsettings
  3. Em Data and Diagnostics, selecione a opção Video Recorder e clique em Configure:
    Botão "Configure" do gravador de vídeo
  4. Agora, o “pulo do gato”: Desmarque a opção Save video recording if test case passes:
    Opção "Save video recording if test case passes"

 

Um abraço,
   Igor