Vladimir Khorikov atua como consultor em diversos tópicos relacionados com desenvolvimento de software, incluindo Domain-Driven Design, programação funcional, padrões para desenvolvimento de aplicações corporativas e boas práticas. Ao longo de anos, desenvolveu diversos cursos populares na Pluralsight e um bocado de artigos.
Recentemente, ele orientou seu trabalho para tornar a escrita de testes de unidade uma tarefa mais natural para todos os desenvolvedores. Além disso, escreveu um livro sobre o tema e, atualmente, está desenvolvendo um curso aprofundado sobre Test-Driven Development.
Neste post, compartilhamos uma entrevista curta com Vladimir Khorikov onde ele, gentilmente, compartilha suas impressões sobre as práticas de teste de unidade hoje. Agradecemos a ele pelo tempo dedicado a responder nossas perguntas.
Questão #1 – Temos discutido sobre a importância de testes automatizados por muito tempo. Entretanto, ainda não é comum ver autoridades técnicas discutindo implicações economicas dessa prática. Em seu livro, você afirma que “O objetivo [de usar testes automatizados] é possibilitar crescimento sustentável de um projeto de software”. Como chegou a esse insight?
V.K. – Principalmente, foi um certo “desapontamento” com a mensagem da maioria dos livros e publicações sobre o tema. A maioria destes recursos apresenta apenas como escrever testes básicos, o que é razoável, mas não vai além disso. O “porquê” escrever testes de unidade é tão importante quanto o “como” – um justifica o outro. Sem um entendimento apropriado do “porquê” precisamos de testes de unidade, é impossível atribuir importância à prática.
Além disso, poucos livros ou recursos on-line detalham os custos ocultos dos testes de unidade. Há dois aspectos principais: manutenabilidade (mais ou menos entendido por nossa indústria hoje) e resistência para refatoração (quase ninguém fala sobre isso hoje).
Todos percebemos as vantagens dos testes unidades em oferecer alguma “proteção” contra regressões (bugs). Entretanto, poucos percebem o quanto essa proteção custa. No meu livro, eu destaco tanto os aspectos percebidos quanto ocultos.
Questão #2 – Qual é o maior impedimento, na sua opinião, para que programadores experientes e bem intencionados produzam bons testes?
V.K. – O principal é não levar em conta os custos dos testes de unidade, particularmente, a dificuldade para refatoração. Por causa disso, as pessoas tendem a produzir um bocado de testes de baixa qualidade. No lugar de ajudar, estes testes costumam trazer prejuízos. Afinal, eles requerem um bocado de tempo de manutenção e atualizações sempre que alguma refatoração acontece. Um efeito secundário, porém importante, é a falta de confiança nos testes que leva a menos melhorias no código e, consequentemente, deterioração.
Questão #3 – Há um certo consenso de que code coverage não é uma boa métrica para testes de unidade. Por que, então, é tão mencionada e usada?
V.K. – Parcialmente, porque não há outras métricas que possam ser coletadas automaticamente e, também, porque é melhor do que nada. Code coverage não é uma métrica de todo ruim, é boa apenas em um sentido – é boa como métrica “negativa”, mas terrível como “positiva”. Ela mostra que os testes não são suficientes quando, particulamente, temos cobertura em áreas importantes do código inferiores a 50%. Entretanto, um alto índice de cobertura não é garantia de que os testes sendo aplicados são bons.
Questão#4 – Há outras métricas, fornecidas por ferramentas de análise estática, que você considera relevantes durante o processo de desenvolvimento de testes?
V.K. – Infelimente, code coverage é a única métrica que pode ser obtida através de ferramentas. Verificações quanto a qualidade dos testes ainda é um processo manual.
Questão #5 – Práticas como “Behavioral Code Analysis” indicam que códigos com muitos commits e autores são aqueles onde dívidas técnicas tem maior impacto. Quais são os impactos desse entendimento para classificação de testes como bons ou ruins?
V.K. – As mesmas análises podem ser feitas para determinar que áreas do código deveriam receber primeiro testes de unidade e onde deveríamos ter mais cuidado com a qualidade dos testes. Na maioria das aplicações line-of-business, esta área será o modelo de domínio (ou lógica do negócio). Priorizando pela qualidade do código no modelo de domínio (e em testes adequados), geralmente provê melhor retorno sobre o esforço.
Questão #6 – Você planeja escrever mais livros sobre testes? O que podemos esperar?
V.K. – Esrever um livro dá trabalho. Dediquei quase um ano para escrever esse. Então, não planejo escrever outro livro tão cedo. Talvez no futuro!
Questão #7 – Além de seu livro, que recursos você recomenda para aqueles que desejam programar melhor?
Há três temas em desenvolvimento de software que tem grande relação (e importância): testes de unidade, domain-driven design (DDD) e programação funcional. Por exemplo, com testes de unidade, é importante seguir o Humble Object pattern e separar o modelo de domínio de dependências “fora do processo” (como bancos de dados) . Isso é o que programação funcional defende também, inclusive impondo isso, como restrição, em algumas linguagens, como Haskell. DDD provê as ferramentas necessárias para construir um modelo de domínio da forma certa.
Eu recomendo o livro de DDD do Eric Evans para quem quer saber mais sobre Domain-Driven Design. Para programação funcional, me agrada muito o estilo de escrita de Scott Wlaschin, sendo que seus artigos em https://fsharpforfunandprofit.com/ me ajudaram a entender o conceito. Ele também escreveu um excelente livro chamado Domain Modeling Made Functional (https://fsharpforfunandprofit.com/books/)