Como Automatizar Testes de aplicações Android – Parte 1 (O desafio)

Olá pessoal,  este ano vou começar com uma pequena série de posts e um pouco DIFERENTE dos posts habituais para falar mais uma vez de teste na prática. Obviamente para ser diferente eu vou deixar este primeiro post um desafio para todos assim como eu tive um desafio no final do ano passado para  preparar e ministrar uma disciplina de teste de software para uma turma de desenvolvedores que estava participando de um curso de desenvolvimento para Android. Preocupado em deixar as aulas de teste mais interessantes,  eu arrisquei adaptar meu material para algo que fosse bastante prático e relevante para essa turma e por isso dei uma estudada no Android e como desenvolver aplicações e criar testes automáticos para o mesmo e acabei descobrindo algumas coisas que o SDK disponibiliza que gostaria de compartilhar com vocês.

Antes de começarmos a desenvolver testes para o Android, preciso passar  algumas informações relevantes para que todos possam conseguir ter um entendimento completo de como automatizar alguns testes para aplicações em Android e também consigam completar o desafio que deixarei neste post.

Para podermos automatizar testes para aplicações Android, precisamos entender alguns de seus componentes básicos, que são: Activities, Services, Content Providers e Broadcast Receivers.

Activities – Uma activity é um dos componentes do Android mais usados nas aplicações pois ele é que  fornece uma tela com a qual os usuários podem interagir. Por exemplo dicar um número de telefone, escrever uma sms, ou visualizar um mapa. Para cada activity é dada uma “janela” na qual “desenhamos” uma  interface de usuário. As “janelas” normalmente preenche toda a tela, mas também podem ser menores do que a tela e flutuar em cima de outras “janelas”.

Services – São componentes de aplicação que podem executar operações de longa duração em segundo plano, portanto não fornecem uma interface de usuário. Um serviço pode ser iniciado por uma aplicação e ele continuará a ser executado em segundo plano, mesmo se o usuário trocar para outra aplicação.

Content Providers – Como o nome já explica, Content Providers é componente responsável por armazenar e recuperar os dados e torna-los acessível para todas as aplicações, ou seja são os provedores de conteúdo. A única forma de compartilhar dados entre aplicações no Android é através de content providers, pois não existe área de armazenamento comum que todos os pacotes Android podem acessar.

Broadcast Receivers – É um componente que responde a anúncios de todo o sistema de broadcast. Muitos brodcast provenientes do sistema, como um broadcast anunciando que a bateria está fraca ou uma sms foi recebida. As aplicações também podem iniciar os broadcast, por exemplo, para permitir que outras aplicações saibam que alguns dados foram disponibilizados para eles usarem. Os broadcast receivers também não possuem interface de usuário, mas eles podem criar uma notificação de barra de status para alertar o usuário quando um evento de broadcast ocorreu.

Bem , depois desta uma breve introdução, vamos por a mão na massa e desenvolver uma calculadora bem simples para que depois possamos automatizar alguns testes para essa aplicação. Quem quiser se aprofundar um pouco mais sobre como desenvolver aplicações para Android pode dar uma olhada neste site para desenvolvedor da Google.
Essa calculadora que desenvolvi possui algumas restrições para cada uma das operações básicas (somar, subtrair, multiplicar e dividir) com o objetivo de exemplificar o uso de algumas técnicas de criação de teste para os alunos da turma e essas técnicas de criação de testes não vem ao caso neste post nem nos seguintes que virão, o nosso objetivo aqui é explicar como desenvolver e automatizar testes para aplicações Android. Outro fator relevante que devo deixar claro é que eu utilizei o eclipse com o plugin ADT para desenvolver meu projeto em Android. Para saber como configurar seu ambiente, veja aqui.
Após configurar o ambiente vamos ao nosso desafio:
Vou deixar alguns requisitos básicos da nossa calculadora para que você possam tentar desenvolver e no próximos post  disponibilizarei o nosso código e explicarei passo a passo como o desenvolvi.  Logo abaixo segue os requisitos da aplicação que vamos automatizar os testes mais na frente:

Nome: Aplicativo Calculadora Fajuta 

[REQ001] Tela principal deve possuir dois campos (EditTexts) para inserir valores e um botão (Button) de cada  funcionalidade da calculadora, que são:
– SOMAR
– SUBTRAIR
– MULTIPLICAR
– DIVIDIR

[REQ002] A operação SOMAR  só efetua soma de números entre 0 e 10, pois a calculadora é fajuta. O resultado deve ser mostrado em um texto (TextView) no canto inferior da tela.

[REQ003] A operação SUBTRAIR é um pouco mais evoluída e consegue efetuar a subtração de números entre 0 e 50. O resultado deve ser mostrado em um texto no canto inferior da tela e caso seja um resultado negativo, o mesmo deve estar na cor vermelha.

[REQ004]  A operação MULTIPLICAR  deve multiplicar  apenas números pares.

[REQ005] A operação DIVIDIR, da mesma forma da operação Somar, só efetua a divisão de números entre 0 e 10.

E claro que qualquer dúvida por mais simples que seja, podem comentar aqui neste post e terei o prazer de responder o mais rápido possível. Para os mais tímidos, podem me mandar um email que tem no meu perfil aqui do Bdb.  Boa sorte a todos !!! 🙂

Imagine um mundo SEM bugs no software

Na indústria de software estamos habituados a ideia de que todo software possui defeitos e que pouco podemos fazer para mudar isso. No vídeo a seguir, de apenas 9 minutos, Jeff McKenna, co-fundador do Scrum apresenta uma visão radical: um mundo sem bugs no software. O vídeo foi extraído de seu próximo livro “Conscious Software Development.”

O vídeo é excelente e nos faz pensar principalmente na atitude em relação aos bugs que temos em nossos projetos. Segundo Jeff, não basta corrigirmos os defeitos encontrados precisamos entendê-los e aprender com eles, só assim construiremos sistemas SEM defeitos.

Assista ao vídeo. Em seguida, destaco os principais pontos abordados por McKenna.

 

Temos sistemas de gerenciamento de defeitos, realizamos triagens, mas será que em algum momento pensamos sobre o que eles são? ou como surgiram? como fazer para não surgirem mais?”

Segundo Jeff, temos sido muito complacentes com os defeitos, acreditamos que existem muitos, e que os mesmo são parte de todos os sistemas. Porém, o autor não acredita nisso e nos convida a imaginar um mundo SEM bugs de software.

“Podemos atingir números bem menores do que as pessoas consideram razoável, e isso pode ser feito de maneira simples”

McKenna indica que, a simples conscientização a respeito dos bugs já possibilita imensos ganhos. Precisamos entender porquê eles estão presentes e agir para evitar novas falhas.

Como diminuir a quantidade de bugs?

– Reduzir o tempo entre a introdução de um bug e sua correção

A medida leva em conta o momento no qual o bug foi introduzido no sistema e não o momento em que o mesmo foi detectado. Para isso é necessário utilizar as ferramentas de controle de código, assim, após identificado o motivo do defeito podermos voltar versões do código e identificar o momento em que ele ocorreu.

Olhando para o exato momento em que o erro aconteceu podemos aprender a escrever menos bugs. Porque esse é o verdadeiro objetivo.”

O objetivo não é encontrar mais bugs e a função dos analistas de qualidade não se resume a isso.

“Classificação e triagem de feitos são uma perda de tempo, em termos de aprendizado sobre como escrever menos bugs”

Segundo McKenna, pouco importa a severidade do defeito e suas características, pois geralmente o critério de correção está diretamente ligado a questões de negócio, como a importância de um determinado cliente. Logo, se estamos tentando aprender a escrever menos bugs, não há diferença entre os mesmos, sejam eles de alta ou baixa prioridade todos são comportamentos não esperados do sistema.

“Corrigir os defeitos era a atividade de maior prioridade”

Jeff, exemplificou suas recomendações com as seguintes práticas executada em um de seus projetos:

1- Sempre que um bug surgisse, a primeira pessoa que estivesse livre passaria a trabalhar no defeito. Onde, um profissional era considerado livre quando terminava a tarefa que estava executando no momento. Bugs possuem prioridade mais alta, que todas as demais tarefas ainda não realizadas. Desse modo, no máximo em alguns dias o defeito era analisado.

2 – Corrigir e entender o problema. A mais alta prioridade era a correção do defeito, associado a criação de novos testes automáticos. Porém, o mais importante é você falar porquê aquele bug estava lá, a razão do mesmo ter ocorrido.

“O que queremos fazer é encontrar o bug o quanto antes para que possamos consertá-lo o mais cedo possível e provar o aprendizado”

Para McKenna, temos o prazo máximo de até 6 meses da introdução de um defeito, para podermos aprender algo através de sua correção, após isso a oportunidade de aprendizado terá sido desperdiçada.

“O objetivo real é escrever software SEM defeitos.”

E para atingir esse objetivo, a principal característica que temos que desenvolver é a de olhar sempre para frente. Se ficamos sempre olhando para trás 6 meses, 1 ano, analisando um código que não vemos a muito tempo, isso literalmente é perda de tempo. Então, o que queremos fazer é olhar para frente a todo o momento e ter a atitude de ZERO defeitos.

“Um bug é algo que você esmaga imediatamente.”

Ao eliminar rapidamente os bugs encontrados acabaremos com tarefas, como a priorização de defeitos. Afinal, a quantidade de bugs pendentes será sempre pequena e desse modo o foco poderá ser maior no que está sendo construído.

Este é um vídeo para ser visto diversas vezes, e se conseguirmos absorver sua ideia central, penso que, poderemos melhorar ainda mais nossos processos e principalmente nossa atitude.

Conheci esse vídeo primeiramente no Software Testing Club, uma excelente fonte de informações para testadores, com bons textos e vídeos sobre a área. Espero que tenham gostado.

…………………………………………………………………………………………………………………………………………..

Agora você já pode acompanhar as novidades do BdB pelo Facebook, acesse e curta nossa página.

Cobertura de código, como ?

No meu ultimo post falei sobre a importância da cobertura de código e o quanto ele é comumente utilizado com critério de saída nas primeiras fases de um projeto de software. Lá eu falei das duas técnicas de medição de cobertura de código mais usadas, são elas a Statement Coverage e Decision Coverage. Agora venho escrever este post para cumprir a promessa que deixei no ultimo post, que é mostrar na prática como utilizar uma ferramenta para fazer a medição da cobertura dos testes, neste exemplo, unitários.

A ferramenta que utilizei para exemplificar as duas técnicas acima foi um plugin para o Eclipse chamada CodeCover.
CodeCover é uma ferramenta de teste glass-box grátis e desenvolvido em 2007 na Universidade do Stuttgart.

Para iniciarmos o exemplo, vou mostrar uma classe (Example.java) com dois métodos bastante simples para facilitar o entendimento das técnicas utilizadas.

public class Example {

	public void firstExample(int a, int b) {
		int c =  a + (2*b);
		if (c>50){
			System.out.println(c);
		}
		System.out.println("Fim 1");
	}
}

Abaixo temos os primeiros testes unitários escritos na classe ExampleTest.java para verificar o funcionamento do método firstExample(int a, int b).

	@Test
	public void testFirstExample() {
		try {
			ex.firstExample(20, 15);
		} catch (final Exception e) {
			Assert.fail();
		}
		Assert.assertTrue(true);
	}

	@Test
	public void testFirstExample1() {
		try {
			ex.firstExample(20, 25);
		} catch (final Exception e) {
			Assert.fail();
		}
		Assert.assertTrue(true);
	}

Para medir a cobertura dos testes acima apenas precisamos marcar as classes Example e ExampleTest para ser usado pela ferramenta de Medição de Cobertura ( Figura 1)

Tela 1 - Clique para ampliar

Após marcar as classes envolvidas (classe de teste e classe a ser testada), iniciamos a execução dos testes no modo CodeCover para JUnit. Ao finalizar a execução dos testes, aparecerá uma aba chamada Test Sessions, no qual podemos marcar os teste unitários executados e visualizar as linhas de código da classe testada que foram exercitado pelo teste. Na tela 2 abaixo podemos ver que o teste testFirstExample exercitou apenas 3 linhas de código de um método que possue 4 linhas de código.

Tela 2 – Clique para ampliar
Tela 3 – Clique para ampliar

Na tela 3, quando marcamos apenas o teste testFirstExample1, verificamos que o mesmo possui uma cobertura completa do método firtExample(int a, int b). Isso quer dizer que apenas o segundo teste (testFirstExample1) é suficiente para se ter 100% de Statement Coverage, ou seja todas as linhas de código foram exercitadas.

Mas se prestar atenção na tela 3 a linha de código numero 8 da classe: if (c>50) {”  está pintada de amarelo, isto quer dizer que essa linha de código não está completamente exercitada, ou seja, esta estrutura condicional ainda precisa ser estimulada por mais teste para que outro fluxo seja tomado, e isso a gente consegue garantir quando testamos esse método com os dois teste anteriores. Olhando para tela 4 abaixo, percebemos que quando marcamos os dois testes (testFirstExample e testFirstExample1), temos 100% de cobertura  de Decision Coverage, pois ambos os teste exercitaram a linha 8 para que o fluxo fosse tomado tando para que C fosse maior que 50 e C fosse menor que 50, exercitando assim a estrutura condicional (if) pode completo.

Tela 4 – Clique para ampliar

Analisando direitinho, podemos perceber que toda suíte de teste que cobre 100% de decision coverage, também cobre 100% de statement coverage, no entanto o inverso nem sempre  é verdade.

Espero ter esclarecido melhor o conceito de Statement e Decision coverage com os exemplos acima. O que vocês acharam ? Caso tenham dúvidas relacionadas a este tema, por favor utilizem o espaço de comentário para que possamos discutir mais sobre o assunto.

Obrigado e até breve !!!

A Metáfora da Dívida Técnica: O preço das gambiarras

O XP (eXtreme Programming) tenta se utilizar de metáforas no desenvolvimento de software para trazer o entendimento de todos para mais próximo do mundo real. Metáforas são um instrumento poderoso.

Recentemente compareci na QConSP, e no meio de tantas palestras uma me chamou a atenção em particular, e se tratava justamente da explicação de uma metáfora (que acredito ser maravilhosa para se comunicar com a gerência ou clientes).

Todos nós sabemos o que é uma dívida no mundo real, e todos nós eventualmente entramos em dívidas, seja um financiamento de um imóvel que você vai pagar por 300 meses, ou um carro que você vai ficar endividado por 60 vezes. O pior de tudo é que além da dívida normal, você irá pagar um montante de juros absurso dependendo do tamanho da dívida que você está assumindo.

Existem as dívidas responsáveis ou conscientes como as citadas acima mas também existem dívidas inconscientes ou não responsáveis que são piores, pois surgem de uma hora para a outra sem te dar tempo para pensar se desejava assumir essa dívida ou não (ex: alguém gastando desordenadamente no cartão de crédito e quando vai ver a fatura fica surpreso).

Pois bem, no desenvolvimento de software é a mesma coisa!

Você tem que adicionar uma funcionalidade no seu sistema. Nesse momento  você enxerga duas formas de fazer isso: Uma forma é rápida de fazer, mas é meio bagunçada e com certeza você iria ter mais trabalho ainda no futuro para modificar aquilo. A outra forma é mais elegante e organizada, porém vai demorar mais. Isso lhe parece familiar?! Esse trade-off acontece o tempo todo no desenvolvimento de sistemas, mas o que esquecemos é das dívidas que assumimos quando escolhemos a forma mais rápida e mais bagunçada (ex.: gambiarras)!

Parece que não temos ciência que todas as vezes que assumimos uma dívidas técnicas no sistema, mais lento o desenvolvimento se torna, mais difícil de modificar as funcionalidades existentes, mais difícil adicionar funcionalidades novas (como mostra o primeiro gráfico) e muito mais provável que uma mudança qualquer tenha impactos indesejados e desconhecidos. Temos que estar cientes das dívidas que assumimos no dia-a-dia do desenvolvimento de software.

Ah, então é por isso que não conseguimos aumentar a velocidade do time depois de tantas sprints??

Talvez! Aí nasce a  questão importante que é o momento que iremos pagar nossas dívidas, ou ao menos parte delas. A grande maioria dos times conhecem os lugares no sistemas que estão com dívidas, e é preciso separar um tempo para PAGAR essas dívidas caso contrário os juros só fazem aumentar. Enquanto as dívidas não são pagas, nós nos deparamos com o cenário onde sprint após sprint, vamos fazer menos coisas (vide o segundo gráfico) pois agora é muito mais difícil modificar o sistema com tantas dívidas do que era no início do desenvolvimento quando não tínhamos dívida ou as poucas dívidas que tínhamos eram controláveis.

Cuidado com suas dívidas técnicas ou elas vão afundar você e seu projeto! 

Os bons testes falham

O aprendiz foi até o programador mestre e disse:

“Todos os meus testes sempre passam. Não mereço um aumento?”

O mestre acertou uma tapa no rosto do aprendiz e respondeu:

“Se todos os seus testes passam, sempre que são executados,

você precisa escrever testes melhores.”

Com a bochecha vermelha, o aprendiz foi até os recursos humanos para reclamar.

Mas essa é outra estória.

Link para o material completo em Inglês

É de fundamental importância que todos os envolvidos no ciclo de vida de um software entendam cada vez mais a integração entre as disciplinas de desenvolvimento e testes, o trecho destacado acima foi retirado do Guia para testes unitários, elaborado por Alberto Savioa da Agitar Software, o qual apresenta de forma simples, divertida e direta um fundamento básico a ser trabalhado em ambas as áreas.

Definir o que é um bom teste de software não é algo simples, seja ele um teste unitário feito pelos desenvolvedores ou mesmo testes funcionais ou não-funcionais elaborados pela equipe de testes. Considerando apenas os aspectos mais básicos, um bom conjunto de testes precisa alcançar uma boa cobertura da aplicação e ser eficiente na tarefa de identificar as falhas presentes no software.

No entanto, me impressiona o número de profissionais de TI, inclusive engenheiros de teste, que não se incomodam quando um ciclo de testes executado apresenta 100% dos casos de teste como passados, e ainda percebem isso como um claro indicador de que o software está “livre” de defeitos. Uma análise, que muitas vezes pode se mostrar enganosa e levar a muitos prejuízos.

Um dos princípios de Testes de Software, segundo o livro “Fundamentos de Testes de Software”, fala sobre a ilusão da ausência de defeitos, o qual tenta alertar contra o fato de que a ausência de bugs, não necessariamente significa que o sistema desenvolvido atende a um determinado padrão de qualidade ou mesmo às necessidades do usuário. Afinal, o problema pode estar nos próprios casos de teste, no planejamento ou até mesmo na maneira como os mesmos foram executados.

Princípio – Não caia na ilusão da ausência de defeitos.

  Em outras palavras, um teste que não encontra falhas
é diferente de concluir que o software está livre de defeitos.
Devemos assumir que todo software contém algumas falhas,
ainda que estas estejam escondidas.

Link – Resumo do Foundations of Software Testing

Logo, seja você um desenvolvedor ou testador, que cria testes manuais ou automáticos e os executa, é preciso ter bastante cuidado ao analisar a eficiência do seu conjunto de testes. Revisar constantemente os testes mais antigos e avaliar os defeitos escapados são boas práticas que podem contribuir na evolução dos testes.

Por fim, precisamos nos desapegar um pouco da associação teste passado e sucesso, e avaliar a cada estágio de teste o nível de confiança que podemos ter nos resultados obtidos, estando sempre atentos ao significado do termo “qualidade” para cada cliente ou projeto.

Aumentando a qualidade do software com apoio do Powerpoint

Como havia prometido no post – Apertem os Cintos, o Analista de Requisitos Sumiu!, descrevo hoje como abordávamos o gerenciamento dos requisitos (estorias) num dos projetos desenvolvidos no C.E.S.A.R. gerenciado com SCRUM. A mesma, já foi inclusive mencionada por Marcelo Nunes no post Mapeando Requisitos em Projetos Scrum.

Espero que de alguma forma, nosso exemplo, possa ser útil a vocês, para que possam tentar aplicá-lo em seus projetos ou que ao menos possa servir de referência para que apliquem suas ideias em seu ambiente de trabalho e com a cooperação dos colegas possam construir soluções para seus problemas. Se você ainda não conhece bem o Scrum, consulte os seguintes links: Scrum em 10 minutosHistórias de Usuário

O que descrevemos nas próximas linhas, como uma abordagem, surgiu naturalmente durante o projeto e foi sendo aprimorado, com o simples intuito de garantir que as estórias selecionadas para a próxima sprint fossem compreendidas de maneira uniforme por toda a equipe, e atingindo esse objetivo outros benefícios eram proporcionados, como: Diminuição do número de defeitos, maior satisfação do cliente, melhor comunicação entre os membros da equipe, entregas realizadas no prazo correto, além de poder servir como guia para novos integrantes da equipe, entre outras vantagens.

A partir do momento em que as estórias haviam sido selecionadas para a nova sprint, os seguintes passos eram iniciados:

  1. Detalhar estórias da sprint 
  2. Discutir o PPT com toda equipe
  3. Implementação da estória
No passo 1, as estórias selecionadas eram descritas através de slides, seguindo a prioridade estabelecida entre as mesmas. Desse modo as mais importantes eram liberadas com maior antecedência para as etapas seguintes. O slides deveriam ser simples e diretos, descrevendo o objetivo central da estória, geralmente continham esboço da interface e informações a respeito do escopo.
Abaixo, exemplificamos o uso dos slides para uma estória fictícia, descrita da seguinte forma: “Como um administrador do blog eu quero saber quais os posts mais acessados para que possa analisar o perfil dos visitantes.”

Já o passo 2, consistia de uma reunião com todo o time, onde o responsável pela elaboração do PPT explicava o funcionamento da estória. Sendo este o momento mais importante da nossa abordagem, o qual permitia um entendimento mais profundo da necessidade do cliente. Durante a reunião todos interagiam procurando esclarecer os detalhes que envolviam a estória, seus possíveis impactos em outras funcionalidades previamente implementadas, além de como a mesma deveria se comportar em determinados cenários.

Ao final da reunião, normalmente algumas mudanças no PPT eram realizadas em razão dos pontos levantados, e a partir desse momento o passo três podia ter continuidade, tendo agora como base também as informações disponíveis no PPT, facilitando o trabalho de desenvolvedores e testadores, através da diminuição da quantidade de retrabalho causado pelo diferente entendimento das estórias.

A abordagem utilizada por nós, atingiu o objetivo do projeto, garantindo que as necessidades do cliente fossem compreendidas pelo time e desse modo proporcionando entregas de maior qualidade. É importante, também, ressaltarmos que o fundamental para o sucesso da abordagem está diretamente ligado a troca de ideias e ao comprometimento com a qualidade, sendo o PPT apenas uma forma rápida e ágil para apoiar essa comunicação.

E o que não podemos nos esquecer, é que a utilização, melhoria e adaptação dos processos deve ser um ato contínuo, onde as características do projeto e das pessoas que fazem o mesmo precisam ser levadas em consideração.

Ficou interessado na abordagem proposta? Caso haja qualquer dúvida ou dificuldade ao tentar aplicá-la em seu ambiente de trabalho, entre em contato conosco.

Os desenvolvedores podem testar seu próprio código?

Por esses dias, estive relendo os posts sobre como são conduzidas as atividades de testes no google, entre outras coisas eles falam sobre os papéis, funções e de que maneira a qualidade de software é conduzida dentro da empresa.

No terceiro post da série, diversas afirmações chamaram a minha atenção e valem a nossa reflexão:

“Who better to do all that testing than the people doing the actual coding? Who better to find the bug than the person who wrote it? Who is more incentivized to avoid writing the bug in the first place?”

A partir dessa afirmação podemos ver que estamos passando por uma grande transição na engenharia de software. Onde há vários anos as empresas dão uma ênfase cada vez maior aos aspectos relacionados à qualidade de software e diversas estratégias surgiram e vêm sendo utilizadas para a organização das equipes e divisão das tarefas.

Porém, o que mais me chama atenção nessa primeira afirmação é como a idéia a que estava acostumado, de que precisamos de pessoas com dois perfis diferentes para testar e desenvolver um software está ficando ultrapassada.

Make it or Break it

Cada vez mais precisamos unir as duas disciplinas que se completam para assim entregar produtos de maior qualidade.

Claro, que para que isso aconteça é necessária uma mudança cultural e comportamental. Abandonarmos os antigos conceitos de que desenvolvedores não conseguem enxergar as falhas em seu próprio código, não gostam e não querem testar e tornar tudo em uma única tarefa.

Diversos benefícios podem emergir dessa tendência, como: detecção de defeitos cada vez mais cedo, maior liberdade para o engenheiro de teste focar em aspectos não funcionais, fluxos de integração e outros pontos que fogem a unidade do desenvolvedor, etc.

  “quality is more an act of prevention than it is detection”

Desse modo, técnicas como o TDD podem ser excelentes caminhos para eliminar essa separação entre testes e desenvolvimento. Ajudando a tornar a qualidade cada vez mais um ato de prevenção do que detecção.

” Testing must be an unavoidable aspect of development and the marriage of development and testing is where quality is achieved”

É óbvio, que existem diferenças entre os diversos tipos de projetos e na realidade de cada uma das empresas, onde cada um possui necessidades diferentes as quais precisam ser avaliadas e planejadas.

Está cada vez mais claro o caminho para produzirmos softwares de maior qualidade, testes e desenvolvimento como uma só tarefa, apresentando um grau de automação cada vez maior. Para seguirmos esse caminho várias mudanças são necessárias tanto nas pessoas, como nos processos e ferramentas.

E vocês o que acham? É esse o caminho a ser seguido?

O que fazer quando você descobre que seu código está uma merda?

Não se desespere, eventualmente você vai descobrir que o código que você está trabalhando a dias está uma merda 🙂 Geralmente é preciso outra pessoa para lhe mostrar que o seu código não está (até por esse motivo que práticas de revisão de código e pair programming são tão importantes). Eventualmente você pode se dar conta sozinho que seu código está ruim, mas é muito mais difícil e improvável.

A boa notícia é a seguinte: Sendo você um bom programador ou não, vai chegar um momento que você vai fazer um código que você não tem orgulho (mas PRECISAMOS nos orgulhar do código que produzimos). Então, se acalme e vamos ao que interessa, desfazer a merda 😛

Já vi muita coisa sobre eXtreme Programming e seus valores, e um valor em especial sempre me pareceu meio obscuro, mas agora chegou um momento onde esse valor é evidenciado. Nesse momento a PRIMEIRA coisa que você precisa é:

CORAGEM! Para admitir que seu código poderia estar muito melhor, e CORAGEM para correr atrás do prejuízo e modificar o que for preciso para melhorar o código que você tinha feito.

Tudo bem… Você já percebeu que o seu código não está bom, e teve coragem de admitir isso e partir em direção de melhorar aquele código. E a segunda coisa, óbvia, que você precisa fazer é:

AGIR! Mudar o panorama da situação! Geralmente algumas mudanças pequenas e a qualidade do seu código já melhora sensivelmente. É claro que você precisa saber COMO melhorar seu código.

A grande maioria das vezes, quando você identifica o problema no seu código, mas também já visualiza as modificações necessárias para melhorá-lo, então é simplesmente seguir essas direções. De qualquer forma, aqui deixo uma listinha com algumas sugestões que são sempre úteis para melhorar seu código:

  • Morte ao código duplicado (mantra de @luizborba).
  • Remover referências erradas/desnecessárias (diminuir acoplamento).
  • Manter cada classe/método com uma única responsabilidade (aumentar a coesão).
  • Verificar se algum padrão de projeto resolve seu problema.
  • Atenção a muitos IFs e SWITCH  CASES, eles são grandes candidatos a um refactoring.
  • etc, etc…

é isso! errar é normal, o importante é consertar! 🙂

Mais sobre Software Craftsmanship…

Hoje eu escutei um podcast da software engineering radio com o famoso Robert Martin (mais conhecido como uncle bob) a respeito de software craftsmanship, e pude notar algumas coisas muito interessantes que ele falou, que eu concordei e decidi compartilhar.

O link da entrevista é esse aqui.

Aqui estão alguns pontos que ele comentou (não necessariamente em ordem):

  • “Software Craftsmanship é um movimento que está relacionado com o aprendizado da arte com os mestres.” Por trás dessa frase tem muitas coisas, e uma das primeiras delas é que todo iniciante no mundo de desenvolvimento precisa ter “mestres” por perto, para que possamos olhar, e aprender com eles como se desenvolve software. O que você aprende na faculdade não é suficiente para encarar o mundo do software sozinho. Se você acha que sozinho dá para aprender tudo, eu diria que você já começou errado. Como no mundo do artesanato convencional, você primeiro aprende com alguém, depois inicia sua caminhada sozinho e refinando sua técnica, e depois você poderá virar “mestre” de outros artesões. O mundo do software é muito parecido com essa realidade.
  • “Só no seu trabalho (das 8h as 17h)  você não vai conseguir ser um mestre e refinar/melhorar sua habilidade e técnica”. Essa é uma daquelas verdades inconvenientes. Mas a moral da história é que se você não usar o seu tempo “livre” para estudar, aprender novas coisas e aprimorar coisas antigas você provavelmente nunca vai poder começar sua jornada em direção a virar um mestre no futuro (na verdade nunca vai virar esse mestre #fact). Uncle Bob cita que ele acha que o tempo ideal para você dedicar nos seus estudos fora do trabalho é algo na faixa de 20 horas semanais. Acho que a quantidade de horas não é importante e nem existe um tempo para todo mundo, mas o fato é que o estudo fora do trabalho é muito importante nessa caminhada do artesão.
  • “Um médico cirurgião muito bom, depois de muitas cirurgias não vira gerente e pára de realizar cirurgias”. Esse é um ponto bem interessante que trás algumas verdades. A primeira delas é que você só aprende fazendo, e fazendo muito. A segunda verdade é que se você se especializa em um determinado artesanato (programar, gerenciar, testar, etc) você não deveria virar gerente depois de se tornar bom, pelo contrário, aí seria onde você começaria a realmente mostrar seu valor.
  • “Só quem sabe o que a equipe de desenvolvimento está passando (dificuldades, desafios, etc) é quem está botando a mão no código” Na verdade esse ponto é mais um combate a funções do tipo “Arquiteto” e similares, aonde você não codifica, mas você que dita a arquitetura (em termos de caixas e setas em power point ou qualquer outra ferramenta de diagramação) . No momento da criação das caixas e setas no powerpoint as decisões que vão ser tomadas estão em um nível acima das que precisam ser tomadas no código, são decisões diferentes e que as vezes até conflitam entre si. Arquitetura é código! Arquitetura e design é código! E os artesões de software são orgulhosos do código que fazem, e também de COMO esse código foi feito.

é isso, que discordar ou concordar com algo, please leave a comment!

Não Existe Plain Text: Uma breve explicação sobre encodings

Nesse post eu vou falar de um ponto que muitas vezes parece não ser importante pelo motivo de (quase) sempre desenvolvermos aplicações em português e inglês, deixando de lado algumas línguas mais complicadas como grego, hebraico, chinês, japonês, e outras línguas asiáticas.

Inicialmente vamos entender um pouco mais o que exatamente é o encoding, e para que ele serve.

Encodings são códigos (geralmente números) que representam um determinado caractere em uma determinada língua/plataforma. A primeira forma de representação desses caracteres foi o tão conhecido Ascii (American Standard Code for Information Interchange), que representa um caractere em questão em forma de bits, mais precisamente 7 bits (depois completaram os 8 bits). O problema é que o universo de caracteres representados no Ascii era muito pequeno, somente 128 caracteres (por conta do seu tamanho). Não precisa nem dizer que os alfabetos pelo mundo a fora possuem muito mais do que 128 caracteres somente (e a china é o nosso principal representante desse leque). O Ascii foi o primeiro, mas diversos outros encodings surgiram depois disso: ISO 8859-1 , GB 2312, etc.

Também é fácil de concluir que com os diversos encodings que surgiram, muitos caracteres conflitavam os seus códigos com outros encodings. Isso é, dois encodings usando o mesmo código para representar o mesmo caractere. Por conta desses problemas foi criado o Unicode, que NÃO É UM ENCODING, mas padroniza a representação de caracteres dos encodings. Então começaram a surgir os encodings que basearam seus representações de caracteres em códigos sugeridos pelo unicode, e aí entra um dos primeiros encodings famosos unicode, que foi o UCS-2.

UCS-2 (Universal Character Set) utiliza 2 bytes para representar caracteres, e é claro que por conta desse espaço maior de armazenamento foram acrescentadas “muitas e muitas” línguas nesse encoding. Infelizmente “muitas e muitas” é diferente de TODAS. Ou seja, o povo decidiu criar encodings ainda maiores, com 16 e 32 bits (sendo este último não muito utilizado).

O UCS-2 teve um problema, basicamente com sistemas linux-like (que por ser um sistema antigo, se baseava completamente no encoding Ascii). Podemos exemplificar o problema com a linguagem C, que tem a convenção de representar uma string como um array de caracteres (representação ascii) terminando em zero. Exemplo: C vai armazenar a string HELLO como 72 69 76 76 79 0, num mais puro Ascii. Na maior parte dos lugares dentro dos sistemas linux-like  vão entender que essa é uma palavra de 5 letras porque ela termina com zero (null). Quando utilizamos o UCS-2, o mesmo HELLO é armazenado em 2 bytes da seguinte forma: 72 0 69 0 76 0 76 0 79 0 0 0. Praticamente todos os lugares vão interpretar isso como uma palavra de uma só letra “H”. Isso não é bom.

Foi aí que surgiram os encodings UTF (Unicode Transformation Format), uma vez que os sitemas linux (baseados em ascii 8 bits, não conseguiam se entender muito bem com os encodings 16 bits como o UCS-2). Esses UTF conseguem fazer os sistemas 8 e 16 bits se entenderem normalmente. O formato UTF mais utilizado é o UTF-8, que utiliza de até 4 bytes para representar um caractere. Como são utilizados esses bytes?

– 1 byte para a representação do caractere Ascii e

– 2 bytes para a representação de caracteres latinos, sírios, hebraicos, gregos, etc. ou 3 bytes para o restante de um plano multilingual que existe.

Com isso nós chegamos até o conceito mais utilizado hoje em termos de encoding, que é o UTF-8, que está se tornando cada vez mais um padrão para páginas, emails, e qualquer outro lugar onde caracteres sejam armazenados.