Archive for the ‘java’ Category

JBoss World 2008

Thursday, February 21st, 2008

Na última semana estive na JBoss World 2008, um evento da Red Hat que discute várias ferramentas e soluções baseadas em produtos JBoss. Fiz uma série de posts no meu blog sobre as apresentações que achei mais interessantes, sugiro que dêem uma olhada. Além disso, todas as apresentações estão disponíveis para download no site do evento.

Refatorando para Fluent Interface

Friday, September 21st, 2007

Ultimamente tenho passado boa parte do meu tempo trabalhando na WebMediaAPI. Para quem não conhece, a WebMediaAPI é uma… API que tem como objetivo padronizar, centralizar e facilitar o acesso à mídias e seu consumo na Globo.com.

Por exemplo, se você quer colocar vídeos no seu site, ao invés de dar vários SELECTs em tabelas que você não conhece e não entende, a idéia é que você possa usar um JAR na sua aplicação que encapsula várias funcionalidades oferecidas pela infraestrutura de WebMedia, simplificando o seu trabalho (pois não terá que descobrir como inventar a roda) e o nosso (centralizando e organizando o consumo de mídias).

No início do projeto um dos maiores desafios foi estabelecer como seria a fachada da WebMediaAPI. Nós tentamos alguns formatos e como precisávamos lançar logo a primeira versão acabamos optando por uma interface tradicional e simplificada. Para dar uma idéia melhor, vamos analisar o código para selecionar os últimos vídeos publicados de um programa:

int quantidade = 5;
long programaId = 456;
Set midias = new HashSet();

WebMediaServices webMediaServices = WebMediaFactory.getServices();
List idsMidias = webMediaServices
	.getIdsUltimasMidiasPublicadasPorPrograma(quantidade, programaId);

for (Iterator iter = idsMidias.iterator(); iter.hasNext();) {
   Long midiaId = (Long) iter.next();
   Midia midia = webMediaServices.getMidia(midiaId.longValue());
   midias.add(midia);
}

Não é muito difícil entender o funcionamento deste código. Só que ele poderia ser muito melhor… Esta interface pode até funcionar mas não é nem um pouco intuitiva. A classe WebMediaServices como pode-se imaginar ficou com dezenas de métodos e virou basicamente um grande saco de funcionalidades. Qualquer método simplesmente ficava nesta classe, o que não é nem um pouco elegante.

Depois de algum tempo tive a idéia de refatorar a API para uma Fluent Interface. A idéia é tentar fazer alguma coisa que se aproxime de uma DSL interna, que não é nada mais do que uma API com nomes interessantes. Ao invés de um saco de métodos a WebMediaAPI agora é acessada através de uma interface semânticamente organizada e seu design é pensado para ser legível e fluente.

Veja como ficou o mesmo serviço para selecionar os últimos vídeos publicados do programa “Altas Horas”:

Long altasHoras = new Long(456);
Set videos = WebMediaAPI.videos().recentes().doPrograma(altasHoras);

Bem mais elegante!

O lado negativo é que quanto mais fácil a API torna-se para o cliente, mais difícil torna-se sua implementação. Construir uma fluent interface muitas vezes me fez perder algumas horas pensando como certas coisas seriam feitas, mas eu gostei do resultado final e acho que para esse tipo de aplicação (WebMediaAPI) valeu a pena.

Para mostrar a diversidade e simplicidade da nova API, veja mais alguns exemplos (repare que eu não tenho que dizer o que eles fazem para você entendê-los):

// 1
Set programas = WebMediaAPI.programas().comTitulo("Fantastico");

// 2
Long redeGlobo = new Long(123);
Set videos = WebMediaAPI.videos().favoritos().doCanal(redeGlobo);

// 3
Long destaquePrincipalGloboVideos = new Long(123);
Integer quantidadeMaxima = new Integer(10);
Set videos = WebMediaAPI.videos().relacionados().aoCanal()
	.doVideo(destaquePrincipalGloboVideos, quantidadeMaxima);

Ainda temos um longo caminho pela frente e muita coisa ainda será melhorada. Já tenho várias idéias novas que na medida do possível serão incorporadas às próximas versões e compartilhadas aqui no blog.

A ameaça dos singletons

Wednesday, September 12th, 2007

Há muito tempo que ouvia sobre os problemas que o padrão singleton representa. É claro que com tantos argumentos não tinha como eu não concordar. Mas eu concordava sem dar muita importância pois nunca havia sentido na pele seus malefícios. Até que finalmente passei por uma grande dificuldade causada por um singleton. Isso finalmente despertou meu ódio por este abominável padrão. Neste artigo explico qual o problema e como o resolvi.

Ontem no desenvolvimento do Menu do GloboVideos 4.2, resolvi exercitar a prática de TDD, ou seja, eu implementeria os testes unitários para guiar o desenvolvimento das classes. O problema é que a classe que representaria o Menu do GloboVideos precisaria utilizar a classe MenuBO (com.globo.portal.cda.menu.business.MenuBO) do Portal.

A idéia era simples, mocar o MenuBO, para isolar o acesso ao banco da minha classe de forma a só testar as regras de negócio do menu do GloboVideos. Mas isso não foi possível, pois esta classe, meus amigos, segue o padrão singleton. Ou seja, o construtor dela é privado, o que impossibilita a criação de Mocks e de SubClasses.

A solução que encontrei foi criar uma classe Proxy. A MenuBOProxy. Não sem antes testar de várias maneiras um jeito de criar mocks com classes de construtor privado. Não consegui. A classe MenuBOProxy apenas implementa todos os métodos de MenuBO, delegando cada uma delas a uma instância do objeto único de MenuBO. Veja como a classe ficou:


public class MenuBOProxy {

	private MenuBO menuBo;

	public MenuBOProxy() {
		this.menuBo = MenuBO.getInstance();
	}

	public MenuBOProxy(MenuBO menuBo) {
		this.menuBo = menuBo;
	}

	public Vector listaItem(MenuVO menu)
		throws BusinessException {
		return menuBo.listaItem(menu);
	}

	public MenuVO listaMenu(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenu(menu);
	}

	public Vector listaMenus()
		throws BusinessException {
		return menuBo.listaMenus();
	}

	public String retornaListaNomeMenu(Vector vetMenuId)
		throws BusinessException {
		return menuBo.retornaListaNomeMenu(vetMenuId);
	}

	public MenuVO listaMenuPorPortalNome(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenuPorPortalNome(menu);
	}

	public MenuVO listaMenuPorId(MenuVO menu)
		throws BusinessException {
		return menuBo.listaMenuPorPortalNome(menu);
	}
}

Com esse proxy foi possivel criar um mock e enfim testar separadamente a lógica do Menu do GloboVideos.

Por hora, a versão atual do GloboVideos também foi desenvolvido utilizando-se singletons seguindo o padrão do Portal. Mas aos poucos estamos migrando suas funcionalidades de forma a permitir uma maior testabilidade no código. Sempre seguindo a máxima de que o padrão singleton é mal, pega um pega geral.

Outros links com mais argumentos e exemplos disso estão disponíveis abaixo:

http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx
http://c2.com/cgi/wiki?SingletonsAreEvil
http://www.softwarereality.com/design/singleton.jsp
http://members.capmac.org/~orb/blog.cgi/tech/coding/no_singletons.writeback
http://www.testingreflections.com/node/view/552