
Essencialmente todos, ao desenvolver a primeira aplicação distribuída, assumem os 8 itens seguintes como verdade. Todos se provam falsos ao longo do tempo, e estes erros causam problemas graves e aprendizados dolorosos.
Para mais detalhes, leiam o artigo escrito por Arnon Rotem-Gal-Oz.
James Gosling em um link fala o seguinte sobre a origem desta lista:
A verdadeira origem desta lista é um pouco mítica, sendo amplamente baseada na experiência coletiva de muitos hackers nos primórdios da construção de sistemas distribuídos. Peter Deutch foi o primeiro agrupar os itens em uma lista. Ele diz o seguinte em sua página:
Eu publiquei as “8 falácias da programação em rede” internamente enquanto trabalhava para “Sun Microsystem Labs” em 1991-92. (As primeiras 4 foram originalmente listadas por Bill ou Dick Lyon; Eu adicionei as outras 4.)
Achei que vali a tradução já que muita gente comete os mesmos erros até hoje
Tags: distribuida, programação, rede, tradução
Bom, no último post eu disse para você não ser repetitivo, e não escrever nos comentários o que o seu código faz. Se você precisa comentar o que o seu código faz, você realmente precisa refatorar o seu código e torna-lo mais legível …
Mas comentários no código não são sempre ruins, o ruim é você escrever em português o que o seu código faz em java, mas existem diversas situações que veremos a seguir onde os comentários são ótimos, ou pelo menso são úteis …
Por exemplo, na interface pública de um serviço, um JavaDoc informando para que serve aquele serviço e com exemplos de utilização são sempre muito bem vindos, principalmente se este comentário informar quais são as validações que serão feitas nos parâmetros e quais são as restrições ao uso daquele serviço …
Eu não posso pegar exemplos de projetos em que estou trabalhando por que isto seria motivo para demissão por justa causa por quebra de sigilo ![]()
Então vamos ficar com alguns exemplos públicos e alguns exemplos mais simples que eu conseguir pensar na hora …
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * This is the only interface you need to create and manage system users, but if you need to manage user privileges take a look at the @link{PrivilegesService} interface */ public interface UsersService { /** * This method should be used only if you are already authenticated in the system, do no forget to send the session id header when calling methods that are not public like this one. * To create a user you need to provide all the needed information, this method will create user in the database and then will try to create the user in the backend system, if the creation works the two accouns will be linked otherwise the database reccord will be erased. * @param userName the user name must be unique within the LDAP domain, this means that there can * @param password * @param email */ public User createUser(String userName, String password, String email); } |
Neste exemplo, não há necessidade alguma de colocar um comentário dizendo que o método createUser cria um usuário, mas o javadoc do exemplo informa de algumas pré condições para a execução do método e também diz qual o fluxo de execução e possíveis falhas. Como neste exemplo o UsersService é a interface publica de um serviço, esta documentação é bastante bem vinda, pois vai ajudar os usuários que vão acessar o serviço a saber o que fazer antes de criar um usuário e a saber possíveis motivos para as falhas.
Bom, acho que todos os outros exemplos que eu procurar vão ser parecidos com isto, resumindo este post e o anterior:
Se um comentário diz o que o método faz, o código é um lixo ou o comentário é redundante, o que o método faz tem que ser óbvio pelo nome do método
Se o comentário diz quando o método deve ser utilizado, algumas pré condições, o fluxo de execução, possíveis erros, e principalmente se ele esta em uma interface publica do sistema, que vai ser entregue a outra equipe/programador/empresa. o comentário é útil
Se o comentário esta em algum método ou variável privada, provavelmente tem algum problema por ai.
Acho que com isto eu encerro este assunto de comentários, eu posso ter me expressado errado, ou o mais provável, muitas pessoas leram o título do post e saíram berrando antes de ler o resto, mas a idéia básica é, o seu código tem que ser muito fácil de ler, os nomes das classes, métodos, variáveis, pacotes e quaisquer arquivos envolvidos no sistema devem dizer o que são, para que servem e por que estão ali. Se você esta colocando um comentário que diz que o método “create” cria um usuário, você deveria chamar o método de “createUser”, mas se o comentário esta informando o usuário do método de que o nome de usuário utilizado não precisa ser único mas o email sim, pois é este o campo utilizado como chave, ai você tem um comentário útil (e um sistema extranho
).
Não é por que o seu código tem comentários que ele é um lixo, mas tome cuidado por que é muito fácil utilizar comentários como desculpa para código ruim. E neste caso, talvez você precise estudar um pouco de rafactoring.
Tags: comentarios, lprodjava, produtividade, qualidade, refactoring
Uma das melhores idéias do Flex, e o que o torna bastante produtivo na minha opinião é a existencia de uma “linguagem” para layout de telas, é o tal de MXML.
Claro que eu sei que é apenas XML, mas é XML com acesso direto as classes existentes e recem criadas, e uma mão na roda para separar o código do layout, facilitando bastante a escrita de código MVC compliant.
O maior problema da arquitetura básica do Flex é não ser “óbvio” como escrever o código de tratamento dos eventos gerados sem poluir o MXML com muitas tags “mx:Script” e muito código ActionScript.
Claro que existem alguns frameworks para o desenvolvimento de aplicações Flex como o Cairngorm e o PureMVC, mas algumas vezes estes frameworks mais complicam do que ajudam, e mesmo utilizando um deles, esta dica que vou apresentar agora de como simular o “code behind” do “.NET” em flex pode ser utilizada sem maiores problemas …
A idéia principal é separa o código ActionScript do código XML, como se fosse uma “partial class” do “.NET”, o Flex não suporta Partial Classes, mas suporta herança, e podemos tirar proveito disto …
Vou mostrar um exemplo bastante simplista aqui, apenas para que vocês peguem a idéia, vejam o código da tela abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?xml version="1.0" encoding="utf-8"?> <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"> <mx:Script> <![CDATA[ import mx.controls.DataGrid; import mx.events.ListEvent; [Bindable] private var current : Object = new Object(); [Bindable] private var all : Array = []; private function saveCurrent(nome : String, idade : Number) : void { var obj : Object = {nome : nome, idade : idade, id : all.length + 1}; var temp : Array = all.slice(0,all.length); temp.push(obj); all = temp; current = obj; } private function updateCurrent(nome : String, idade : Number) : void { current.nome = nome; current.idade = idade; } private function newCurrent() : void { current = new Object(); } private function selectionChange(evt : ListEvent) : void { current = (evt.target as DataGrid).selectedItem; } ]]> </mx:Script> <mx:Label fontSize="24" width="100%" textAlign="center" text="Cadastro de Pessoas"/> <mx:HBox width="100%"> <mx:Label text="Nome:" width="100"/> <mx:TextInput id="currentNome" text="{current.nome}"/> </mx:HBox> <mx:HBox width="100%"> <mx:Label text="Idade:" width="100"/> <mx:NumericStepper id="currentIdade" value="{current.idade}" minimum="5" maximum="150"/> </mx:HBox> <mx:HBox width="100%" horizontalAlign="center"> <mx:Button label="Salvar" click="saveCurrent(currentNome.text,currentIdade.value)" enabled="{!current.id}"/> <mx:Button label="Novo" click="newCurrent()" enabled="{current.id}"/> <mx:Button label="Atualizar" click="updateCurrent(currentNome.text,currentIdade.value)" enabled="{current.id}"/> </mx:HBox> <mx:DataGrid width="100%" dataProvider="{all}" change="selectionChange(event)"> <mx:columns> <mx:DataGridColumn headerText="Id" dataField="id"/> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Idade" dataField="idade"/> </mx:columns> </mx:DataGrid> </mx:VBox> |
Apenas para este bastatne simples, já temos quase metade do arquivo contendo ActionScript e metade contendo MXML.
Em um caso simples destes isto não chega a incomodar, mas quando o arquivo começa a crescer, isto atrapalha a leitura do código fonte, o que é bastante ruim. Então a minha sugestão, ou “dica” de como resolver isto, é separar o código ActionScript em um arquivo .as e manter apenas o layout no arquivo MXML, como pode ser visto no seguinte exemplo (considerando que o nome do arquivo mostrado acima seja telaexemplo.mxml)
Criar a classe “exemplo.TelaExemploBase” no diretório correspondente com o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package exemplo { import mx.containers.VBox; import mx.controls.DataGrid; import mx.events.ListEvent; public class TelaExemploBase extends VBox { [Bindable] protected var current : Object = new Object(); [Bindable] protected var all : Array = []; public function TelaExemploBase() { super(); } protected function saveCurrent(nome : String, idade : Number) : void { var obj : Object = {nome : nome, idade : idade, id : all.length + 1}; var temp : Array = all.slice(0,all.length); temp.push(obj); all = temp; current = obj; } protected function updateCurrent(nome : String, idade : Number) : void { current.nome = nome; current.idade = idade; } protected function newCurrent() : void { current = new Object(); } protected function selectionChange(evt : ListEvent) : void { current = (evt.target as DataGrid).selectedItem; } } } |
Alterar o arquivo MXML para o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?xml version="1.0" encoding="utf-8"?> <TelaExemploBase xmlns="exemplo.*" xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" > <mx:Label fontSize="24" width="100%" textAlign="center" text="Cadastro de Pessoas"/> <mx:HBox width="100%"> <mx:Label text="Nome:" width="100"/> <mx:TextInput id="currentNome" text="{current.nome}"/> </mx:HBox> <mx:HBox width="100%"> <mx:Label text="Idade:" width="100"/> <mx:NumericStepper id="currentIdade" value="{current.idade}" minimum="5" maximum="150"/> </mx:HBox> <mx:HBox width="100%" horizontalAlign="center"> <mx:Button label="Salvar" click="saveCurrent(currentNome.text,currentIdade.value)" enabled="{!current.id}"/> <mx:Button label="Novo" click="newCurrent()" enabled="{current.id}"/> <mx:Button label="Atualizar" click="updateCurrent(currentNome.text,currentIdade.value)" enabled="{current.id}"/> </mx:HBox> <mx:DataGrid width="100%" dataProvider="{all}" change="selectionChange(event)"> <mx:columns> <mx:DataGridColumn headerText="Id" dataField="id"/> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Idade" dataField="idade"/> </mx:columns> </mx:DataGrid> </TelaExemploBase> |
A idéia básica é utilizar o MXML para extender a classe ActionScript que contem o código, a diferença é que tudo o que deve ser acessado do MXML na classe criada não pode ser privado, tem que ser no mínimo protected (o que foi utilizado no exemplo).
Outro truque é definir o “xmlns” para o pacote da classe que vai ser extendida como pode ser visto na linha 2.
E para testar isto é necessária uma “aplicação flex”, eu utilizei apenas o código abaixo para o projeto de testes:
1 2 3 4 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*"> <local:telaexemplo width="100%" height="100%"/> </mx:Application> |
Mas claro que você pode fazer algo mais elaborado
Espero que esta dica ajude alguem, ja que eu tive bastante trabalho reorganizando código depois que descobri que isto era muito melhor do que colocar tudo no MXML logo que comecei a trabalhar com Flex.

Mas mesmo assim, o livro é recomendado para iniciante e intermediario no máximo, pois existem alguns tópicos mais avançados que não são tratados, mas nada que faça falta no dia a dia.
Acho que o maior diferencial do livro é ser 100% prático, apresentar todos os conceitos utilizando exemplos desenvolvidos pelo próprio leitor, facilitando o aprendizado.
Garanto que se você ler o livro e fizer todos os exercícios e as duas aplicações propostas no livro, no final você vai conseguir desenvolver as suas aplicações em RoR sem maiores problemas.
Se tiver dúvidas, vou ficar feliz em responde-las e com certeza, se vocês gostarem do livro, as dúvidas vão ajudar a melhorar a próxima versão do livro ![]()
Então agora é só vocês comprarem o livro e começar a estudar.
Para quem quiser dar uma olhada antes do livro chegar nas bancas, segue o “indice” com o título dos capítulos:
- Dedicatória
- Agradecimentos
- Sobre o autor
- Prefácio
- Introdução ao Ruby
- Instalação do Ruby
- Primeiros passos
- Variáveis e escopo
- Tipos básicos do Ruby
- Blocos de código
- Procs
- Números
- Valores booleanos
- Strings
- Constantes
- Intervalos numéricos
- Arrays
- Hashes
- Símbolos
- Expressões regulares
- Classes e métodos
- Métodos
- Módulos
- Operadores condicionais e loops
- If elsif else end
- case when else end
- Operadores de loop
- while
- for
- until
- begin
- loop
- Padrões importantes
- Nomes de arquivos
- Classes, e atributos e métodos de acesso
- Nomenclatura de métodos
- Dominando o Ruby!
- Ambiente de desenvolvimento
- Multi plataforma
- Aptana RadRails
- NetBeans
- IntelliJ IDEA
- Vim
- Windows
- Notepad++
- E-TextEditor
- Linux
- GEdit
- Kate
- Mac
- TextMate
- Plug-ins para os editores
- Escolhendo o seu
- Rails básico
- Criando a primeira aplicação
- Estrutura de diretórios de uma aplicação
Rails
- Scripts padrão do Rails
- Gerando código, um cadastro instantâneo
- A primeira Migration
- O primeiro model
- O primeiro controlador
- Métodos básicos do ActiveRecord
- Recebendo parâmetros nos controladores
- Respondendo a requisições
- As primeiras views
- Precisando de ajuda para limpar o código das
views?- Configurando rotas, um nome bonito para URLs
- Continuando o desenvolvimento
- Conferindo as migrations geradas
- Escrevendo modelos
- Gerando todo o código
- Um pouco de segurança na aplicação
- Um layout menos ruim para a aplicação
- Associando usuários a projetos
- Adicionando tipos de tarefa a um projeto
- Cadastrando as horas trabalhadas
- Um relatório para a aplicação
- Limpando um pouco o código e se livrando um pouco do
inglês- Suporte a testes no Rails
- RUnit básico
- Testando modelos
- Escrevendo fixtures
- Testando as validações
- Asserções disponíveis
- Testes funcionais, testando os controladores e
helpers- Tornando testes mais divertidos e úteis (inclusive
para o seu chefe)- Notificação de testes executados
- De volta às User Stories
- Uma olhada nas especificações
- Utilizando objetos falsos ou mocks
- Finalizando a definição de comportamento do
sistema com as User Stories- ActiveRecord avançado
- Utilizando o ActiveRecord para consultas
- Métodos de busca dinâmicos por atributos
- ActiveRecord::Base.find
- ActiveRecord::Base.find_bysql
- Associações polimorficas
- Mais sobre associações
- Callbacks para associações
- Outros métodos úteis do ActiveRecord
- Use todo o poder do RESTful
- Introdução ao REST
- Métodos do protocolo HTTP
- Princípios do REST
- RESTful: The Rails way
- Tema de casa
- Paginação
- Paginação manual
- Will_paginate
- Outros plug-ins
- paginating_find
- Paginator
- Upload de arquivos
- Attachment_fu
- File_column
- Outros plug-ins úteis
- Brazilian-rails
- Exception_logger
- Exception_notifier
- JRails
- Restful_authentication
- Annotate_models
- Acts_as_taggable_on_steroids
- Juggernaut
- Mydry
- Calendar_date_select
- Css_graph
- Backgroundrb
- Quais plug-ins utilizar na sua aplicação
- AJAX on Rails Quase sem JavaScript
- Reutilizando código entre projetos
- O plug-in biblioteca
- Plug-ins de geração de código
- Finalizando o assunto
- Colocando tudo isto em produção
- CGI
- FastCGI
- Mongrel
- Mod_rails
- JRuby
- Opções de deployment
Junto com o livro vou colocar no ar o site http://livro.urubatan.com.br onde vou publicar mais exemplos, quaisquer correções que sejam necessárias, e qualquer um que comprar o livro vai poder deixar a opinião e fazer perguntas.
PS.: Este livro não vai te transformar em um ninja fodão que desenvolve qualquer sistema em 2 horas. Mas é um bom começo se você quer aprender Ruby On Rails.
Tags: anuncio, livro, rails, Ruby, ruby on rails
Este não é o post que diz passo a passo como fazer isto, este vai ser o próximo, este post é para dizer que descobri que o Free Pascal tem um cross compiler para arm-wince, se vocês acessarem http://www.lazarus.freepascal.org/, na parte de downloads para windows existe o download do lazarus+free pascal e também o download do crosscompiler para Windows Mobile.
Não existe o download deste cross compiler para linux, mas depois de perder algum tempo, eu ja montei um .sh que compila todo o free pascal e o cross compiler para windows mobile no linux ![]()
Só falta agora fazer isto funcionar com o lazarus …
Assim que eu fizer isto funcionar no Lazarus eu posto aqui para vocês um passo a passo de como programar em linux/Object Pascal, de modo visual, criando aplicações para windows mobile
O canal seria ter uma forma de desenvolver utilizando o mono para Compact Framework, mas como não encontrei ainda nenhuma forma decente de fazer isto, voltar a brincar de “Delphi” até que vai ser divertido
Tags: fpc, free pascal, lazarus, linux, Mobile, phone, pocket, wince
Continuando com a seqüência de posts com títulos polêmicos que comecei dizendo que “Comentário no código é para os fracos“, segue um curso básico de refactoring para quem é pobre (por que vou utilizar o eclipse que é uma excelente IDE e alem de tudo é “di grátis”), e preguiçoso, por que o eclipse vai fazer quase todo o trabalho para nós.
O ponto de partida vai ser o “exercício” que deixei no final do post sobre comentários no código.
Par quem não quiser ler todo o outro post, o código inicial vai ser este abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | package blog; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class VeryBadlyNamedFile { private static final char[] asdfg = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'}; private String an; private BufferedReader rfsdw; private FileReader temp; public VeryBadlyNamedFile(String an, BufferedReader rfsdw, FileReader temp) { super(); this.an = an; this.rfsdw = rfsdw; this.temp = temp; } public void doIt() throws IOException { ctfiidne(); startDoing(); try { canIDoAnyThing(); } catch (RuntimeException yicdet) { nowReallyDoIt(); } } private void nowReallyDoIt() { firstDoTheOtherThing(); reallyDoItInternal(); } private void firstDoTheOtherThing() { rfsdw = new BufferedReader(temp); } private void reallyDoItInternal() { while (true) { try { imDoingIt(); } catch (Exception e) { break; } } } private void imDoingIt() throws Exception { String s = rfsdw.readLine(); if (s == null) throw new Exception("hahaha, I bet you did not understood the code"); System.out.println(s); } private void ctfiidne() throws IOException { File a = new File(an); if (!a.exists()) { FileWriter wrfedsd = new FileWriter(a); wrfedsd.write(asdfg); wrfedsd.close(); } } private void canIDoAnyThing() { if (new File(an).exists() && new File(an).canRead() && new File(an).canWrite()) throw new RuntimeException(); } private void startDoing() throws FileNotFoundException { File f = new File(an); temp = new FileReader(f); } } |
Antes de começar o refactoring, vamos definir o que é refactoring de uma forma bem simples:
Refactoring = Alterar partes do código de uma aplicação sem quebrar outras partes da aplicação que dependam daquele código.
Refactoring é uma forma de melhorar o design de um código existente enquanto ele continua funcionando.
Gosto muito de uma frase espetacular do Fowler, um dos papas do desenvolvimento ágil, que coloco abaixo:
“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999
Nos vamos utilizar os recursos de refactoring do Eclipse para transformar este lixo acima em alguma coisa legível, mantendo exatamente o mesmo comportamento, ou seja, sem quebrar o código que já funciona.
Para facilitar o trabalho, este tutorial (se é que pode ser chamado de tutorial), vai ser um simples “passo a passo” que eu utilizei para alterar este código no Eclipse, que é a minha segunda IDE preferida (a melhor de todas na minha opinião é o IntelliJ IDEA, mas se eu utilizasse este, não seria um tutorial para quem é pobre
)
Siga os passos abaixo:
1 | fileLineReader.useDelimiter("\n"); |
1 2 3 4 5 6 7 8 9 | Iterable<String> lineIterator = new Iterable<String>(){ @Override public Iterator<String> iterator() { return fileLineReader; } }; for(String line : lineIterator){ System.out.println(line); } |
1 2 3 4 5 6 7 | File file = new File(fileName); boolean fileExists = file.exists(); if (!fileExists) { FileWriter fileWriter = new FileWriter(file); fileWriter.write(conteudoPadraoParaNovoArquivo); fileWriter.close(); } |
Pronto, o Eclipse acabou de nos ajudar a ter um código menos porco na classe do post sobre comentários de código.
Claro que o código ainda não esta nenhum primor, mas a idéia deste post era mostrar que é possível utilizar recursos da IDE para facilitar o refactoring de código porco quando este for encontrado.
E não se iluda, se você estuda para melhorar o seu conhecimento sobre desenvolvimento e ser um profissional cada vez melhor, provavelmente o código que você escreveu a dois meses atrás você ache muito ruim hoje.
Só para finalizar o post, o seu código deve ter ficado parecido com este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package blog; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.util.Iterator; import java.util.Scanner; public class TextFileToScreenPrinter { private static final char[] standardContentForNewFiles = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'}; private String fileName; private Scanner fileLineReader; public TextFileToScreenPrinter(String fileName) { super(); this.fileName = fileName; } public void doIt() throws IOException { ensureFileAlreadyExists(); abortIfCanNotReadOrWriteFile(); printEachLineFromFileToConsole(); } private void printEachLineFromFileToConsole() throws FileNotFoundException { createLineReader(); forEachLineInTheFilePrintItOnTheScreen(); } private void createLineReader() throws FileNotFoundException { fileLineReader = new Scanner(new File(fileName)); fileLineReader.useDelimiter("\n"); } private void forEachLineInTheFilePrintItOnTheScreen() { Iterable<String> linesInTheFile = initializeLineIteratorFromLineReader(); for(String line : linesInTheFile){ System.out.println(line); } } private Iterable<String> initializeLineIteratorFromLineReader() { Iterable<String> lineIterator = new Iterable<String>(){ @Override public Iterator<String> iterator() { return fileLineReader; } }; return lineIterator; } private void ensureFileAlreadyExists() throws IOException { File file = new File(fileName); boolean fileExists = file.exists(); if (!fileExists) { FileWriter fileWriter = new FileWriter(file); fileWriter.write(standardContentForNewFiles); fileWriter.close(); } } private void abortIfCanNotReadOrWriteFile() { boolean fileExists = new File(fileName).exists(); boolean canReadTheFile = new File(fileName).canRead(); boolean canWriteToTheFile = new File(fileName).canWrite(); if (!fileExists && !canReadTheFile && !canWriteToTheFile) throw new RuntimeException(); } } |
E o atalho de teclado mais mágico de todos é:
COMMAND+SHIFT+L (CTRL+SHIFT+L em PCs) -> Lista os atalhos de teclado.
Acho que isto já esta bom para começar, se você for realmente um preguiçoso inteligente (o tipo que passa um pouco mais de tempo pensando para ter uma solução melhor agora e trabalhar menos no futuro), provavelmente você vai prestar atenção nos menus do eclipse e vai ir decorando as teclas de atalho com o tempo
PS.: Será que alguém vai ficar ofendido com o titulo deste post e vai ficar reclamando que não é pobre ou não é preguiçoso?
Tags: Eclipse, Java, livro2, refactoring
Provavelmente serei crucificado por causa deste post, mas se você se der ao trabalho de ler até o final, provavelmente vai concordar comigo que comentários no código são para os fracos, programador hardcore de verdade escreve código legível!
É exatamente isto que eu estou dizendo, por exemplo, o que faz o código abaixo?
1 2 3 4 5 6 7 8 9 10 | public String write(StringBuilder fle, StringBuffer con) { File f = new File(fle.toString()); FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); String lin; while((lin=br.readLine())!=null){ con.append(lin).append("\n"); } return con.toString(); } |
Difícil? E este ainda é um código simples, mas vamos dar uma melhorada nele …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public String read(StringBuilder fle, StringBuffer con) { //Opens the file with the name container in the fle parameter File f = new File(fle.toString()); //Create a file reader, then a buffered reader to make our work easier FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); String lin; //Read each line of the file until it is null while((lin=br.readLine())!=null){ //Put the content read into the buffer pointed by the parameter "con" con.append(lin).append("\n"); } //The caller already have the content, because he created the buffer, but I'll return the string anyway return con.toString(); } |
Mais fácil certo? Bastou ler os comentários, mas o código continua um lixo.
Ou seja, esta é uma gambiarra utilizada por péssimos programadores para contornar a própria limitação de não conseguir escrever um código decente.
Então qual a solução que eu recomendo?
Vamos tentar reescrever este método então:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public String readFileContents(File fileToRead) { boolean canReadFile = fileToRead.exists(); if(!canReadFile) return ""; StringBuilder buffer = new StringBuilder(); BufferedReader readerForFile = openBufferedReaderForFile(fileToRead); readFileContetIntoBuffer(buffer,readerForFile); closeFileReader(readerForFile); return buffer.toString(); } private BufferedReader openBufferedReaderForFile(File fileToRead){ return new BufferedReader(new FileReader(fileToRead)); } private void readFileContetIntoBuffer(buffer,readerForFile){ String line; while((line=readerForFile.readLine())!=null){ buffer.append(line).append("\n"); } } private void closeFileReader(readerForFile){ readerForFile.close(); } |
Agora se você prestar atenção no nome do método “readFileContents” já vai saber o que o método faz, Além disto, o código do método é quase legível em inglês. A leitura dele ficaria mais ou menos assim:
if not can read file, return null
open Buffered Reader For File: fileToRead
read File Contet Into Buffer: buffer, readerForFile
close File Reader: readerForFile
return buffer.toString();
Ou seja, qualquer um que entenda inglês, como qualquer desenvolvedor tem a obrigação de entender, vai ler o método como se fosse um comentário.
E eu já vi gente fazendo pior do que isto, o código tinha comentários, mas parecia com esta coisa ai em baixo:
1 2 3 4 5 | public String write(StringBuilder fle, StringBuffer con) { File f = new File(fle.toString()); FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); String lin; while((lin=br.readLine())!=null){ con.append(lin).append("\n"); } return con.toString(); } |
Com certeza tinha muito menos linhas de código do que a minha versão ![]()
Mas não é uma tarefa fácil entender o código que uma criatura destas escreve
Claro que o exemplo que eu apresentei foi um exemplo bem simples, e que escrever código legível requer uma certa prática …
Então, vou fazer uma proposta:
Vou deixar um exemplo de código abaixo, e vocês tentam torna-lo mais legível. Em um ou dois dias eu posto a minha resposta aqui.
Quem quiser pode postar nos comentários o código que escreveu.
Para que o código fique colorido no blog, basta colocar dentro de uma tag <pre lang=”java” line=”1″> … </pre>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | package blog; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class VeryBadlyNamedFile { private static final char[] asdfg = new char[] {'I', ' ', 'c', 'a', 'n', ' ', 'd', 'o', ' ', 'v', 'e', 'r', 'y', ' ', 'u', 'g', 'l', 'y', ' ', 'c', 'o', 'd', 'e'}; private String an; private BufferedReader rfsdw; private FileReader temp; public VeryBadlyNamedFile(String an, BufferedReader rfsdw, FileReader temp) { super(); this.an = an; this.rfsdw = rfsdw; this.temp = temp; } public void doIt() throws IOException { ctfiidne(); startDoing(); try { canIDoAnyThing(); } catch (RuntimeException yicdet) { nowReallyDoIt(); } } private void nowReallyDoIt() { firstDoTheOtherThing(); reallyDoItInternal(); } private void firstDoTheOtherThing() { rfsdw = new BufferedReader(temp); } private void reallyDoItInternal() { while (true) { try { imDoingIt(); } catch (Exception e) { break; } } } private void imDoingIt() throws Exception { String s = rfsdw.readLine(); if (s == null) throw new Exception("hahaha, I bet you did not understood the code"); System.out.println(s); } private void ctfiidne() throws IOException { File a = new File(an); if (!a.exists()) { FileWriter wrfedsd = new FileWriter(a); wrfedsd.write(asdfg); wrfedsd.close(); } } private void canIDoAnyThing() { if (new File(an).exists() && new File(an).canRead() && new File(an).canWrite()) throw new RuntimeException(); } private void startDoing() throws FileNotFoundException { File f = new File(an); temp = new FileReader(f); } } |
E agora um “main” só para executar o lixão acima.
1 2 3 4 5 6 7 8 9 | package blog; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { new VeryBadlyNamedFile("c:\\anyFile.any",null,null).doIt(); } } |
Os exemplos estão em java, mas em qualquer linguagem os comentários para explicar o código servem para mascarar a incapacidade dos programadores escreverem código decente.
PS.: Só para constar, eu não acho de verdade que vocês não devem comentar o código, mas se vocês não escrevem código legível, ou escrevem código que realmente precisa de um comentário para outro programador entender, então vocês não aprenderam a programar ainda!
PS2.: só para constar, o código deste post foi inventado na hora, inspirado em coisas que ja vi em diversos lugares por ai, masescrevi ele direto no blog, então existe uma grande possibilidade de não compilar.
PS3.: acho que preciso de exemplos melhores, mas vocês devem ter entendido a idéia deste post
Tags: dicas, livro2, produtividade, refactoring
Em todos os meus trabalhos com Ruby On Rails até agora eu não achei necessária uma IDE, pois eu sempre fui mais produtivo com simples editores de texto (tudo bem, não eram editores tão simples assim), As IDEs eram sempre lentas, muito mais lentas que os editores de texto. Mas o pessoal da JetBrains se superou, na verdade não se superou, pois o IntelliJ IDEA ja é expetacular.
Mas o RubyMine é a IDE para Rails mais rápida até agora, com performance similar ao GEdit e GVim que são os meus editores favoritos (mesmo preferindo o KDE não consigo me acostumar com o Kate).
Eu não sei direito como eles fizeram, mas o code completion para Ruby e Rails esta muito rápido.
A IDE ficou Leve, o que é uma novidade interessante, pois o IntelliJ IDEA é quase tão pesado quanto o Eclipse.
E o melhor de tudo! O RubyMine tem Refactorings para código Ruby, coisa que não encontrei em nenhuma outra IDE (o NetBeans tem algumas tentativas, mas no meu último teste não funcionaram muito bem).
Bom, segue então uma lista do que faz o RubyMine ser uma ótima IDE para desenvolvimento Rails na minha opinião, com alguns screenshots ![]()




Isto fora os recursos ja conhecidos do IntelliJ IDEA para edição de HTML e Javascript, com refactorings para ambos. E o fato de o RubyMine ser a IDE mais rápida para Ruby que eu encontrei até agora. Fazem ela ser a minha preferida desde ontem também
Claro que trabalhei com ela muito pouco tempo, mas mesmo assim, ja gostei bastante do que vi.
Só falta ver como vão ficar os preços, ja que é uma IDE comercial.
Se o preço for bom, por exemplo, próximo ao preço do TextMate, vai valer a pena com certeza!
Tags: ide, intellij, jetbrains, rails, Review, Ruby, rubymine

E só pra constar, ele esta mais rápido do que as versões do KDE3 que eu estava utilizando antes.
Então se estiver com o mesmo problema, é só fazer o mesmo.
PS.: parece que isto faz o KDE não reconhecer monitores conectados ao computador depois dele ligado, mas ai é só ativar e desativar o serviço quando necessário, eu vou testar ligando o note na televisão em casa no findi e atualizo o post dizendo o que aconteceu.
Não sei se alguem chegou a sentir falta, mas o blog ficou um bom tempo meio que jogado as traças, quase sem posts, e ainda por cima passou dois dias fora do ar …
Bom, os dois dias fora do ar foram por pura bocabertice, eu esqueci de pagar a anuidade do dominio para a fapesp …
Ja o tempo quase sem posts no blog tem um motivo mais nobre, este fim de semana estarei finalizando o último capitulo do meu livro sobre Ruby On Rails que eu ja entrego com uma semana de atraso para a editora ![]()
Mas ele esta pronto! E contando com revisões da editora e o tempo necessário para a publicação, ele deve estar disponível entre o final deste ano e o início do próximo
Fora isto também tenho mais novidades …
Não trabalho mais com consultoria há algum tempo já, estou trabalhando para a HP, e acho que é a primeira vez que encontro uma empresa que posso pensar em trabalhar por muitos anos ainda. Ou seja, estou gostando bastante do trabalho
Bom, acho que era isto, a partir da próxima semana devo postar aqui com mais frequencia, já que o livro ja vai estar finalizado
A idéia de escrever este post veio desta discussão no GUJ, que começou falando de testes unitários e terminou sobre orientação a objetos.
Então seguem as minhas opiniões.
O primeiro erro que todos cometem ao iniciar em OO é achar que Orientação a Objetos é sobre classes, isto não faz nenhum sentido, Orientação a Objetos como o próprio nome diz, é sobre Objetos, então, qualquer coisa que não seja um objeto não é realmente importante quando se fala em Orientação a Objetos.
OK, mas por que todos caem no mesmo engano então? porque a grande maior parte das linguagens de programação orientadas a objeto, utilizam classes como moldes para objetos, e durante o desenvolvimento se cria os moldes, ja que os objetos só existem em tempo de execução nestas linguagens.
Quais linguagens não funcionam assim? Bom, agora me vem a cabeça SmallTalk, IO e Ruby, mas devem ter outras.
SmallTalk porque não existe realmente distinção entre “tempo de desenvolvimento” e “tempo de execução” em SmallTalk, tudo esta sempre executando.
IO porque não utiliza o conceiro de classes (a não ser que eu tenha entendido a linguagem errado) e sim objetos template.
E Ruby porque as classes em Ruby são objetos também, mas das três é a que mais se aproxima do “padrão” que citei antes.
Outro erro bastante comum, desta vez quando se utiliza alguma tecnologia de mapeamento Objeto/Relacional, é achar que objetos são tabelas, mapeamento Objeto/Relacional serve para salvar o estado de um objeto em um banco de dados relacional, apenas isto, um objeto do tipo Usuario por exemplo, não possui um atributo “grupo_id”, mas pode possuir um relacionamento com um objeto do tipo Grupo. Percebam que eu escrevi atributo e não campo, pois tabelas tem campos e linhas, objetos possuem atributos e métodos.
Uma coisa bastante comum, ainda utilizando mapeamento O/R é achar que um objeto possui os mesmos atributos que a tabela correspondente, mas neste caso até os nomes são diferentes, infelizmente nestes casos, um objeto precisa ter um atributo “id” que mapeia para a chave primária da tabela, mas um objeto não tem uma chave primária, ele tem apenas atributos.
Então, como solucionar estes problemas?
Bom, no geral, um objeto tem comportamento, e alguns atributos também, mas o importante em um objeto é o que ele faz e como ele faz.
Claro que existem objetos que não tem comportamento, objetos em um sistema são a representação binária de alguma coisa do mundo real, e existem coisas no mundo real que não tem comportamento, tem apenas atributos, como por exemplo mesas e cadeiras, mas exceto se você estiver mapeando um destes objetos no seu sistema, todos os objetos tem um comportamento.
Por exemplo, se você criar um objeto do tipo Usuário, se ele não possuir nenhum comportamento, com certeza o seu sistema esta construído de forma errada, pois pelo menos eu, não conheço nenhum usuário que fique parado como uma estátua o tempo todo, e se este for o caso, com certeza ele não é usuário de sistema nenhum, portanto ele não deveria existir no seu sistema.
A mesma coisa se aplica a um carro, você conhece algum carro que não se move? Que não tenha comportamento algum? A única desculpa para um carro que não tem comportamento algum é um sistema para um museu de carros, onde só importa a carcaça do carro e os atributos dele, principalmente o ano de fabricação.
Outra coisa que todos entendem errado é o padrão MVC (Model, View, Controller).
Na definição do padrão, o controlador esta la apenas como ponto de entrada, ele passa parâmetros para um método de um Model, pega o resultado disto e passa para uma View, se ele estiver fazendo mais do que isto, ele possui parte do código que deveria estar dentro do Model, por tanto, o seu Controller esta errado!
Beleza, mas se eu estou dizendo que todos cometem os mesmos erros, como eu posso dizer que OO é fácil então?
Porque a maioria aprende primeiro a programar de forma estrutural, e depois passa para orientação a objetos, e como as pessoas aprendem coisas novas utilizando como base suas experiências anteriores, utilizam os paradigmas procedurais para tentar programar orientado a objetos, esta é basicamente a raiz do problema.
Para tornar a vida de todos mais fácil, o primeiro contato com programação nos cursos e faculdades deveria ser com SmallTalk e não com portugol ou pascal.
Se você aprender primeiro orientação a objetos, conseguira passar para programação procedural com uma facilidade muito maior do que alguem que aprende primeiro programação procedural tentando aprender orientação a objetos.
O pior é que as linguagens de programação que não são 100% OO contribuem ainda mais para aumentar este problema, vamos pegar o Java como exemplo de uma linguagem não 100% OO.
“Mas me disseram que java era uma linguagem de programação OO”
Bom isto também é verdade, eu disse não 100% OO, não disse que não era OO.
Exemplos de coisas que não são OO em Java: tipos primitivos e métodos estáticos
Basicamente eu acho que na linguagem é só isto que não é OO, mas isto ja causa problemas o suficiente confundindo a cabeça de muita gente.
“Perai, métodos estáticos ficam dentro de classes, como podem não ser OO?”
Mérodos estáticos são uma forma porca de programação procedural dentro de uma linguagem OO que teve uma linguagem procedural como origem, como por exemplo o Java e o C++.
Métodos estáticos não fazem parte de uma classe, utilizam a classe apenas como namespace, o que é diferente de fazer parte.
Em um método estático, não é possível nem saber a qual classe ele pertence, como é possível tanto em object pascal quanto em Ruby, ja que estas não possuem métodos estáticos e sim métodos de classe.
E os tipos primitivos estes sim, não tem relação nenhuma com orientação a objetos, só estão la porque quando a linguagem foi criada não era possível fazer uma classe ter a mesma performance do que um tipo mapeado diretamente do processador da máquina, eles existem em Java por problemas de performance e não por serem Orientados a Objeto.
Alguns design patterns foram criados apenas para contornar limitações da pataforma (Exemplo prático, com um banco de dados OO decente não seria necessário criar o pattern DTO), da mesma forma algumas das regras sobre a utilização de OO foram criadas apenas porque a maioria das pessoas não entende OO, como a regra que diz favoreça composição em vez de herança.
Este é um engano terrível cometido por muitas pessoas que eu não consigo entender.
Muita gente acha que estender uma classe é uma forma de compartilhar código, por exemplo:
Existe uma entidade no sistema de nome Cliente, e em algum momento é necessário criar um ClienteDependente que vai possuir todos os mesmos atributos de cliente mais um que aponta para o responsável, não faz sentido algum fazer ClienteDependente estender Cliente para compartilhar este código, porque o comportamento deles não é o mesmo, por exemplo, ClienteDependente não paga a conta, mas Cliente sim, neste caso seria melhor refatorar o sistema e criar uma entidade que pudesse realizar compras (Ou criar objetos do tipo Compra se o sistema foi bem modelado), e fazer com que Cliente e ClienteDependente estendessem desta, pois neste caso elas estariam realmente compartilhando o comportamento e não apenas evitando algum código aparentemente repetido.
Estender uma classe é estender o comportamento, ou seja, só faz sentido estender o comportamento se a classe “filha” tiver todo o comportamento da classe “pai”, ou seja, é um relacionamento o tipo “é um”. Mas como quase ninguém consegue entender que estender uma classe estende o comportamento (não me parece uma coisa tão complexa assim para se entender), foi criada esta regra que diz: Não use herança, use composição. Simplesmente para evitar que pessoas façam porcaria por não entender conceitos que são estupidamente simples, mas que todos tem mania de complicar.
Outro erro bastante comum é tentar colocar em uma classe apenas o comportamento de todo o sistema, se for para fazer isto, utilize programação procedural, pois você vai estar utilizando a classe apenas como namespace mesmo, não vai nem lembrar que em tempo de execução estara trabalhando com diversos objetos criados a partir daquela forma.
Orientação a objetos é simples, é um paradigma de desenvolvimento que modela um sistema transformando conceitos do mundo real como objetos que colaboram entre si para atingir um objetivo.
Acho que o nome Objeto pode ajudar a confundir boa parte das pessoas, pois em um sistema OO, Compra pode ser um tipo de Objetos, mas no mundo real, compra não é um objeto. Mas para resolver isto eu simplesmente assumo que qualquer um que queira ser um programador precisa ter capacidade para trabalhar com abstrações, não tenho uma explicação melhor para alguem que não consegue entender que Compra pode ser um tipo de Objeto em um sistema OO, assim como Viajem também pode ser um tipo de Objeto (estou utilizando “Tipo de Objeto” em vez de classe porque o que importa em um sistema OO são as instâncias e não as classes) dependendo do problema a ser resolvido.
Acho que são estes os erros mais comuns na orientação a objetos, lendo isto você não concorda comigo? OO é simples, as pessoas é que complicam!
Você lembra de algum outro erro muito comum em OO? deixe um comentário.
Se eu lembrar de mais coisas simples que as pessoas tem mania de complicar eu escrevo outro post.

Ele funciona muito bem integrado com qualquer IDE, no eclipse por exemplo, basta adicionar o infinitest.jar no classpath do projeto a mandar executar a classe: org.infinitest.Infinitest
Uma tela parecida com esta vai ficar aberta enquanto você desenvolve:

Quando algum teste falha, aparece na area branca da tela o nome da classe de testes, o método e a linha da falha, e a barra da parte inferior da janela fica vermelha
O Infinitest funciona com Java + JUnit, ou seja, nada de easyb pelo menos por enquanto
Acho que vou fazer um plugin pro infinitest pra usar o Snarl também, como este do Autotest do ruby
Bom, acho que era isto, testem o Infinitest, vocês vão achar bem divertido
Tags: infinitest, tdd
Publiquei eles só no meu blog em ingles, mas acho que vale o link aqui pelo menos …
Para quem é tão preguiçoso quanto eu, eu criei um plugin para o rails que reutiliza tudo (ou quase) o que você ja definiu na migration para gerar o model, o nome do plugin é mydry.
E para quem trabalha com Grails, e estava triste até agora por não poder utilizar BDD de forma fácil, eu criei o plugin easyb-test que permite utilizar o easyb para escrever testes para a sua aplicação Grails.
Se quiserem um exemplo de como usar este plugin do easyb, é só olhar o material da minha palestra do FISL deste ano.

Então nos vemos no FISL, espero que os que aparecerem por la assistam a minha palestra, vai estar bem legal ![]()
Não vai ser só aquele CRUD básico que é apresentado em todos os lugares, estou preparando um esquema bem legal para vocês
<updated>
Acabou de ser publicado na grade de horários, a palestra vai ser dia 19 de abril as 16h ![]()
Espero que pelo menos um ou dois de vocês apareçam por la para que eu não fique sozinho na sala ![]()
</updated>

Ok, mas como deixar de perder tempo escrevendo a tal da documentação?
A solução que me vem a cabeça é BDD, ou seja, Behavior Driven Development, junto com a tão falada, documentação executável …
Mas isto existe?
Sim existe, e o pessoal doRuby On Rails já esta bastante acostumado com isto, utilizando o RSpec.
Mas este post não é sobre Ruby On Rails e nem sobre RSpec, e sim sobre o Easyb, que é uma biblioteca para escrita de “Documentação Executável” utilizando Groovy, muito fácil de utilizar para testar código Java …
Para começar com a brincadeira, vou ir ao site do projeto e fazer o download do último release (atualmente 0.7)
criar um projeto java novo no eclipse.
criar uma pasta de nome lib e copiar os seguintes jars para a pasta:commons-cli-1.1.jar easyb-0.7.3.jar groovy-all-1.5.0.jar (todos vem no zip do easyb)
criar mais uma source folder de nome behavior
(O meu eclipse esta com o plugin para edição de código groovy instalado)
Crio um build.xml para executar os testes (ainda não existe um plugin para o eclipse, mas sinceramente, não achei necessário)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?xml version="1.0" encoding="UTF-8"?> <project name="project" default="run_tests"> <path id="all.path"> <pathelement location="${basedir}/bin" /> <pathelement location="${basedir}/bin-groovy" /> <fileset dir="${basedir}/lib" includes="**/*.jar" /> </path> <taskdef name="easyb" classname="org.disco.easyb.ant.BehaviorRunnerTask" classpathref="all.path" /> <!-- ================================= target: default ================================= --> <target name="run_tests" description="--> description"> <easyb failureProperty="easyb.failed"> <classpath> <path refid="all.path" /> </classpath> <behaviors dir="${basedir}/behavior"> <include name="**/*Story.groovy" /> <include name="**/*Specification.groovy" /> </behaviors> <report location="story.txt" format="txtstory" /> <report location="behavior.txt" format="txtbehavior" /> <report location="easyb.xml" format="xmleasyb" /> </easyb> </target> </project> |
Este build.xml declara a tag do easyb e executa todos os testes, alem de gerar os relatórios, que vocês vão gostar bastante …
Os tipos de relatórios variam bastante de acordo com a versão do easyb, a equipe de desenvolvimento esta melhorando bastante isto, eu estou utilizando aqui a versão do trunk do subversion, se quiserem baixar a mesma versão que uso aqui, podem baixar via git deste repositório : git clone git://github.com/urubatan/easyb.git
(Eu fiz um fork do projeto para adicioar algumas features, e ja estou enviando os patches para os desenvolvedores)
Agora vamos começar a brincadeira ![]()
Dentro do diretório behavior vou criar um diretório de nome users e um arquivo de nome PermitirRegistroDeUsuariosStory.groovy dentro deste último.
Ou seja, este arquivo vai conter os testes, e a documentação das regras de negócio sobre a criação de novos usuários no sistema …
Quero ter uma breve descrição da história nos meus relatórios, então adiciono uma tag description no inicio do arquivo (esta tag por enquanto só existe no meu fork).
1 2 3 | description """Qualquer novo visitante do site deve poder se registrar no sistema,
desde que as regras de validação definidas sejam atendidas.
Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança""" |
As histórias são compostas basicamente de 4 comandos:
scenario – define um cenário da história, ou seja, um bloco contendo os outros 3 comandos
given – define a situação inicial
when – define um gatilho, uma ação do usuário que ira disparar alguma ação do sistema, este comando é opcional
then – define o que o sistema deve fazer, e o que vai ser testado
alem destes existe o “and” que atualmente é um comando que não executa nada, serve apenas para deixar o código mais legivel, mas isto vai mudar na próxima versão, o and vai repetir o comando anterior, semelhante ao que acontece no RSpec.
Conhecendo estes comandos podemos começar a escrever a nossa documentação ![]()
Vou adicionar alguns cenários a minha história e alguns detalhes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | scenario "Um novo usuário precisa confirmar a senha", { given "Um novo usuário", { } when "O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma", { } then "A validação do usuário deve falhar", { } when "O usuário preenche o nome de usuário e confirma a senha corretamente", { } then "A validação do usuário deve passar",{ } } scenario "Um nome de usuário deve ser único no sistema", { given "Um usuário com o formulário preenchido corretamente", { } then "O registro deve criar o usuário no sistema", { } when "O nome de usuário ja existe no sistema", { } then "O registro do usuário deve falhar",{ } } } |
Com isto, podemos ver no diretório do projeto os seguintes arquivos criados:
behavior.txt que até o momento esta em branco
story.txt que contem o seguinte texto:
Story: permitir registro de usuarios
Qualquer novo visitante do site deve poder se registrar no sistema,
desde que as regras de validação definidas sejam atendidas.
Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança
scenario Um novo usuário precisa confirmar a senha
given Um novo usuário
when O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma
then A validação do usuário deve falhar
when O usuário preenche o nome de usuário e confirma a senha corretamente
then A validação do usuário deve passar
scenario Um nome de usuário deve ser único no sistema
given Um usuário com o formulário preenchido corretamente
then O registro deve criar o usuário no sistema
when O nome de usuário ja existe no sistema
then O registro do usuário deve falhar
e easyb.xml que contem uma versão XML dos dois relatórios combinados …
Se você prestar atenção no story.txt, substituindo as palavras em ingles que fazem parte da DSL do easyb, por palavras em portugues, esta é uma ótima documentação para ser validada com o cliente, e com a garantia de que não vai ficar desatualizada por que este é o código fonte dos testes, por tanto sera alterado sempre que a regra de negócio for alterada …
Como assim?
Vamos seguir trabalhando no sistema, agora que ja temos o “behavior”, ou seja, o comportamento definido, vou adicionar algum código a esta história que devera ser testada sempre junto com o build automatizado do sistema:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package users; description """Qualquer novo visitante do site deve poder se registrar no sistema, desde que as regras de validação definidas sejam atendidas. Um usuário registrado podera alterar a sua senha sempre que desejar, mas a senha devera atender aos padrões minimos de segurança""" scenario "Um novo usuário precisa confirmar a senha", { given "Um novo usuário", { user = new User() } when "O usuário preenche o nome de usuário e a senha, mas sem confirmar a mesma", { user.setName "validName" user.setPassword "aPassword" } then "A validação do usuário deve falhar", { ensureThrows(PasswordValidationException){ user.validate() } } when "O usuário preenche o nome de usuário e confirma a senha corretamente", { user.setName "validName" user.setPassword "aPassword" user.setPasswordConfirmation "aPassword" } then "A validação do usuário deve passar",{ user.validate() } } scenario "Um nome de usuário deve ser único no sistema", { given "Um usuário com o formulário preenchido corretamente", { user = new User('userName','password','password') userManager = UserManager.getInstance() } then "O registro deve criar o usuário no sistema", { userManager.create(user) } when "O nome de usuário ja existe no sistema", { user = new User('userName','otherPassword','otherPassword') } then "O registro do usuário deve falhar",{ ensureThrows(UserAlreadyExistsException){ userManager.create(user) } } } |
Pronto, este é todo o código desta história, e foi apenas o que eu escrevi até agora.
Agora preciso criar as classes User, UserManager e implementar os métodos corretamente, para que os testes passem., por que no momento os testes não estão nem rodando, ja que estas classes não existem ainda …
Criada a classe User:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package users; public class User { private String name; private String password; private String passwordConfirmation; public User() { super(); } public User(String name, String password, String passwordConfirmation) { super(); this.name = name; this.password = password; this.passwordConfirmation = passwordConfirmation; } public String getName() { return name; } public void setName(String userName) { this.name = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPasswordConfirmation() { return passwordConfirmation; } public void setPasswordConfirmation(String passwordConfirmation) { this.passwordConfirmation = passwordConfirmation; } public void validate() { throw new RuntimeException(); } } |
E a classe UserManager:
1 2 3 4 5 6 7 8 9 10 11 | package users; public class UserManager { private static UserManager instance = new UserManager(); public static UserManager getInstance(){ return instance; } public void create(User user){ throw new RuntimeException(); } } |
Os testes agora executam mas falham.
Implementando corretamente o método “validate” da classe User, ja temos 2 testes passando:
1 2 3 4 | public void validate() throws PasswordValidationException { if(password==null || passwordConfirmation==null || !password.equals(passwordConfirmation)) throw new PasswordValidationException(); } |
E agora, finalizando a implementação do método create da classe UserManager.
1 2 3 4 5 6 7 8 | public void create(User user) throws InvalidUserException, PasswordValidationException, UserAlreadyExistsException{ if(user==null) throw new InvalidUserException(); user.validate(); if(users.containsKey(user.getName())) throw new UserAlreadyExistsException(); users.put(user.getName(), user); } |
Todos os testes passam, e o nosso código funciona perfeitamente.
Claro que a DSL do easyb é bem mais completa que isto, é possível testar apenas a especificação de uma classe em vez de uma história completa (eu uso histórias para as regras de negócio importantes para o cliente, e especificações para classes internas do sistema), existem diversos “ensure” para validar o estado desejado, tudo isto vocês podem ver na página do projeto: http://www.easyb.org
E como eu falei antes, este é o código dos testes do sistema, desta forma, quando o usuário solicitar uma alteração, se altera o teste, depois se altera o código.
Quando o seu chefe pedir para você documentar o código escrito até agora, você executa os testes, e copia os txts gerados e envia para ele por e-mail.
Os testes você seria obrigado a escrever de qualquer forma, ja que acredito eu que se você leu até aqui, você acredita que testes de código são importantes.
Como você iria escrever os testes de qualquer forma, agora você precisa fazer uma coisa a menos, que é documentar aquilo que escreveu, por que algum dia você vai querer tirar férias, e outro desenvolvedor vai precisar alterar o código que você escreveu
Depois de ler até aqui, o que você acha do easyb?
O que você acha de Behavior Driven Development?
Você concorda comigo, quando digo que o easyb tornou possível BDD em Java? (Sim eu sei que existe o JBehave, mas eu acho o trabalhoso demais, e sei que é possível trabalhar com BDD utilizando qualquer xUnit, mas ai eu perco muito da vantagem da documentação executável)
Você vai pelo menos testar isto no seu próximo projeto?
Eu estou escrevendo alguns pequenos patches e enviando para eles sempre que sinto falta de alguma coisa, e fora isto o projeto vai ter diversas melhorias bastante significativas em pouco tempo!
Parabens aos desenvolvedores, e viva o Groovy, tornando o desenvolvimento Java mais divertido e menos trabalhoso!