quarta-feira, 16 de março de 2016

Tópicos relevantes do livro Código Limpo (Clean Code)

Tópicos relevantes do livro Código Limpo: Clean Code A Handbook of Agile Software Craftsmanship


O livro Código Limpo (Clean Code - A Handbook of Agile Software Craftsmanship) é basicamente um atalho pra você aprender as boas práticas dos grandes programadores poupando dores de cabeça e, principalmente, tempo e dinheiro. Eu mesmo, durante minha carreira relativamente curta de desenvolvimento de software já colecionava uma série de mandingas, cacoetes e práticas que poderiam ser (algumas) consideradas boas e outras eufêmicamente "teimosas".
Basicamente, quando leio um livro, gosto de ter à mão um lápis e uma caneta de grifar para poder destacar e anotar o que julgo importante. Também tenho um Kindle™ que me permite fazer isso de forma “ecologicamente correta”. Entretanto, desta vez o livro não era meu, então, tive que anotar minhas considerações em blocos de papel e, posteriormente, no documento que aqui compartilho convosco. Todavia, antes de começar, recomendo a todos que leiam o livro na íntegra, pois realmente vale cada um dos 60 reais que o meu brother William Lopes (conhecido pelas alcunhas Maica, Capi, Non, entre outros) pagou (acabei de consultar a Amazon.com e vi que está custando 170 hoje: http://www.amazon.com.br/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882).


A organização desse post segue-se mais ou menos assim: o título é o capítulo de onde retirei a informação e os tópicos são as práticas que considerei relevantes seguidas de algum comentário (in-) oportuno meu. Também vale a pena frisar que há muito mais no livro do que eu aqui vos transcrevo, no entanto, anotei os pontos que mais chamaram a atenção pra minha insignificante vida de programador.


Nomes
  1. Nomes significativos, independente do tamanho, o nome deve expressar o que a variável/método/classe se propõe a fazer. É melhor um nome do tipo somarOTotalPagoAFornecedores do que um método chamado somar e um comentário gigantesco, perecível e ignorável dizendo o que o dissilábico método faz. E é isso que a anotação seguinte expressa:
  2. Melhor um nome extenso e significativo do que um nome curto e confuso. Isso quer dizer que você não deve se preocupar em economizar caracteres para descrever o comportamento do seu método enquanto o nomeia. No entanto, cautela e bom-senso devem sempre predominar nas escolhas.
  3. Nem sempre é (ou não é) possível começar pelo ótimo, o ideal é fazer um brainstorming inicial e refatorar usando-se as ferramentas (IDE). Em outras palavras, você “vomita” o código funcional e depois faz o refactoring. Tentar começar pelo "código limpo" em muitas ocasiões me custou muito tempo, simplesmente pela minha vaidade de não colocar uns ifs dentro dos outros.
  4. O código deve contar uma história. Quem vai lê-lo deve entendê-lo na integra, sem auxílio de comentários e documentações. Aqui a dica vai além da nomenclatura dos artefatos. "Contar uma história facilmente compreensível" é basicamente a dica do livro.
  5. Os nomes devem ser refatorados com o tempo. Uma classe/função/método/variável pode perder o significado original, portanto, é sempre importante manter a nomenclatura em acordo com a intenção real e atual do método. Aqui cabe ressaltar o trabalho extra que os comentários geram. Eu, particularmente, até ler o livro, era um cara que gostava de enfeitar as classes com belos textos, às vezes até rebuscados, detalhando o funcionamento das minhas rotinas. Percebi (leia-se: fui convencido) mais tarde que esses comentários só serviam para ficar desatualizados.
  6. Nomes pronunciáveis são sempre melhores que nomes acrônomicos. AgentConsoleLoginRequest é melhor que ACLRequest. Obvio, não?.
  7. Classes → substantivos, métodos → verbos. Básico de qualquer curso de programação; classe define coisas e, os métodos, como essas coisas se comportam.
  8. Nomes devem ser significativos dentro do contexto (domínio) do software. A palavra "nota" pode ter significados diferentes em um sistema de vendas, um acadêmico e um sistema de anotações pessoais, por isso é sempre bom estar de acordo com o vocabulário do seu cliente. Vai por mim, já passei muita raiva porque o cliente mencionava uma funcionalidade ou artefato usando uma palavra e no software estar representada por outra. Usar um vocabulário comum é essencial.


Funções

  1. Devem ser pequenas! 5 ou 10 linhas é mais que o necessário. É isso! O Joshua Kerievsky fala no seu livro "Refatoração para Padrões" que a média de linhas dos métodos do seu sistema não devem ser maior do que 5 (“Your methods can be no longer than five lines of code”).
  2. Devem fazer somente o que se propõem a fazer.
  3. Devem fazer somente 1 tarefa. A 2 e a 3 se complementam. Um método denominado somar(a, b) deve somar a e b (ponto). Não tem que incrementar outras variáveis, não tem que validar se o usuário pode somar a com b, não tem redirecionar para outra página, não tem que fazer mais nada. Tem que somar a com b! Outra dica interessante é que se você usar “e” ou “ou” na nomenclatura do seu método tem grandes chances dele estar acumulando responsabilidades; na dúvida: refatore.
  4. Quanto menos parâmetros, melhor:
    1. zero parâmetros: o ideal;
    2. 1 parâmetro: bom;
    3. 2 parâmetros: aceitável;
    4. 3 parâmetros: ruim;
    5. 4 parâmetros: melhor repensar;
  5. Exceções são melhores do que códigos de erro. Concordamos que não devemos exibir um UnauthorizedException, na tela do usuário, mas ainda assim é melhor do que exibir um "error 403".
  6. Uma função que trata códigos de erro não deve fazer mais nada além de tratar os códigos de erro. Basicamente as anotações 1, 2 e 3 juntas.


Comentários

Essa foi pra mim a parte mais dolorosa: parar de comentar. Quando eu aprendi a fazer meu primeiro if no saudoso Clipper 5, mais ou menos no verão de 1996, comentários eram o que diferenciavam o bom programador do ruim; o cara organizado do porco relaxado. Acabei carregando esse hábito comigo para as outras linguagens: C, C++, PHP e mais tarde pro Java. Até pouco tempo atrás eu ficava bravo se alguém me falasse que comentar era ruim.
  1. Comentários são ruins. Isso é um fato, aceite.
  2. Javadoc é aceitável, mas também é ruim. Geralmente são gerados pelas IDEs aqueles cabeçalhos de métodos entre “/**” e “*/” com as meta-variáveis @param, @see, @author, etc. Isso é de certa forma, segundo o autor, aceitável, porém desencorajado. Você acaba refatorando o método e se esquece de alterar a quantidade de parâmetros, tipos, etc; é justamente isso que diz a a notação seguinte:
  3. O programador acaba alterando a função mas não a documentação.
  4. A regra básica é: sempre que precisar comentar, refatore. Resumidamente:  "se você se sentir tentado a colocar um comentário para explicar seu código, é porque ele não está compreensível" (coloquei entre aspas porque não me lembro quem disse isso).
  5. Um tipo de comentário válido é aquele que expressa algo que não pode ficar claro no código: uma decisão de negócio, por exemplo:
// desculpe, me obrigaram a fazer isso


Formatação

  1. Melhora a legibilidade.
  2. Deve ser empregada por toda a equipe de maneira consensual.  “Ao ler um código, não ser possível identificar quem o escreveu”. Todos devem praticar de forma igual. Eu costumo usar o padrão da IDE para evitar entrar numa luta recursiva toda vez que alguém usar o recurso de auto-formação antes de commitar uma classe.
  3. Espaçamentos devem ser padronizados. Entre métodos, entre declarações de variáveis, entre parênteses, entre chaves, enfim, reúna a equipe e entre em um acordo sobre o que deverá ser empregado como padrão de espaçamento, redija um documento e disponibilize à todos.
  4. Separar contextos dentro da classe. Declaração de variáveis estáticas privadas de públicas; declaração de variáveis dos métodos e por aí vai. No meu caso, uso somente uma quebra de linha simples para separar os contextos, sem traços, pontos ou aquelas horrorosas série de sinais de igualdade (ex: “=======”).
  5. Variáveis devem ser declaradas próximo de onde serão usadas (dentro do método). Eu aprendi a declarar as variáveis nos inícios dos métodos, quando comecei a programar em C. Não tenho certeza se isso era um requisito da linguagem, mas sei que me acostumei a fazer isso e acabou sendo outra mania que migrei para as demais linguagens. Não o faça! Declare suas variáveis próximas aos pontos onde você irá utilizá-las.
  6. Métodos devem ser posicionados imediatamente abaixo dos métodos que os chamam. Se um método A chama um método B, posicione o método B imediatamente abaixo do método A. Isso facilita a leitura de quem pegar seu código no futuro. Geralmente as ferramentas de refactoring já fazem isso automaticamente quando você vai extrair um bloco de código para um método.
  7. Linhas devem ser quebradas em qualquer posição entre 100 e 120 caracteres (eu uso 128... porque sim). Tanto no Netbeans quanto no Eclipse, eu coloco a margem da direita na posição 128 e NUNCA, repito, NUNCA deixo meu código ultrapassá-la. Acho que isso é uma prática que veio das telas 80x24 (tipo Clipper) que a galera usava para programar antigamente; 80 colunas por 24 linhas. Assim, para uma melhor visualização do código, os programadores recomendavam não ultrapassar a coluna 80 para não gerar rolagem horizontal. Hoje, com as telas alta resolução isso não se faz mais necessário, mas o autor acha importante quebrar a linha em algum ponto entre o começo e o fim do seu “range” visual.
  8. Aninhamento horizontal são ruins porque geralmente as IDEs não os respeitam. Aquelas declarações de variáveis, enums e qualquer outra coisa que você tenta alinhar em colunas, colocando os sinais de igual exatamente um abaixo do outro, não funcionam. O primeiro aloprado que usar a formatação automática vai destruir em milésimos de segundos os minutos preciosos que você gastou tentando alinhá-las. Eu adotei uma regra simples: não brigue com a IDE.


Estrutura de dados

  1. Um objeto não deve expor seus atributos internos. A primeira ideia que vem a mente ao ler isso é gerar métodos get e set para todos os atributos, o que é de certa forma válido, mas ainda devemos considerar a observação seguinte:
  2. Getters e setters acabam quebrando o encapsulamento quando indiscriminadamente usados. A lição aqui é ser cauteloso no que sua classe vai expor. Talvez não haja a necessidade da sua classe externar atributos como precoCusto e margemDeLucro quando você pode simplesmente expor um método que retorna o preço final (eu sei que foi um exemplo medíocre, desculpa).
  3. Lei de Demeter: o módulo não deve enxergar o interior do objeto que manipula. Uma função f de uma classe c só deve chamar
    1. métodos de c;
    2. objetos usados por f;
    3. objetos passados por parâmetro para f;
    4. variáveis de instância de c.
Esse assunto por si só, rende um post inteiro, portanto, se quiser se aprofundar mais, dá uma olhada nesse post aqui.
  1. Train Wrecks (acidentes ferroviários) ocorrem quando há encadeamento de chamada de métodos. Quando há encadeamento, melhor separá-los em variáveis locais conhecidas:
a.getB().getC();
deve ficar:
B b = a.getB();
C c = b.getC();
No entanto, o ideal é que a classe A retorne o objeto esperado a partir de um método adequadamente nomeado e especificado (comportamento estaria em a):
a.getQualquerCoisaQueBFazComC();
  1. Objetos DTO não devem possuir comportamentos. São burros, ou como o pessoal gosta de dizer: anêmicos.


Exceções e erros

  1. Sempre preferir exceções ao invés de retornar códigos de erro. Como foi mencionado em uma nota anterior, é melhor lançar uma UnauthorizedException do que um “Error 403”.
  2. Sempre optar por exceções não verificadas. Exceções verificadas propagam alterações para níveis que não deveriam, por exemplo: um método que passa a lançar uma nova exceção verificada deverá alterar todas as estruturas de outros níveis que o usa.
  3. Contextualize as exceções. Geralmente um tipo de exceção por módulo é mais do que o suficiente.
  4. Nunca retorne null. Retornar null implica em verificação if-null por todo o código, sem contar as atormentadoras NullPointerExceptions que fazem qualquer programador se sentir um newbie.
  5. Null deve ser encarado como uma condição anormal. Você deve considerar que um null em qualquer ponto do código é algo anormal e deve ser verificado.
  6. Nunca passar ou receber null como parâmetro.


Classes

  1. Devem ser pequenas. Pode ser difícil definir “pequena” aqui, mas considere a dica do  Joshua Kerievsky no "Refatoração para Padrões" sobre o tamanho médio dos métodos para mensurar suas classes.
  2. Possuir um único propósito e ter a responsabilidade bem definida (coesão). Uma dica: geralmente quando a descrição (Javadoc, por exemplo) de uma classe usa “e” para descrevê-la, significa que ela possui mais de uma responsabilidade.
  3. Escolher um bom nome pode ser a forma exata de separar adequadamente as responsabilidades.
  4. Recomenda-se começar declarando variáveis públicas e estáticas (constantes) seguidas pelas privada e estáticas, seguidas pelas, seguidas pelas variáveis de instância privadas.


E é isso. As práticas acima, como eu disse, são só um amontoado de anotações que eu considerei importantes  para usar no meu dia a dia  enquanto eu lia; nem sequer abrange o conteúdo todo do livro. Me arrependi muito de ter negligenciado tal material por tanto tempo e se há um livro de TI que eu recomendaria para alguém que está iniciando sua carreira, não tenho dúvidas que seria esse.




terça-feira, 11 de novembro de 2014

JSF 2 - Eventos

O objetivo desse post é ir um pouco além das categorias de eventos mais utilizadas pelo framework: action listeners e value change listeners.

Action e Value Change Listeners

Como todo mundo que desenvolve JSF deve conhecer, utilizamos action listeners quando queremos executar a lógica de aplicação sem que, no entanto, tenhamos que redirecionar o fluxo das páginas retornando um outcome.

A imagem abaixo mostra o exemplo de um listener:


E o componente (action source) que dispara o evento:


Da mesma mesma forma, sem grandes novidades, utilizamos os value change listeners. Primeiro o código Java:


O script JSF:



O que grande parte dos iniciantes JSF desconhece é que existe outra forma de reproduzir este comportamento implementando os listeners de outra forma - estendendo as interfaces javax.faces.event.ActionListener e javax.faces.event.ValueChangeListener respectivamente. O exemplo a seguir mostra a implementação de um action listener usando a interface proposta:

A interface javax.faces.event.ActionListener especifica o método processAction que se comporta de forma parecida que o método myActionListener do primeiro exemplo. A maior diferença está no fato de que cada vez que uma ação for executada uma instância de MyActionListener será criada.

O botão abaixo dispara um evento que é tratado pela implementação MyActionListener. A maior diferença aqui é que, ao invés de usar o atributo actionListener do h:commandButton, utilizamos a tag f:actionListener especificando o nome totalmente qualificado da classe no atributo type:


Uma das grandes vantagens desta última abordagem é que podemos especificar mais de um action listener para o h:commandButton e eles serão executados na ordem em que forem especificados no corpo do componente:


E é o mesmo no que diz respeito aos value change listeners. Primeiro o código Java:


Depois o JSF:


Os System Events

Os action e value change listener vão resolver a maior parte dos seus problemas de eventos enquanto desenvolvedor JSF. Porém, existem aquelas ocasiões em que precisamos de algo mais. O modelo de componentes do JSF permite associar listener aos componentes em momentos distintos da sua existência. Um bom exemplo é um listener que seria executado no momento imediatamente antes do componente ser renderizado na página. No exemplo a seguir, foi especificado um método listener que recebe um ComponentSystemEvent como parâmetro. O método simplesmente faz o cast do componente que disparou o evento para um UIInput e configura a data atual como o seu valor padrão.


A seguir, o trecho JSF do component que dispara o evento:


A novidade aqui é a tag f:event que especifica o tipo (atributo type) de evento que será disparado e seu respectivo listener (método myPreRenderListener, no managed bean). Outros momentos da existência do componente pode ser observado na doc https://docs.oracle.com/javaee/6/javaserverfaces/2.1/docs/vdldocs/facelets/f/event.html .

Ainda quanto aos System Events, você pode aumentar um pouco mais a capacidade da sua aplicação reagir aos momentos da sua execução. A superclasse de ComponentSystemEvent, SystemEvent, permite que você trate eventos de mais baixo baixo nível, como, por exemplo, a inicialização e a finalização da aplicação. O exemplo a seguir mostra exatamente isso:

A classe acima implementa a interface javax.faces.event.SystemEventListener com o intuito de tratar os eventos derivados da interface javax.faces.event.SystemEvent. A interface provê dois métodos: isListenerForSource, usada para determinar se o evento gerado é do tipo apropriado para ser tratado e o processEvent, onde ele deve ser adequadamente tratado. Para exemplificar, eu irresponsavelmente trataei eventos distintos no mesmo método. O trecho do faces-config.xml a seguir diz para o container que a minha implementação é um listener de eventos do sistema. Todo o código abaixo deve ser inserido entre e
.

O conjunto de eventos que podem ser tratados desta forma está descrito em https://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/api, na seção "direct subclasses".








terça-feira, 23 de dezembro de 2008

Validação de formulários com jQuery

Requisitos:
jquery-1.2.6.js
Você pode ver o script funcionando aqui:
http://www.infernatica.xpg.com.br///validacao01.html


Esse é um exemplo simples de validação de formulários HTML utilizando jQuery. Parte do princípio que é necessário apenas verificar se os campos foram devidamente preenchidos, mas pode ser facilmente estendido para atender propósitos mais específicos. Vou apresentar os códigos e em seguida discuti-los; acredito que essa seja a maneira mais simples e eficiente para explicá-los.

O formulário HTML é bem simples, dois campos do tipo input text, textarea e uma div para exibir as mensagens de erro.

A figura acima apresenta o código do formulário que deverá ser validado. Trata-se de um simples formulário HTML, composto de três campos, respectivamente nome, sobrenome e observações, sendo os dois primeiros do tipo input text e o último um text-area. Observe que defini dois atributos extras para cada objeto de inserção de dados: label e req. Na verdade, é perfeitamente possível substituir o atributo label pelo próprio name, porém utilizei o label para apresentar informações mais detalhadas para o usuário. O outro atributo, req, serve para definir que o campo é obrigatório. Observe também que há uma div (#divError), configurada para não ser exibida (style=”display:none”), cujo propósito é apresentar as mensagens de erro oriundas da validação.

Resumidamente, a estratégia desta validação é percorrer os campos do formulário e verificar em quais deles está presente e definido como true o atributo req. Os elementos que definem req=true devem possuir pelo menos um caractere preenchido em seu valor (value).
O código entre a linha 8 e 12 serve para fazer a ligação (binding) entre o evento submit do formulário e a função JavaScript validar que criei. A variável canSubmit serve para determinar se o formulário pode ser postado (true) ou não (false). A variável messages irá armazenar todas as mensagens de erro que serão exibidas para o usuário. Observe que ela é iniciada com um elemento do tipo unordered list (<ul>). O código da linha 22 define que a função subseqüente (aquela que lhe é passada como parâmetro) deverá ser executada para todos os elementos que possuir o atributo req definido como true. Na linha 24 é onde se verifica se pelo menos um caractere foi digitado no input (ou no text-area); se detectado um elemento vazio, a variável canSubmit é configurada como false e à variável messages é concatenado o label do elemento que está vazio, entre tags do tipo list item (<li> e </li>), como é exigido pelos elementos list. A execução prossegue para determinar se existem mais campos vazios e, se houver, o procedimento se repete, concatenando mais mensagens de erro à variável messages.
Após todos os elementos que definem req=true terem sido percorridos, o primeiro passo é concatenar, à variável messages, a tag que encerra o unordered list (</ul>). Em seguida é feita uma verificação condicional (if da linha 33) para determinar se o formulário pode ser postado. A verificação consiste, basicamente, em verificar o valor de canSubmit; se falso, as mensagens concatenadas em messages serão inseridas dentro da div cujo id é divError e exibidas com o efeito fadeIn do jQuery, configurado para 300 milissegundos. A última linha da rotina retorna o valor de canSubmit que, se for true, faz com que o formulário seja submetido e, caso contrário, o submit é cancelado.
A figura a seguir ilustra o funcionamento da validação. Você pode testá-la deixando algumas tags sem o atributo req=true. Como eu disse, a partir daí, criar uma validação mais específica não é muito trabalhoso.




O código completo da validação:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Validação com jQuery</title>

<script language="javascript" src="jquery-1.2.6.js"></script>
<script language="javascript">
$(
function(){
$("#mainForm").bind("submit", validar);
}
);

/**
* Executa a verificação
*/
function validar(e){
// determina se o form pode ser submetido ou não
var canSubmit = true;

// acumula as mensagens de erro
var messages = "<ul>";

// faz uma busca por todos elementos que especificam o atributo req=true
$("[req=true]").each(
function(){
if($(this).val().length < 1){
canSubmit = false;
messages += "<li>" + $(this).attr("label") + " é obrigatório</li>";
}
}
);
messages += "</ul>";

// verifica se vai exibir as mensagens de erro
if(canSubmit == false)
$("#divError").html(messages).css("color", "red").fadeIn(300);

return canSubmit;
}
</script>

<style>

p{
margin: 2px;
padding: 2px;
}

</style>

</head>

<body>
<form method="post" id="mainForm">
<!-- div que irá exibir as mensagens de erro -->
<div id="divError" style="display:none"></div>

<p>Nome</p>
<input type="text" name="name" label="nome do usuário" req="true"/>

<p>Sobrenome</p>
<input type="text" name="sobrenome" label="sobrenome do usuário" req="true"/>

<p>Observações</p>
<textarea name="obs" label="observações sobre o usuário" req="true"></textarea>

<br/>
<input type="submit" value="Enviar"/>
</form>
</body>
</html>

sábado, 12 de abril de 2008

Precedência de operadores em Java

Precedência de opereadores em Java
Da maior para a menor

Operador Descrição
. [] ()
(tipo)
Máxima precedência: separador, indexação, parâmetros, conversão de tipo
+ - ~ ! ++ -- Operador unário: positivo, negativo, negação (inversão bit a bit), não (lógico), incremento, decremento
* / % Multiplicação, divisão e módulo (inteiros)
+ - Adição, subtração
<< >>
>>>
Translação (bit a bit) à esquerda, direita sinalizada, e direita não sinalizada (o bit de sinal será 0)
< <= >=
<
Operador relacional: menor, menor ou igual, maior ou igual, maior
== != Igualdade: igual, diferente
& Operador lógico e bit a bit
^ Ou exclusivo (xor) bit a bit
| Operador lógico ou bit a bit
&& Operador lógico e condicional
|| Operador lógico ou condicional
?: Condicional: if-then-else compacto
= op= Atribuição

Considere a expressão:

1 | 2 ^ 3 * 2 & 13 | 2

  1. A análise é feita da esquerda para a direita.
  2. O primeiro cálculo a ser executado é 3 * 2, que resulta em 6.
  3. Em seguida, o resultado anterior é comparado com o 13, uma operação & (E): 6 & 13, que resulta em 4.
  4. Agora é feita uma operação de ^ (Ou exclusivo) com o 2 (mais a esquerda) e o 4 da operação anterior. O resultado é 6.
  5. É executada, então, a operação | (Ou) mais a esquerda: 1 | 6 que resulta em 7.
  6. Por último, é executadada a operação de | (Ou): 7 | 2 que também resulta em 7.
A mesma expressão acima poderia ser escrita da seguinte forma:

((1 | (2 ^ ((3 * 2) & 13))) | 2)