Luiz Gustavo S. de Souza

14 de outubro de 2012

Configurando o JBoss Tools 3.3.1 no Eclipse Indigo

Arquivado em: Uncategorized — luizgustavoss @ 7:12

Bem, depois de tanto tempo volto a me dedicar um pouco ao blog. Já faz realmente muito tempo desde que escrevi o último artigo.

Pretendo voltar à ativa por aqui com vários assuntos, muitos dos quais já de conhecimento de muitos desenvolvedores, mas procurando dar uma visão diferente e mais prática, como sempre tenho procurado fazer.

Bom, este post trata de um assunto que já foi tema de outros posts. No post Preparando um Ambiente de Desenvolvimento Java EE Baseado em Eclipse eu demonstrei como preparar um ambiente de desenvolvimento baseado no Eclipse utilizando os principais plugins. Já no post Adicionando Servidor de Aplicações JBoss ao Eclipse eu mostrei como adicionar o servidor de aplicações JBoss ao Eclipse, para facilitar o desenvolvimento das aplicações e controle do servidor através da IDE.

No entanto, mesmo que esta seja uma tarefa trivial para quem já desenvolve a um certo tempo, e para muitos nem mereça um post, para muitas pessoas esta não é uma tarefa tão simples e intuitiva. Prova disso são as experiências que tenho como professor em um curso de especialização em Java, onde muitas vezes os alunos não sabem sequer como configurar o workspace adequadamente com uma JDK.

Pensando nisto, e principalmente em meus atuais e futuros alunos, é que me disponho a postar coisas simples como esta, que são de grande ajuda para quem está começando.

Neste post não vou mostrar toda a configuração de um ambiente do ZERO novamente; para isto você pode consultar o post citado anteriormente, fazendo as devidas ressalvas com relação à versão da IDE e dos plugins.

O que vou mostrar aqui é algo mais direto: como instalar uma versão adequada do JBoss Tools ao Eclipse Indigo. Para isto vou assumir que você já tenha o Eclipse Indigo instalado, e se não tem você pode baixá-lo a partir do site http://www.eclipse.org/downloads/. Eu recomendo que você baixe a versão Eclipse IDE for Java EE Developers, que já traz alguns plugins voltados ao desenvolvimento JEE. Escolha a versão adequada para seu sistema operacional e, após efetuar o download, descompacte o arquivo em seu local de escolha.

Uma vez instalado, inicie o Eclipse:

Uma vez inicializado o Eclipse, é importante escolher a perspectiva Java EE para se trabalhar com o desenvolvimento JEE, e principalmente para facilitar a configuração de um servidor de aplicações. Se você selecionou, na inicialização, um workspace novo, o IDE terá a seguinte aparência (provavelmente):

Repare que, no canto superior direito a perspectiva Java EE está selecionada, e na parte inferior a aba de servidores está selecionada.

Se quisermos, por exemplo, adicionar o servidor de aplicações JBoss 6.1 em novo ambiente, podemos clicar no link “new server wizard”. Ao fazer isso um wizard será apresentado, e nele podemos observar que a opção de adicionar o JBoss 6.1 não está disponível:

Se clicarmos no link “Download additional server adapters”, a seguinte tela será apresentada, nos dando a opção de baixar mais plugins para outros servidores, dentre ele o JBoss Tools:

Ao selecionar a opção desejada e avançar, os procedimentos seguintes levarão à instalação do plugin. Os passos seguintes são bem intuitivo.

Outra maneira de instalar o plugin do JBoss Tools é através de um arquivo local, mas eu sinceramente não gosto desta opção. As experiências que tive mostraram que esta é uma opção mais demorada e propensa a erros, mas ainda assim pode ser uma opção para quem está sem conexão no momento de fazer a configuração. Para isso será necessário baixar o arquivo do site do projeto JBoss Tools, mas por não considerar esta opção a melhor, vou ignorá-la e apresentar a forma que, assim como a primeira forma apresentada, é para mim mais adequada.

Acesse o site http://www.jboss.org/tools/download. No link de downloads é possível encontrar a versão estável do plugin para o Eclipse Indigo. Esta é a principal razão pela qual não utilizo ainda o Eclipse Juno, que é a última versão do IDE Eclipse; o plugin do JBoss Tools ainda não é estável para ele.

Bem, após clicar no link voc~e será redirecionado à uma página onde é possível ter acesso ao update site do plugin, que é um link que usaremos para a configuração do mesmo no Eclipse:

Copie o link apresentado e, voltando ao Eclipse, selecione o menu “Install New Software…”:

Na tela seguinte clique no botão “Add…” e a seguinte janela de configuração será apresentada, onde é possível inserir o link copiado da página do plugin e indicar um nome para o mesmo:

Depois disso os recursos do plugin serão apresentados para que você escolha qual deles quer instalar. Eu aconselho a instalação de todos. Sendo assim selecione todas as opções apresentadas e clique no botão “Next >”:

Dependendo da banda de sua conexão, os passos seguintes podem ser bem demorados. Basicamente você terá que confirmar as escolhas feitas, aceitar alguns termos de licença e aguardar o download dos itens. Ao final será solicitado que a IDE seja reinicializada. Simplesmente aceite.

Depois de reiniciada a IDE, tente novamente adicionar o servidor de aplicações JBoss 6.1 à IDE. Você verá que o adaptador estará disponível.

Para os passos seguintes da configuração do servidor você pode consultar o post referenciado no início deste post, pois o processo será basicamente o mesmo.

É importante ressaltar que não basta ter uma JRE configurada no Eclipse. É preciso ter uma JDK configurada. Os procedimentos para esta configuração também podem ser encontrados em um dos posts citados no início deste post, referente à criação de um ambiente de desenvolvimento completo baseado no eclipse.

Bem, é isto. Espero que esta dica seja proveitosa para muitos que estão começando.

Até o próximo post!

1 de janeiro de 2012

Os números de 2011

Arquivado em: Uncategorized — luizgustavoss @ 14:04

Os duendes de estatísticas do WordPress.com prepararam um relatório para o ano de 2011 deste blog.

Aqui está um resumo:

A sala de concertos da Ópera de Sydney tem uma capacidade de 2.700 pessoas. Este blog foi visitado cerca de 36.000 vezes em 2011. Se fosse a sala de concertos, eram precisos 13 concertos egostados para sentar essas pessoas todas.

Clique aqui para ver o relatório completo

15 de janeiro de 2011

WeaverFX – Um concorrente para o Apache Pivot?

Arquivado em: Dica Rápida — Tags:, , — luizgustavoss @ 14:49

Esta semana, participando de um post do GUJ, fiquei sabendo da existência de uma plataforma RIA que muito se assemelha ao Apache Pivot.

O WeaverFX tem a mesma proposta: uma plataforma que permita a criação de aplicações ricas que possam rodar tanto no desktop quanto na web, na forma de applets.

Só hoje tirei um tempo para olhar o site, e ver alguns exemplos. Minha opinião pessoal? Não gostei.

Tenho que admitir que não me dei ao trabalho de criar uma aplicação de exemplo, me contentando apenas com os exemplos apresentados no site do projeto, mas isso foi devido à primeira impressão que tive.

Primeiramente há o fato de que é necessário instalar uma runtime específica para que se possa executar as aplicações. Uma vez que o Apache Pivot não me exige isto, já conto um ponto negativo para o WeaverFX em relação ao Apache Pivot.

 

 

Outra coisa que definitivamente não me agradou foi o “acabamento” dos componentes, e do resultado final das aplicações.

 

 

 

 

 

Apenas para efeito comparativo, eis uma imagem de uma aplicação que fiz em Pivot:

 

 

Ok, o post é tendencioso, admito que prefiro o Apache Pivot, mas também não me coloco na obrigação de ser imparcial =)

Há pessoas que gostaram do WeaverFX, e acredito que realmente é uma questão de escolha. Eu já fiz a minha =)

 

Para quem quiser saber mais sobre o projeto, acessem o site: http://www.weaverfx.com/

1 de dezembro de 2010

Jogo da Memória com Apache Pivot

Arquivado em: Artigo — Tags:, , — luizgustavoss @ 4:38

É grande com satisfação que posto este pequeno tutorial!

Tenho percebido, pelas estatísticas do blog, que o “Jogo da Memória em Java”, um de meus primeiros posts neste blog, é o tutorial mais acessado.

A grande maioria da galera que acessa este tutorial está buscando uma solução fácil para algum trabalho de faculdade, mas no fundo, este tutorial representou muito mais pra mim. Foi meu primeiro desafio pessoal em Java, algo que eu quis fazer para realmente me desafiar, e aprender a programar em Swing.

Agora, tenho o prazer de postar aqui o mesmo jogo, com algumas pequenas modificações  funcionais, escrito na plataforma Pivot.

Sim! Apesar de ser escrito em Java, o Apache Pivot é uma plataforma RIA completa.

Não vou entrar em detalhes para explicar o código. Ao invés disso, vou disponibilizar aqui o código do jogo, e deixar o desafio de executar o jogo para aqueles que se interessarem em aprender mais sobre esta fascinante plataforma RIA.

Este jogo, apesar de pequeno, demonstra muitos dos recursos disponíveis no Pivot.

Visitem o site do projeto, e leiam os tutoriais http://pivot.apache.org/.

A versão 2.0 estará saindo em breve (tenho acompanhado a lista de desenvolvimento e de usuários, e recomendo).

 

 

 

Definição da interface através do arquivo memgame.wtkx:

 


<Window title="Pivot's Memory Game" maximized="true"
    xmlns:wtkx="http://pivot.apache.org/wtkx"
    xmlns:content="org.apache.pivot.wtk.content"
    xmlns="org.apache.pivot.wtk">
    <content>
        <Border>
            <content>
	            <GridPane columnCount="6" styles="{horizontalSpacing:1, verticalSpacing:1,
                    showHorizontalGridLines:true, showVerticalGridLines:true}">
                    <rows>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="1">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="2">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="3">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="4">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="5">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="6">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="7">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="8">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="9">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="10">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="11">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="12">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="13">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="14">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="15">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="16">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="17">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="18">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="19">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="20">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="21">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="22">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="23">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="24">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="25">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="26">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="27">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="28">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="29">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="30">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                        <GridPane.Row>
                            <PushButton toggleButton="true" wtkx:id="31">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="32">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="33">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                            <PushButton toggleButton="true" wtkx:id="34">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="35">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
				            <PushButton toggleButton="true" wtkx:id="36">
				                <buttonData>
				                    <content:ButtonData text=""/>
				                </buttonData>
				            </PushButton>
                        </GridPane.Row>
                    </rows>
                </GridPane>
            </content>
        </Border>
    </content>
</Window>

Classe que manipula os componentes de tela:


package votti.pivot.memgame;

import org.apache.pivot.collections.Map;
import org.apache.pivot.wtk.Alert;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.Button;
import org.apache.pivot.wtk.ButtonPressListener;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.MessageType;
import org.apache.pivot.wtk.PushButton;
import org.apache.pivot.wtk.Window;
import org.apache.pivot.wtkx.WTKXSerializer;

import votti.pivot.memgame.component.MemGameButtonData;

public class Main implements Application, ButtonPressListener {

	private String defaultImage = "img/default.gif";
	private boolean firstClick = true;
	private boolean right = true;
	private PushButton buttonOne;
	private PushButton buttonTwo;
	private Button clickedButtonOne;
	private Button clickedButtonTwo;

    private Window window = null;
    private String[] images18;
    private String[] images36;
    private PushButton[] buttons;

    @Override
    public void startup(Display display, Map<String, String> properties)

        throws Exception {
        WTKXSerializer wtkxSerializer = new WTKXSerializer();
        window = (Window) wtkxSerializer.readObject(this, "memgame.wtkx");

        prepareImagesArray();

        buttons = new PushButton[36];

        for(int aux = 0; aux < 36; aux++){
        	buttons[aux] = (PushButton) wtkxSerializer.get(String.valueOf(aux+1));
        	buttons[aux].setButtonData(new MemGameButtonData(defaultImage, images36[aux]));
        	buttons[aux].getButtonPressListeners().add(this);
        }

        window.open(display);
        window.setWidth(500);
        window.setHeight(520);
    }

    @Override
    public boolean shutdown(boolean optional) {
        if (window != null) {
            window.close();
        }

        return false;
    }

    @Override
    public void suspend() {
    }

    @Override
    public void resume() {
    }

    public static void main(String[] args) {
        DesktopApplicationContext.main(Main.class, args);
    }

    private void prepareImagesArray(){

		int posicaoNoArray, x, y;
		this.images18 = new String[18];

		for ( x = 0; x < (18); x++ ){
			this.images18[ x ] = new String("img/" + ( x + 1 ) + ".gif");
		}

		this.images36 = new String[ (36) ];

		for ( x = 0; x < 2; x++ ){
			for ( y = 0; y < (18); y++ ){
				do{
					posicaoNoArray = ( int ) ( Math.random() * (36) );
				}while( this.images36[ posicaoNoArray ] != null );
				this.images36[ posicaoNoArray ] = images18[ y ];
			}
		}
	}

	@Override
	public void buttonPressed(Button button) {

		if( firstClick ){

			if ( !right ){

				buttonOne = (PushButton) clickedButtonOne;
				buttonTwo = (PushButton) clickedButtonTwo;

				((MemGameButtonData)buttonOne.getButtonData()).setDefaultURL();
				((MemGameButtonData)buttonTwo.getButtonData()).setDefaultURL();

				window.repaint();
			}

			clickedButtonOne = button;

			buttonOne = (PushButton) clickedButtonOne;
			((MemGameButtonData)buttonOne.getButtonData()).setButtonURL();

			firstClick = !firstClick;
		}
		else{

			clickedButtonTwo = button;
			buttonTwo = (PushButton) clickedButtonTwo;

			if ( clickedButtonTwo == clickedButtonOne ){

				right = false;

				Alert.alert(MessageType.WARNING, "Not permited action!", window);
			}
			else{

				((MemGameButtonData)buttonTwo.getButtonData()).setButtonURL();

				if ( ((MemGameButtonData)buttonOne.getButtonData()).getButtonURL().equals(
						((MemGameButtonData)buttonTwo.getButtonData()).getButtonURL())){

					right = true;

					buttonOne.setEnabled( false );
					buttonTwo.setEnabled( false );
				}

				else{
					right = false;
				}

				firstClick = !firstClick;
			}
		}

	}
}

Mensagens dinâmicas com MessageFormat

Arquivado em: Code Tip — Tags:, , — luizgustavoss @ 2:23

Esta é uma rápida dica sobre uma classe muito útil da API Java, a classe MessageFormat. Não vou dar muitas explicações, e mais detalhes podem ser encontrados na própria API: http://download.oracle.com/javase/1.4.2/docs/api/java/text/MessageFormat.html

Dentre as muitas coisas legais que esta classe permite fazer (formatação de valores monetários, data, hora), temos uma maneira de tratar mensagens internacionalizadas (ou não) cujo conteúdo muda de acordo com o valor específico de um parâmetro. Explico melhor:

Digamos que você precise internacionalizar, ou apenas armazenar em um properties, a seguinte frase:

“Duke, você nos visitou uma vez.”

Digamos que você precise tratar esta frase, de maneira que quando a quantidade de visitas for maior, ela mude para:

“Duke, você nos visitou (n) vezes”

Certo! O tal (n) alí pode ser qualquer número, então o que muita gente faz são concatenações para conseguir o resultado esperado, por exemplo:

“Duke, você nos visitou” + n + “vezes”;

Vamos Piorar a situação? E se o Duke nunca lhe visitou, ou seja, n é igual a zero? E é lógico que não é somente o Duke que lhe visita, então você ainda tem o seguinte:

m*, você nos visitou uma vez. (quando n = 1)

m* + você nos visitou + n + vezes. (quando n > 1)

m*, você nunca nos visitou. (quando n = 0)

*onde m pode ser o Duke ou qualquer pessoa.

Isto ainda pode ficar mais complicado quando você precisa passar a mensagem para mais de um idioma, pois a posição das partes variantes (m e n) pode ser diferente na mensagem. Este cenário é comum em sistemas internacionalizados.

Apesar de a maioria dos frameworks web com foco em componentes de apresentação apresentarem algum suporte a este tipo de situação, algumas vezes será necessário tratar mensagens assim no código Java.

Para estas situações a classe MessageFormat é ideal.

Em primeiro lugar, podemos ter apenas uma mensagem que trata todas as possibilidades, acredite. Basta colocarmos, para cada parte variável da mensagem, um placeholder, que identificará a presença de um valor dinâmico. Como no exemplo temos dois valores variáveis (n e m) teremos dois placeholders na mensagem. A sintaxe de um placeholder é um numérico entre chaves: {0} e {1}. Os valores indicam a posição dos parâmetros passados para o método que formatará a mensagem.

Nossa mensagem então ficaria assim:

{1}, você nos visitou {0} vezes.

Mas espere! Isto ainda não nos atende. Apenas uma das variações da mensagem está contemplada; precisamos do tipo de formato choice: este tipo de formato nos permite escolher dinamicamente uma parte da mensagem de acordo com o valor passado a um placeholder:

{1}, você {0,choice,0# nunca nos visitou.|1# nos visitou uma vez.|1<nos visitou {0,number,integer} vezes}.

Na mensagem acima, está em destaque a sintaxe do tipo de formatação choice; ele é colocado após o número do placeholder, depois de uma vírgula.

Em vermelho está o texto que será apresentado caso o valor passado ao placeholder seja zero. Em verde está o texto que será apresentado caso o valor passado ao placeholder seja um. Em azul está o texto que será apresentado caso o valor passado ao placeholder seja maior que um.

OK, mas como fazer a mágica da transformação? Basta passar a mensagem e os parâmetros para o método format, da classe MessageFormat. Abaixo coloco uma classe de exemplo, que mostra ainda a mesma mensagem traduzida em inglês e espanhol, para demonstrar que a localização dos placeholders pode mudar sem afetar o resultado esperado.


import java.text.MessageFormat;

public class FormatacaoMensagem{

private static String ingles = "You have {0,choice,0#never visited us|1#visited us once|1<visited us {0,number,integer} times}, {1}.";
private static String portugues = "{1}, você {0,choice,0#nunca nos visitou.|1#nos visitou uma vez.|1<nos visitou {0,number,integer} vezes}.";
private static String espanhol = "Usted {0,choice,0#nunca nos ha visitado, {1}|1#nos ha visitado una vez, {1}|1<nos ha visitado {0,number,integer} veces, {1}}.";

public static void main(String[] args){

Object[] nenhum = {
new Integer(0),
"Duke"

};

Object[] um = {
new Integer(1),
"Duke"

};

Object[] varios = {
new Integer(2),
"Duke"

};

System.out.println( MessageFormat.format(ingles, nenhum) );
System.out.println( MessageFormat.format(ingles, um) );
System.out.println( MessageFormat.format(ingles, varios) );

System.out.println( MessageFormat.format(portugues, nenhum) );
System.out.println( MessageFormat.format(portugues, um) );
System.out.println( MessageFormat.format(portugues, varios) );

System.out.println( MessageFormat.format(espanhol, nenhum) );
System.out.println( MessageFormat.format(espanhol, um) );
System.out.println( MessageFormat.format(espanhol, varios) );

}
}

Eis o resultado final:

Vale a pena conferir a API para as outras opções que a classe oferece.

Está dada a dica!

Dica: Prototipação com Balsamiq

Arquivado em: Dica Rápida — Tags:, , — luizgustavoss @ 1:26

Esta é uma dica rápida, de uma ferramenta que veio ao encontro de minhas necessidades, e pode ser o que você também procura.

Há algum tempo deixei de usar o iPlotz, e hoje uma colega de trabalho me indicou o Balsamiq.

Não vou explicar muito, apenas colocar uma imagem de uma tela e deixar o link para quem tiver interesse.

 

 

A instalação é fácil, mas é preciso ter instalada a plataforma AIR da Adobe (o que também é fácil conseguir – há um link na página de instalação para se chegar na instalação do AIR).

Eis a página do projeto: http://balsamiq.com/

 

Está dada a dica!

22 de novembro de 2010

Trabalhando com o SVN no Eclipse

Arquivado em: Tutorial — Tags:, , , , , — luizgustavoss @ 2:17

Introdução

Neste pequeno tutorial vou apresentar uma descrição básica de como se trabalhar com o Subversion (SVN) no Eclipse.
Embora outros servidores de controle de versão estejam sendo utilizados cada vez mais pelo mercado, como o Git, por exemplo, o SVN ainda é, sem dúvida, utilizado por uma grande quantidade de usuários nas empresas.
Apesar da grande utilização, nem sempre as melhores práticas são adotadas quando se trabalha com este tipo de ferramenta, nem mesmo recursos como merging e branching são utilizados na maioria das vezes (ou pela maioria dos usuários), o que acaba por provocar a  subutilização da ferramenta, afetando consequentemente a produtividade das equipes.

Objetivos

Apresentar orientações básicas de como trabalhar com o SVN no Eclipse, que é um dos ambientes de desenvolvimento Java mais utilizados do mercado.
Serão apresentados exemplos de como criar um branch, realizar um merge entre o branch e o trunk, e resolver problemas de conflito durante o merge.
Os conceitos apresentados são válidos para outros ambientes de desenvolvimento, mas os procedimentos podem mudar de acordo com os plugins utilizados em cada um.

Pré-Requisitos

Como não é o foco do tutorial apresentar a instalação do servidor SVN, é necessário ter um repositório disponível para os testes. Uma dica, para se testar em uma máquina local, é instalar o VisualSVN Server Manager.
É necessário também ter o plugin do SVN instalado no Eclipse. Um exemplo de como a instalação do plugin pode ser feita pode ser encontrado no seguinte endereço: http://luizgustavoss.wordpress.com/2009/12/13/preparando-um-ambiente-de-desenvolvimento-java-ee-baseado-em-eclipse/

Mão na Massa!

Configurando o repositório no Eclipse

Para começar a utilizar um repositório do SVN é necessário configurá-lo n o Eclipse. Para isso é preciso ter a URL do repositório, o que pode ser conseguido com o administrador do repositório.
Com a URL em mãos, abra a perspectiva do repositório SVN no Eclipse:

Clicando com o botão auxiliar do mouse, selecione a opção para adicionar um novo local:

Adicione a URL do repositório de testes no campo indicado:

Pode ser necessário informar o usuário e senha para acesso. Esta informação pode ser conseguida com o administrador do servidor:

Após estes passos, o repositório será apresentado na perspectiva, conforme abaixo:

A estrutura sugerida pelo SVN possui três diretórios: branches, tags e trunk.

/trunk -  o diretório onde o desenvolvimento principal do projeto ocorre, ou seja, onde sempre está a versão mais recente e estável dos artefatos oficiais;
/branches – o diretório onde pode-se criar ramificações da linha principal de desenvolvimento (trunk);
/tags – o diretório onde se pode armazenar ramificações da linha principal que são criadas, e talvez destruídas, mas nunca modificadas.

Criando uma aplicação Java

Crie, no C:\, um diretório chamado workspace, e nele crie dois diretórios chamados work1 e work2. Estes serão os workspaces usados para os testes.

Abra o Eclipse apontando para o workspace work1. Após configurar o ambiente (adicionar um JDK apropriado) crie um projeto Java simples, chamado Calculadora. Neste projeto crie um pacote chamado testes.svn, e nele crie uma classe chamada Calculadora.java, com os seguintes métodos:


public class Calculadora {

public BigDecimal somar(BigDecimal param1, BigDecimal param2) throws Exception{
return null;
}

public BigDecimal subtrair(BigDecimal param1, BigDecimal param2) throws Exception{
return null;
}

public BigDecimal multiplicar(BigDecimal param1, BigDecimal param2) throws Exception{
return null;
}

public BigDecimal dividir(BigDecimal param1, BigDecimal param2) throws Exception{
return null;
}
}

Esta é a estrutura do projeto após a criação da classe:

Vamos agora colocar o projeto no repositório que configuramos anteriormente. Clique com o botão auxiliar do mouse sobre o projeto, vá até a opção de menu “Team” e escolha a opção “Share Project”:

Na próxima tela, escolha a opção SVN e prossiga. Na tela seguinte, escolha o repositório configurado anteriormente e prossiga:

Na próxima tela, temos a opção de configurar o nome sobre o qual o projeto será armazenado no repositório, e sua localização. Marque a segunda opção, e clicando no botão “Select…” informe o diretório trunk:

Ao retornar da tela, esta deverá ser a configuração da tela:

Prossiga, e na tela final digite uma mensagem inicial para o versionamento e confirme:

O seguinte comando será executado contra o servidor, adicionando o projeto ao repositório:

mkdir –parents -m “Versionamento do projeto Calculadora.” https://votti/svn/calculadora/trunk/Calculadora
checkout https://votti/svn/calculadora/trunk/Calculadora -r HEAD –depth=immediates –force

Logo em seguida, será apresentada a perspectiva de sincronização, onde poderemos “commitar” o projeto no repositório, ou seja, enviar o conteúdo do projeto para o repositório, literalmente.
As setas cinza sobre os arquivos e diretórios indicam que estes arquivos devem ser comitados, então selecione os mesmos e, clicando com o botão auxiliar do mouse sobre os itens selecionados, escolha a opção “commit”:

Na tela seguinte, inclua um comentário inicial e confirme:

Os seguintes comandos serão executados, indicando que os artefatos foram “commitados” com sucesso:

add -N C:\workspace\work1\Calculadora\.settings
A         C:/workspace/work1/Calculadora/.settings
add -N C:\workspace\work1\Calculadora\src
A         C:/workspace/work1/Calculadora/src
add -N C:\workspace\work1\Calculadora\src\testes
A         C:/workspace/work1/Calculadora/src/testes
add -N C:\workspace\work1\Calculadora\src\testes\svn
A         C:/workspace/work1/Calculadora/src/testes/svn
add -N C:\workspace\work1\Calculadora\.settings\org.eclipse.jdt.core.prefs
A         C:/workspace/work1/Calculadora/.settings/org.eclipse.jdt.core.prefs
add -N C:\workspace\work1\Calculadora\.project
A         C:/workspace/work1/Calculadora/.project
add -N C:\workspace\work1\Calculadora\src\testes\svn\Calculadora.java
A         C:/workspace/work1/Calculadora/src/testes/svn/Calculadora.java
add -N C:\workspace\work1\Calculadora\.classpath
A         C:/workspace/work1/Calculadora/.classpath
commit -m “Versionamento inicial dos artefatos.” (8 paths specified)
Adding         C:/workspace/work1/Calculadora/.classpath
Adding         C:/workspace/work1/Calculadora/.project
Adding         C:/workspace/work1/Calculadora/.settings
Adding         C:/workspace/work1/Calculadora/.settings/org.eclipse.jdt.core.prefs
Adding         C:/workspace/work1/Calculadora/src
Adding         C:/workspace/work1/Calculadora/src/testes
Adding         C:/workspace/work1/Calculadora/src/testes/svn
Adding         C:/workspace/work1/Calculadora/src/testes/svn/Calculadora.java
Transmitting file data …

Voltando à perspectiva Java, podemos perceber que o projeto está no repositório, pela notação à frente do nome do projeto, e podemos ver ainda qual usuário realizou o “commit” da classe Calculadora:

Pois bem, temos o projeto versionado no trunk. Como dito anteriormente, no trunk deveriam ser mantidos os códigos estáveis de um projeto. Para a realização de testes ou implementações que podem ser instáveis por um longo período, pode ser preferível criar um branch. No branch colocamos uma cópia do projeto que está no trunk, mas sem perder a referência. A equipe que trabalha no código do branch pode ainda manter uma sincronização com o trunk, trazendo deste as atualizações pertinentes, evitando que o código do branch fique desatualizado com relação ao trunk,  mas evitando que o código instável do branch influencie negativamente o código do trunk.
Para nosso tutorial, vamos supor que a implementação dos métodos da classe Calculadora serão  realizados no branch. No dia-a-dia tal implementação poderia ser feita no trunk, mas como nosso objetivo é aprender a criar branches, vamos supor que esta seja uma necessidade real.

Criando um Branch

Para criar um branch vá até a perspectiva do repositório SVN e, expandindo os diretórios, clique com o botão auxiliar do mouse sobre o projeto Calculadora, e no menu de contexto escolha a opção “Branch/Tag…”:

Na tela seguinte precisamos informar o diretório destino, no repositório, para o projeto. Como estamos criando um branch, o diretório destino será o branch. Porém, como podem existir vários branches de um mesmo projeto ao mesmo tempo, é conveniente criar um subdiretório com um nome que identifique o objetivo do branch.
Para fazer isso, selecione o branch através do botão “Select…”:

Ao voltar para a tela anterior, dê um nome ao subdiretório. Isso pode ser feito adicionando o nome à URL resultante do processo anterior. Para este exemplo, o diretório será “metodos_calculadora”. Eis a URL final:

https://votti/svn/calculadora/branches/metodos_calculadora

Lembre-se de marcar na tela a opção que permite que o diretório adicional seja criado (Create any intermediate folders that are missing.):

Na próxima tela podemos escolhar qual revisão queremos para o branch. No nosso caso vamos escolhar a opção HEAD, que indica que será enviada para o branch a versão mais atual existente no trunk. Porém, se necessário, uma versão específica poderá ser selecionada:

Na tela seguinte adicione um comentário pertinente, e faça a confirmação:

Se formos agora à perspectiva do repositório, poderemos ver que o conteúdo do trunk foi copiado para o branch configurado:

Veja que até o momento copiamos o conteúdo do projeto para o trunk e a partir do trunk criamos um branch para realizar a implementação, mas no nosso workspace temos apenas o projeto que está “ligado” ao trunk. Isso significa que se fizermos qualquer modificação, e fizermos um commit, estas modificações serão enviadas ao trunk.

Realizando modificações no branch

Se quisermos realizar modificações no branch criado, teremos que configurar um projeto que esteja “ligado” a ele.
Para fazer isso, vamos reiniciar o Eclipse e como workspace vamos selecionar o diretório work2, criado no início do tutorial. Assim que tiver aberto o Eclipse no novo workspace faça as configurações necessárias (configuração de uma JDK padrão, por exemplo).
Abra a perspectiva do SVN e, assim como no início do tutorial, insira uma novo local de repositório, informando a URL do repositório de exemplo.
Ao terminar o processo de configuração do repositório, abra o diretório branch. Clique com o botão auxiliar do mouse sobre o diretório “metodos_calculadora”, e no menu de contexto escolha a opção “Checkout…”:

Com isso vamos copiar o conteúdo do branch para o repositório, para trabalhar nele.
A próxima tela apresenta os dados para o projeto qe será criado:

Repare que o nome do projeto foi recuperado e dado como sugestão. Também há a possibilidade de escolher uma revisão específica, ou então a última (HEAD). Vamos manter as configurações sugeridas.
Na próxima tela será sugerido como workspace o workspace atual (work2). Mantenha o valor sugerido e prossiga, clicando em “Finish”.
Ao voltar para a perspectiva Java, é possível verificar que o projeto foi configurado, e que referencia o branch criado:

Agora vamos simular a situação real de ter que alterar o código em ambos os locais, trunk (work1) e branch (work2) e ter de mantê-los sincronizados.
Vamos começar codificando a classe Calculadora no workspace work2, que referencia o branch, no qual estamos:


public class Calculadora {

    public BigDecimal somar(BigDecimal param1, BigDecimal param2) throws Exception{
        return param1.add(param2);
    }

    public BigDecimal subtrair(BigDecimal param1, BigDecimal param2) throws Exception{
        return param1.subtract(param2);
    }

    public BigDecimal multiplicar(BigDecimal param1, BigDecimal param2) throws Exception{
        return param1.multiply(param2);
    }

    public BigDecimal dividir(BigDecimal param1, BigDecimal param2) throws Exception{
        return param1.divide(param2);
    }
}

Depois de codificar a classe, faça o commit das modificações no branch, descrevendo as modificações:

É extremamente importante realizar o commit de todas as alterações do workspace no brach/trunk antes de realizar qualquer operação de merge. Aliás, é uma exigência!
Vamos agora realizar uma modificação no projeto do trunk, para ver como recuperar esta modificação, depois, no branch. Mude de workspace, voltando para a workspace work1.
Você verá que, como esperado, os métodos na classe Calculadora do workspace work1 estão como antes, sem implementação.
Adicione então, à classe Calculadora, um método a mais:

public BigDecimal potencial(BigDecimal param1, BigDecimal param2) throws Exception{
return null;
}

Faça o commit da modificação, adicionando um comentário pertinente:

Retorne para o workspace work2.

Realizando um merge do trunk para o branch

Agora, no workspace work2, vamos realizar um merge para receber as atualizações do trunk, ou seja, o novo método adicionado à classe Calculadora.
Este procedimento deveria ser, como comentado anteriormente, uma prática realizada frequentemente para que o branch não fique muito tempo desatualizado em relação ao trunk. Isto minimiza problemas de conflito na hora de mover para o trunk as modificações do branch, procedimento este que realizaremos depois.

Selecione a classe Calculadora no projeto, e clicando com o botão auxiliar do mouse sobre ela escolha a opção de “Merge…” no menu “Team”:

A tela seguinte nos apresenta algumas opções para a operação de merge:

Para este tutorial as duas primeiras opções são as que interessam.
Para esta operação que realizaremos agora, mantenha selecionada a primeira opção. Esta opção é usada para capturar mudanças que foram realizadas no trunk ou outro branch, e trazê-las ao branch no qual estamos trabalhando. Confirme a operação, clicando em “Next”:

A próxima tela apresenta uma sugestão do artefato a partir do qual desejamos realizar o merge, ou seja, a classe Calculadora  presente no projeto do trunk. Neste ponto você poderia apontar para a mesma classe presente em algum outro branch, caso existisse, ou seja, não precisa ser necessariamente um merge a partir do trunk. Mas no nosso caso manteremos a sugestão, pois realmente precisamos realizar o merge com o trunk.
Na próxima tela são apresentadas opções para a operação. Basicamente, as sugestões marcadas por padrão são melhores, pois indicam que a cada problema encontrado, o usuário deverá ser consultado sobre o que fazer. Mantenha as sugestões apresentadas por padrão:

Ao confirmar, a seguinte tela é apresentada, indicando que uma atualização foi encontrada:

Após a conclusão da operação, você verá que o método adicionado na classe Calculadora do trunk apareceu na classe Calculadora do branch:

Vale lembrar que, apesar de termos realizado esta operação para apenas uma classe, ela pode ser realizada para vários artefatos ao mesmo tempo.
Agora que a classe foi modificada, faça o commit das alterações no branch, informando um comentário pertinente para a mudança:

Realizando um merge do branch para o trunk

Depois do trabalho realizado no branch, precisamos reintegrá-lo ao trunk, uma hora ou outra.
Muitas vezes o trabalho em um branch pode ser tão rápido quanto algumas horas, ou longo a ponto de levar vários dias ou meses. O tamanho do trabalho a ser realizado é que irá determinar isso.
Independente de quanto tempo ele leve, o fato de realizar periodicamente o merge do trunk com o branch, como feito anteriormente, deve minimizar os problemas de conflitos quando chegar a hora de trazer o branch para o trunk, uma vez que, idealmente, os conflitos existentes já terão sido resolvidos no momento em que se levou as mudanças do trunk para o branch.
Vamos agora trazer o que foi feito no branch para o trunk. Mude para o workspace work1.
Selecione a classe Calculadora no projeto, e clicando com o botão auxiliar do mouse sobre ela escolha a opção de “Merge…” no meu “Team”

Na tela que aparece em seguida, mantenha selecionada a segunda opção, que nos permitirá trazer as mudanças do branch para o trunk:

Na tela seguinte, na qual informamos a partir de onde será feito o merge, selecione a classe Calculadora do branch, como indicado:

Na próxima tela confirme as opções oferecidas como padrão, e ao finalizar a tela seguinte será apresentada, indicando que uma atualização será realizada:

Confirme clicando no botão “OK”. Ao término da operação as atualizações do branch serão aplicadas ao trunk.

Lidando com conflitos entre o trunk e o branch

Até agora realizamos o merge entre o trunk e o branch sem nenhum problema de conflito, mas isto está longe de ser a realidade do dia-a-dia de trabalho das equipes de desenvolvimento. Na verdade os conflitos são muito comuns. As boas práticas procuram melhorar a produtividade das equipes, manter a estabilidade dos repositórios (principalmente do trunk) e minizar os conflitos, mas eliminar os conflitos, principalmente em um ambiente onde muitos desenvolvedores atualizam os mesmos arquivos, é algo muito difícil. Por esta razão é bom se acostumar com estes conflitos, e se acostumar a resolvê-los também.
Para simular este cenário, vamos modificar o último método adicionado à classe Calculadora. Perceba que ele ainda não foi implementado, e que recebe dois parâmetros. Na verdade precisamos modificar um de seus parâmetros, e também precisamos implementá-lo.
Ainda no workspace work1 modifique o método como abaixo:

public BigDecimal potencial(BigDecimal param1, int param2) throws Exception{
return param1.pow(param2);
}

Realize o commit das modificações, e sim, coloque um comentário! (não é à toa que estou batendo nesta tecla):

Agora mude para o workspace work2 e também faça estas modificações no métod, exatamente como no trunk, realizando o commit ao final.
Depois de realizado o commit, faça um merge, trazendo do trunk as modificações para o branch.
Apesar de termos alterado o mesmo método em ambos os locais, nenhuma atualização é encontrada, uma vez que as modificações foram exatamente as mesmas, ou seja, nenhum conflito é encontrado.
Vamos agora simular um conflito real, quando o mesmo local é modificado, porém com valores diferentes.

Mude para o workspace work1 e altere o método dividir conforme apresentado abaixo, realizando o commit ao final:


public BigDecimal dividir(BigDecimal param1, BigDecimal param2) throws Exception{
return param1.divide(param2, BigDecimal.ROUND_UP);
}

Agora mude para o workspace work2 e altere o método dividir conforme apresentado abaixo, realizando o commit no final:

public BigDecimal dividir(BigDecimal param1, BigDecimal param2) throws Exception{
return param1.divide(param2, BigDecimal.ROUND_HALF_EVEN);
}

Agora tente novamente trazer do trunk para o branch as modificações na classe Calculadora e veja o resultado.

Desta vez há um conflito, pois o método foi modificado em mais de um local (repositório), e no mesmo ponto.
As opções apresentadas na tela que é apresentada são:

- Marcar como em conflito. Resolverei mais tarde.
- Resolver o conflito usando a minha versão do arquivo.
- Resolver o conflito usando a versão do arquivo que está chegando.
- Me deixe editar o arquivo com os marcadores de conflito inseridos.
- Abrir um editor gráfico de solução de conflitos.

Particularmente recomendo lidar o quando antes com os conflitos, portanto, escolha a última opção e confirme. O Editor apresenta os conflitos a serem resolvidos:

Suponhamos que nossa versão do branch está correta. Então feche o editor, e uma mensagem será apresentada, perguntando se o conflito foi resolvido:

Marque que o conflito foi resolvido (primeira opção) e confirme:

Na tela que indica que uma atualização será feita faça a confirmação. Depois realize o commit da classe Calculadora no branch.
Desta forma, cada implementação do método, no trunk e no branch, ficou de uma forma. Se quiséssemos deixá-las iguais, bastaria ter aceito a diferença vinda do trunk (caso esta fosse a correta) ou então, a partir do trunk, puxar as alterações do branch e aceitá-las.

 

Conclusão

Neste tutorial foram apresentados os passos necessários para se configurar um repositório SVN no Eclipse e para se adicionar um projeto ao repositório.
Foram apresentados também os passos necessários para se criar um branch, como realizar o merge entre o branch e o trunk (em ambas as direções) e como resolver conflitos de versionamento.
Com isso concluímos este tutorial!
Espero que tenha sido de bom proveito, e que com o que foi apresentado aqui você possa melhorar sua rotina de trabalho aplicando mais algumas boas práticas no seu dia-a-dia de utilização do SVN.

12 de outubro de 2010

Swing e Pivot

Arquivado em: Code Tip — Tags:, — luizgustavoss @ 11:53

Este post é uma rápida nota sobre uma combinação que eu acredito que será muito útil para a criação de aplicações desktop.

Trata-se da combinação de Swing com o Pivot. Isto será possível a partir da versão 2.0.

A imagem abaixo mostra um exemplo, e em seguida coloco o link do exemplo, e de onde é possível obter os fontes:

 

Link do exemplo:

http://ixnay.biz/pivot-demos/swing-demo.html

 

URL  para obter o fonte:

http://svn.apache.org/repos/asf/pivot/trunk/demos/src/org/apache/pivot/demos/swing/

9 de setembro de 2010

Boas Práticas na Utilização de Controle de Versão

Arquivado em: Dica Rápida — Tags:, — luizgustavoss @ 17:35

Controle de versões representa a possibilidade de compartilhar arquivos, armazenar todas alterações e resolver os conflitos de edição. A sua utilização é fundamental durante todo o ciclo de desenvolvimento, armazenando artefatos de especificações até o código fonte.

Com o controle de versão é possível que diversos desenvolvedores editem o mesmo documento e todas alterações sejam armazenadas para que o histórico seja mantido e conflitos nas edições solucionados. Outra função muito importante do controle de versões é armazenar todas alterações que um documento sofreu e permitir a recuperação de qualquer uma das versões anteriores.

Embora a utilização de controle de versões possa facilitar a vida dos desenvolvedoes, a falta de organização e padronização pode levar a mais problemas do que soluções.

A seguir serão apresentadas algumas boas práticas referentes a utilização de ferramentas de controle de versão, mais especificamente o Subversion, retiradas de algumas das referências citadas ao final do documento.

Usar um layout de repositório adequado

Há alguns pontos a considerar quando se está configurando um repositório do Subversion. O primeiro deles é se será criado um único repositório para vários projetos, ou um repositório para cada projeto, ou então alguma forma de combinação das duas opções. Há prós e contras em cada uma das opções.

Há benefícios ao se utilizar um único repositório para vários projetos, e o mais óbvio deles é evitar a duplicidade de manutenção:

  • Um único backup a ser feito periodicamente;
  • Um único ponto a exportar e carregar quando há uma nova versão do Subversion que é imcompatível com as anteriores;
  • Facilidade para mover dados entre projetos, e sem perder o histórico destes dados (mover dados entre repositórios diferentes causa a perda do histórico dos dados).

A contrapartida de se utilizar um único repositório para vários projetos é que:

Diferentes projetos podem ter diferentes requisitos de autorização e autenticação;
O Subversion utiliza números de revisão que são globais no repositório; isso faz com que mudanças em projetos distintos aumentem o número de revisão de projetos não relacionados.

O meio termo seria ter alguns repositórios criados, e cada um deles conter projetos relacionados. Desta forma, os projetos relacionados podem compartilhar dados facilmente, e caso novas revisões sejam criadas no repositório, elas estarão relacionadas a projetos que estão, de alguma forma, também relacionados.

Além da organização dos repositórios em si, há ainda a questão da organização dentro dos repositórios. Há várias maneiras de organizar o repositório de um projeto, pois cada divisão existente não é nada mais do que um diretório, e o Subversion não impede a criação de diretórios. Embora exista esta flexibilidade, o projeto Subversion recomenda, oficialmente, a idéia de um “projeto raiz“ que representa o ponto principal de um projeto. Um repositório pode conter um ou mais “projetos raiz“, e o “projeto raiz“ possui exatamente três subdiretórios:

/trunk -  o diretório onde o desenvolvimento principal do projeto ocorre, ou seja, onde sempre está a versão mais recente dos artefatos oficiais;
/branches – o diretório onde pode-se criar ramificações da linha principal de desenvolvimento (trunk);
/tags – o diretório onde se pode armazenar ramificações da linha principal que são criadas, e talvez destruídas, mas nunca modificadas.

Um repositório poderia se parecer com o seguinte:


calc/
----trunk/
----tags/
----branches/
calendar/
----trunk/
----tags/
----branches/
spreadsheet/
----trunk/
----tags/
----branches/

Se há múltiplos projetos em um mesmo repositório, é possível organizá-los em grupos dentro do repositório, colocando projetos com objetivos similares em subdiretórios, como a seguir:

</p>
utils/
----calc/
--------trunk/
--------tags/
--------branches/
----calendar/
--------trunk/
--------tags/
--------branches/
…
office/
----spreadsheet/
--------trunk/
--------tags/
--------branches/

Faça o commit de conjuntos lógicos de mudanças

É importante ficar bem claro que o objetivo principal de um sistema de controle de versão não é o de realizar backup dos dados versionados, mas manter o controle de versões lógicas de modificações feitas nos artefatos.

Sendo assim, realizar um commit apenas ao final do dia, com a idéia de que se está salvando o trabalho feito não é nada bom se este trabalho não estiver logicamente completo. Agindo assim só se está realizando um backup diário do trabalho.

Uma operação de commit deve ter um significado maior: ela deve refletir um trabalho completo para corrigir um erro, a incorporação completa de uma nova funcionalidade ao sistema, ou alguma tarefa particular, mas sempre por completo. Uma operação de commit irá gerar um identificador globalmente reconhecido dentro do repositório, que identifica este trabalho por completo, como se fosse um nome. Este identificador poderá ser utilizado, posteriormente, para identificar uma correção em uma ferramenta de acompanhamento de solicitações,  ou então ser passado como parâmetros a comandos do Subversion quando se deseja desfazer uma mudança, ou então copiá-la de um branch a outro.

Utilizar ferramentas de acompanhamento de solicitações de maneira adequada

Ao utilizar ferramentas de acompanhamento de solicitações (correção de bugs, novas funcionalidades, etc…) faça links cruzados entre o número da solicitação aberta e do commit, ou commits que a atendem.

Uma maneira de fazer isso é incluir o número da solicitação que se está atendendo no comentário do commit, e adicionando o número da revisão, resultante do commit, nos comentários que se faz em uma solicitação, para explicar seu andamento ou seu encerramento.

Acompanhar operações de merge manualmente

Ao realizar um commit depois de uma operação de merge, escreva uma mensagem descritiva explicando o que foi integrado, como por exemplo:

Realização da integração das versões 3490:4120 do /branches/algumbranch para /trunk.

Saber quando criar branches

O debate sobre quando criar branches, ou não, é um detabe antigo, e realmente não há uma palavra final sobre isso, pois cada equipe ou projeto pode assumir uma política diferente. A seguir são descritas as três políticas mais comuns de criação de branches:

Nunca criar branches

Eesta é a política utilizada por projetos que acabaram de nascer, e que ainda não têm código executável.
Os usuários realizam o commit das mudanças diárias diretamente no /trunk.

Eventualmente o /trunk pode parar de funcionar (não compila, não passa em testes unitários), quando alguém realiza o commit de mudanças complexas.

Prós:
* É uma política fácil de seguir.
* Novos desenvolvedores têm uma barreira menor para iniciar.
* Ninguém precisa saber como criar branches e realizar integrações (merge).
Contras:
* Desenvolvimento caótico.
* O código pode se tornar instável a qualquer momento.

Sempre utilizar branches

Esta é a política utilizada por projetos que favorecem um forte gerenciamento e supervisão.
Cada usuário cria e trabalha em um branch privado para cada tarefa de codificação.

Quando a codificação está completa, alguém (o autor original do código, um colega ou o gerente) revisa todas as modificações no branch as integra ao /trunk.

Prós:
* Há a garantia de que o /trunk sempre estará consistente e estável.
* Nenhum desenvolvedor precisa manter em sua máquina, por muito tempo, modificações incompatíveis com o /trunk.
Contras:
* Os desenvolvedores ficam artificialmente isolados uns dos outros, possivelmente criando mais conflitos de integração que o necessário. Requer que os desenvolvedores façam integrações com maior frequência, para diminuir os conflitos.

Criar branches quando necessário

Esta é a prática utilizada pelo projeto Subversion.

Os usuários realizam o commit das mudanças diárias diretamente no /trunk.

Regra #1: o /trunk tem que compilar e passar nos testes de regressão sempre!
Regra #2: uma operação de commit de um conjunto de modificações não pode ser tão grande a ponto de desencorajar a revisão por parte de um colega.
Regra #3: se as regras #1 e #2 entrarem em conflito (exemplo: é impossível realizar uma série de commits sem corromper o /trunk) então o desenvolvedor deve criar um /branch e realizar uma série de commits de pequenos conjuntos de modificações lá. Isso permite que seja feita a revisão por parte de um colega, sem desestabilizar o /trunk.

Pros:
* Tem-se a garantia de que o /trunk está estável todo o tempo.
Contras:
* Adiciona algumas obrigações ao trabalho diário dos usuários: eles devem compilar e testar o código antes de cada commit realizado.

Tenha cuidado ao realizar a atualização de sua área de trabalho

Alguns cuidados, apesar de muito básicos, são ignorados por quem está começando a utilizar um sistema de controle de versão. Vejo constantemente amigos reclamando de estagiários que fazem uma verdadeira bagunça no código versionado, sobrescrevendo atualizações de colegas, criando com isso muitos problemas.

Ao invés de realizar um commit direto em algum artefato, é adequado verificar se há atualizações pendentes para o mesmo. Plugins dificilmente permitem que se realize um commit em um código que possui uma versão mais nova no servidor, mas ainda assim é uma boa prática.

Quando não há conflitos nos arquivos é difícil fazer alguma besteira. Os problemas surgem com eles.

Os plugins das IDEs permitem que se faça a verificação dos conflitos, e a solução deles, passo-a-passo. Ainda assim muitas pessoas (acreditem) ignoram os conflitos e simplesmente forçam um commit de suas atualizações, “matando” as modificações de seus colegas. Acredite, se você não quer ter sua mãe escumungada pelos seus colegas, seja cauteloso. Ao solucionar conflitos, tenha paciência e copie para sua versão as atualizações pertinentes feitas pelos seus colegas. Quando o trecho em conflito refletir uma mesma mudança feita por você e outra pessoa, verifique com a pessoa o que ela acha melhor manter na versão, principalmente se você não conseguir entender a codificação dela.

Só faça o commit quando você tiver certeza de que as mudanças feitas pelos outros colegas de trabalho foram contempladas em sua versão. Se você não conseguir resolver os conflitos, chame uma pessoa mais experiente.

Quando você não tiver uma pessoa disponível para lhe ajudar a resolver os conflitos, é preferível copiar seu código para um arquivo de backup, aceitar todas as atualizações do servidor (sobrescrevendo as suas) e depois realizar novamente as suas alterações sobre a nova versão. Isso porque você certamente entenderá melhor as suas modificações do que a de seus colegas. Esta é uma prática que eu uso às vezes (quando há conflitos demais), e vários colegas me dizem também usar a mesma prática. Pelo menos se garante que nenhum trabalho alheio será estragado.

Quando tiver novas dicas para este post eu o atualizarei.

Está dada a dica!

Referências

http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html

http://svnbook.red-bean.com/

http://www.iovene.com/21

Dicas de Boas Práticas de Codificação

Arquivado em: Dica Rápida — Tags: — luizgustavoss @ 17:06

Este post não traz nenhuma novidade para quem já desenvolve há algum tempo, e a intenção é atingir aqueles que estão começando a programar em Java.

Resolvi juntar algumas dicas de padrões de codificação e melhores práticas para códigos a serem aplicados no desenvolvimento de aplicações Java.

São abordados padrões de nomes de arquivos, organização de código, endentação, comentários, declarações, sentenças, espaços em branco, convenção de nomes, práticas de programação e exemplos de código.

Estes padrões são baseados em princípios de engenharia de software que produzem códigos fáceis de entender, fáceis de manter e escaláveis. As convenções aqui adotadas foram fortemente baseadas no documento de Convenção de Codificação para a Linguagem de Programação Java, da Sun Microsystems.

Algumas constatações reforçam a necessidade de se adotar uma padronização durante do desenvolvimento:

  • 80% dos custos de um software é referente à manutenção.
  • Dificilmente qualquer software é mantido durante toda sua vida útil pelo autor original.
  • Convenções de código aumentam a legibilidade do software, permitindo que os desenvolvedores entendam novos códigos mais rapidamente e completamente.

No desenvolvimento de sistemas o uso de padrões de codificação promove o aumento da consistência do código e da produtividade da equipe. A seguir são descritas as principais instruções para a codificação de um código Java com padronizado e com qualidade.

Convenção de Nomes

Mantenha o tamanho dos nomes grande o bastante para transmitir o que eles representam. Exemplo: primeiroNome, sobrenome, ordemServico, etc.

Nomes de Classes e Interfaces

Os nomes de classe devem ser substantivos e, em caso de nomes compostos, utilize nomes com a primeira letra de cada palavra interna maiúscula. Use palavras inteiras evitando acrônimos e abreviaturas. Exemplo: Cliente ou ContaCliente.

Nomes de Métodos

Os nomes dos métodos devem ser verbos, em casos compostos com o primeiro nome minúsculo, e com a primeira letra de cada palavra interna em maiúsculo. Exemplo:

calcularPagamento().

Nomes de Variáveis

Os nomes de variáveis devem estar com uma primeira letra minúscula e, em caso de nomes compostos, com a primeira letra de cada palavra interna em maiúsculo. Exemplo: contraPeso, primeiroNome, etc.

Use abreviações consistentemente. Exemplo: numPedido, numChamado. Neste caso, num representa Numero.
Evite os nomes que são similares. Exemplo: o numCliente e numcliente.

Use nomes no plural para representar coleções tais como uma disposição ou um vetor. Exemplo: CustomerPK[] clientes ou Vector politicasDeAcesso.

Nomes de Constantes

Os nomes de constantes para tipos de dados ordinais devem ter todas as letras em maiúsculo, separadas por underscore. Exemplo:

public static final int MAX_POLICY_AMOUNT; ou
public static final char PROCESS_INFO_COMMAND;

Documente com Comentários

Adicione comentários para facilitar a compreensão do código. Mantenha o comentário simples e separe-os de tal forma o código fique limpo e legível. Escreva também os comentários onde alguma explanação é necessária. Não escreva comentários para as coisas óbvias. Forneça documentação de acordo com a especificação do javadoc, tal que os arquivos do Java código podem ser usados para produzir a documentação externa das classes.

Documentação de Classes

Para documentar classes forneça comentários imediatamente antes de sua definição, especificando a finalidade e histórico de desenvolvimento.

Documentação de Interfaces

Para documentar interfaces especifique a finalidade nos comentários da documentação, imediatamente antes de sua definição. Para cada método siga os padrões da documentação de métodos de membro.

Documentação de Pacotes

Forneça documentação que especifique o relacionamento de um pacote com suas classes e Interfaces.

Use Linhas em Branco

Forneça linhas em branco entre as seções do código para melhorar a legibilidade. Use uma linha em branco nas seguintes circunstâncias:

  • Para separar as definições de classes das definições de métodos;
  • Para separar as variáveis locais de um método;
  • Para separar blocos de código; e
  • Para separar comentários das seções lógicas do código.

Espaços em Branco e Tabulação

Use o espaço em branco para melhorar a legibilidade do código nas seguintes circunstâncias: Entre uma palavra-chave e um parêntese. Exemplo:

while (condicao) {
}

Após vírgulas na lista entre parênteses. Exemplo:


operacao(param1, param2, param3);

Entre um operador binário e seu operando. Exemplos:


x += y + z;
a = (a + b) / (c * d);

Entre expressões em uma declaração “for”. Exemplo:


for (expr1; expr2; expr3)

Na utilização de casts.


umMetodo((byte) num, (Object) x);

Variáveis Locais

Declare uma variável local por linha do código e adicione um comentário que identifique a variável. Exemplo:

int contador = 0; // contador para número de referências

Declare todas as variáveis locais no começo dos blocos. Isto facilitará a localização das definições variáveis pelo programador. Exemplo:


private void calcularProcessosPendentes() {
boolean processoEncerrado = false; // indica término do processamento
}

Use cada variável local para uma finalidade específica.
Inicialize todas as variáveis locais onde elas são declaradas. A única razão para não inicializar uma variável no local onde ela é declarada é quando o valor inicial da variável depende de um processamento que ocorrerá posteriormente.


int contador = 0; // contador para número de referências
int maxReferencias; // o número máximo de referências a serem processadas
…
maxReferencias = getMaxRefencias(…, …);

Evite as declarações locais que sobreponham declarações em níveis superiores. Exemplo:


int contador = 0; //…
…
metodo() {
    if (condicao) {
        int contador = 0;
        …
    }
    …
}

Atributos de Membro

Para declarar atributos de membro utilize os seguintes padrões:

Finalidade: Documente a finalidade do atributo;
Visibilidade: Mantenha a visibilidade tão baixo quanto possível;
Iniciação: Certifique-se de que todos os atributos estão inicializados antes que sejam alcançados. Inicialize todos os atributos no momento da criação do objeto. A inicialização posterior pode ser usada para os campos que não são acessados regularmente.

Métodos de Membro

Para declarar métodos de membro utilize os seguintes padrões:

Nomenclatura: use get/set como um prefixo do nome do campo para todos os métodos de ascensão, a menos que forem do tipo booleano. Use o prefixo “is” para nomes de métodos que referenciem campos booleanos. Utilize também a primeira palavra do nome do método de membro como um verbo forte, ativo. Exemplo:


getPotenciaMotor(), setPotenciaMotor(), isAutomatico(), reduzirMarcha().

Visibilidade: Mantenha a visibilidade de funções de membro tão restritiva quanto possível para minimizar o acoplamento entre as classes;
Documentação: Inclua um cabeçalho para especificar as seguintes informações da função de membro:

  • O propósito da função;
  • Seu valor de retorno;
  • Os parâmetros;
  • As mudanças nas versões do código.

Parâmetros

Evite nomear parâmetros com o mesmo nome que as variáveis de membro. Isto evitará referenciar cada variável de membro utilizando o operador “this”, dificultando a localização de erros. Documente os parâmetros de uma função de membro no header usando a tag @param do javadoc. A documentação deve ser obrigatória para descrever todas as limitações ou pré-condições.

Declarações ou Comandos

Cada linha deve conter no máximo um comando. Exemplo:

contador++; x = y; // EVITE ISSO!

Chaves ou Blocos

Siga um esquema consistente para a abertura e fechamento de chaves. Alinhe a abertura e fechamento das chaves verticalmente. Isto facilitará a identificação do começo e término dos blocos. Exemplo:

class Cliente
{
    public void operacaoParaCliente()
    {
        if(condicao)
        {
        }
    }
}

Alternativamente, ponha a chave da abertura na extremidade da linha que começa o bloco. A chave de fechamento deve começar uma nova linha e ser posicionada no começo do comando de bloco. Exemplo:


class Cliente {
    public void operacaoParaCliente() {
        if(condicao) {
        }
    }
}

Ordem dos Membros

Declare membros de acordo com a ordem de visibilidade, do mais visível para menos visível, conforme modelo abaixo:

construtores (constructors)
public member functions
protected member functions
private member functions

Minimize a utilização do modificador de acessos public e protected. Isto reduz o acoplamento e deixa o código mais compreensível. Evite usar nomes de objetos para acessar membros estáticos (static members), em vez disto, use o nome da classe preferivelmente.

Concatenação de Strings

Evite realizar a concatenação de Strings com o operador “+“. Strings são objetos imutáveis, e por esta razão, a cada vez que uma concatenação é realizada, novos objetos são criados na memória:

String a = “Evite“;
a = a + “realizar a concatenação“;
a = a + “de Strings assim!“;

Para concatenação, procure utilizar as classes StringBuilder ou StringBuffer:


StringBuilder a = new StringBuilder(“Procure“);
a.append(“realizar a concatenação“);
a.append(“de Strings assim!“);

Cuidados na Manipulação de Objetos que Podem Estar Nulos

Ao realizar a chamada de métodos em objetos que poderiam estar nulos, tenha sempre o cuidado de testá-lo antes, a menos que tenha a certeza de que o objeto não estará nulo.
Um exemplo útil, no caso de comparação de Strings:

Ao invés de realizar a comparação desta maneira:


if(umaString.equals(““)){
…

Faça o seguinte, chamando o método equals no valor literal:


if(““.equals(umaString)){
...

Remover Imports Desnecessários

É importante, por uma questão de economia de memória, manter nas classes e interfaces somente as definições de imports que são utilizadas.
Uma outra prática importante, que já é reforçada pelas IDE’s, é fazer o import classe a classe, ao invés de importar todos as classes de um determinado pacote.

Utilize Parênteses Sempre que Puder

Não economize na utilização de parênteses quando estes puderem deixar uma expressão mais clara.

Atribuição de Variáveis

Evite fazer múltiplas atribuições a uma mesma variável em uma única linha:

fooBar.fChar = barFoo.lchar = 'c'; // EVITE ISSO!

Referência a Atributos e Métodos Estáticos

Sempre referencie membros estáticos (atributos e métodos) através da classe, e não de uma instância da mesma:


UmaClasse.metodoEstatico(); // OK
instanciaDeUmaClasse.metodoEstatico(); // EVITE ISSO!

Utilize Chaves Sempre!

Sempre utilize chaves para delimitar blocos de comandos, mesmo que estes tenham apenas uma instrução:

if(determinadaCondicao) // EVITE ISSO!
    realizaOperacao();

if(determinadaCondicao){ // OK
    realizaOperacao();
}

Bom, definitivamente não há nada de novo aqui para quem já desenvolve há algum tempo, com uma ou outra adaptação.

O importante é definir quais práticas se adequam à sua realidade/equipe/projeto e seguí-la.

Está dada a dica!

Referência

http://www.oracle.com/technetwork/java/codeconv-138413.html

Older Posts »

Tema: Silver is the New Black. Blog no WordPress.com.

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.