Ultimamente tenho passado boa parte do meu tempo trabalhando numa aplicação chamada WebMediaAPI. Trata-se de uma… ahm… API de uso interno que tem como objetivo padronizar, centralizar e facilitar o acesso à mídias e seu consumo em sites da Globo.com.
Por exemplo, quando o pessoal do G1 quiser colocar vídeos no seu site, ao invés de dar vários SELECTs em tabelas que eles não entendem e não conhecem, a idéia é que eles possam usar um JAR na aplicação deles que encapsula várias funcionalidades oferecidas pela nossa infraestrutura de WebMedia, simplificando o trabalho deles (pois não terão que descobrir como inventar a roda) e o nosso (centralizando e organizando o consumo de mídias na empresa).
No início do projeto um dos maiores desafios foi estabelecer como seria a fachada desta API. 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 ter uma idéia melhor, veja o código para selecionar os últimos vídeos publicados do programa “Altas Horas”:
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);
} |
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 algo que se assemelha a 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 novo código para selecionar os últimos vídeos publicados do programa “Altas Horas” (exatamente a mesma coisa que o código anterior faz):
Long altasHoras = new Long(456);
Set videos = WebMediaAPI.videos().recentes().doPrograma(altasHoras); |
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 valeu a pena.
Para mostrar a diversidade e simplicidade da nova API, veja mais alguns exemplos (repare que eu não tenho que dizer nada sobre o que eles fazem para você entendê-los):
// exemplo 1
Set programas = WebMediaAPI.programas().comTitulo("Fantastico");
// exemplo 2
Long multishow = new Long(123);
Set videos = WebMediaAPI.videos().favoritos().doCanal(multishow);
// exemplo 3
Long destaquePrincipalGloboVideos = new Long(123);
Integer quantidadeMaxima = new Integer(10);
Set videos = WebMediaAPI.videos().relacionados().aoCanal()
.doVideo(destaquePrincipalGloboVideos, quantidadeMaxima); |
// exemplo 1
Set programas = WebMediaAPI.programas().comTitulo("Fantastico");
// exemplo 2
Long multishow = new Long(123);
Set videos = WebMediaAPI.videos().favoritos().doCanal(multishow);
// exemplo 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, mas já dá para perceber uma difirença significativa entre as duas versões.