quarta-feira, 5 de agosto de 2009

Embarcadero RAD Studio 2010

Para quem desenvolve com ferramentas originalmente criadas pela Borland (que depois passaram a ser desenvolvidas pela sua subsidiária CodeGear, que foi comprada pela Embarcadero), uma boa novidade: está chegando a versão 2010, com mais de 120 melhorias, pelo que informa sua página oficial. Resta saber se todas estas melhorias serão facilmente percebidas e serão realmente úteis a maioria.

Entre as principais novidades estão:

  • IDE Insight – Permite que você encontre qualquer arquivo, componente, propriedade, etc. apenas digitando parte do nome.
  • Code Formatter – Permite aplicar uma formatação de código pré-configurada.
  • Class Explorer – Permite visualizar dependências entre arquivos, conteúdo de classes, hierarquia de classes, etc.
  • Data Visualizers – Melhorias no depurador (como mostrar tipos Date como uma data e não um número de ponto-flutuante, etc.)
  • Debugger Thread Control – Facilita a depuração de programas com várias threads

Veja o vídeo (em inglês, sem legendas):

Apesar de ainda não terem muitas das facilidades encontradas em IDEs como Eclipse e NetBeans, são muito boas para RAD e certamente irão melhorar a medida que a Embarcadero for amadurecendo nesse segmento. Afinal, trata-se apenas do segundo release trazendo a marca da empresa.

quinta-feira, 30 de abril de 2009

O Java e o MySQL passam a ser da Oracle

A compra da Sun pela Oracle concluída no domingo (19/04) e anunciada na semana passada (20/04) pegou de surpresa os desenvolvedores de todo o mundo. Negociada em US$ 7,4 bilhões, em meio a “crise” (que, cá entre nós, não assustou o setor de T.I.), a Sun finalmente cedeu à oferta.

Fora a negociação, o que mais tem deixado a comunidade de cabelo em pé é a questão: como fica o suporte ao MySQL, agora que a Oracle dá as cartas ? E ainda, como fica as tecnologias baseadas em Java e ferramentas de código aberto (NetBeans, OpenOffice, etc.) suportadas pela Sun ?

A IBM, que já tentou a aquisição da Sun e não obteve sucesso, teria mais simpatia dos desenvolvedores, por apoiarem diversas iniciativas opensource (Eclipse, GNU/Linux, etc.).

Claro que as versões de código aberto são de domínio público e não podem ser controladas, mas não se sabe se os desenvolvedores da Sun continuarão auxiliando estes projetos. Enquanto não há uma posição clara sobre como ficarão estes casos, diversas especulações vão surgindo na Internet, sobretudo as que falam na idéia da Oracle acabar com a versão paga do MySQL.

Em minha opinião, como não há risco para as versões livres, não haverá perigo para os desenvolvedores e empresas que a adotaram. Para as versões pagas, com certeza o suporte não irá cessar em médio prazo. Porém, quanto à continuidade de seu desenvolvimento, a coisa realmente pode mudar. Talvez a Oracle ofereça promoções para migração para o banco de dados com seu nome ou até mesmo continue com o MySQL como uma opção mais “viável” para pequenas empresas. Quem sabe assim mais empresas migram para versão aberta ?

sábado, 11 de abril de 2009

TDD na Prática – Parte V: Testabilidade e a UML

Seguindo nossa pequena série sobre TDD, vamos ver sobre como a testabilidade influencia no design, sobre a diferença de escrevermos os testes antes ou depois e como a UML pode se relacionar com TDD.

(Lembrando que nas próximas partes da série será dado início à implementação de um pequeno e simples Jogo da Velha, nos moldes do TDD)

Como podemos testar um Jogo da Velha ? O que deve ser verificado ?

Esta pergunta pode gerar uma grande lista de coisas que devem ser checadas. Nela, com certeza faltarão coisas simples, óbvias, que serão deixadas de lado pelo fato de geralmente nos atermos às coisas mais importantes, de maior impacto na aplicação. Porém, devemos lembrar que antes de testarmos coisas complexas, temos que ter certeza de que as simples estão funcionando corretamente. Testando-as, teremos segurança para prosseguir para os testes mais complexos, os quais, por exemplo, envolvam a interação de diversos objetos. Neste caso, cada objeto deve ter seu comportamento individual testado, para que o novo teste se concentre na (correta) cooperação entre os mesmos.

QuebraCabeca

Assim, deve-se começar pelo trivial e ir pouco a pouco aumentando a complexidade sobre o que será verificado. Pondere, também, a importância que cada nova verificação tem para a aplicação, do ponto de vista da relação custo-benefício do teste. Veja mais sobre este assunto na Parte IV: Quem, Onde, Quando, O Que e Como.

Complexidade

Fique atento à relação Complexidade do Assunto do Teste versus Complexidade do Código do Teste. Num teste, o o que deve ser verificado pode ser complexo mas não o como. Se seu teste começar a ficar difícil de ser implementado, pare e repense o problema. Pode ser que você precise refatorar seu código de teste. Muitas vezes isto acontece devido ao código criado para o teste estar pouco coeso. Talvez porque ele esteja fazendo mais trabalho do que somente as verificações necessárias, ou talvez porque, na verdade, esteja fazendo mais que somente um teste. Analise com cuidado a responsabilidade atribuída ao método de teste criado e verifique seu é possível refatorá-lo (fazer um Extract Method, por exemplo).

Contudo, se continuar difícil testar uma determinada funcionalidade é porque não deve ser seu código de teste que está ruim, mas, infelizmente, o modelo que você criou/planejou para a(s) classe(s) participante(s) do teste não ficou “testável”.

Testabilidade do Modelo

Este conceito de “testabilidade”, ou seja, do código que você escreveu ser fácil de testar, é um dos principais aspectos do TDD. Isto porque o design de seu projeto muda para se tornar “testável”. Muitas vezes aquele diagrama de classes UML que você criou para ajudar a pensar sobre seu modelo e, sobretudo, o diagrama de seqüência que lhe ajudou a pensar na interação entre os objetos destas classes, irão sofrer alterações significativas.

Esta é a parte em que o TDD começa a guiar o design de seu modelo. Muitas vezes um modelo que parece muito bem feito num diagrama pode ser dificílimo de testar. E por que isto acontece ? Acontece porque os testes forçam seu modelo a expor responsabilidades antes não percebidas, a tornar as dependências entre as classes mais explícitas e também deixam-no mais próximo de como ele será utilizado, o que, no diagrama, pode estar bem longe da realidade (dependendo, claro, da experiência de seu criador).

Daí, os métodos mudam, outros aparecem, classes antes não detectadas surgem, dependências são deixadas visíveis, bem claras e quando você voltar e olhá-lo num diagrama para ver o que se tornou, você terá uma agradável surpresa: seu modelo melhorou !

As verificações forçarão a criação de um modelo mais simples e flexível, mais coeso e bem menos acoplado. Você perceberá quando algo no modelo estiver ruim, pois provavelmente começará a sentir dificuldades para testá-lo. Esta será a hora de adaptá-lo, de torná-lo mais leve, de deixá-lo apto a ser verificado.

Este é o impacto que diferencia criar os testes antes versus criar os testes depois. Você não tem os benefícios da melhoria do modelo se criar os testes depois. E sofrerá um bocado pra fazer alguns testes.

testability

Quando o teste é feito após o código ter sido implementado, você precisará encontrar meios de conseguir retirar a informação que você precisa verificar. Em muitos casos, como a classe não foi pensada para fornecê-la, você precisará alterar seu código ou o código de classes à ela relacionadas. Dependências não poderão ser trocadas por substitutos, pois o modelo não foi planejado para testes. Assim, tudo fica um pouco mais complicado.

Criando os testes antes, você definirá de antemão como obter as informações desejadas e planejará a possibilidade de substituição de dependências, facilitando e acelerando os testes.

UML

Então se os diagramas acabam mudando, qual a necessidade de criá-los ? Creio que a UML é uma excelente ferramenta, sendo válida independente da forma como o projeto seja implementado. Mesmo se o modelo precisar ser adaptado para ficar testável. O exercício de modelagem é importante para se criar uma visão geral do problema, pensar sobre o relacionamento das classes, antever problemas e pré-definir regras de negócio. Um diagrama de classes bem construído, por exemplo, pode servir como um bom ponto de partida para a construção do modelo que será lapidado pelos testes.

Isto pode parecer um pouco contraditório para os puristas de TDD, mas vejo a representação visual como um meio de documentação válido para o projeto. Principalmente diagramas conceituais. É muito mais simples expressar o modelo de um projeto de um forma visual e facilitar a comunicação com os integrantes da equipe. A agilidade da representação visual cai como aquela máxima: “uma imagem vale por mil palavras”.

logo_uml

São vários os benefícios da representação visual e estas justificam o uso de uma ferramenta de sincronização dos diagramas com o código, já que se tornaria inviável a atualização manual dos mesmos. Diagramas de interação, por exemplo, como o de seqüência ou de colaboração, podem sofrer tantas modificações que o custo de mantê-los pode desmotivar sua manutenção.

A contradição entre a UML e o TDD pode ser definida rapidamente assim: Com a UML, você define o modelo através da criação dos diagramas, escreve o código para implementá-los e depois cria os testes. Com TDD, você define o modelo através da criação dos testes e cria o código.

Meu ponto é: crie um rascunho para o modelo através da criação dos diagramas, deixe os testes definirem o modelo final (“testável”), crie o código e sincronize os diagramas. Assim, é tirado proveito dos dois lados.

Documentação Executável

No caso de equipes que não necessitam de diagramas como artefatos para documentação da aplicação, elas ainda podem se beneficiar da “documentação executável” criado pelos testes. Como um manual de utilização do código da aplicação, através do código dos testes é possível aprender a utilizar uma determinada classe e saber exatamente como sua instância se comporta, isoladamente ou em conjunto. Esta documentação estará sempre atualizada, pois os testes são executados freqüentemente, e conterão as regras de negócio e restrições que permeiam o modelo, sendo uma excelente forma (não visual) de conhecê-lo.

Mesmo para as equipes que usam documentação visual, a documentação criada pelos testes deve ser sempre considerada como uma boa fonte de consulta para o conhecimento da aplicação.

quarta-feira, 4 de março de 2009

Qt com licença LGPL

A Nokia decidiu permitir a adoção da Lesser General Public License (LGPL) versão 2.1 opcionalmente à GPL 3 para seu framework de construção de interfaces gráficas para desktop e dispositivos portáveis, o Qt. A Qt 4.5, liberada ontem, já saiu com esta licença.

Na prática, significa que a versão do framework poderá ser usada para fins comerciais e assim mais pessoas e empresas se interessarão a investir no desenvolvimento do framework, ganhando tanto a comunidade quanto a Nokia, que poderá incorporar as novidades e correções à sua versão paga.

googleearth

Google Earth, uma das diversas aplicações que usam Qt

Veja também:anúncio da Nokia sobre a liberação do Qt como LGPL.

terça-feira, 3 de março de 2009

Revistas: ESM edições 1 e 2

Para quem gosta de ler artigos relacionados à Engenharia de Software, aí vão duas edições gratuitas da Engenharia de Software Magazine, da editora DevMedia, disponíveis para download.

Edição 1

Capa da edição 1

 

 

 

 

 

 

 

 

pdf Download em baixa resolução
pdf Download em alta resolução

Edição 2

Capa da edição 2

 

 

 

 

 

 

 

 

pdf Download em baixa resolução
pdf Download em alta resolução

Aproveitem !

sexta-feira, 27 de fevereiro de 2009

Funcionamento dos frameworks xUnit - Parte 2/2

Para complementar o descrito na Parte 1, vamos ver o uso de test fixtures e dos métodos setUp e tearDown.

Em muitos casos quando estamos construindo uma classe de testes para verificar determinada funcionalidade, diversos métodos de teste irão operar sobre um mesmo objeto ou conjunto de objetos. Ao escrevermos código para configurar o estado destes objetos repetidamente, em cada método de teste, estaremos duplicando código desnecessariamente.

Ao invés disto, podemos utilizar um test fixture, isto é,  um conjunto de dados de teste que será compartilhado por diversos testes. Geralmente este conjunto de dados serão objetos que alocaremos para serem verificados nos testes.

Para fazer isto numa xUnit, geralmente existem os métodos setUp e tearDown. No primeiro alocamos e configuramos os objetos que serão usados nos diversos métodos de teste. No segundo, destruímos estes objetos.

Como você já deve ter imaginado, estes objetos serão atributos da classe de testes, para que possam ser alocados por setUp e desalocados por tearDown.

A sua classe de teste, filha de TestCase, executa cada um dos métodos de teste que você criou da seguinte forma:

  • chama setUp
  • chama seu método de teste
  • chama tearDown

Ou seja, cada método de teste é sempre executado depois de setUp e antes de tearDown, o que permite que os objetos configurados (fixtures) sejam usados em seu teste e logo após descartados.

Esse comportamento faz com que cada método de teste possa ser executado sempre da forma, como se os objetos sob os quais ele opera estivessem “recém configurados”. O método tearDown garante que o dado configurado para o teste seja “resetado” para o próximo teste, fazendo com que os dados de um teste não interfiram no comportamento de outro.

Exemplo (CppUnit):

class TesteContaBancaria : public TestCase
{
public:
...
void setUp();
void tearDown();

private:

void FicaNegativaAoSacarValorMaiorQueSaldo();
void FicaNegativaAoTransferirValorMaiorQueSaldo();

ContaBancaria *_conta; // fixture
};

...

void TesteContaBancaria::setUp()
{
// configura a conta para ser usada nos testes
_conta = new ContaBancaria();
_conta->DefinirSaldo( 1000.00 );
}

void TesteContaBancaria::tearDown()
{
delete _conta;
}

void TesteContaBancaria::FicaNegativaAoSacarValorMaiorQueSaldo()
{
_conta->Sacar( 1000.01 );

assert( _conta->EstaComSaldoNegativo() );
}

void TesteContaBancaria::FicaNegativaAoTransferirValorMaiorQueSaldo()
{
ContaBancaria outraConta;

_conta->Transferir( 1000.01, outraConta );

assert( _conta->EstaComSaldoNegativo() );
}