O ContractJ é um conjunto de: anotações + aspectos + um plugin para o eclipse para facilitar o uso disto, mas pode ser utilizado em qualquer ambiente que tenha suporte ao AspectJ.
A idéia básica de Design By Contract é que seja possível documentar todas as pré condições e pós condições de um método, e a partir desta documentação, caso seja passado um parâmetro inválido, ou o estado posterior a execução seja inválido, deve ser gerada uma excessão.
O ContractJ possui algumas anotações para definição de pré condições e pós condições, e ja possui aspectos implementados para estas anotações, desta forma ele faz o trabalho sujo de cuidar das condições definidas e gerar excessões quando for necessário, e as próprias anotações ja servem como documentação pois estão exatamente no ponto que possui a pré ou pós condição, e podem caso seja necessário, ser processadas utilizando o APT por exemplo, para geração de algum documento mais formal.
Para ficar um pouco mais claro, vamos pegar um exemplo (o mesmo do site do projeto):
@NotNegative public int calculaExpectativaDeVida (@NotNull Pessoa pessoa);
Este método, precisa receber uma Pessoa existente, por tanto, o parâmetro pessoa, foi anotado com um @NotNull, e claro que a expectativa de vida de alguem não pode ser negativa, então o método foi anotado com um @NotNegative.
A partir deste ponto, todos os que lerem o código vão ficar sabendo que o parâmetro pessoa não pode ser nulo, e que o resultado do calculo não pode ser negativo, ou seja, as pré e pós condições estão corretamente documentadas.
Para prosseguir, o ideal é que o projeto esteja sendo compilado com o AspectJ, existem plugins para o Eclipse, NetBeans e IntelliJ IDEA para facilitar a compilação do código com o AspectJ, mas se você quiser muito, pode também utilizar Load-Time-Weaving para não interferir no processo de compilação do projeto.
Em runtime, utilizando qualquer uma das duas opções apresentadas, se o método calculaExpectativaDeVida receber um parâmetro null, uma InvalidArgumentException sera lançada, e caso por algum erro de programação, o método retorne um valor negativo, sera lançada uma IllegalStateException.
Pronto, temos a documentação, e a verificação em runtime implementadas, sem quase nenhum esforço.
Para melhorar só se isto estivesse integrado com uma ferramenta MDA e as definições de pré e pós condições fossem flexíveis o suficiente para serem lidas do código OCL definido no diagrama UML, mas já é um ótimo começo.
Quem quiser instalar ele para testar, ou até mesmo usar no próximo sistema que for desenvolver, é só usar este Update Site no eclipse: http://update.aspectbrains.org/
Ou então baixar da página do projeto no source forge.
Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!
Tags: Eclipse, Java, produtividade, Trabalho
Fala Urubatan,
Só para efeitos de registro, estou com um projeto também baseado em DBC (Design By Contract) para o Spring chamado de Spring DBC. Ele possue os mesmos recursos do Contract4J (e até alguns a mais) mas com uma pequena diferença: Ele usa aspectos dinâmicos e não estáticos como o Contract4J. Isso significa que você pode criar seus contratos em cima de seus pojos naturalmente, e toda a ‘mágica’ se dará em tempo de execução, através dos pointcuts do Spring.
Dá uma conferida no projeto: http://opensource.atlassian.com/projects/spring/browse/SPR-2698
Grande abraço,
Ricardo Ferreira
Reply to this comment[...] depois que eu escreve um post sobre Design By Contract, na verdade em um dos comentários postados, fiquei sabendo do Spring DBC (Spring Design By [...]
Reply to this commentOlá, Urubatan e outros.
Como vocês estão desenvolvendo um sistema de design by contract para Java, talvez queiram dar uma olhada no sistema Nice (pronuncia-se como em português, não como em inglês; razão, trata-se de palavra francesa). Neste sistema, o design by contract tem exatamente a forma proposta por Bertrand Meyer. Nice também implementa a idéia de objetos transparentes: No caso de classes estáticas, não é preciso declarar classes. Há também um sistema de inferência, o sistema de dispatch atua em todos os argumentos (dispatch múltiplos) com casamento de padrões; isto significa que um método pode ser despachado por duas, três, quatro classes ao mesmo tempo. No caso de despacho apenas pelo primeiro argumento, caimos no caso de Java. Eis um exemplo:
int fact(int n)
requires
n >= 0 : “n! ==> n >= 0″
ensures
result > 0 : “Negative result.”,
result < 10000 : “Number too big.” {
var acc = 1;
for (int i: 1 .. n) {
acc= acc*i;}
return(acc); }
void main(String[] args) {
let win = new Frame(”Applet de Botão”);
let prg = new DbC_Example();
prg.init();
prg.start();
win.setSize(400, 200);
win.add(prg);
win.show(); }
Observe que as classes estáticas não precisam ser declaradas. Se declarar, é verificada a consistência, etc. Além disso, não é preciso declarar as classes a que pertence uma variável. O sistema deduz. A variável pode pertencer a várias classes ao mesmo tempo. No caso acima, não declarei as classes de win e prg. Tudo foi deduzido. Mas se quisesse, poderia ter declarado.
A propósito, Nice não resolve o mais grave problema de Java, que é a falta da otimização TCO. Em um site da SUN, engenheiros da SUN dizem que há planos para implementar uma hard TCO. Neste caso, haveria TCO até entre chamadas de métodos diferentes. A TCO seria feita pela própria máquina virtual Java. Com o Java atual, sem TCO, Java usa memória demais, tornando o sistema lento. Em meus projetos, Java chega a ser de dez a vinte vezes mais lenta do que Scheme, C ou Clean.
A SUN levou dez anos para nos dar geradores. Se esperarmos o TCO deles, vai levar outros dez anos. Então minha idéia é fazer uma soft TCO, como na linguagem Scala. Talvez vocês queiram participar do projeto. A soft TCO só atuaria dentro de um único método, como SCALA.
Bigloo implementa uma hard TCO e consegue desempenho próximo da linguagem C (quatro vezes mais lento, contra vinte vezes, no caso da Java Server 6). O problema com a Bigloo é que exige um runtime muito grande (a bigloo_s tem 700 K, zipado). Queria uma TCO com zero de overhead. Nice tem zero de overhead, ou seja, você só precisa do que Java oferece.
Reply to this comment