Recomendação sobre TDD

{ June 1st, 2009 }


cmilfont

Autor: cmilfont

O Bruno Pereira comentou em post passado sobre a dificuldade que ele teve em adotar TDD:

“Já tentei algumas vezes escrever os testes unitários no começo, mas simplesmente prefiro a abordagem de escrever os testes posteriormente, preferencialmente acompanhando o desenvolvimento das funcionalidades de negócio.”

Notei em diversas consultorias que isso é muito comum por diversos motivos, o principal a meu ver é justamente entender como começa o código do teste, em dois extremos: se depois que definiu o fluxo de processo de negócio de alguma forma [como UML, CRC ou mesmo apenas com UC] ou se já começa algum esboço em código sem ter discutido bem como funciona totalmente o negócio.

A primeira abordagem, definir todo o processo primeiro, deixa a grande maioria dos desenvolvedores confortáveis já que é algo tradicional que vinhamos fazendo, mas o problema é que invariavelmente descamba para BDUF.

A segunda abordagem, que está ligada ao desenvolvimento iterativo e incremental, já deixa um sentimento de que “algo está faltando” em grande parte dos times que tenho trabalhado. A resistência maior é deixar um sentimento de que não preparamos a arquitetura adequadamente e essa pode sofrer um revés num futuro próximo, claro que isso é uma bobagem para quem conhece como TDD funciona, mas é algo comum que tenho notado e precisa ser desmistificado.

Note que não estou falando aqui do sistema inteiro, apenas uma funcionalidade, mesmo assim a mudança cultural de quebrar uma funcionalidade em tarefas e ir desenvolvendo com “passos de bebê” é algo que dificulta a adoção.

Como sanar essas deficiências?

Precisamos de uma forma que conversassemos sobre a funcionalidade inteira mas que me permita ir avançando e atualizando conforme eu vá entendendo melhor como funciona.

Tenho trabalhado essas deficiências nos últimos times que peguei com BDD [Behaviour Driven Development] , iniciando a escrita das histórias [descrição daquela funcionalidade na visão de uma pessoa] seguindo o modelo de template que o Dan North sugeriu. O resultado é que os times avançaram porque eles notaram como iniciar satisfatoriamente com testes sem comprometer a velocidade do desenvolvimento.

O BDD nos trouxe os testes para o inicio de qualquer código, praticamente sem distinguir que se está testando antes e associado com outras práticas como “Programação em Par” facilitou a linguagem ubíqua do time.

Independente se é ágil ou tradicional eu tenho notado uma deficiência na coleta de informações, seja como User Stories ou Use Cases, onde os analistas de negócio, ou seja lá como são chamados nos times, não sabem pensar em negócio. Uma das coisas mais ridículas que vejo é o sujeito explicar para seu time uma funcionalidade com base em um DER ou outra estrutura técnica, dizendo coisas como: “a tabela tal, associada a entidade x”.

Tenho tentado corrigir isso nos times que enfrento como princípio básico, antes de qualquer coisa eu tento disciplinar a pensarem em negócio. Faço exercícios simples como questioná-los com “esqueçam de qualquer termo técnico” e “como essa funcionalidade é no papel?” ou “se não tivesse computador, como fariam isso?”, perguntas simples para instigar o raciocínio sobre a funcionalidade. Após esse exercício, escrevemos essa história em um arquivo e partimos para sua implementação.

Em março desse ano eu palestrei no primeiro encontro da XPCE sobre BDD, vejam os slides. Em termos de ferramentas você pode conferir como temos trabalhado em um projeto recente seguindo os posts do Jefferson Girão:

Parte 1 http://jefferson.eti.br/?p=96
Parte 2 http://jefferson.eti.br/?p=105
Parte 3 http://jefferson.eti.br/?p=139

Enfim, acredito que BDD seja um caminho natural para adoção de TDD por seu time já que eles terão código de teste, antes de qualquer coisa, na forma de negócio e o TDD já florescerá quando forem testar o modelo criado ou sugerido pelo código BDD. Ainda tem uma vantagem adicional, terão a documentação do sistema executável e comprovável.

Posted in Behaviour Driven Development, Design Patterns, Engenharia de Software, Melhores práticas, Metodologia, Métodos Ágeis, Test Driven, teste, XP, xpce ~ 7 Comments

Palestra Test Driven Development

{ March 29th, 2009 }


cmilfont

Autor: cmilfont

Palestra realizada no evento do grupo XPCE em 28/03/2009.

Posted in Design Patterns, Engenharia de Software, Java, Linguagens, Melhores práticas, Metodologia, Métodos Ágeis, Orientação a Objetos, palestras, Test Driven, teste, XP, xpce ~ 1 Comment

Retrabalho e prejuízo

{ January 8th, 2009 }


cmilfont

Autor: cmilfont

Em todos os projetos que trabalhei até hoje no mercado local [Ceará] existem profissionais mais ou menos qualificados a partir de uma base mínima de qualidade que um profissional tem que possuir dentro do modelo “Enterprisey” – que estamos acostumados e que responde pela quase totalidade dos projetos de software.

Essa base mínima eu proponho que seja – dentro do modelo exposto -  raciocínio lógico. O resto ele pode aprender.

Raciocínio lógico está ligado diretamente a noção de avaliar a situação, encontrar um padrão, investigar soluções existentes e implementar a solução, além claro de bom senso.

Não adianta pregarmos que os profissionais deveriam ser melhor escolhidos assim ou assado porque a realidade é que as empresas não tem como medir satisfatoriamente quem é ou não competente e mais cedo ou mais tarde você se deparará com indivíduos em sua equipe vindos por diversas nuances administrativas, seja aquele superqualificado cheio de títulos ou o primo do diretor da empresa.

Aonde quero chegar com essa história?

Precisamos avaliar os riscos necessários com bastante antecedência para que toda a equipe e consequentemente o projeto não sejam lesados e paguem o preço da incompetência às vezes de um único elemento. Parece óbvio? Acredite, não é!

Temos um projeto em um cliente – uma Alfândega – que precisamos refatorar todo o código criado por um determinado profissional com apenas dois ou três meses pronto. O projeto ainda está no início e já temos que refazer código.

Convenhamos, tudo bem que o código de meia hora atrás já é legado, mas código tão recente não deveria já ser refatorado sem mudança na lógica de negócio ou arquitetural. Algo muito errado aconteceu.

Mudanças não funcionais acontecem, surge um novo paradigma ou framework que reduz o tempo de desenvolvimento e convenientemente é adequado sua mudança, isso é comum durante a manutenção de um software já em produção com um meio século de uso – que em informática dura cerca de 4 ou 5 anos.

O nosso em questão não há motivos. Projeto novo, sem restrição ou adequação à “Arquitetura de Referência”, Frameworks de última milha na plataforma Java como JSF, Spring e Hibernate. Testes unitários – mas não TDD.

Como dito, separei um exemplo em código para demonstrar aonde quero chegar. Tem uma lógica bastante simples, existe um processo de apreensão de mercadorias na alfândega e liberação dessa mercadoria.

Há 3 tabelas que representam isso no modelo E/R: TB_DEVOLUCAO, TB_ITEM_APREENSAO, TB_ITEM_DEVOLUCAO. Segundo a lógica relacional, a TB_ITEM_DEVOLUCAO é uma tabela de junção entre a devolução e os itens apreendidos para indicar que item será devolvido.

Seguindo minha definição, um profissional com raciocínio lógico encontraria fácil a solução do mapeamento entre essas entidades apenas lendo a documentação, ele saberia que o Hibernate tem um mapeamento de OneToMany com Join Table Uni ou Bidirecional.

Mas não, ele criou essa bizarrice:

@Entity
@Table(name="TB_DEVOLUCAO")
public class Devolucao {
 
	@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	@JoinColumn(name="SEQ_ITEM_DEVOLUCAO")
	@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private List<ItemDevolucao> itensDevolucao = 
		new ArrayList<ItemDevolucao>();
 
}
 
@Entity
@Table(name="TB_ITEM_DEVOLUCAO")
public class ItemDevolucao { //Para que essa entidade?
 
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="SEQ_ITEM_DEVOLUCAO", columnDefinition="NUMERIC")
	private Integer codigo;
 
	@OneToOne
	@JoinColumn(name="SEQ_ITEM_APREENSAO")
	private ItemApreensao itemApreensao;
 
}

Esse profissional em questão é graduado em computação, tem mestrado em uma federal, certificação como arquiteto Java e diversas outras certificações e pasme, anos de experiência em projetos. Mas não tem o básico, raciocínio lógico. Não investiga e não sabe desenvolver software de qualidade.

O código em questão pode parecer bobagem até mas isso se repete em todo o código criado por esse profissional.

Um profissional responsável em refatorar o código com apenas curso técnico e uma mísera certificação de programador java refatorou assim [como deve ser]:

@Entity
@Table(name="TB_DEVOLUCAO")
public class Devolucao {
 
	@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	@JoinTable(name="TB_ITEM_DEVOLUCAO",
		joinColumns = @JoinColumn(name="SEQ_ITEM_DEVOLUCAO"),
		inverseJoinColumns = 
				@JoinColumn(name="SEQ_ITEM_APREENSAO")
	)
	@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private List<ItemApreensao> itensDevolvidos = 
				new ArrayList<ItemApreensao>();
 
}

Ad Hominem da minha parte? Tomar uma exceção pela regra? nada disso, eles são legião! Isso é meu cotidiano.

O prejuízo que esse profissional acarreta a todos os envolvidos é enorme e até difícil de ser mensurado porque envolve custos e humor da equipe que impacta em outros custos imperceptíveis na conta final que é a “fodisse” dos caras que tiveram que refatorar, ou seja, fizeram o seu e o trabalho alheio.

Ah, mas XP não prega o código coletivo? ir lá e consertar? Mas quebra o principal valor que é “Respeito”. Além do mais o projeto em questão seque o velho Cascata – mas culpa do cliente que exigiu ser assim, exigiu não, obriga.

Pela minha experiência de nada adianta você jogar um Clean Code nas mãos dele e pedir para estudar, ele vai continuar escrevendo nmDesc em uma propriedade ou IRepository em uma Interface. Ele foi treinado assim e sem raciocínio lógico no máximo que voce vão conseguir é retreiná-lo para conseguir comer a banana por outro túnel.

Um projeto sem um líder técnico responsável com aptidão e experiência necessária aliado a método baseado em BDUF sem um processo restritivo [como TDD] com modelagem ultrapassada com papéis de analista de sistemas “UMLizados” deixa esse tipo de profissional cometer esses pecados e prejudicar a todos os envolvidos retrabalho desnecessário.

É fácil resolver isso? É! O problema maior é que não podemos simplesmente aceitar que “o cliente quer assim”, temos um dever ético com nossa profissão de não permitir que o paciente escolha como ele quer ser operado e ceder médicos que não tenham capacidade de operá-lo.

Posted in Certificações, Design Patterns, Engenharia de Software, Java, Melhores práticas, Metodologia, Métodos Ágeis, Scrum, Test Driven, XP ~ 16 Comments