Refatorando para Fluent Interface
Friday, September 21st, 2007Ultimamente 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.