Categoria: Desenvolvimento (Página 5 de 8)

Quais anotações usar nos componentes do Spring 3

spring-logo

Como praticamente todos os frameworks modernos, o Spring 3 permite a declaração de componentes (Spring Beans) via anotação, tornando o uso de XML desnecessário. Porém, é comum haver confusão sobre as diferentes anotações que parecem fazer a mesma coisa.

Definindo quais classes o Spring deve considerar

Quando adicionamos uma anotação em uma classe, estamos colocando ali uma meta-informação, isto é, uma informação arbitrária que vai além do código executado e das características da classe como nome, modificador de acesso, etc.

Entretanto, o Spring (ou qualquer outro framework) precisa encontrar e ler a classe com a anotação para que ela possa efetivamente ser usada.

Isso é feito através de configuração XML:

<context:component-scan 
    base-package="br.com.pacote.projeto.service,
                  br.com.pacote.projeto.controller"/>

Ou ainda através da anotação de configuração @ComponentScan:

@Configuration
@ComponentScan({
    "br.com.pacote.projeto.service",
    "br.com.pacote.projeto.controller"})
public class ConfiguracaoSpring { ... }

Nos exemplos acima, especificamos os pacotes onde o Spring irá procurar por classes. Ele irá vasculhar qualquer classe com as anotações de componentes que estão nesses pacotes ou em subpacotes.

Agrupando componentes com estereótipos

Primeiro, existe uma anotação genérica @Component. Com essa anotação, uma classe passa a ser um bean disponível para injeção de dependências nos demais componentes do sistema.

Por outro lado, há também anotações mais específicas que possibilitam marcar as classes com estereótipos, assim como na UML. Dessa forma, os componentes podem ser agrupados por seu “tipo” ou comportamento.

Se uma classe é anotada com @Service pode-se facilmente pressupor que ela contém regras de negócio, transações ou lógica relacionada ao modelo da aplicação.

Se a anotação é @Repository, fica óbvio que a classe implementa o padrão de projeto Repository (que não o mesmo que DAO, mas é de alguma forma análogo).

Por fim, se a anotação é @Controller podemos associar a classe diretamente a um controlador do padrão MVC.

Alguns benefícios

Embora tudo isso a princípio pareça apenas um mero enfeite, é possível listar algumas vantagens:

  • Ajuda na separação lógica de camadas da aplicação.
  • Possibilita a utilização de Programação Orientada a Aspecto (AOP – Aspect Oriented Programming), como usado módulo Spring Data JPA, o qual “gera” dinamicamente a implementação de interfaces anotadas com @Repository.
  • Permite o tratamento pontual de exceções lançadas por camadas específicas, novamente com o exemplo da camada de acesso a dados (@Repository), onde o Spring irá traduzir as exceções de cada driver de banco de dados para classes padronizadas.
  • Você também pode criar qualquer funcionalidade que se aplique por camada, basta usar um pouco a imaginação. 😉

Considerações

Minha única ressalva com relação ao uso das anotações como novo padrão em detrimento dos tradicionais e “verbosos” XML’s é com relação ao desempenho da configuração component-scan. Se definirmos um pacote muito abrangente, isto é, que contém muitas classes, o Spring irá levar um tempo considerável listando as classes a procura das anotações. Mapear os beans em XML ajuda se o tempo de inicialização da aplicação for um requisito importante.


Este artigo foi baseado na minha resposta no StackOverflow em Português!

Which component annotations to use in Spring 3

spring-logo

As the majority of modern frameworks, Spring 3 allows one to declare its components (Spring Beans) via annotations, making XML unnecessary. However, it can cause some confusion about the different annotations available that apparently do the same thing.

Defining where Spring should look for annotations

When we add an annotation to some class, we are putting a meta-information, that is, an arbitrary information that has nothing to do the code or the properties of the class, like its name, modifiers, etc.

However, Spring (as any other framework) needs to find and read annotated classes in order they can effectively be used.

This is done through XML configuration:

<context:component-scan 
    base-package="com.package.project.service,
                  com.package.project.controller"/>

Also through the annotation @ComponentScan:

@Configuration
@ComponentScan({
    "com.package.project.service",
    "com.package.project.controller"})
public class SpringConfiguration { ... }

In the above example, we defined in which packages Spring should search for classes. It’ll look for classes with component annotations in these packages and in their subpackages.

Grouping components with stereotypes

Firstly, there is the generic @Component. This annotation makes one class a bean available for dependency injection to the remaining components of the system.

On the other hand, there are more specific annotations that allow us to mark beans with stereotypes, as in UML. This way, the components can be grouped by their “type” or behavior.

If one class is annotated with @Service you can just suppose it contains business methods, high level transactions or some logic related to the application model.

The annotation @Repository makes it obvious that the component implements Repository design patter (which is not the same of DAO, even though they are somehow analogous).

Finally, the annotation @Controller associates a component with a MVC controller.

The benefits

At first it looks like frills, but actually there are a few advantages:

  • It helps separating the logical layers of the application.
  • It enables Aspect Oriented Programming (AOP), like Spring Data JPA module, which dynamically “implements” interfaces annotated with @Repository.
  • It allows you treat separately exceptions that are specific of a layer, using again the example of data access layer (@Repository), where Spring will translate specific database driver exceptions into standardized classes.
  • You can also create any new feature specific to a layer. Just use your imagination and creativity. 😉

Considerations

The performance of “component-scan” is my main reservation about annotations as a new standard against the traditional and verbose XMLs. If we configure a broad package, that is, containing many classes, it can slows down the application startup, since Spring will take some time to list all classes and check them for annotations. Maybe mapping your beans with XML will be better if startup time is an important requirement for you.


This article was based on my Answer on StackOverflow in Portuguese!

HTML e Javascript: trocando dois elementos de posição (swap)

Você tem dois elementos quaisquer na estrutura do documento da sua página (DOM). Como invertê-los, isto é, colocar um no lugar do outro?

Abordagens para solução

O problema não é tão simples quanto pode parecer a princípio, pois ao movermos um dos elementos, perdemos sua posição original e não é tão fácil armazenar a localização de um elemento em Javascript.

Vamos analisar algumas abordagens nos tópicos abaixo.

Variável auxiliar

Podemos usar o princípio básico da troca de valores entre variáveis. Por exemplo, dadas as variáveis A e B, podemos trocar os valores usando uma variável auxiliar AUX:

AUX = A
A = B
B = AUX

Simples, não? Mas estamos aqui falando da posição de elementos na estrutura HTML. O que seria nossa variável auxiliar? A resposta é: um elemento criado dinamicamente.

Colocando isso numa solução reutilizável em forma de um plugin para jQuery:

(function ($) {
    $.fn.swap = function(anotherElement) {
        var a = $(this).get(0);
        var b = $(anotherElement).get(0);
        var swap = document.createElement('span');
        a.parentNode.insertBefore(swap, a);
        b.parentNode.insertBefore(a, b);
        swap.parentNode.insertBefore(b, swap);
        swap.remove();
    }
}(jQuery));

Demo no jsfiddle

A utilização é muito simples:

$(seletorElemento).swap(seletorOutroElemento);

Puff! Os elementos foram trocados.

Armazenando a posição do elemento

Outra abordagem, que não envolve a criação de um elemento adicional, é armazenar a posição de pelo menos um dos elementos. Na verdade, só precisamos armazenar a posição do elemento que será movido primeiro.

O problema está em como representar a posição de um elemento, pois a sua inserção será feita relativamente a algum outro. Se usarmos o anterior como referência, teremos problemas se ele for o primeiro. Se usarmos o posterior, teremos problemas se ele for o último. Pior, os dois elementos a serem trocados podem estar próximos um do outro, em sequência!

Não vou descrever minuciosamente as nuances do algoritmo que desenvolvi porque não creio ser interessante, mas considere a seguinte implementação:

(function ($) {

    $.fn.swap = function(anotherElement) {

        var sameParentStrategy = function(one, another) {
            var oneIndex = one.index();
            var anotherIndex = another.index();
            var swapFunction = function(first, second, firstIndex, secondIndex) {
                if (firstIndex == secondIndex - 1) {
                    first.insertAfter(second);
                } else {
                    var secondPrevious = second.prev();
                    second.insertAfter(first);
                    first.insertAfter(secondPrevious);
                }
            }
            if (oneIndex < anotherIndex) {
                swapFunction(one, another, oneIndex, anotherIndex);
            } else {
                swapFunction(another, one, anotherIndex, oneIndex);
            }
        };

        var differentParentsStrategy = function(one, another) {
            var positionStrategy = function(e) {
                var previous = e.prev();
                var next = e.next();
                var parent = e.parent();
                if (previous.length > 0) {
                    return function(e) {
                        e.insertAfter(previous);
                    };
                } else if (next.length > 0) {
                    return function(e) {
                        e.insertBefore(next);
                    };
                } else {
                    return function(e) {
                        parent.append(e);
                    };
                }
            }
            var oneStrategy = positionStrategy(one);
            var anotherStrategy = positionStrategy(another);
            oneStrategy(another);
            anotherStrategy(one);
            return this;
        };

        //check better strategy
        var one = $(this);
        var another = $(anotherElement);
        if (one.parent().get(0) == another.parent().get(0)) {
            sameParentStrategy(one, another);
        } else {
            differentParentsStrategy(one, another);
        }

    };

}(jQuery));

Note as diferentes estratégias de troca, dependendo dos elementos serem ou não filhos de um mesmo “pai”.

Demo no jsfiddle.

Clonagem dos elementos

Uma terceira alternativa, um tanto simplista na verdade, é clonar os dois elementos e substituir os originais um pelo outro. Vejamos o código:

(function ($) {
    $.fn.swap = function(anotherElement) {
        // cache elements
        var $div1 = $(this),
            $div2 = $(anotherElement);
        // clone elements and their contents
        var $div1Clone = $div1.clone(),
            $div2Clone = $div2.clone();
        // switch places
        $div1.replaceWith($div2Clone);
        $div2.replaceWith($div1Clone);
    }
}(jQuery));

Análise das soluções

Cada abordagem parece ter seu ponto fraco. Criar um elemento auxiliar deixa qualquer um com um pé atrás por causa da criação e inserção de um elemento “inútil” ao DOM. Porém, a complexidade do algoritmo que calcula a posição dos elementos e as várias funções usadas da API do jQuery chega a dar calafrios na espinha. E quanto a clonar os elementos? Isso não pode ser algo do bem!

Note que a primeira abordagem, por ser simples e direta, pode facilmente ser implementada sem usar a API do jQuery. Usei propositalmente a API nativa do Javascript para gerar um ganho de desempenho, pois, como veremos a seguir, isso faz muita diferença. Já as demais abordagens exigiriam alterações nada triviais para depender apenas da API nativa.

Ao invés conjecturar, vamos logo ao teste de desempenho. Preparei oito cenários com os algoritmos de troca descritos acima. Para cada algoritmo, o desempenho para troca de nós que estão no mesmo nível e o desempenho para troca de nós que estão em locais diferentes do HTML foram medidos separadamente. Além disso, o algoritmo que usa a “variável auxiliar” foi desmembrado em dois: o primeiro usando a API do jQuery e o segundo, como descrito no respectivo tópico, usando a API nativa.

Considere o seguinte gráfico:

Desempenho de algoritmos de swap

A legenda para relacionar cor e algoritmo:

  • Azul escuro: nós no mesmo nível armazenando a posição do elemento.
  • Vermelho: nós em níveis diferentes armazenando a posição do elemento.
  • Amarelo: nós no mesmo nível com variável auxiliar e a API do jQuery.
  • Verde escuro: nós em níveis diferentes com variável auxiliar e a API do jQuery.
  • Roxo: nós no mesmo nível com variável auxiliar e API nativa, sem jQuery.
  • Azul claro: nós em níveis diferentes com variável auxiliar e API nativa, sem jQuery.
  • Pink: nós no mesmo nível usando clonagem.
  • Verde claro: nós de níveis diferentes usando clonagem.

Teste no jsperf

Conclusões

Os resultados confirmaram algumas das suspeitas:

  • A clonagem é muito lenta.
  • Usando a API do jQuery, armazenar o local da variável é mais rápido do que criar e inserir um elemento auxiliar.
  • Porém, usar a API nativa do Javascript gerou um ganho em torno de 10x no desempenho. Mesmo com a alteração no DOM gerada pera inserção da variável auxiliar, o desempenho desta solução superou todas as demais.

Não pretendo aqui tirar nenhum mérito de uma excelente biblioteca como o jQuery, pois em muitos casos ela nos permite obter um desempenho muito superior a uma “solução caseira”. Porém, não devemos tomar qualquer biblioteca por uma solução definitiva para todos os problemas.

Muitos cenários exigirão código específico e usar uma API nativa, de modo a remover camadas de abstração, muitas vezes é o melhor caminho.

Nós, desenvolvedores, devemos ser flexíveis o suficiente para trabalhar em diferentes níveis de abstração. Devemos saber quando “baixar” o nível… 😉

Este artigo foi baseado na minha resposta no StackOverflow em Português e nas respostas de outros excelentes desenvolvedores como Marcelo Gibson e Zuul!

O que são e como funcionam transações em SQL?

Bancos de dados relacionais que operam no padrão SQL em geral são transacionais, isto é, eles permitem a execução de uma sequência de operações como um bloco indivisível de forma a garantir a integridade dos dados em um ambiente com acesso concorrente.

O Problema

Imagine três operações sequenciais que afetam a base de dados e não usamos uma transação para controlá-las. Vamos usar como exemplo um caso de uso comum de um e-commerce:

  1. Verificar se possui o produto em estoque
  2. Inserir um novo registro da compra
  3. Debitar o estoque

Agora vamos supor que dois clientes estão tentando finalizar suas compras neste e-commerce fictício. O servidor recebe duas requisições quase simultaneamente e começa a processar os pedidos na sequência apresentada acima. Os dois pedidos estão sendo processados paralelamente em threads diferentes. Tanto o cliente A quanto o cliente B selecionaram um produto com apenas uma unidade em estoque.

Podemos acabar com a seguinte linha de execução:

  1. Thread A verifica o estoque (passo #1) e insere o registro da compra (passo #2)
  2. thread A é bloqueada e B passa a ser executada
  3. Thread B verifica o estoque (passo #1), o qual ainda não foi debitado, e insere o registro da compra (passo #2)
  4. Thread B atualiza o estoque (passo #3), que agora fica zerado
  5. Thread B é bloqueada e A passa a ser executada
  6. Thread A atualiza o estoque (passo #3), que agora fica negativo!

Apesar de verificarmos o estoque a ordem de execução dos diferentes processos é imprevisível, então neste cenário concorrente ela não traz garantia do valor no passo seguinte.

A Solução

Bancos de dados transacionais usam o conceito ACID:

  • Atomicidade: uma transação é uma sequência de operações indivisível, ou é executado como um todo, ou tudo é desfeito.
  • Consistência: ao final da transação, o estado dos dados deve ser consistente.
  • Isolamento: embora alguns sistemas permitam quebrar o isolamento, em geral, uma transação em andamento não pode ser acessada por outras transações de modo a evitar leitura de um estado inconsistente, uma “sujeira”.
  • Durabilidade: em caso de sucesso (commit) a persistência dos dados deve ser garantida

Para garantir esses conceitos, em geral, os bancos de dados usam bloqueios quando ocorrem acessos simultâneos à mesma estrutura de dados. Ou seja, se alguém já está mexendo nos dados, os demais tem que aguardar sua vez numa fila até ele acabar.

Na prática

Ao usar bancos de dados transacionais, nós podemos usufruir deste controle de gerenciamento por parte dos SGBDRs (Sistemas Gerenciadores de Bancos de Dados Relacionais).

Incluindo o conceito de transação ACID no exemplo anterior, vamos ver como fica a execução:

  1. Thread A inicia uma transação, verifica o estoque (passo #1) e insere o registro da compra (passo #2)
  2. Thread A é bloqueada e B passa a ser executada
  3. Thread B inicia uma transação, mas ao tentar verificar o estoque ela é bloqueada porque a transação de A ainda não acabou
  4. Thread A atualiza o estoque, que agora fica zerado, e faz commit na transação.
  5. Thread B é desbloqueada e passa a ser executada
  6. Thread B conclui a verificação do estoque (passo #1) e retorna um erro pois não encontra o produto disponível no estoque
  7. Thread B executa um rollback para desfazer outras alterações que tenha efetuado, por exemplo, se houve outro produto debitado na mesma transação.

O resultado final é como se somente a thread A tivesse executado e B nunca existisse.

Nem tudo é um mar de rosas

Existem alguns problemas inerentes a transações ACID, sendo o desempenho o maior deles.

Embora seja importante garantir a integridade dos dados, para muitos sistemas onde a disponibilidade é o fator mais crítico um modelo que bloqueia acessos simultâneos torna-se inviável. Este é um dos principais fatores para o surgimento e a adoção de diversos sistemas de bancos de dados não transacionais e NoSQL.

O importante é entender que o uso de transações tem um custo e em algumas ocasiões este pode ser alto demais. Uma das representações mais comuns do trade-off de persistência de dados é a seguinte (retirada deste artigo):

tradeoff-database

O gráfico demonstra que consistência, disponibilidade e particionamento (escalar o banco de dados em diversos nós) são recursos que afetam uns aos outros. Você simplesmente não pode ter o melhor dos três e isso foi provado no teorema de CAP.

Bancos de dados relacionais geralmente sacrificam o particionamento em prol da consistência e da disponibilidade, enquanto alguns sistemas NoSQL sacrificam a consistência dos dados.

Note que o termo “geralmente” ou “em geral” foi cuidadosamente utilizado no artigo porque os diferentes sistemas de bancos de dados permitem vários níveis de configuração de isolamento de transações e acesso simultâneo, possibilitando um ajuste fino do desempenho de cada funcionalidade

Este artigo foi baseado na minha resposta no StackOverflow em Português!

Como desabilitar campos em sistemas web

Quando lidamos com sistemas web, é frequente a necessidade de desabilitarmos algum campo na página, com a finalidade de impedir a alteração por parte do usuário.

O problema é que o navegador não envia campos desabilitados com disabled na submissão do formulário. Esta característica comumente deixa os novatos atordoados.

Solução: readonly

Uma solução é usarmos o atributo readonly, porém existem efeitos colaterais:

  • Se for um campo de texto, o usuário poderá selecionar e copiar o conteúdo, o que pode ser uma vantagem em alguns casos.
  • Além disso, os estilos do campo permanecerão os originais, isto é, o usuário poderá não perceber que se trata de um campo somente-leitura.

Para contornar o segundo ponto e dar feedback visual para o usuário, adicione um estilo para manter a usabilidade, por exemplo, deixando o fundo da caixa um pouco acinzentado.

Exemplo com CSS inline:

<input type="text" value="Valor fixo" 
    style="background: #EEE; cursor: not-allowed; color: #777"
    readonly />

Exemplo com uma classe CSS:

.desabilitado {
    background: #EEE; 
    cursor: not-allowed; 
    color: #777;
}

<input type="text" value="Valor fixo 2" class="desabilitado" readonly />

Veja o exemplo funcional do código acima no jsfiddle.

Considerações de segurança

Alguém pode argumentar que desabilitar campos na tela não é uma boa prática do ponto de vista de Segurança da Informação, pois hoje um usuário pode facilmente burlar essa limitação através da Ferramenta do Desenvolvedor (F12), alterando as propriedades do campo. Isso está correto, em parte.

O importante é entender que a necessidade de desabilitar campos é parte essencial do funcionamento dos sistemas. Não é seu objetivo garantir a segurança da informação daquele campo.

Este artigo tem por objetivo auxiliar o desenvolvedor front-end com um elemento puramente visual e não isenta as validações necessárias no back-end.

Entendido!?

Este artigo foi baseado na minha resposta no StackOverflow em Português!

Executando Python (ou qualquer outra linguagem) no navegador

browsers-war-java-script-engines

Há alguns dias surgiu uma questão muito interessante no StackOverflow em Português sobre a possibilidade de executar uma linguagem arbitrária num browser, assim como é feito hoje com o Javascript.

Como poderíamos executar a nossa própria linguagem numa página web? Vamos encarar o desafio e implementar isso na prática!

Requisitos

Temos dois métodos para incluir código Javascript numa página web.

Dentro da tag <script>:

<script type="text/javascript">
alert('código javascript executando');
</script>

De uma fonte externa:

<script type="text/javascript" src="script.js"></script>

A ideia é permitir a inclusão de nossa linguagem da mesma forma.

Dentro da tag <script>:

<script type="text/nossalinguagem">
...
</script>

De uma fonte externa:

<script type="text/nossalinguagem" src="nosso-script.abc"></script>

Não estou ainda considerando código inline, como às vezes usado em eventos onclick, onchange, etc.

No entanto, existem particularidades na execução de tags <script>:

  • Elas são executadas sequencialmente, na ordem em que aparecem no HTML.
  • Se um script é incluído com o atributo src, o mesmo deve ser baixado e executado antes do navegador continuar a exibir o restante da página ou executar outros scripts. Este é o motivo pelo qual os scripts incluídos em um site devem ficar no final da página (perto do </body>) sempre que possível.

Nossa linguagem deve co-existir com o Javascript numa página HTML, como no trecho abaixo:

<script type="text/javascript">
var a = 6;
</script>
<script type="text/nossalinguagem">
print(a) # deve mostrar 6
</script>

Análise da solução

Como o navegador por padrão ignora linguagens que ele não conhece, não há problemas em declarar tags <script> com um atributo type qualquer. Entretanto, como fazer o navegador executá-lo?

Inicialmente, havia pensado que a única solução seria criar um loader em Javascript capaz de carregar a página e processar o conteúdo, adicionando programaticamente o HTML ao DOM e executando os scripts encontrados. Isso nada mais é que do uma versão do PHP ou algum template processor em Javascript, não é mesmo?

Porém, os navegadores modernos disponibilizam uma API que permite interceptar alterações na página, incluindo a criação de tags durante o carregamento do HTML. Trata-se do MutationObserver.

As possibilidades são extraordinárias!

Usando o MutationObserver

Para usar o MutationObserver, basta instanciá-lo passando em seu construtor uma função listener, a qual receberá como parâmetro as alterações na página, e invocar o método observe informando o elemento que desejamos monitorar, neste caso, todo o documento.

Vejamos um exemplo básico:

// cria instância do observer
var mutationObserver = new MutationObserver(function(mutations) {

    // itera sobre as alterações no documento
    mutations.forEach(function(mutation) {

        // recupera nós adicionados
        var addedNodes = mutation.addedNodes;

    });

});

// inicia monitoração das alterações de nós em qualquer nível do documento
mutationObserver.observe(document, { childList: true, subtree: true })

Só resta verificar se os nós adicionados são da nossa nova linguagem e delegar a execução a um interpretador.

Definindo uma linguagem: Python

Mas qual linguagem utilizar? Deveria ser uma linguagem de alto nível e poderosa, para obter um ganho de produtividade em relação ao Javascript.

Python me parece uma boa escolha!

Construindo (ou emprestando) um interpretador

O primeiro passo seria construir um interpretador em Javascript para nossa linguagem escolhida. Porém, não vamos reinventar a roda! Há diversas implementações desta linguagem em diversas plataformas. Para Javascript temos o Brython, uma implementação do Python 3.

Este projeto já cumpre parcialmente nossos requisitos quanto à interpretação da linguagem em tags <script> e acesso aos valores do Javascript. Porém, os scripts em Python são executados somente após o carregamento de toda a página através do evento onload do body e não conforme a sequência das tags <script> como desejamos.

Veja o exemplo de uso original do Brython:

<body onload="brython({debug:0, cache:'none'})">

Então vamos usarmos o MutationObserver para delegar a execução dos scripts ao Brython assim que o script for encontrado na página, oferecendo uma integração melhor da linguagem e atendendo os requisitos propostos.

Delegando a execução ao Brython

Nossa linguagem depende do interpretador Brython, então precisamos saber como delegar a execução dos scripts para ele. A má notícia é que o Brython não disponibiliza um meio direto para isso. A boa notícia é que lidamos com um projeto open source, então nada melhor que inspecionar o fonte para descobrir como ele faz isso!

Tudo o que precisamos é do trecho:

//define o nome do módulo como 'main' por que está na página principal
**BRYTHON**.$py_module_path['**main**'] = window.location.href;

//executa o analisador/conversor para Javascript 
var $root = **BRYTHON**.py2js($python_source, '**main**');

//recupera o código Javascript 
$javascript = $root.to_js();

Definindo um nome para nossa linguagem de script: Pyscript

Nossa linguagem de script merece um nome próprio. Como luizscript é muito feio, decidi calcular a equação:

Javascript – Java + Python = Pyscript

Então, nossa tag de script será:

<script type="text/pyscript"></script>

Adicionando suporte à linguagem Pyscript

Com toda a bagagem que juntamos até aqui já podemos criar a implementação do MutationObserver para dar suporte ao Pyscript em uma página web.

Vamos criar o arquivo pyscript.js:

//init brython 
brython();

//create observer instance
var mutationObserver = new MutationObserver(function(mutations) {

    //iterate over document changes
    mutations.forEach(function(mutation) {

        //get new node
        var node = mutation.addedNodes[0];

        //is it the type we want?
        if(node && node.tagName === 'SCRIPT' && node.type === 'text/pyscript') {

            //test log
            console.log('Pyscript found!');

            //python source
            var $src;

            //If src attribute is found, do a synchronous ajax to get 
            //the code in order to execute it immediately
            if (node.src!=='') {

                if (window.XMLHttpRequest){
                    // for IE7+, Firefox, Chrome, Opera, Safari
                    var $xmlhttp = new XMLHttpRequest();
                } else {
                    // for IE6, IE5
                    var $xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                $xmlhttp.open('GET', node.src, false);
                $xmlhttp.send();
                if ($xmlhttp.readyState === 4 && $xmlhttp.status === 200) {
                    $src = $xmlhttp.responseText;
                }
                if ($src === undefined) { // houston, we have a problem!!!
                    console.log('Error loading pyscript: ' + node.src);
                    return;
                }

            } else {

                //without src, source is tag content
                $src = node.textContent || node.innerText;

            }

            //python -> javascript
            __BRYTHON__.$py_module_path['__main__'] = window.location.href;
            var $root = __BRYTHON__.py2js($src, '__main__');
            var $jssrc = $root.to_js();

            //eval in global scope
            if (window.execScript) {
               window.execScript($jssrc);
               return;
            }

            //fix for old browsers
            var fn = function() {
                window.eval.call(window, $jssrc);
            };
            fn();
        } 
    });    

});

//init observer, monitoring changes in all nodes of any level
mutationObserver.observe(document, { childList: true, subtree: true });

O código acima inicia um observador (MutationObserver) para todos os elementos da página. Se uma tag <script> for encontrada cuja linguagem (atributo type) for text/pyscript, então o código será delegado ao Brython. No caso da tag ter o atributo src, nos dizendo que o código Python está em um arquivo externo, então fazemos uma chamada Ajax síncrona para recuperar o código e executá-lo imediatamente.

Aplicando numa página web

Para a utilização da nossa linguagem Pyscript em uma página qualquer, precisamos incluir tanto o Brython quanto nossa implementação do MutationObserver, nesta ordem, logo no início do código HTML.

Vejamos o exemplo:

<html> 
<head> 
<script type="text/javascript" src="brython.js"></script> 
<script type="text/javascript" src="pyscript.js"></script>

E – voilà – temos nossa própria linguagem rodando na página!

Um exemplo prático

<!DOCTYPE html>  
<html> 
<head> 
<meta charset="UTF-8"> 
<title>Pyscript Test Page</title>

<!-- init brython and pyscript --> 
<script type="text/javascript" src="brython.js"></script> 
<script type="text/javascript" src="pyscript.js"></script>

<!-- set javascript variable --> 
<script type="text/javascript"> 
var value = 1; 
</script>

<!-- python: print text and javascript variable --> 
<script type="text/pyscript"> 
print('Print Test!!!') 
print(value) 
</script>

</head>

<body> 
    <div id="content">Conteúdo</div> 
</body>

<!-- python: browser interaction --> 
<script type="text/pyscript"> 
from _browser import doc, alert

alert('Variable value: ' + str(value))

mylist = ['items', 'of', 'mylist'] 
doc['content'].text = 'Content from python: ' + ' '.join(mylist) 
</script>

<!-- python: execute external script --> 
<script type="text/pyscript" src="myscript.py"></script>

</html>

Nesta página, após incluir nossas dependências no início, existem várias tags de script:

  • A primeira executa Javascript que inicializa a variável value.
  • A segunda executa Python e imprime a variável value no console do navegador.
  • A terceira executa Python e interage com o navegador, exibindo uma caixa de alerta e manipulando o conteúdo (texto) do elemento <div id="content">.
  • A quarta e última executa Python a partir de um arquivo externo.

O conteúdo do arquivo myscript.py é bem simples. Vejamos:

d = { '11': 'um', '22': 'dois' }
for i in d: print(i, '=', d[i])

O script acima cria um “dicionário” d (dict) e então exibe chaves e valores de seus elementos num loop for.

Voltando um pouco ao terceiro script, note que importamos a biblioteca _browser, pertencente ao Brython. Ela nos dá uma interface para acessar as funcionalidades do navegador de forma simples e direta.

É importante observar que o Brython não contém todas as bibliotecas em seu script principal. Para cada import é feito o download da respectiva biblioteca, a não ser que a mesma já tenha sido carregada em um import anterior ou incluída numa tag <script>.

Assista ao vivo

Quer ver o exemplo funcionando? Ele está disponível no link http://utluiz.github.io/pyscript/!

Nota: não se esqueça de acessar a ferramenta do desenvolvedor (F12) para verificar o console!

Quer o código-fonte? Ele está disponível na minha conta do Github: https://github.com/utluiz/utluiz.github.io!

Algumas considerações sobre desempenho

A esta altura, um desenvolvedor mais experiente já estaria se coçando todo sobre a questão do desempenho dessa solução.

Existem iniciativas das empresas que desenvolvem navegadores (Google, Mozilla, etc.) para criar soluções que melhoram o desempenho do Javascript. Hoje, executar código no navegador não é mais um problema. Mas será que isso é suficiente para suportar algo tão profundo quanto uma nova linguagem?

Obviamente, a conversão de código Python para Javascript é muito lenta! Por outro lado, o Brython coloca o código-fonte convertido em um cache para não precisar realizar o processo novamente. Ao analisar o código-fonte do Brython me deparei com soluções de armazenamento usando a API local storage do HTML5, então mesmo se a página for recarregada a conversão não será feita novamente para o mesmo bloco de script.

Mas e quanto à execução? Se o código final executado é em Javascript, então o navegador consegue fazer as mesmas otimizações que no código nativo! Bem, mas isso não significa que será tão eficiente quanto código nativo, afinal existe um overhead natural, pois cada instrução Python pode gerar várias instruções em Javscript.

Limitações da solução

Devido a limitações do Brython, o código Javascript não consegue acessar os objetos e variáveis definidos no código Python. De qualquer forma, não consigo ver isso como uma grande necessidade.

Outra limitação é quanto a código inline mencionado no início do artigo. Por enquanto, não podemos fazer algo como no código abaixo:

<button onclick="python: print(1)">Botão</button>

Não que seja impossível. Poderíamos manipular o valor do atributo onclick dentro do MutationObserver, substituindo-o por uma função Javascript que delega a execução do código para o Brython! Bem, já está meio tarde, então deixo isso como lição de casa. 😉

De qualquer forma, essa limitação é facilmente contornada removendo o atributo onclick e adicionando um listener ao respectivo evento através de código Python, como nos é informado na própria documentação do Brython:

btn.bind('click', show)

Compatibilidade com navegadores

Segundo a documentação, o MutationObserver é compatível com o seguintes navegadores:

  • Google Chrome: versão 26 em diante
  • Mozilla Firefox: versão 14 em diante
  • Internet Explorer: versão 11 em diante
  • Opera: versão 15 em diante
  • Safari: versão 6 em diante

Como sempre, o mais “atrasadinho” é o Internet Explorer. Porém, estamos olhando para o futuro. Em alguns anos a maioria dos usuários do IE poderá executar nossa solução sem dificuldades.

A documentação do Brython não informa sobre sua compatibilidade, mas olhando o código-fonte encontrei implementações específicas para IE 6 e 7. Portanto, a limitação deve ficar mesmo com o MutationObserver.

Considerações finais

Na prática, creio ainda não ser viável aplicar esse tipo de solução em aplicações reais. Por outro lado, é um ótimo exercício!

O que podemos esperar do futuro? Muitos desenvolvedores estão ansiosos por rodar suas linguagens prediletas no navegador!

Hoje JVMs como a do Java já executam diversas linguagens como Scala, Ruby, Python, PHP e assim por diante. Quem sabe, em breve, poderemos testemunhar a ascensão da liberdade de linguagem dentro dos navegadores web!

Instalando, Configurando e Usando o Eclipse Kepler

O Eclipse é um IDE (Integrated Development Environment, ou Ambiente de Desenvolvimento Integrado) extremamente poderoso e flexível, sendo o mais utilizado no mercado e para diversas finalidades: desenvolvimento Java, Android, C++, modelagem de processos, desenho de relatórios e assim por diante.

Utilizar um bom IDE é essencial para a produtividade, pois suas inúmeras ferramentas e funcionalidades farão a diferença no dia-a-dia na procura por defeitos, formatação e melhoraria do código, integração com sistemas SCM (Source Control Management ou Gerência de Configuração), como SVN, CVS, GIT, Mercurial ou Bazaar e muitas coisas.

Baixando o Eclipse

Acesse http://www.eclipse.org/downloads/ para baixar o Eclipse IDE for Java EE Developers. Escolha a versão correspondente ao seu sistema, que no meu caso é um Windows 64 bits. Veja a imagem abaixo:

10_baixar_eclipse

Ao clicar no link, você será redirecionado para outra página onde poderá escolher um “espelho” (mirror), isto é, uma cópia do arquivo que esteja num servidor próximo de onde você mora. Clique na seta verde para efetivamente iniciar o download, conforme a imagem:

11_baixar_eclipse_2

O download será iniciado e o navegador exibirá a seguinte página:

15_baixar_eclipse_6

No futuro, considere contribuir para tornar o Eclipse ainda melhor.  😉

Instalando o Eclipse

Neste e nos próximos tutoriais, o diretório c:\starcode será adotado como base para a instalação de programas e para armazenamento de arquivos. Caso queira, substitua “starcode” pelo nome da sua empresa, organização ou o que desejar, somente evite espaços em branco e acentos. Procure o arquivo baixado com o Eclipse e descompacte no diretório c:\starcode\eclipse, conforme as imagens abaixo:

12_baixar_eclipse_3

Neste exemplo, estou usando o 7-Zip. Abrindo o arquivo baixado, pressione F5 ou clique no menu Arquivo > Copiar Para.... Na caixa de diálogo, digite c:\starcode.

13_baixar_eclipse_4

Confirme e verifique se o conteúdo do diretório c:\starcode\eclipse está conforme a imagem:

14_baixar_eclipse_5

Configurando o Eclipse

Antes de executar o Eclipse, vamos ajustar alguns parâmetros de uso de memória para melhorar o desempenho geral de nosso IDE. Edite o arquivo eclipse.ini no seu editor de textos favorito (sugiro usar o Notepad++). O arquivo original deve conter algo assim:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130807-1835
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms40m
-Xmx512m

É importante entender o que estamos fazendo, pois este ajuste depende da configuração do computador onde o Eclipse será executado. Os seguintes parâmetros serão ajustados ou adicionados:

  • X:MaxPermSize / launcher.XXMaxPermSize: este parâmetro define a quantidade máxima de memória permanente que o Java irá usar para armazenar informações sobre estrutura de classes (bytecode). A memória “permanente” irá limitar a quantidade de classes que podemos usar. Este parâmetro deve ser aumentado se você tiver muitos projetos com muitos jars diferentes. O parâmetro launcher.XXMaxPermSize serve para algumas versões do Eclipse, então vamos mantê-lo por questões de compatibilidade.
  • XX:PermSize: iremos acrescentar este parâmetro para definir a quantidade inicial de memória permanente que o Java irá alocar. Se o valor deste parâmetro for muito pequeno, o desempenho do aplicativo será prejudicado em alguns momentos, pois o Java terá que interromper a execução para alocar mais memória frequentemente.
  • Xmx: define a quantidade máxima de memória dinâmica que o java irá alocar para instâncias de objetos e variáveis que são alocados e desalocados a qualquer momento.
  • Xms: define a quantidade inicial de memória dinâmica.

O valor padrão do parâmetro XXMaxPermSize está razoável, mas acrescentaremos o XX:PermSize para melhorar o tempo de inicialização do Eclipse, de modo que ele não tenha que ficar alocando memória muitas vezes.

Já os valores de Xmx e Xms podem ser ajustados dependendo da configuração do seu computador. Como eu trabalho com vários projetos e tenho 8 Gibabytes de memória RAM, irei colocar um valor máximo de 2 Gigabytes de memória no Xmx e um valor inicial de 512 Megabytes no Xms.

O arquivo de configuração final ficou assim:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130807-1835
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms512m
-Xmx2G
-XX:PermSize=128m
-XX:MaxPermSize=256m

Executando o Eclipse

Execute o arquivo eclipse.exe. Você verá por algum tempo o splash a seguir:

16_eclipse_splash

Depois você será saudado com a tela de seleção de Workspace (Workspace Launcher). Um Workspace consiste num local (diretório) onde ficarão as suas configurações do Eclipse e pode também conter vários projetos (embora não seja necessário que os projetos estejam no mesmo local). Isso significa que, com uma única instalação do Eclipse, você pode criar vários Workspaces em diferentes diretórios e cada um terá suas configurações e projetos específicos e independentes. O Eclipse pode ser executado mais de uma vez e assim você pode trabalhar em múltiplos Workspaces simultaneamente, porém não é possível abrir o mesmo Workspace em duas instâncias do Eclipse.

Digite o valor c:\starcode\workspace, conforme a imagem abaixo, para criar um novo Workspace no diretório informado e clique em OK.

17_workspace_selection

Aguarde alguns instantes e finalmente o IDE irá aparecer, exibindo a tela de boas-vindas (Welcome):

18_workspace_welcome

Feche a tela de boas-vindas clicando no link Workbench, no canto superior direito. Neste momento a tela de trabalho do Eclipse será apresentada:

19_eclipse_ide

Configurando o Workspace

Vamos realizar algumas configurações básicas e visuais. A primeira é trocar a perspectiva de trabalho. O Eclipse é um IDE multifuncional e isso significa que ele lhe permite executar diversas atividades, por exemplo: codificar em Java, criar consultas a bancos de dados, depurar a execução do programa (debug), sincronizar os arquivos locais com um repositório remoto, etc. Certas atividades estão associadas a perspectivas, as quais contém os componentes (chamados de Views) adequados para a tarefa que você está realizando.

Clique no menu Window > Open perspective > Java. Note que que a janela mudou ligeiramente, conforme a imagem abaixo.

20_eclipse_java_perspective

Vamos analisar rapidamente alguns componentes da tela:

  • Menu principal (no topo da tela): acesso às funcionalidades atualmente disponíveis. Alguns menus podem mudar dependendo da perspectiva atualmente selecionada ou do arquivo atualmente sendo editado.
  • Barra de ferramentas (abaixo do menu principal): os botões contém ações mais comuns e também podem mudar dependendo da perspectiva e do arquivo.
  • Package Explorer (esquerda): view que lista os projetos e arquivos dos projetos.
  • Problems (parte de baixo): view que exibe erros e alertas encontrados nos projetos.
  • Tela central (em branco): editor onde serão abertos os arquivos.

Note ainda no canto superior direito a caixa Quick Access, onde você pode digitar qualquer coisa (configuração, nome de arquivo, etc.) e o Eclipse irá retornar os resultados rapidamente. À direita desta caixa estão listadas as perspectivas recentemente utilizadas, então você pode trocar facilmente a qualquer momento.

Irei fechar as views TaskList e Outline, pois não iremos utilizá-las neste momento.

Vamos realizar também algumas configurações para otimizar nosso trabalho. A primeira é desligar o corretor ortográfico em Inglês, caso contrário tudo o que escrevermos em Português ficará sublinhado de vermelho. Acesse o menu Window > Preferences..., pesquise pela configuração Spelling e desmarque a opção principal, conforme a tela abaixo:

21_disable_spelling

Caso esteja acessando a Internet sob um servidor Proxy, configure-o em Network Connection. Note que alguns plugins do Eclipse não funcionarão adequadamente mesmo com essas configurações de Proxy. Além disso, Proxies com NTLM não podem ser configurados através deste método. Verifique o tipo de Proxy que você possui e, se tiver dificuldades, serão necessárias soluções mais específicas que estão fora do escopo deste tutorial.

22_network

Se você tem um JDK devidamente instalado, o Eclipse deve tê-lo encontrado e adicionado automaticamente à sua configuração. Entretanto, verifique se está correto na configuração Installed JREs.

23_installed_jre

Após realizar as configurações acima, clique em OK.

Criando um projeto para teste

Vamos criar um projeto simples com o objetivo de verificar a instalação e permitir que você se acostume com o ambiente do Eclipse. Acesse o menu File > New  > Java Project. Dê um nome ao projeto e clique em Finish.

24_create_project

A view Package Explorer irá exibir o novo projeto. Clique na seta à esquerda do nome para mostrar seu conteúdo.

25_project_created

Vamos criar uma classe Java. Acesse File > New > Class ou simplesmente clique no botão indicado em vermelho na figura acima.

Na próxima tela, preencha o campo Package com o valor br.com.starcode.teste. O padrão para nomes de pacotes é usar sempre letras minúsculas, não usar caracteres especiais, números somente em situações especiais. Subpacotes são definidos usando o caractere de ponto final (.). Preencha também o campo Name com o nome da classe. Nomes de classes devem manter o padrão CamelCase, isto é, usa-se maiúsculas nas inicias das palavras, por exemplo “MinhaPrimeiraClasse”. Evite caracteres especiais e números. Marque a opção “public static void main(String[] args)” e clique em Finish para confirmar a criação da classe.

26_create_class

Veja como está a visualização:

27_new_class

Vamos editar o método main da nossa classe. Este método é especial para o Java, pois a execução do programa incia-se nele. Primeiro remova a linha com o comentário TODO, depois digite o conteúdo abaixo no lugar:

System.out.println("Testando o Programa!");

Teremos o conteúdo da imagem abaixo.

28_code

Não se esqueça de salvar o arquivo. Pressione Ctrl+S ou clique em File > Save.

E finalmente vamos executar nosso primeiro programa em Java. Clique com o botão direito do mouse sobre a classe e acesse o menu Run As > Java Application.

29_run_java_application

A view Console será aberta, exibindo a saída que nosso programa imprimiu e provando o sucesso da execução.

30_run_result

Depurando o programa

Aproveitando o exemplo da execução, vamos supor que você precisa fazer a depuração (debug) do programa por algum motivo. A depuração permite interromper temporariamente a execução do programa em um determinado ponto, inspecionar e alterar valores de variáveis e continuar a execução linha a linha para analisar o comportamento do programa.

Antes de iniciar a depuração, vamos criar um breakpoint, isto é, vamos marcar a linha onde queremos que a execução do programa seja interrompida. Existem várias formas de fazer isso, por exemplo:

  • Clique na linha desejada e pressione Ctrl+Shift+B.
  • Dê um duplo clique na barra azul à esquerda do editor, na altura da linha desejada.

30_breakpoint

  • Clique com o botão direito na barra azul à esquerda do editor e selecione a opção Toggle Breakpoint.

30_breakpoint 2

O resultado é uma bolinha azul à esquerda da linha, conforme a imagem abaixo.

30_breakpoint done

Para remover o breakpoint, execute novamente um dos procedimentos citados (tecla de talho, duplo clique ou menu de texto).

Agora vamos executar o programa em modo de depuração (debug mode). Clique com o botão direito sobre a classe e acesso o menu Debug As > Java Application.

30_debug as menu

Após o início da execução, quando um breakpoint for encontrado, o Eclipse irá perguntar se você deseja mudar a visualização para a perspectiva Debug.

30_change perspective

Clique em Yes e a tela do Eclipse mudara, exibindo outras views e a linha atual sendo executada em verde claro no editor.

30_breakpoint stopped

Confira alguns detalhes da tela acima:

  • Debug: view que exibe as threads do programa atual e a pilha de chamadas. Como temos apenas um programa simples, há apenas uma thread. E como estamos na classe principal, o único item da pilha consiste do nome da classe, do nome do método e do número da linha sendo executada.
  • Variables: view que exibe as variáveis do escopo atual, de forma que você pode ver e até modificar os valores.
  • Breakpoints: view que exibe todos os breakpoints do workspace.

Neste momento, estamos com a execução do programa interrompida na linha 7. Além de conferir as variáveis do escopo atual, você pode executar um trecho do código e conferir o valor retornado através do Inspect.

Como não temos nenhuma variável, vamos inspecionar o texto contido na função println. Selecione o texto, clique com o botão direito e selecione o menu Inspect.

30_inspect menu

O Java irá executar o trecho selecionado e retornar o resultado numa caixa amarela, conforme a imagem abaixo:

30_inspect result

Embora em nosso exemplo tenhamos usado uma String simples, poderíamos ter feito com qualquer trecho, por exemplo, uma conta matemática ou uma chamada de método. Apenas tome um certo cuidado com a função Inspect, pois o código selecionado é realmente executado, afetando variáveis e valores do seu programa.

Dicas para organização e manutenção de projetos

Logo seu Workspace pode ficar abarrotado de projetos e, consequentemente, o desempenho do Eclipse e sua experiência como desenvolvedor cairão drasticamente. Além de separar seus projetos em vários Workspaces, existem técnicas que ajudam no dia-a-dia, tanto no que se refere à organização quanto ao desempenho.

Vamos criar um projeto adicional para efeito de exemplo. Siga os passos anteriores, mas crie um projeto com outro nome.

31_second_project

Veja como ficou o Workspace:

32_two_projects

Seguindo nosso exemplo, vamos supor que não queremos mais usar o primeiro projeto por algum tempo. Nós podemos fechá-lo, de modo que ele ainda existirá, mas não ocupará recursos. Ao fechar um projeto, o Eclipse não listará os arquivos nem fará cache das classes contidas nele. Para fechar um projeto, clique com o botão direito sobre ele e selecione a opção Close Project.

33_close_project

O ícone do projeto vai mudar e você não poderá mais acessar o seu conteúdo até abri-lo novamente.

34_closed_project

Se desejar abrir o projeto para acessar os arquivos, dê um duplo clique no mesmo ou clique com o botão direito e selecione o menu Open Project. Não precisa fazer isso agora.

Partindo para outro exemplo, vamos supor que você está com muitos projetos no Workspace. Há alguma forma de agrupá-los e organizá-los adequadamente? Para isso existem os Working Sets.

Vamos criar dois Working Sets. Clique no menu da view Package Explorer (conforme indicado em vermelho na imagem abaixo) e então selecione a opção Top Level Elements > Working Sets.

35_view_menu

A tela de configuração dos Working Sets é exibida:

36_configure_working_sets

Primeiramente vamos criar um Working Set chamado “Projetos Principais” com o nosso primeiro projeto. Clique no botão New..., digite o Working set name, adicione o projeto na lista da direita (Working set content) e clique em Finish.

37_new_working_set1

Depois, clique novamente em New... e repita a operação para criar outro Working Set chamado “Projetos Secundários”, incluindo desta vez o segundo projeto que criamos.

38_new_working_set2

Após confirmar a inclusão você pode ordenar os Working Sets. Selecione um item da lista e clique em Up para mover o item para cima ou em Down para mover o item para baixo. A ordenação final ficou da seguinte forma:

39_organizing_workingsets

Clique em OK e confira o resultado:

40_organized_projects

Por fim, se quiser excluir um projeto do seu Workspace, selecione o item e pressione a tecla Delete. Uma tela de confirmação será exibida.

41_delete_project

Note que existe uma opção chamada “Delete project contents on disk (cannot be undone)”. Caso a opção não esteja marcada o projeto será excluído do Workspace, mas não do seu disco rígido. Isso é importante caso não queira perder os dados ou esteja usando o projeto em outro Workspace. Caso a opção esteja marcada, o projeto e todos os arquivos contidos nele serão removidos não apenas do Eclipse, mas também apagados do seu disco, não sendo possível recuperá-los.

Resumo

Neste tutorial você aprendeu a baixar, instalar, configurar o Eclipse. Também viu como criar e organizar projetos, além de executar e depurar um programa simples em Java.

Apesar de tratar-se de uma introdução básica, este tutorial lhe dá uma base para avançar para usos mais avançados da plataforma Java, os quais disponibilizarei em breve.

Installing, Configuring and Using Eclipse Kepler

Eclipse is a IDE (Integrated Development Environment) extremely powerful and flexible, being the most used for various purposes: Java development, Android, C++, processes modeling, report design and so on.

Utilizing a good IDE is essential for productivity because its countless tools and features will make the difference in our daily searching for defects, refactoring, integrating with SCM (Source Control Management) like SVN, CVS, GIT, Mercurial or Bazaar, and other stuff.

Downloading Eclipse

Go to http://www.eclipse.org/downloads/ in order to download Eclipse IDE for Java EE Developers. Choose the corresponding version for your system, in my case, Windows x64. Look at the image below:

10_baixar_eclipse

When you click on the link, you’ll be redirected to another page where you will choose a “mirror”, that is, a copy of the file in a server next to you. Click on the green arrow to begin the download, according to the image:

11_baixar_eclipse_2

The download will start and the browser will show you this page:

15_baixar_eclipse_6

In the future, consider donating to make Eclipse even better.  😉

Installing Eclipse

In this and next tutorials, the directory c:\starcode will be adopted as the base directory for installing applications and storing files. If you want, replace “starcode” with the name of your company, organization or whatever you want, just avoiding whitespaces or special characters. Find the downloaded file, unpack it in the directory c:\starcode\eclipse, according to the following image:

12_baixar_eclipse_3

In this example, I’m using 7-Zip. Open the file and press F5 or go to menu File > Copy to.... In the dialog, type c:\starcode.

13_baixar_eclipse_4

Confirm and check if the content in the directory c:\starcode\eclipse is like the image:

14_baixar_eclipse_5

Configuring Eclipse

Before opening Eclipse, let’s tune a few parameters that affect the memory usage in order to get the a better general performance of our IDE. Edit eclipse.ini in your favorite text editor (I suggest Notepad++). The original file should be something like this:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130807-1835
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms40m
-Xmx512m

It’s important to understand exactly what we’re doing here, because the changes we’re going to do depend on the environment Eclipse is running. The following parameters will be modified or added:

  • X:MaxPermSize / launcher.XXMaxPermSize: this parameter defines the maximum amount of permanent memory Java will use to store information about class structure (bytecode). The “permanent” memory will limit the total of classes we can load in memory. This parameter should be increased if you have many projects with many jars each. The parameter launcher.XXMaxPermSize is used in older versions, so we’ll keep it for compatibility.
  • XX:PermSize: we’ll add this parameter to define the initial amount of permanent memory Java will allocate. If the value is too small, the performance will suffer because Java will in interrupt the execution of the program frequently in order to allocate more memory.
  • Xmx: defines the maximum amount of dynamic memory Java will allocate to store object instances and variables that can be allocated and deallocated at any moment.
  • Xms: defines the initial amount of dynamic memory.

The default value of XXMaxPermSize parameter is reasonable, but we’ll add XX:PermSize in order to obtain better initialization speed. That way Eclipse won’t need increase the memory many times.

The values of Xmx and Xms can be modified depending on your computer power. As I work in various projects and I have 8 Gigabytes of RAM, I’ll put a maximum of 2 Gigabytes in Xmx and an initial 512 Megabytes in Xms.

The final version of the configuration file goes like this:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130807-1835
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms512m
-Xmx2G
-XX:PermSize=128m
-XX:MaxPermSize=256m

Running Eclipse

Execute the file eclipse.exe. You’ll see the splash screen for a while:

16_eclipse_splash

After that, you’ll be welcomed with the Workspace selection screen (Workspace Launcher). A Workspace is a place (a directory, actually) where your Eclipse’s configurations are stored, containing as many projects as you like (even though they don’t need to be in the same place). It means that, with only one Eclipse install, you’re able to create many Workspaces in different directories and each one will have its specific and independent configuration and projects. Eclipse can be executed in multiples instances so you can work in multiples Workspaces simultaneously, with the exception that you cannot open the same Workspace in different instances at the same time.

Let’s continue. Type c:\starcode\workspace and click OK, as the image below, in order to create a brand new Workspace in this directory.

17_workspace_selection

Wait a few moments and finally your IDE will appear, showing the Welcome screen:

18_workspace_welcome

Close the Welcome screen clicking on Workbench link, at the top-right corner. Now, the main work screen will be presented:

19_eclipse_ide

Configuring the Workspace

Let’s do some basic and visual configuration. The first is to change the perspective. Eclipse is a multifunctional IDE and that means it allows you do different activities, for instance: write Java code, create database queries, debug the program, commit and update files from a remote repository, etc. Certain activities are associated to perspectives, which contain the components (named Views) more suitable for the task you are doing.

Go to Window > Open perspective > Java. Notice that the window changed a bit, according to the image below.

20_eclipse_java_perspective

Let’s quickly look at some components of that screen:

  • Main Menu (at the top): it gives you access to all available features. Some items and menus change according to the perspective currently selected or according to the file currently being edited.
  • Toolbar (below main menu): the buttons contain the most used actions and also change according to perspective or file.
  • Package Explorer (at the left): view that lists projects and their files.
  • Problems (at the bottom): view that shows errors and warnings found by compilers and validators in the build process.
  • Center screen (blank): editor where files will be opened and edited.

Notice the Quick Access box near the top-right corner. You can type anything there (configuration name, file name, etc.) and Eclipse instantaneously will show you the results. At the right of this box, the recently used perspectives are listed, so you can swap to another one quickly at any time.

I’ll close the views TaskList and Outline, because we won’t use them in this example.

Let’s do also some configuration in order to speed our work up. Firstly, if your first language is not English, turn off spell checking. Go to Window > Preferences..., search for “Spelling” and uncheck the main option, according to the image:

21_disable_spelling

In case you’re under a proxy server, go to Network Connection configurations. Know that some plugins won’t work even with this configuration. Unfortunately, proxies with NTLM authentication cannot be configured through this method. Check your proxy type, maybe the solution is out of scope for this tutorial.

22_network

If you have JDK correctly installed, Eclipse should found it and add it automatically to its configuration. However, check if it’s ok in  Installed JREs.

23_installed_jre

After accomplish your desired configurations, press OK button.

Creating a test project

Let’s create a simple project with goal of verify the installation and make you comfortable with Eclipse environment. Go to menu File > New  > Java Project. Give it a name and press Finish.

24_create_project

Package Explorer view will display the new project. Click on the arrow at left to show its content.

25_project_created

Let’s create a Java class. Go to File > New > Class or just click on the red-circled button highlighted in the image.

In the next screen, fill Package field out with the value br.com.starcode.teste. The default convention for naming packages is to use always lower case characters and avoid numerals, unless in special cases. Subpackages are separated using the dot character (.). Type also the class name in the Name field. Class names should follow the CamelCase convention, that is, an initial upper-case character for each word, for instance: “MyFirstClass”. Avoid special characters and numbers. For now, check the option “public static void main(String[] args)” and press Finish.

26_create_class

Now we should have this view:

27_new_class

Let’s edit the main method of our class. This method is “special” to Java in the sense the program will start its execution by this method. So, remove the line with TODO comment and then type the following in its place:

System.out.println("Testando o Programa!");

We should have this:

28_code

Don’t forget to save the file. Press Ctrl+S or click File > Save.

Finally, let’s run our first Java program. Click with the right button on the class and go to menu Run As > Java Application.

29_run_java_application

The Console view will appear, showing the output of our program and proving the success of the execution.

30_run_result

Debugging the program

With the previous example, let’s suppose for any reason you need to find a bug. In order to do that you need to stop the program execution at some point and run it line by line, inspecting variables values and following the behavior of the program.

Before we start debugging, let’s create a breakpoint, that is, let’s mark the line we want interrupt the execution of the program. There are many ways to accomplish that, for instance:

  • Go to the line with the cursor and press Ctrl+Shift+B.
  • Double-click the blue bar at left of the editor, in the same direction of the target line.

30_breakpoint

  • Right-click the blue bar at left of the editor and choose Toggle Breakpoint option.

30_breakpoint 2

As a result, we have a small blue circle at the left of the line, as the image below.

30_breakpoint done

In order to remove the breakpoint, do again one of the procedures above (shortcut, double-click or menu).

Now, let’s run the programming in debug mode. Right-click the class and go to Debug As > Java Application.

30_debug as menu

After starting the execution, when the program reach a breakpoint, Eclipse will ask if you want to change for debug perspective.

30_change perspective

Choose Yes and Eclipse screen will change, showing other views and then, in the editor, the current line to be executed in light green.

30_breakpoint stopped

Check out some details of the screen above:

  • Debug: view showing program threads and the stack of method calls. As we have only one simple program, there’s only one thread. And as we’re in the main class, the only item in the stack is our class, its method and the number of the line being executed.
  • Variables: view showing variables in the current scope. You can look at and also change the values here.
  • Breakpoints: view showing all breakpoints set in the Workspace.

Until this moment, the execution is interrupted at line 7. You can inspect the values of variables in the current scope and also run a snippet of code in order to see the value returned by it through Inspect.

We haven’t any variables, so let’s inspect the text contained in println function. Select the text, right-click the selection and go to Inspect.

30_inspect menu

Java will execute the selected snippet and show the result in a yellow box, according to this image:

30_inspect result

Even though in this example we have only a simple String to inspect, we could have done it with any snipped that return a value like a method call or an arithmetic expression. Just take care with Inspect because the code is actually executed, so it can change the state of your program, affecting instances, variables and its values.

Tips for project maintenance and organization

Soon your Workspace may become bloated with projects and, consequently, Eclipse performance and your user experience will get worse. Of course, you can separate your projects in different Workspaces, but there are other alternatives.

Let’s create an additional project for this example. Follow the previous steps, but this time, use another name.

31_second_project

Now our Workspace is like this:

32_two_projects

Let’s suppose now, we won’t work in the first project for a while. We can close it so it’ll exists, but won’t use any of our precious resources. When we close a project, Eclipse won’t list its files nor will cache its classes. In order to close a project, right-click the project and choose Close Project.

33_close_project

The project icon will change and you will be unable to access its content until you open it gain.

34_closed_project

In order to open the project, double-click it or right-click it and choose Open Project. You don’t need to do it right now.

Going to another example, let’s suppose you have many projects in your Workspace. Is there a way to group and organize them properly? For that reason there are Working Sets.

Let’s create two Working Sets. Open the menu of Package Explorer view (as indicated in red in the image below) and then go to Top Level Elements > Working Sets.

35_view_menu

The Working Sets configuration screen will be displayed:

36_configure_working_sets

In the first place, let’s create a Working Set called “Main Projects” containing our first project. Press New... button, type the Working set name, add the project in the right list (Working set content) and press Finish.

37_new_working_set1

Then press New... again and repeat the procedure to create another Working Set called “Secondary Projects”, this time including the other project we created.

38_new_working_set2

Now you can sort the Working Sets. Select an item in the list and press Up in order to move the item up or Down in order to move the item down. The final order goes like this:

39_organizing_workingsets

Press OK and check out the result:

40_organized_projects

Finally, if you want delete a project from your Workspace, select it and press Delete. A confirmation dialog will be shown.

41_delete_project

Notice the option “Delete project contents on disk (cannot be undone)”. If this option is not checked the project will be removed from Workspace, but the files will remain in the Hark Disk. It’s important if you don’t want lost data or when the project is used in another Workspace. In case the option is checked, the project and all its files will not only be removed from Eclipse, but erased from the Hard Drive, so you won’t be able to recover them later.

Summary

In this tutorial you learned how to download, install and configure Eclipse. You also had some examples of how to create, organize, run and debug a simple Java program.

Despite of being a basic introduction, this tutorial will give you the foundation to more advanced topics, which I’ll soon make available.

Instalando e Configurando o Java Development Kit 7 para Desenvolvimento


Nota: Este artigo faz parte de uma série de tutoriais que estou preparando. O primeiro passo, obviamente, é configurar um ambiente de desenvolvimento completo. Meu objetivo é permitir que você tenha um ambiente funcional para então acompanhar sem dificuldades tutoriais sobre tecnologias específicas como JAX-RS, JSF, JPA, etc., evitando assim confusões sobre aspectos secundários.


Antes de pensar em desenvolver algo em Java, precisamos instalar a versão Java para desenvolvimento, isto é o JDK. Diferente do JRE (Java Runtime Environment),que geralmente instalamos para usar aplicativos, bancos, e outros, o JDK vem com várias ferramentas e o compilador javac.

Baixando o Instalador

Acesse http://www.oracle.com/technetwork/java/javase/downloads/index.html e clique no link indicado na imagem:

Baixar JDK

Na próxima tela, primeiro aceite os termos da licença para liberar os downloads e então escolha a versão do Java compatível com seu ambiente. No meu caso, tenho um Windows 64 bits, então escolhi a versão indicada na figura:

00_baixar_jdk_2

Aguarde o download terminar.

Instalando o Java Development Kit (JDK) e o JRE (Java Runtime Environment)

Execute o instalador que você escolheu. No programa que será aberto, que deve ser algo como a imagem abaixo, simplesmente clique em “Next” na tela inicial e novamente em “Next” na tela seguinte para iniciar a instalação.

02_instalar_jdk

No meio da instalação do JDK, será iniciada a instalação do JRE, que é a versão de execução do Java. Clique em “Next” para iniciar a instalação e ser informado de que “mais de 3 bilhões de dispositivos executam Java”.

04_instalar_jre

Ao final, clique em “Close” para finalizar instalação.

Configurando o ambiente

No caso do Windows, precisamos configurar as variáveis de ambiente para que o Java que instalamos fique sempre disponível quando precisarmos.

Acesse as “Configurações Avançadas do Sistema” (Pressione Ctrl+Pause para facilitar) e, na aba Avançado, clique no botão Variáveis de Ambiente.

05_configurar_var_amb

Verifique, nas Variáveis do sistema, se existe uma variável chamada JAVA_HOME. Certifique-se de que o Valor dessa variável contém o caminho para a pasta do JDK que acabamos de instalar, conforme a imagem:

06_configurar_java_home

Note que, no exemplo acima, já havia uma variável da versão anterior, então ela foi atualizada.

Depois disso, edite também a variável Path que está em “Variáveis do sistema” e acrescente o caminho %JAVA_HOME%\bin, se já não houver. Veja o exemplo na imagem abaixo:

07_configurar_path

Agora teste sua instalação abrindo o Prompt de Comando e digitando java -version. Veja como ficou o resultado:

08_versao_java

Pronto!  😀

Agora você já possui a versão mais atualizada de desenvolvimento da plataforma Java.

Não perca as próximas publicações com as demais configurações de um ambiente de desenvolvimento completo!

Então o usuário não sabe o que quer? Conte-me mais sobre o esforço da equipe na elicitação de requisitos e o seu entendimento sobre o domínio da aplicação

wonka-requisitos

Volta e meia um desenvolvedor desabafa: “Usuário não sabe o que quer”. Ou ainda: “Usuário é burro”. Não questionarei a validade dessas afirmações, por vezes elas podem ser verdadeiras.

Por outro lado, devolvo a pergunta: como desenvolvedor, quanto empenho você coloca em entender o que o usuário está realmente precisando?

Usuários, em geral, não sabem nem o que um sistema de software é capaz de fazer, então não espere que lhe digam em detalhes o que você deve implementar. Casos de uso, histórias de usuário, diagramas, desenho das interfaces e outros recursos, por mais simples que sejam, não são suficientes para comunicar tudo o que é necessário.

Os usuários estão preocupados em resolver problemas de negócio e não em verificar uma lista de inputs da especificação de uma tela. Provavelmente eles sentirão falta daquela coluna do relatório somente quando este já estiver concluído. É preciso entender como um usuário utiliza esse relatório para um determinado fim, assim como o seu objeto ao executar uma determinada ação do sistema.

A única forma de entregar software com adequação e acurácia é compreender a necessidade do usuário do ponto de vista dele e do negócio e, independente da forma como uma solicitação chega até nós, traduzir esta necessidade em uma solução concreta. E isso sem esquecer das qualidades técnicas.

Página 5 de 8

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.