01 6 / 2012

No unread items

Fato raro. Há algum tempo venho lutando contra os feeds. Por mais que eu filtre o conteúdo, sempre acabo abrindo algumas abas para ler. Isso se tornou um hábito diário, pra não dizer um vício, desde meados de 2010.

Foi justamente nessa época que desisti do emprego, do qual eu estava insatisfeito, por não estar conseguindo evoluir tecnicamente. Eu sei que toda culpa é minha, só que eu me encontrava em um estado inerte, sem estímulo algum vindo de fora. Era um ciclo vicioso e eu sabia que precisava mudar. Foi então que comecei uma busca desesperada por conhecimento.

Alguns meses antes de outubro de 2010, comecei a visitar regularmente alguns blogs e ler artigos técnicos. Comecei a utilizar um aplicativo desktop para receber os feeds até migrar em outubro para o google reader. Foi justamente nessa época de desempregado que comecei a gastar muitas e muitas horas lendo os feeds.

Mesmo depois de voltar a trabalhar, continuo mantendo sempre que possível meus feeds em dia, é difícil já que o tempo é escasso. O que acabei percebendo é que os feeds já não agregam tanto como antigamente e eles acabam tomando muito do meu tempo livre. Eu já vinha percebendo isso há algum tempo, mas depois de ler esse post “Estamos criando uma cultura de distração”, percebi que os feeds realmente estão mais me atrapalhando do que ajudando.

Não tenho tantos problemas com sms, ligações, checar e-mail, facebook, etc, porém, os feeds me atrapalham. Então a partir de hoje não abro mais o google reader pelos próximos meses. Pretendo dedicar mais meu tempo com livros, pet projects e com o blog. Vamos ver o resultado.

Screenshot tirada ontem:

Por algum motivo o google marca desde dezembro 2009, deve ser a primeira vez que acessei o serviço, mas comecei a utilizar efetivamente por volta de outubro de 2010.

22 12 / 2011

Migrando para o tumblr

No início do blog eu havia escolhido como plataforma o wordpress pois eu não queria ter trabalho de manter servidor, ter que ficar pagando, fazer muitas customizações, etc. Porém, com o tempo percebi que o blog dentro wordpress.com me deixava muito limitado. Eu precisava de um pouco mais de liberdade para fazer pequenas customizações.

Acabei conhecendo o tumblr. De cara o que me chamou mais a atenção foi a possibilidade de editar o html e apontar um domínio .com para blog, tudo com uma conta básica grátis. Depois acabei encontrando vários themes legais grátis, coisa difícil de achar no wordpress. Além disso é bem mais leve e fácil de usar. Isso tudo me fez migrar para o tumblr, veja algumas customizações que fiz:

  • customização do theme (html/css)
  • domínio .com
  • google analytics
  • google prettify no lugar do syntax highlight
  • jQuery
  • RSS redirecionados para o feedburner
  • comentários com plataforma disqus

A versão grátis do wordpress não permite nada disso. A única coisa que falta no tumblr, que no wordpress é melhor, é um gerenciador de galerias (tanto para fazer upload quanto para exibí-las) mas não faz tanta falta.

A migração dos posts foi rápida porém rudimentar, ctrl+c/ctrl+v no html e o editor do tumblr cuidou de tudo, só tive que inserir as imagens novamente, limpar alguns &nbsp; perdidos e ajustar tags <pre><code> para os exemplos de código funcionarem no prettify. Fazer dessa forma só foi possível pois são pouquíssimos posts.

Durante a migração desses posts resolvi não migrar 2 sobre o dropbox. Muita gente chegava neles através do google esperando um “how to” para usar dropbox no pen drive só que não era nada disso.

05 12 / 2011

JavaScript assíncrono

Essa foi a pergunta inicial que motivou a escrita desse post. Tudo começou com a função ajax() do jQuery. A descrição na documentação diz o seguinte: “Perform an asynchronous HTTP (Ajax) request”. Na documentação você irá encontrar que existe o parâmetro async. Ele é true por default, alterando para false a requisição será síncrona. Então surge a pergunta, como o JavaScript executa isso de forma assíncrona?

Primeiro é necessário entender que assíncrono não é necessariamente multithread, concurrent ou parallel. Assíncrono é apenas ter impressão de que duas ou mais tarefas estão sendo feitas ao mesmo tempo. Uma coisa importante saber é que JavaScript não tem suporte a threads então, para possibilitar esse comportamento assíncrono, são disponibilizadas basicamente 2 funções: setTimeout()setInterval(). setTimeout(func, delay) aceita 2 parâmetros, o primeiro é uma função e o segundo o tempo (em milesegundos) para aguardar até que a função seja executada. setInterval() funciona da mesma forma porém, a função será executada continuamente até que clearInterval() seja chamada. Nos exemplos mais a frente elas serão utilizadas. Veja os exemplos mais básicos com setTimeout():

console.log("início");
setTimeout( function() { console.log("aguardou 3 segundos e executou"); }, 3000);
console.log("executando diversas tarefas...");
console.log("fim");

/* saída
início
executando diversas tarefas...
fim
aguardou 3 segundos e executou */
console.log("início");
setTimeout( function() { console.log("função 1: aguardou 0ms e executou"); }, 0);
console.log("executando diversas tarefas...");
setTimeout( function() { console.log("função 2: aguardou 0ms e executou"); }, 0);
console.log("fim");

/* saída
início
executando diversas tarefas...
fim
função 1: aguardou 0ms e executou
função 2: aguardou 0ms e executou */

Somente após executar todas as funções/métodos que as funções passadas à setTimeout() são executadas. As engines JavaScript dos navegadores implementam uma espécie de fila para essas funções. Talvez para inserir nessa fila seja feito um cálculo com o tempo atual e o delay da função.

setTimeout( function() { console.log("função 1: aguardou 100ms e executou"); }, 100);
setTimeout( function() { console.log("função 2: aguardou 0ms e executou"); }, 0);

/* saída
função 2: aguardou 0ms e executou"
função 1: aguardou 100ms e executou */

Callback

Callback nada mais é do que passar uma função como parâmetro, geralmente elas são passadas a uma função assíncrona e executadas ao término da função. Por exemplo, quando finalizar uma inserção na base de dados, o usuário é avisado que os dados foram gravados com sucesso.

function gravaDados(callback) {
console.log("realizando operação I/O");
callback();
}

console.log("início");
var callbackSucesso = function() { console.log("dados salvos"); };
setTimeout(function() { gravaDados(callbackSucesso); }, 0);
console.log("fim");

/* saída
início
fim
realizando operação I/O
dados salvos */

A idéia é que a operação de I/O que bloqueia a execução do programa por aguardar respostas de alta latência (disco/rede) fique por último, liberando assim outras funções de rápida execução que dependem exclusivamente do processador, como a interface com o usuário (html).

Single thread

Para comprovar como o JavaScript é single thread veja o exemplo:

setTimeout( function() { console.log("função 1: aguardou BEM MAIS que 100ms e executou"); }, 100);
var t1 = (new Date()).getTime();
for (var i = 0; i < 1000000000; i++) {}
var t2 = (new Date()).getTime();
console.log("demorou :" + (t2 - t1) + "ms");

/* saída
demorou :9587ms
função 1: aguardou BEM MAIS que 100ms e executou */

A saída é auto explicativa. Esse ‘for’ gigante é um operação CPU bond e consome um bom tempo do processador causando atraso para executar outras funções com delay ‘vencido’. Esse mesmo problema ocorreria se colocarmos esse ‘for’ em uma função e passar para setTimeout(), iria atrasar a execução de todas as outras funções passadas à setTimeout() ou setInterval().

Veja aqui um exemplo que movo 2 quadrados pela tela. A cada 20ms os quadrados são movidos 1 pixel para direita, o que dá a impressão de um movimento bem suave (smooth). O segundo quadrado (rough) o movimento não é contínuo, travando de tempos em tempos pois existe uma função consumindo muito processamento, atrasando a execução da função que move o quadrado 1 pixel para direita. Dessa forma fica perceptível que o quadrado está travando. Clique para abrir o exemplo.

Investigando a função ajax() do jQuery

Existem as seguintes chamadas dentro da função ajax():

xhr.open( s.type, s.url, s.async );
xhr.send( ( s.hasContent && s.data ) || null );

xhr é um objeto XMLHttpRequest criado para browsers que não sejam IE. Eu esperava que em algum lugar do send() tivesse um setTimeout() porém, como xhr trata-se de um objeto do navegador, a classe não é escrita em JavaScript em sim em C++. Baixando o código fonte do firefox 8 é possível encontrar a classe XMLHTTPRequest. Para encontrar a classe:

grep -r -i "xmlhtmlrequest" /home/bruno/Downloads/mozilla-release > /home/bruno/Desktop/xmlhtmlrequest

No arquivo XMLHTTPRequest.cpp encontramos a função Open() que acaba delegando para XMLHttpRequestPrivate::Open

bool
XMLHttpRequestPrivate::Open(JSContext* aCx, JSString* aMethod, JSString* aURL, bool aAsync, JSString* aUser, JSString* aPassword)

Veja que a função recebe o parâmetro aAsync. A implementação de Open() não é nada trivial e eu não entendi muita coisa mas dá para perceber a utilização de thread. Já que entender o código levaria um grande tempo, a maneira mais rápida é experimentar e observar para chegar a uma conclusão empírica.

Experimento

  • colocar breakpoint na chamada xhr.send()
  • colocar breakpoint no controller da aplicação que irá pegar a requisição
  • chamar ajax() com parâmetro async = false e depois com async = true

Com os breakpoints eu consigo controlar o fluxo tanto do lado no cliente quanto no servidor. Para melhor observar, coloquei um Thread.sleep(10000) no controller para simular uma longa requisição.

Resultados

  • async = false: após apertar F10 (Step Over) perco o fluxo no Firebug e o breakpoint no controller é acionado. Após executar toda stack no lado do servidor o fluxo no Firebug volta para mim.
  • async = true: após apertar F10 (Step Over) passo por cima da função, o JavaScript continua executando e o breakpoint no controller é acionado.

Um segundo teste foi feito retirando o breakpoint do controller, com async = false a função send() demora para voltar, enquando com async = true a volta é instantânea.

Conclusões do experiemento

  • Com async = false o comportamento foi como o esperado, tudo executado na ordem em que foi chamado.
  • Com async = true era esperado o comportamento igual a uma função passada ao setTimeout(), ou seja, o controller só iria ser disparado após todo JavaScript ser executado. Isso não ocorreu. Uma suposição minha é que pelo fato de send() chamar um método de um objeto nativo do navegador escrito em C++, ele é executado em uma thread diferente da thread de código JavaScript. Com async = false a thread do JavaScript puro espera até que a thread do navegador retornar, com async = true as duas threads são executadas paralelamente.

Conclusão final

As funções setTimeout() e setInterval() devem ser utilizadas para operações que não travam o processo, seja por esperar uma resposta ou por ter um alto consumo do processador. Animações na parte de UI geralmente não consomem processamento exagerado, dessa forma é possível executar um variedade de funções em um intervalo de alguns milesegundos, dando ao usuário a impressão de que tudo está ocorrendo ao mesmo tempo. Para o processador, milesegundos são uma eternidade, sendo possível executar funções de baixo tempo de processamento e ficar ocioso até a próxima.

Também foi possível constatar que objetos de classes JavaScript implementadas pelo navegador podem delegar a execução de uma função para um código em outra linguagem que utiliza thread, fazendo com que a execução seja paralela ao código JavaScript normal, diferenciando do comportamento assíncrono do JavaScript obtido através de setTimeout() e setInteval().

Investigações futuras

Pesquisas sobre JavaScript assíncrono acabaram me levando até o Node.js que é conhecido como o “JavaScript do lado do servidor”. Existe um grande hype em cima desse assunto. O interessante é que no site, na seção about, é dito que Node.js praticamente não faz chamadas diretas de I/O, fazendo com que o processo não trave. Para utilizar mais processadores é necessário criar um novo processo chamando child_process.fork(). O site afirma que com node.js programadores menos experts são capazes de construir aplicações rápidas.

27 10 / 2011

JavaScript, OO e prototype

Ultimamente estou estudando um pouco sobre web, principalmente o que envolve o lado do cliente, ou seja, CSS, JavaScript, JQuery e Ajax. O que me deixa mais surpreso é a linguagem JavaScript e suas bizarrices (variáveis globais, ===, != undefined/null, etc..), entretanto, alguns dias lendo código faz tudo parecer normal.

Muitos projetos utilizam JQuery, nem é preciso dizer o quanto facilita o desenvolvimento. O que acontece é que muita gente conhece pouco ou nada de JavaScript e começam a trabalhar diretamente com o framework jQuery sem conhecer de verdade a linguagem (meu caso).

Uma coisa bizarra que descobri é como escrevemos uma classe em JavaScript. Primeiro ela é declarada como “function NomeDaClasse(parametros) { … }” e depois usamos um “new NomeDaClasse()” sem dar erro mesmo com parâmetros declarados (até compreendo pois é uma linguagem dinâmica). Veja alguns exemplos e suas respectivas saídas:

function MinhaClasse(parametro) {
	this.campoPublico = parametro;
}

var obj = new MinhaClasse();
console.log(obj.campoPublico);
obj.campoPublico = 'campo público';
console.log(obj.campoPublico);
/*
Saída:
undefined
campo público
*/

Adicionando um método:

function MinhaClasse(parametro) {
	this.campoPublico = parametro;

	return {
		soma: function(a, b) {
			return a + b;
		},
		outroMetodo: function() {
			return 'teste';
		},
		propriedade: 'prop'
	}
}

var obj1 = new MinhaClasse();
var obj2 = new MinhaClasse();
console.log(obj1.soma(1, 1));
console.log(obj2.soma(2, 2));
console.log(obj1.soma === obj1.soma);
console.log(obj1.soma === obj2.soma);
/*
Saída:
2
4
true
false
*/

O objeto retorna um map, então obj.chave retorna o valor que é uma function, dessa forma é possível chamá-la. Note que obj1.soma === obj2.soma é false. Para campos devemos ter memoria alocada separadamente para cada objeto já que cada um pode guardar um estado diferente, agora para métodos isso pode se tornar um desperdício de memória em grandes sistemas.

Uma forma de compartilhar o método entre objetos de mesma classe é o uso do objeto prototype presente em todo objeto.

var obj1 = new MinhaClasse();
var obj2 = new MinhaClasse();
MinhaClasse.prototype.soma2 = function (a, b) {
	return a + b;
}
console.log(obj1.soma2 === obj2.soma2);
/*
Saída:
true
*/

Veja que as instâncias criadas anteriormente também acessam o método inserido. Com prototype também é possível criar um mecanismo de herança.

function Pai() {
}
Pai.prototype.subtracao = function(a, b) {
	return a - b;
}

MinhaClasse.prototype = new Pai();
// setar novamente o construtor
MinhaClasse.prototype.constructor = MinhaClasse;

function MinhaClasse() {
	// não pode utilizar o return
}

var m = new MinhaClasse();
console.log(m.subtracao(10, 1));
/*
Saída:
9
*/

JavaScript é uma linguagem estranha e propensa a causar erros e muita bagunça no código, requer mais atenção e disciplina. Uma grande sacada é o CoffeeScript que gera código JavaScript e vice-versa, e também inspeciona o código com o JavaScript Lint. Essas ferramentas são ótimas porém, nada impede alguém de escrever funções e classes bizarras ou usar o prototype indevidamente criando verdadeiros monstrinhos.

11 9 / 2011

Um pouco sobre expressões regulares

Conhecida também como Regex (Regular Expressions), as expressões regulares surgiram para suprir a necessidade de tratar caracteres de forma programática. São uma ferramenta muito útil na caixinha de qualquer desenvolvedor e promove um ganho de produtividade dependendo onde empregada. Há algumas semanas venho anotando alguns casos onde precisei utilizar regex para coisas cotidianas, são expressões simples mas que sem elas eu teria que fazer um trabalho braçal e demorado.

Irei mostrar alguns exemplos utilizando a ferramenta The Regulator que é para testar regex em .Net pois fica mais fácil de visualizar. A ferramente ainda possui alguns recursos interessantes como syntax highlight, uma espécie de IntelliSense, gerador de código da expressão em C#/VB.Net e um analisador que tenta “traduzir” a expressão para inglês (não fica muito fluente). Seguem alguns exemplos, os primeiros são bem simples, o último já aumenta um pouco a complexidade.

Retirar número de linhas

Encontrei o código fonte de uma implementação de uma classe do JDK em um site onde as linhas estavam numeradas. Copiando o código da página html, os números ficam misturados ao código fonte, impossibilitando sua compilação.

O frame da esquerda mostra os “matches” que são os caracteres que a expressão capturou. A partir do match é possível dar um replace e eliminar todas as ocorrências, deixando o código limpo para ser compilado.

A expressão ^\s*[0-9]+ quer dizer o seguinte:

capture no início de cada linha ^, espaço \s de zero ou mais *, com qualquer caractere de 0 até 9 [0-9], com pelo menos 1 ou mais desses caracteres seguidos +

Remover espaços

Tenho uma espécie de lista com nome de cidade, estado e ddd. O problema é que para cada cidade, essas informações estão em uma linha e separadas por espaços. Por exemplo, para ordenar por estado, a forma mais fácil seria colocar esses dados em colunas de uma planilha eletrônica e ordenar. A solução é substituir os espaços por um tab e colar o texto na planilha ou substituir por ponto e vírgula e importar como CSV.

\s{2,} significa:

capture qualquer espaço em branco \s (espaço, tab, line feed, etc..) pelo menos 2 vezes seguidas {2,}

Um ponto que deve-se levar em consideração é o tipo de informação da qual está sendo analisada. Nada impede de ter um espaço a mais entre ‘São’ e ‘Paulo’. A precisão de uma expressão regular vai depender muito do estado do texto e do que se quer procurar.

Retirar todas as strings do código fonte

Você precisa implementar internacionalização em um software legado onde todas as strings estão misturadas ao código fonte. Para isso precisamos buscar por tudo que está entre aspas.

A expressão “.+” significa:

capture o caractere seguido por um ou mais caracteres quaisquer .+até encontrar um caractere

Lendo ao pé da letra parece que a expressão não funciona corretamente quando temos aspas na string, por exemplo, o println irá produzir: Olá “Bruno”. Seja bem vindo. A primeira vista parece que o match ocorre em “Olá “, “\”, ” + nome + “ e “. “. O acontece é que a expressão irá capturar o máximo possível de ocorrência antes de parar. Para capturar o menos possível, é necessário utilizar o metacaractere non-greedy (também conhecido como lazy quantifier), que é a adição de um ponto de interrogação ? ao lado direito de um metacaractere quantitativo *, ? e +. Veja como fica com non-greedy:

Então corrigindo:

“.+” -> capture o caractere seguido por um ou mais caracteres quaisquer .+ até encontrar o último caractere

“.+?” -> capture o caractere seguido por um ou mais caracteres quaisquer .+ até encontrar o primeiro caractere

Procurando por tags HTML

Uma tag html utilizando uma determinada classe CSS precisa ser pesquida, o problema é que a ordem dos atributos pode variar, por exemplo, não é garantido termos sempre um padrão <tag class=”menu” ….. >, então, o emprego de uma regex cabe perfeitamente nessa situação. No exemplo abaixo procuro pela tag li utilizando a classe menu-horizontal.

<li.+class=”menu-horizontal” significa:

capture <li, seguido por um ou mais caracteres quaisquer .+ até encontrar a sequência de caracteres class=”menu-horizontal”

Outro exemplo, esse um pouco mais complexo, é procurar por tags HTML inválidas. Por exemplo, o DTD do XHTML 1.0 define que a tag img de conter os atributos alt src sendo fechada por / no final.

<\s*img[^>]+((?<!/\s*)|(?<!src=.+)|(?<!alt=.+))> significa:

capture o caractere <, espaço \s de zero ou mais *, seguido da sequência img, qualquer caractere que não seja > [^>] um ou mais +, tudo que não seja o caractere / seguido de espaço \s zero ou mais (?<!/\s*), ou | a sequência src= seguida por quaisquer caracteres (?<!src=.+) , ou | a sequência alt= seguida por quaisquer caracters (?<!alt=.+), até encontrar o caractere >

Nessa expressão foi usado o recurso de negative lookbehind que irá capturar qualquer coisa que precede > não dê o match no padrão (ex: negative lookbehind ->(?<!), padrão -> src=.+). Com esse recurso é possível construir expressões que não seriam possíveis utilizando uma classe de caracteres com negação (ex: [^src=]).

Analisando o exemplo, a sequência que está destacada em azul (logo3) dá a impressão de que não era para estar sendo capturada já que temos uma barra /src= e alt=. O ponto chave é que (?<!/\s*) só permite espaço (zero ou mais) antes de >, o que faz com que a sequência seja capturada já que temos espaço e caracteres que antecedem >.

Uma dica é não tentar validar todo html/xhtml, para isso existem parsers xml que irão poupar muito trabalho e serão bem mais precisos que um punhado de regex que facilmente atingirão uma alta complexidade. Nesse caso as regex são utilizadas para coisas pontuais.

20 7 / 2011

Design by Contract (DbC) – parte 1

DbC é um conceito criado por Bertrand Meyer em meados dos anos 80 e está presente em seu clássico livro “Object-Oriented Software Construction”. Muitas pessoas não conhecem e é algo que ficou meio esquecido até os últimos tempos porém, é um conceito simples que aumenta consideravelmente a qualidade do software. Vou começar com alguns exemplos para mostrar do que se trata.

Suponha que o método/função abaixo é largamente utilizado por vários desenvolvedores em um sistema:

double imposto(double valor, Date data) {
    double aliquota = aliquotaPara(data);
	return valor * aliquota;
}

Todos sabemos que imposto é cobrado em cima de ganhos, caso exista um valor negativo, que indica perda no contexto do sistema, o método deve calcular como? Retorna zero? Retorna um valor negativo? Retorna em módulo? É necessário também a data em que esse imposto será cobrado, caso não tenha uma data, o que o método irá fazer? Utiliza uma alíquota de 0%, 1%, 10%?

Diante desses problemas, decidiram que o método imposto() só é utilizado quando existe um valor maior igual a zero e uma determinada data (não nula). A partir dessa decisão, começaram a se espalhar “ifs” por todo código.

if ((valor > 0) && (data != null)) {
	obj.imposto(valor, data)
}
...

if (valor >= 0) {
	obj.imposto(valor, data)
}

Além de causar redundância, note que na primeira chamada alguém esqueceu do >= e segunda chamada alguém esqueceu de verificar se data não é nula. Em vista desses problemas, a melhor solução é colocar essas validações dentro do método.

double imposto(double valor, Date data) {
	if (valor >= 0  && data != null) {
		double aliquota = aliquotaPara(data);
		return valor * aliquota;
	}
	else {
		// o que fazer???
	}
}

A validação de parâmetros por um método/função é conhecida como sua pré-condição para funcionar corretamente. Caso essa condição não seja satisfeita, o método irá lançar uma exceção. Essa é uma forma de indicar que existe um erro no software. A fim de evitar identação desnecessária, troquei alguns operadores para caso a condição falhe teremos uma exceção lançada.

double imposto(double valor, Date data) {
	// pré-condição
	if (valor < 0  || data == null) {
		throw new IllegalArgumentException();
	}
	double aliquota = aliquotaPara(data);
	return valor * aliquota;
}

Seguindo essa lógica, se o método recebe os parâmetros corretos ele deve devolver o que é esperado, essa é a sua pós-condição. No contexto do sistema, imposto significa um valor igual ou maior que zero pois, não faz sentido receber imposto do governo (imposto negativo seria uma restituição).

double imposto(double valor, Date data) {
	// pré-condição
	if (valor < 0  || data == null) {
		throw new IllegalArgumentException();
	}
	double aliquota = aliquotaPara(data);
	double retorno = valor * aliquota;
	// pós condição
	if (retorno < 0) {
		throw new RuntimeException();
	}
	return retorno;
}

Relação Client/Supplier - Uma pré-condição deve ser satisfeita por alguém que está chamando o método (o client/cliente). Quem fornece o método (supplier/fornecedor) executa a pré-condição, passando com sucesso, ele tem a obrigação de entregar o que promete executando a pós-condição antes de retornar. Essa relação cliente/fornecedor é chamada de contrato. Cada uma das partes deve cumprir o acordo, ou seja, quem chama o método passa os parâmetros corretos e quem executa retorna dentro do que é previsto.

Existe mais um tipo de condição que está relacionada aos dados do objeto. Para um objeto responder corretamente é necessário que ele tenha seus dados consistentes, para isso é escrita condição invariante. Imagine um objeto que seja responsável em representar um relógio, ele possui os campos hora, minuto e segundo além de vários métodos públicos. Os valores desses campos devem sempre estar dentro de um intervalo.

public class Relogio {
	private int hora;
	private int minuto;
	private int segundo;
	// métodos omitidos

	private void invariante() {
		if !(0 <= hora && hora <= 23 &&
		      0 <= minuto && minuto <= 59 &&
		      0 <= segundo && segundo <= 59) {
			throw new RuntimeException();
		}
	}
}

Essa condição deve ser executada sempre ao início e fim de cada método público para validar o estado do objeto. Ela também é utilizada no construtor. É possível que essa condição seja temporariamente violada durante a execução de um método porém, ela deve estar válida antes de sair do método público. Vale notar que sempre chamar o método invariante() ao final dos métodos públicos causa poluição no código e sempre há o risco de alguém esquecer (procedimentos manuais falham). Por esse motivo e entre vários outros, existem frameworks para aplicar DbC de forma mais eficiente. Isso será assunto para outro post.

Em resumo, um contrato é composto de pré-condições, pós-condições e invariantes. No próximo post irei aprofundar um pouco mais no assunto.

21 6 / 2011

Applying UML and Patterns – notas

Li esse livro muitos meses atrás, sempre esbarrava com ele na internet e algumas vezes até fisicamente. Apesar do título, o livro é muito mais que UML e patterns. Ele apresenta o UP (Unified Process) que é a base do RUP, esse foi o motivo inicial para querer lê-lo. Utilizando o processo, é desenvolvido um sistema chamado POS (Point of Sale) que é utilizado em um caixa de supermercado. Dentro desse contexto são inseridos conceitos sobre análise e design orientado a objetos, UP, patterns GRASP e GoF, arquitetura e UML. Aqui vão alguns pontos dos quais achei que merecem destaque:

Análise e design orientado a objetos (OOA/D)

- A habilidade mais importante no desenvolvimento orientado a objetos é a atribuição de responsabilidades à objetos. Isso influencia a robustez, manutenibilidade e reusabilidade de componentes de software.

- A análise orientada a objetos está relacionada a criação de uma descrição do domínio do problema da perspectiva de objetos. Isso envolve a identificação de conceitos, atributos e associações. O resultado disso pode ser expresso em um modelo de domínio que mostra os conceitos de domínios ou objetos. Um modelo de domínio não é a descrição do software a nível de implementação, é apenas uma visualização de conceitos ou modelos mentais de um domínio do mundo real. A idéia chave de OO é que classes, métodos e atributos possuem nomes inspirados no modelo de domínio, diminuindo assim um gap representacional.

- Para domínios que não são do mundo real, devemos cuidadosamente prestar atenção no vocabulário e conceitos que os experts do domíno utilizam. Por exemplo, em um domínio de telecomunicações, teríamos conceitos como Message, Connection, Port, Dialog, Route, Protocol.

- O modelo de domínio não é o modelo de dados. Devemos pensar em comportamento e não em dados para criar nossas classes.

- É natural descobrir mudanças (novos conceitos, classes, métodos…) durante o design e implementação.

- O conhecimento em análise e design orientado a objetos é reutilizável, principalmente na camada do domínio.

Unified Process

- UP é bastante flexível e aberto, ele encoraja a inclusão de outras práticas de outros métodos iterativos como Extreme Programming (XP) e Scrum. TDD, refactoring e integração contínua são práticas do XP que cabem dentro de um projeto UP.

- A prática chave do UP e outros métodos modernos é o desenvolvimento iterativo. Isso significa organizar o projeto em uma série de minis-projetos que são entregues em um curto espaço de tempo (por exemplo, a cada 3 semanas). O resultado de cada iteração é ter um sistema parcial que foi executado, testado e integrado. Cada iteração inclui sua própria análise de requisitos, design, implementação, teste e possui um time-box definido.

- Ao longo do livro, Larman coloca diversos alertas sobre estar “cascateando” ao invés de praticar um desenvolvimento iterativo e incremental.

- UP utiliza uma combinação de desenvolvimento dirigido a risco (risk-driven) e ao cliente (client-driven). Risk-driven significa planejar para o início iterações visando identificar e reduzir os maiores riscos, desenvolvendo centrado na arquitetura, focando na construção, teste e estabilização da arquitetura central. Normalmente, não ter uma arquitetura sólida significa alto risco. Client-driven é construir as funcionalidades que o cliente mais se importa.

- Apenas código testado demonstra o verdadeiro design.

Fases do UP

1. Inception (concepção): fase onde temos visão aproximada do negócio, escopo e estimativas vagas. Podem ser criados protótipos/prova de conceito. Já existe uma preocupação com requisitos não-funcionais também. Esta não é a fase onde todos os requisitos e estimativas são definidas, boa parte disso é feito na fase seguinte. Durante a inception é onde temos o parecer se o projeto é viável ou será abortado. Geralmente essa fase dura 1 semana e possui somente 1 iteração.

2. Elaboration (elaboração): a visão é refinada, são resolvidas questões de alto risco, implementação do núcleo da arquitetura, identificação de requisitos e escopo e estimativas mais realistas. Nessa fase são escolhidos os casos de uso de maior valor para o cliente, além daqueles que tenham parte significativa na arquitetura. A fase possui duas ou mais iterações de 2 até 6 semanas.

3. Contruction (construção): implementação iterativa dos itens de menor risco e de fácil implementação. Os requisitos são estabilizados para que haja pouco pertubação durante o desenvolvimento.

4. Transition (transição): testes beta e deployment.

Dadas as fases do UP, durante cada iteração são praticadas um pouco de cada disciplina. A intensidade de cada disciplina varia de acordo com a fase que o projeto se encontra. A famosa figura abaixo exemplifica isso.

Famosa figura das disciplinas do UP. Imagem retirada do Wikipedia

O livro enfatiza as fases de inception e elaboration, são nelas onde a maior parte das atividades de business modeling, requirements e analysis & design. É onde se aplica análise de requisitos, análise e design orientado a objetos, patterns (GRASP e GoF) e UML.

Artefatos

Ao contrário do que muitos pensam, a geração de artefatos/documentos é opcional. A dica é somente utilizar aqueles que agregarem valor ao projeto. Quase tudo no UP é opcional porém, alguns princípios como contínua verificação da qualidade, desenvolvimento iterativo e dirigido a risco (risk-driven) não são.

Arquitetura

O livro cobre basicamente tópicos sobre arquitetura relacionados ao desenvolvimento em camadas e separação em pacotes. São apresentados alguns exemplos, inclusive de MVC. O autor procura justificar por que se deve desenvolver dessa maneira.

A utilização de camadas (layers) ajuda a solucionar diversos problemas como:

  • mudanças no código que impactam outras partes do sistema
  • regras de negócio misturadas com interface do usuário que impedem que o programa seja oferecido em outras interfaces
  • impossibilidade de reuso de código, processamento distribuído ou substituição de um componente por uma implementação diferente
  • dificuldade de distribuir trabalho entre os desenvolvedores

Documentar a arquitetura não é só gerar um monte de diagramas, é importante colocar quais foram as motivações, fatores que influenciaram nas decisões e soluções alternativas pensadas.

GRASP

Os padrões GRASP, no sentido de pattern, são uma forma de tentar justificar de alguma forma as decisões tomadas em relação a atribuição de responsabilides a objetos. GRASP são uma forma mais básica de construção de código, é mais básico que os conhecidos design patterns (strategy, decorator, factory, facade, composite, command, etc). Junto, são apresentados conceitos sobre coesão e acoplamento que fazem parte dos 9 patterns que compõe o GRASP. Este link contém um resumo de todos os patterns GRASP e dos GoF que são apresentados no livros. Uma observação interessante é que acoplamento entre classes estáveis não é muito problema, como por exemplo o Java SE. O maior problema é o acoplamento entre classes de negócio que não são estáveis, essas últimas frequentemente sofrem mudanças.

UML

Quase todos os exemplos são demonstrados utilizando UML. O livro possui explicações sobre diagramas de classe, sequencia/comunicação e pacotes. Recomendo um livro só sobre UML caso queira mais detalhes ou que a informação esteja mais enxuta e direta. Um comentário interessante sobre UML é que o propósito dos diagramas é primariamente o entendimento e não a documentação.

Além dos tópicos acima, o livro cita alguns assuntos/conceitos como TDD, Refactoring, DbC (Design by Contract), CQS (Command Query Separation), Liskov Substitution, Law of Demeter e Open-Closed.

Achei interessante as familiaridades do UP com Scrum, eles acabam compartilhando das mesmas ideias básicas. Foi um livro que surpreendeu de forma positiva, acabei aprendendo muito mais do que imaginava.

26 3 / 2011

Um exemplo do ISP

No post anterior dei um exemplo onde é possível usar uma classe abstrata juntamente com uma Interface para evitar repetições em implementações de métodos em comum, facilitando a manutenção. Esse tipo de implementação pode parecer uma “mão na roda” mas é necessário ter em mente o ISP (Interface Segregation Principle). O princípio significa basicamente que uma classe não pode ser forçada a implementar um método que não será utilizado.

É comum ocorrer uma situação onde um cliente de uma Interface força uma mudança na mesma. Utilizando o exemplo do post anterior, suponha que a classeDiferente precise de um novo método chamado novaAcao() que está relacionado aos conceitos abstraídos em INegocio. Uma solução seria colocar novaAcao() emINegocio e implementá-lo na classe Diferente. Já que não faz sentido para outras classes, NegocioAbstrata implementa um comportamento default.

public interface INegocio {
 	// métodos omitidos
	double novaAcao();
}

public class Diferente implements INegocio {
	public double novaAcao() {
		return 99.0;
	}
}

abstract class NegocioAbstrata implements INegocio {
	// provê um comportamento default
	public double novaAcao() {
		return 0.0;
	}
}

É uma solução tentadora porém, em algum lugar no código haverá um objetoINegocio e não teremos certeza se a chamada de novaAcao() poderá ser feita ou terá algum efeito. Isso pode levar ao uso de reflection para verificar o tipo concreto do objeto que é uma péssima prática pois aumenta o acoplamento, complexidade e polui o código. Agora imagine quando qualquer cliente de INegocio (herdando ou não da classe abstrata) precisar de um método. A Interface ficará inchada e poluída e isso é um sinal de baixa coesão. Então, a melhor solução é separar as interfaces, isso irá evitar a baixa coesão e um possível uso de reflection.

public interface INegocioNovo {
	double novaAcao();
}

public class Diferente implements INegocio, INegocioNovo {
}

Para mais informações sobre ISP entre outros princípios OO, veja este link onde possui alguns pdfs do autor (Robert C. Martin).

25 3 / 2011

Interface ou classe abstrata, por que não as duas?

Esta é uma dúvida que todo mundo já teve, criar uma Interface* ou classe abstrata? A resposta como sempre é “depende”. Em ambos os casos é possível definir uma interface (de comportamento) e conseguimos programar para interface. Isso significa que podemos ter uma referência para uma classe abstrata ou Interface e nunca uma instância concreta do tipo definido, dessa forma alcançamos o conceito de polimorfismo.

Dado que eu quero programar para interface e que eu tenho uma interface que representa algum conceito das regras de negócio de um sistema, devo utilizar uma classe abstrata ou Interface? Para responder devemos contextualizar o problema. Minha interface de regras de negócio será implementada por várias classes e muitas dessas implementações serão iguais. Nesse caso o uso de uma classe abstrata é indicado pois iremos escrever menos código repetido e é possível o uso do pattern template method. Veja o exemplo:

public abstract class NegocioAbstrata {
	public abstract double A();
	public abstract double B();
	// template method
	public final double C() {
		return A() * B();
	}
	public double D() {
		return 4.0;
	}
}

O método A() e B() variam para todas subclasses, D() pode eventualmente ser sobrescrito e C() é invariável. O que ocorre se surgir uma classe que não queria seguir o que foi definido em C()? Uma alternativa seria transformar a classeNegocioAbstrata em Interface e escrever todos os métodos para as subclasses o que causaria repetição (dentro do contexto apresentado). Uma solução para isso seria fazer a classe abstrata implementar uma Interface.

public interface INegocio {
	double A();
	double B();
	double C();
	double D();
}

abstract class NegocioAbstrata implements INegocio {
	public abstract double A();
	public abstract double B();
	// template method
	public final double C() {
		return A() * B();
	}
	public double D() {
		return 4.0;
	}
}

public class Concreta1 extends NegocioAbstrata {
	public double A() {
		return 1.0;
	}
	public double B() {
		return 2.0;
	}
}

public class Concreta2 extends NegocioAbstrata {
	public double A() {
		return 2.0;
	}
	public double B() {
		return 4.0;
	}
	@Override
	public double D() {
		return 16.0;
	}
}

public class Diferente implements INegocio {
	public double A() {
		return -10.0;
	}
	public double B() {
		return -50.0;
	}
	public double C() {
		return A() + B() + D();
	}
	public double D() {
		return 75.0;
	}
}

public class Main {
	public static void main(String[] args) {
		List lista = new ArrayList();
		lista.add(new Concreta1());
		lista.add(new Concreta2());
		lista.add(new Diferente());

		for (INegocio n : lista) {
			System.out.println(n.C());
		}
	}
}
// saída
// 2.0
// 8.0
// 15.0

Caso haja a necessidade de colocar um método a mais em INegocio, ele poderia ser implementado pela classe abstrata evitando assim que Concreta1, Concreta2 … ConcretaN sejam quebradas. Apenas quem implementa diretamente INegocio deve implementar o novo método.

Um problema com essa abordagem é que é possível fazer referência para NegocioAbstrata quando seria necessário fazer somente para INegocio. É possível alterar a visibilidade de NegocioAbstrata para ser disponível somente dentro do pacote como está declarada no código acima, as classes concretas são public porém, não conheço nenhum artifício para evitar que seja feita uma referência dentro do mesmo pacote. Assim, deveria ficar bem documentado os motivos para não utilizar nenhuma referência para classe abstrata.

Para mais informações sobre “programar para interface” e design patterns, consultar o livro (GoF) Design Patterns.

* Interface grafada desse modo significa interface do Java (IExemplo) e de outras linguagens, interface escrita normal está em um significado mais amplo, como por exemplo a interface de uma classe/objeto.

15 2 / 2011

Pragmatic Programmer – notas

Pragmatic Programmer é um livro que já ouvi falarem muito. Sempre foram comentários interessantes e por esse motivo resolvi lê-lo inteiro. Ele foi lançado em 1999 e está na 26ª edição. Vale ressaltar que os autores Andy Hunt e Dave Thomas (as vezes grafados como Andrew e David respectivamente) estão presentes no Agile Manifesto, por isso existem muitos elementos agile pelo livro. Pode até servir como uma breve introdução ao tema.

O motivo desse post não é um resumo nem uma análise sobre o livro. Durante a leitura grifei alguns trechos e fiz algumas notas sem nenhuma pretensão, agora estou compartilhando. Alguns trechos traduzi, outros condensei em um parágrafo ou escrevi a ideia que interpretei. Talvez alguns assuntos do livro não irão aparecer pois já foram bastante discutidos e não chamaram minha atenção. Mesmo assim tem alguns bons conselhos que são conhecidos por todos e que valem a pena serem repetidos.

Seguem os trechos:

Read More