Eloquent JavaScript – Parte 1

Janeiro 29, 2012

Já programei em Javascript diversas vezes, mas nunca me disciplinei a aprender a linguagem direito. Sempre seguia tutoriais para descobrir o jeito mais direto de fazer o que eu queria.

Recentemente voltei a programar em Javascript e desta vez decidi ler livros introdutórios sobre essa linguagem. Comecei com o Eloquent Javascript, que está disponível gratuitamente online.

Capítulos 1 e 2

Esses dois capítulos apresentam o básico de programação e a sintaxe básica de Javascript. Passei rapidamente por esses dois capítulos. Uma coisa que eu não lembrava (ou não sabia :P) era o seguinte:

Temos 6 tipos em Javascript: number, string, boolean, object, function e undefined.

O interessante é que segundo a especificação do Javascript (ecma) number é implementado como um double 64 bits (padrão IEEE 754), ou seja, 1 bit pra sinal, 11 bits para expoente e 52 bits de precisão. Isso significa que podemos representar inteiros entre -2^{52} - 1 a 2^{52} -1.

Capítulo 3 – Funções

Neste capítulo comenta-se sobre funções em programação geral e em Javascript. Há duas principais novidades que aprendi aqui.

Quando o número de parâmetros passados a uma função é menor que o número de parâmetros exigidos pela mesma, os parâmetros faltantes são completados com undefined. Por outro lado, se o número de parâmetros passados for maior, os parâmetros excedentes são descartados.

A outra coisa é que apenas funções definem escopo. Ao contrário de linguagens como C++, blocos ou laços não definem escopo. Assim, considere o exemplo abaixo:

var a = 2;
for(var i = 0; i <= 10; i++){
    var a = i;
}
// 'a' vale 10

As variáveis a no código acima se referem à mesma coisa. Agora considere o mesmo exemplo, só que com uma função:

function f(){
    var a = 10; 
}
var a = 2;
f();
// 'a' vale 2

Neste exemplo a variável a tem escopo local em f.

Capítulo 4 – Estruturas de dados: Objetos e Arrays

Uma das principais estruturas em Javascript é o Object. Ele é basicamente um array associativo (também conhecido como dicionário), ou seja, um array onde podemos usar strings como índices e elementos podem ser adicionados dinamicamente.

A sintaxe básica para a instanciação de um objeto é

var obj = new Object();
// ou simplesmente...
var obj = {};

Para inserir uma chave no objeto, podemos usar alguma das seguintes alternativas:

obj["chave"] = valor;
// ou...
obj.chave = valor;
// ou...
var v = "chave";
obj[v] = valor;

Se a chave não existia, ela é criada. Se já existia, seu valor é substituído. Para acessar o valor é da mesma forma, só que se tentarmos acessar o valor de uma chave que não existe, retorna-se undefined.

Para deletar uma chave do dicionário:

delete obj["chave"];
// ou...
delete obj.chave;
// ou...
var v = "chave";
delete obj[v];

Para testar se uma chave está definida no dicionário, usa-se a keyword in:

key in obj; // retorna um boolean

Outra estrutura útil é o Array, que pode ser instanciado como

var arr = new Array();
// ou simplesmente...
var arr = [];

Essa estrutura funciona com um mecanismo parecido com o dicionário, com a principal diferença de que as chaves devem ser números naturais e ao criar uma chave de valor N, todos os índices de 0 a N que ainda não existem são criados também.

Exemplo,

var arr = [];
arr[0] = 2; // arr = [2]
arr[4] = "oi"; // arr = [2, undefined, undefined, undefined, "oi"] 

Capítulo 5 – Tratamento de erros

Javascript possui um mecanismo de tratamento de exceção, com sintaxe try-catch-finally parecida com a de Java:

function foo(){
    throw Error("mensagem de erro");
}

try {
    foo();
}
catch (erro) {
    alert(erro.message); // Imprime "mensagem de erro"
}
finally {
    // Trecho de código A
}
// Trecho de código B

Basicamente qualquer objeto pode ser repassado para a keyword throw e nesse caso o bloco do catch será chamado. No exemplo, a variável erro apontará para o objeto Error, que é pré-definido e possui o campo message.

O bloco do finally é chamado no caso em que ocorre uma interrupção prematura do bloco try ou do catch (via return ou outro throw, por exemplo), representando um fluxo de código alternativo ao trecho B, que provavelmente só deve ser executado na ausência de erros.

Uma dúvida que me surgiu é como tratar diferentes tipos de exceções. Em Java é possível utilizar múltiplos blocos de catch. Já em Javascript, você deve tratar explicitamente através de if e else‘s. Uma alternativa nesse caso é adicionar no objeto um campo errorType contendo uma string, por exemplo [3].

Referências

[1] Dynamically creating keys in javascript associative array
[2] W3 Schools – JavaScript Array Object
[3] Handling specific errors in JavaScript

Anúncios

Buenos Aires

Janeiro 22, 2012

Estive em Buenos Aires a trabalho durante a semana passada inteira. Não pude conhecer muito da cidade pois só tive tempo para fazer turismo no último dia. De qualquer maneira, esse post será um breve registro de minhas experiências na Argentina.

Transporte

Os ônibus são muito baratos, pois parecem que contam com subsídio do governo. Diferentemente do Brasil, lá você paga um valor proporcional à distância até seu destino. Mas mesmo no caso mais caro, creio que não chega a 2 pesos. Além disso, só se aceitam moedas como pagamento.

Para quem está nas proximidades do centro, o metrô (conhecido por subte) é uma boa opção, custando 2.50 pesos (mapa). A linha A é particularmente curiosa devido a seus vagões de madeira.

Linha A - Subte

Táxis não são muito caros. Usei essa opção entre no trecho Aeroporto-hotel. Aliás, o número de táxis é muito grande comparado ao número de veículos particulares. Só é preciso tomar cuidado com taxistas mal-intencionados.

Comida

Do ponto de vista gastronômico, tive recomendações de experimentar o bife de chorizo e bife de lomo que são dois cortes bovinos. Eu gostei bastante. Também tive o privilégio de ir a um churrasco (asado) tipicamente argentino. Diferentemente daqui (pelo menos de São Paulo), o churrasco é feito em fogo mais baixo, deixando a carne assar por mais tempo, resultando em uma textura mais macia.

Lugares

No tour de um dia, visitei alguns lugares famosos como a Casa Rosada, a Catedral Metropolitana, o bairro Puerto Madero, o bairro do Boca, incluindo o estádio do Boca Juniors e el Caminito.



El Caminito

Outras atividades

Durante a semana também fui a um show de tango e pratiquei um esporte chamado padél, que é uma espécie de tênis, só que mais leve, com quadra menor e raquetes que madeira. Eu nunca tinha ouvido falar, mas de acordo com a wikipedia é o segundo esporte mais popular na Argentina!

Conclusão

Algumas impressões: achei as calçadas muito estreitas, pelo menos na parte central da cidade; Achei curioso que alguns bares possuam entregadores para levar o café na bandeja até escritórios próximos; Os argentinos que conheci do trabalho são bastante educados e receptivos.

Senti falta de saber falar espanhol para poder me comunicar melhor e também gostaria de ter tido mais tempo para visitar outros pontos turísticos.


Testes Unitários em Java

Janeiro 8, 2012

Hoje vou discutir um pouco sobre testes unitários em Java, especificamente usando os frameworks JUnit e EasyMock.

Introdução

Basicamente, testes unitários visam garantir que as partes de um programa estão corretas, da maneira mais independente possível. Isso em geral é feito através de assertivas, que verificam se as saídas desses componentes respeitam condições pré-estabelecidas.

Testes unitários são bastante utilizados em uma metodologia de desenvolvimento chamada Test Driven Development (TDD). A ideia básica dessa metodologia é, antes de implementar uma funcionalidade, escrever testes que a verifiquem e então implementar o código mais simples que passe em todos os testes. Os testes criados são geralmente testes unitários automatizados e que devem ser executados a cada nova funcionalidade implementada.

Em Java, há um framework chamado JUnit, que auxilia na criação e execução/automação desse tipo de teste. Já o EasyMock, é um complemento de frameworks como o JUnit e pode ser utilizado para diminuir a dependência entre diferentes partes do código.

JUnit

Usar o JUnit em sua forma mais básica é bem simples. A maior parte da configuração é feita através de anotações. Métodos anotados com @Test são invocados pela classe org.junit.runner.JUnitCore.

A principal vantagem do JUnit é sua integração com diversas ferramentas, como por exemplo o eclipse e o maven. O eclipse provê interfaces para a criação de novas classes de testes e a execução dos testes usando o JUnit. Para mais informações sobre a integração com o eclipse, este tutorial [1] é excelente.

O maven, por sua parte, usa na sua convenção de diretórios o src/test, onde devem ser colocados os fontes de testes. Além disso, à fase test está associado o plugin surefire, que roda os testes através do JUnit.

Note que como a fase test é anterior à fase package ou install, na maior parte das vezes em que se faz o build do código, os métodos anotados com @Test são automaticamente executados.

Outra observação é que por padrão, o plugin só considera as classes com os nomes dentro de um desses padrões: **/*Test.java, **/Test*.java ou **/*TestCase.java. Eu particularmente não entendo porque o padrão não inclui também todos os testes do diretório src/test/java/. Enfim, é possível incluir ou excluir classes explicitamente, conforme descrito aqui.

A dependência do JUnit (no meu caso, a versão 4.10) deve ser incluída no arquivo POM:

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <scope>test</scope>
</dependency>

Para pular os testes, principalmente se estes forem muito demorados, pode-se passar o parâmetro
-Dmaven.test.skip=true para o maven.

EasyMock

Dado o princípio de testes unitários de só testar um dado método ou uma função, é importante que isolemos esse pedaço de código de dependências externas. Para isso, podemos usar mocks, que visam reproduzir o comportamento da classe externa.

O framework EasyMock fornece uma maneira simples de criar esses mocks. Dada uma interface java, podemos criar um mock que “implementa” essa interface. Podemos então especificar, para cada método, qual o valor esperado para uma dada entrada.

Como um exemplo, podemos definir uma interface que provê dados de entrada. Para o código que vai usá-la não importa se os dados virão de uma base de dados, arquivo de texto, entrada padrão, etc. A restrição é que os métodos especificados pela interface sejam definidos.

public interface IDataReader {    
    enum Mode {
        MODE1,
        MODE2
    }
    int getValue(Mode mode);
}

Na nossa interface de exemplo, temos um método que retorna um valor de acordo com um modo.

Para facilitar os testes unitários, podemos usar o design pattern chamado injeção de dependência (dependency injection). Nesse padrão, temos um consumidor que faz uso da interface de maneira transparente e o injetor que escolhe a implementação dessa interface.

A ideia é que o injetor fique fora do consumidor, para que possamos controlá-lo sem mexer em seu código. Uma possibilidade é manter uma referência interna para a classe que provê a implementação, e que possamos setar esse membro externamente. Por exemplo, vamos criar a seguinte classe:

public class App {

    private IDataReader dataReader;
	
    public App(IDataReader dataReader){
        this.dataReader = dataReader;
    }
}

Note que passamos um objeto de uma classe que implementa IDataReader pelo construtor. Dessa forma, ao criar uma nova implementação para IDataReader (no nosso caso será o mock) não precisamos mexer em uma linha sequer do código de App.java.

Vamos adicionar o método mutiply, que fará uso da interface IDataReader. O código completo da classe App fica:

public class App 
{
    private IDataReader dataReader;
    
    public App(IDataReader dataReader){
        this.dataReader = dataReader;
    }
    public int multiply(){
        int value1 = dataReader.getValue(Mode.MODE1);
        int value2 = dataReader.getValue(Mode.MODE2);
        return value1 * value2;
    }
}

Neste exemplo de brinquedo, multiplicamos os resultados das chamadas do método getValue para cada um dos dois modos. Agora vamos criar a classe pare testar o método multiply.

public class AppTest {

    private IDataReader mockReader;
	
    @Before
    public void setup(){
        mockReader = EasyMock.createMock(IDataReader.class);
    }
	
    @Test
    public void testApp(){
				
        EasyMock.expect(mockReader.getValue(Mode.MODE1)).andReturn(6);
        EasyMock.expect(mockReader.getValue(Mode.MODE2)).andReturn(7);
		
        EasyMock.replay(mockReader);
		
        App tester = new App(mockReader);
		
        assertEquals("Result", 42, tester.multiply());
    }
}

No código acima, o membro mockReader contém uma referência para a implementação mock da interface IDataReader. O método setup anotado com @Before, é chamado antes de cada teste rodar e consiste em criar uma instância mock.

A sintaxe da função estática expect é meio estranha, mas podemos ler da seguinte maneira: estamos dizendo que quando o método getValue() for chamado com o parâmetro mode.MODE1, ele retornará 6, enquanto que com o parâmetro mode.MODE2() retornará 7.

Além disso, por padrão supõe-se que o método será chamado apenas uma vez. Se a chamada de tester.mutiply implica na chamada de getValue1 (getValue2) mais de uma vez, o teste apontará um erro. É possível especificar o número de vezes que o método será chamado, com o método times:

EasyMock.expect(mockReader.getValue(mode.MODE1)).andReturn(6).times(4);

Nesse caso o método deverá ser chamado no máximo 4 vezes. Se quisermos relaxar a condição de contagem de uso, podemos usar métodos como times(int min, int max), atLeastOnce() e anyTimes() [4].

O método estático replay serve para consolidar as definições feitas com o expect. Finalmente a implementação mock é passada como parâmetro para o construtor da classe App e podemos verificar se a multiplicação está se comportando como o esperado.

Para incluir o easymock como dependência do maven, basta incluir:

<dependency>
  <groupId>org.easymock</groupId>
  <artifactId>easymock</artifactId>
  <version>3.1</version>
</dependency>

Referências

[1] http://www.vogella.de/articles/JUnit/article.html
[2] Wikipedia – Unit Testing
[3] Wikipedia – Dependency Injection
[4] Easy Mock Documentation
[5] Easy Mock Java Docs
[6] http://www.vogella.de/articles/EasyMock/article.html