Build, Programming

O erro do criador do Ant

No livro Pragmatic Project Automation, publicado em 2004, há um trecho em que James Duncan Davidson (criador do Ant e do Tomcat) admite que foi um erro ter usado XML para descrever os passos do build do Ant.

Segue uma tradução livre:

O criador do Ant exorciza um de seus demônios
por James Duncan Davidson

A primeira versão do Ant não tinha esse monte de tags que você vê espalhadas pelos arquivos de build. Ao invés disso, era usado um arquivo de properties e a classe java.util.Properties para definir quais tasks deveriam ser executadas para um determinado target. Funcionou bem para pequenos projetos mas começou a entrar em colapso à medida que os projetos cresciam.

O motivo do colapso era a maneira que o Ant enxerga o mundo: um projeto é uma coleção de targets (alvos). Um target é uma coleção de tasks (tarefas). Cada task tem um conjunto de propriedades. É obviamente uma árvore hierárquica. Porém, arquivos .properties tem apenas mapeamentos chave=valor, nos quais essa estrututura de árvore não encaixa.

Eu queria um formato de arquivos hierárquico que capturasse a visão de mundo do Ant. Mas eu não queria criar meu próprio formato. Eu queria usar um formato padrão e, mais importante, eu não queria criar um parser. Eu queria reusar o trabalho dos outros. Eu queria o caminho mais fácil.

Na época, XML estava despontando no radar. A spec tinha sido finalizada, ainda que bem recentemente. SAX tinha se tornado um padrão de-facto, mas não tínhamos JAXP ainda. Eu estava convencido que XML era a next big thing depois do Java. Código portável e dados portáveis. Duas frases de efeito que ficam bem juntas.

E já que os dados no XML tem uma estrutura de árvore, parecia perfeito para o tipo de coisa que precisava ser expressado em um arquivo de build. Adicione o fato de que XML era um formato de texto editável manualmente, e parecia um casamento feito nos céus. E eu não precisava criar um parser. Trato feito.

Em retrospecto, XML provavelmente não foi a escolha correta como parecia. Eu tenho visto arquivos de build com centenas, e até milhares, de linhas e, nesses tamanhos, editar XML não é tão amigável como eu esperava. Além disso, quando você mistura XML e os mecanismos baseados em reflection do Ant que permitem estender e customizar tasks, você acaba com um ambiente que oferece o poder e a flexibilidade de uma linguagem de script — mas com a dor de cabeça de tentar expressar essa flexibilidade com tags no XML.

Minha intenção nunca foi que o formato de arquivo se transformasse em um linguagem de script. Afinal de contas, minha visão original do Ant era que teríamos a declaração de algumas propriedades que descreveriam o projeto e que as tasks escritas em Java fariam toda a lógica. Os atuais desenvolvedores do Ant em geral pensam o mesmo.

Mas quando eu fundi XML e reflection no Ant, fiz algo que é 70–80% de um ambiente de script. Só que não percebi na época. Negar que as pessoas iriam usar o XML do Ant como uma linguagem de script é equivalente a pedir para que finjam que açúcar não é doce.

Se eu soubesse o que sei agora, eu teria tentado usar uma linguagem de script de verdade, como JavaScript via o componente Rhino ou Python via Jython, com bindings para objetos Java que implementariam a funcionalidade expressadas nas tasks. Então, haveria uma forma natural de expressar lógica, e não estaríamos presos ao XML como formato que é muito ruim para o maneira como as pessoas querem usar a ferramenta.

Um processo de build é algo que comumente será customizado. Usar XML para definir os passos de um build foi um erro no Ant. E que foi herdado pelo Maven.

O poder de uma linguagem de script casa muito bem com a definição de um processo de build. E isso foi levado em conta em ferramentas mais novas como Gradle, que usa a linguagem Groovy.

Anúncios
Javascript, Programming

Criando um jogo em Javascript [5/5] – Pontuação

Que tal finalizar nossa versão do jogo da galinha do Atari?

Fizemos o pano de fundo do jogo, no primeiro post.

A movimentação do personagem principal a partir do teclado foi feita no segundo post.

Alguns carros movimentados automaticamente foram inseridos no terceiro post.

No quarto post, o GAME OVER foi detectado ao ocorrer a colisão dos carros e nosso personagem principal.

Iniciando a pontuação

Vamos criar uma variável pontos para armazenar o número de pontos e também uma função desenhaPontos que, quando invocada, desenha os pontos no canto superior esquerdo da página.

var pontos = 0;
function desenhaPontos(){
    contexto.fillStyle = "black";
    contexto.font="12pt Monospace";
    contexto.fillText(pontos, 5, 20);
}

Na função do setTimeout, precisamos desenhar os pontos atuais. Devemos invocar a função que acabamos de criar depois de desenhar o fundo:

setInterval(function(){
    desenhaFundo();
    desenhaPontos();
    dilminha.desenhaImagem();
    carrinhoAmarelo.desenhaImagem();
    carrinhoAzul.desenhaImagem();
    carrinhoPolicia.desenhaImagem();

    //restante do código...
},50);

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/pontuacao/15-zerado.html

Pontuação zerada

Continue lendo

Javascript, Programming

Criando um jogo em Javascript [4/5] – Colisão

Vamos continuar nossa versão em Javascript do jogo da galinha do Atari.

No primeiro post, fizemos o pano de fundo do jogo.

Já no segundo post, fizemos o personagem principal, movendo-o a partir das setas do teclado e limitando até onde é possível ir.

Depois, no terceiro post, colocamos alguns carros que são movimentados automaticamente.

Agora, vamos detectar a colisão dos carros e nosso personagem principal, ocasionando um GAME OVER.

Detectando a colisão

Tanto o personagem principal como os três carrinhos são objetos criados a partir do construtor Sprite. Todos esses objetos tem as propriedades x, y, largura e altura.

Uma maneira de saber se houve colisão é considerar que as figuras são retângulos e verificar se houve intersecção.

Colisão de retângulos

Vamos definir um método colidiu no construtor Sprite que retorna true se houve intersecção entre os retângulos dos personagens:

function Sprite(caminhoDaImagem, xInicial, yInicial) {
    //restando do código...

    this.colidiu = function(outro){
        var colidiuNoXTopo = outro.x >= this.x && outro.x <= (this.x + this.largura);
        var colidiuNoYTopo = outro.y >= this.y && outro.y <= (this.y + this.altura);
        var colidiuNoXBase = (outro.x + outro.largura) >= this.x && (outro.x + + outro.largura) <= (this.x + this.largura);
        var colidiuNoYBase = (outro.y + outro.altura) >= this.y && (outro.y + outro.altura) <= (this.y + this.altura);
        return (colidiuNoXTopo && colidiuNoYTopo) || (colidiuNoXBase && colidiuNoYBase);
    }
}

Na função do setTimeout, logo após mover os carrinhos vamos verificar se algum colidiu com o personagem principal. Se houve colisão, vamos setar como verdadeira a variável gameOver.

Ainda na mesma função, depois de desenhar o fundo, o personagem principal e os carros, caso o jogo tenha terminado, vamos escrever com uma fonte vermelha bem grande o texto GAME OVER. Para isso, devemos utilizar a função fillText do contexto 2D. Também colocaremos um return antecipado, impedindo que os carros movam-se se o jogo tiver terminado.

Teremos então:

setInterval(function(){
    desenhaFundo();
    dilminha.desenhaImagem();
    carrinhoAmarelo.desenhaImagem();
    carrinhoAzul.desenhaImagem();
    carrinhoPolicia.desenhaImagem();

    if(gameOver){
        contexto.fillStyle = "red";
        contexto.font="Bold 80px Sans";
        contexto.fillText("GAME OVER", canvas.width/16, canvas.height/2+20);
        return;
    }

    carrinhoAmarelo.move(7, 0);
    carrinhoAzul.move(-5, 0);
    carrinhoPolicia.move(10, 0);

    if(carrinhoAmarelo.colidiu(dilminha)
        || carrinhoAzul.colidiu(dilminha)
        || carrinhoPolicia.colidiu(dilminha)){
        gameOver = true;
    }
},50);

Outra coisa que precisamos fazer é impedir que o personagem principal seja movido pelo teclado depois do GAME OVER. Para isso, faremos um retorno antecipado caso a variável gameOver esteja setada.

document.onkeydown = function(event) {
    if(gameOver){
        return;
    }
    //restante do código...
}

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/colidindo/13-colisao.html

Colisão do carro amarelo com o personagem

Continue lendo

Javascript, Programming

Criando um jogo em Javascript [3/5] – Carros

Daremos continuidade à implementação em Javascript de uma versão do jogo da galinha do Atari.

No primeiro post, fizemos o pano de fundo do jogo.

Já no segundo post, fizemos o personagem principal, movendo-o a partir das setas do teclado e limitando até onde é possível ir.

Agora, vamos colocar alguns carros, que poderão colidir com o nosso personagem principal.

Carros

Colocaremos, sobre o nosso fundo, três carros:

Carrinho amareloCarrinho azulCarrinho de polícia

Essas imagens podem ser baixadas em:
http://a-dilminha.appspot.com/carrinho-amarelo.png
http://a-dilminha.appspot.com/carrinho-azul.png
http://a-dilminha.appspot.com/carrinho-policia.png

Precisamos inseri-las na página.

Para o nosso personagem principal, fizemos da seguinte maneira:

function desenhaImagem(){
   contexto.drawImage(imagem, x, y, imagem.width, imagem.height);
};

//personagem principal
var imagem = new Image();
imagem.src = "../../dilminha.png";
var x = 320;
var y = 400;
imagem.onload = desenhaImagem;

Para os carros, devemos fazer coisa parecida, alterando os valores do src, do x e do y. Então, teríamos o seguinte código:

//carrinho amarelo
var imagem2 = new Image();
imagem2.src = "../../carrinho-amarelo.png";
var x2 = -10;
var y2 = 300;
imagem2.onload = desenhaImagem;

//carrinho azul
var imagem3 = new Image();
imagem3.src = "../../carrinho-azul.png";
var x3 = 560;
var y3 = 200;
imagem3.onload = desenhaImagem;

//carrinho de polícia
var imagem4 = new Image();
imagem4.src = "../../carrinho-policia.png";
var x4 = 10;
var y4 = 100;
imagem4.onload = desenhaImagem;

Repare nos números para o x e y em cada imagem. Quanto maior o x, mais para direita. Quanto maior o y, mais para baixo. Assim, o carrinho amarelo fica na faixa de baixo, bem à esquerda (até um pouco fora da tela). Já o carro azul é posicionado na faixa do meio e à direita. O carrinho de polícia fica na fixa de cima, à esquerda.

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/carros/10-carrinhos.html

Imagem da Dilminha sobre o fundo

Continue lendo