Dividindo seu sistema web através da própria web

Sistemas que vivem isolados e sozinhos são raridade. É comum que sistemas integrem-se com outros, sejam novos ou legados. Como fazer essa integração? Temos várias respostas já bem estudadas e debatidas. Mas vamos além: não é interessante criar sistemas dessa forma, quebrado em menores?

Cada vez mais temos pequenas aplicações, mais focadas. As grandes aplicações agora são compostas por diversas outras menores, sem que o usuário final perceba. Uma página que te mostra o preço de um livro pode, na verdade, estar consultando uma dezena de subsistemas independentes.

É uma forma de diminuir o acoplamento, diminuir pontos únicos de falhas e poder trabalhar mais independentemente em subsistemas distintos. O keynote do QCon 2012 desse ano do Netflix mostrou esse aspecto.

Por exemplo, na Amazon o sistema de recomendação de produtos pode ser carregado através de um sistema secundário, assim como os dados de um sistema de reviews:

Além do http, a html na camada de apresentação permite novamente a qualquer desenvolvedor iniciante incluir em seus sistemas partes de sistemas externos que contribuem para a criação de uma aplicação diferente.

Por exemplo, o Caelum Online possui um sistema de pontuação e de badges que permite ao aluno crescer e demonstrar seu conhecimento a medida que aprende e ensina dentro da plataforma:

Mas poderia ser demais para a plataforma de ensino online da Caelum ter/ser um sistema de badges. O código dela está ligado a uma solução de educação e o código de badges faz parte de um outro sistema de gamification, um sistema que poderia ser inclusive utilizado por outros projetos. Seria ruim se um desenvolvedor da equipe da Caelum que quisesse melhorar o sistema de badges tivesse de conhecer a plataforma de ensino e vice-versa.

Extraímos esse e outros pequenos sistemas e colocamos em um site externo. Agora como integrar os dois lados? O http e o html facilitam a integração, com rest por exemplo. São os mesmos Do lado do sistema que controla badges nos cadastramos e cadastramos uma badge para o mínimo de 1000 pontos:

Do lado da plataforma de ensino, adicionamos um iframe (integração via html com um simples http GET por baixo do pano):


<iframe src="http://www.melbadger.com:80/1/all/555" ></iframe>

E a cada nova atividade que vale ponto, fazemos um post através do seguinte código em Ruby:

uri = URI.parse "http://melbadger.com/my_tenant_secret/uri/add"
Net:Http.post_form uri, {"data[category]" => "points", "data[quantity]" => 200, "data[enduser_id]" => 1}

Ou em Java:

PostMethod post = new PostMethod("http://melbadger.com/my_tenant_secret/uri/add");
post.addParameter("data[category]", "points");
post.addParameter("data[quantity]", "200");
post.addParameter("data[enduser_id]", "1");
new HttpClient().execute(post);

E pronto. Toda vez que um usuário atingir uma determinada pontuação, a integração entre os dois sistemas cuidará de mostrar a lista de badges atualizada. Mais: podemos codificar, através de mecanismo simples, uma forma de se precaver no caso do sistema de gamification estar caído, para que o site principal não exiba mensagens de erro desnecessariamente.

Extraindo um sistema assim permite evoluí-lo de maneira simples e razoavelmente independente. Mas isso não significa que não há cuidados a serem tomados, como o tempo de carregamento de uma página, o número de requests simultâneos e diversas outras otimizações da web que são importantes.

7 Comentários

  1. Rafael Guerreiro 28/08/2012 at 14:27 #

    Essa separação por sistemas menores é bem interessante, de fato as manutenções ficam muito mais isoladas.

    Por mais que seja mínimo, ainda existe algum acoplamento, por exemplo: se eu quiser que o sistema de badge só seja acessado por alguém que tem acesso ao sistema de ensino e que cada aluno veja somente as suas badges, eu estaria amarrando o mesmo usuário nos dois sistemas. Correto?

    E, para melhorar um pouco a performance, seria interessante se as badges fossem carregadas via ajax e mostradas posteriormente. Como foi mostrado nos dois últimos links.

    Excelente post, vai abrir a cabeça de muita gente!

  2. Sérgio Lopes 28/08/2012 at 14:36 #

    Minha maior preocupação com um sistema de integração baseado em iframes é seu altíssimo custo de performance. Além de ser uma requisição a mais, seu carregamento bloqueia o disparo do onload e a simples criação da tag já tem um custo mais alto: http://www.stevesouders.com/blog/2009/06/03/using-iframes-sparingly/

    O maior problema é o que o pessoal chama de front end SPOF (single point of failure). Você depender de um serviço externo blocante faz sua disponibilidade girar em função da disponibilidade desse serviço externo. Se o serviço cai, sua página fica indisponível pro usuário (o browser fica tentando acessar o serviço até dar timeout, o que pode demorar minutos).
    http://www.stevesouders.com/blog/2012/03/28/frontend-spof-in-beijing/

    Eu costumo preferir integrações server-side, mas aí nesse caso mataria a questão da simplicidade de se colocar apenas uma tag e pronto.

    Mesmo usando o iframe, há algumas técnicas de carregamento assíncrono que o pessoal andou pesquisando, algo que minimiza o problema do iframe bloquear o onload:
    http://www.aaronpeters.nl/blog/iframe-loading-techniques-performance

    Outra coisa que muitas bibliotecas de widgets usam hoje em dia (facebook, twitter, google etc) é fazer a integração através de um script e não de iframe. O script pode ser carregado assincronamente com mais facilidade e ainda pode conversar com a página de origem (diferente do iframe). Mas, em geral, esses scripts acabam criando o iframe no final das contas, disparando mais um request (eu tentaria um script que já monta o widget direto, pra evitar o iframe…).

  3. Guilherme Silveira 28/08/2012 at 17:13 #

    Obrigado Rafael!
    Sergio, pensando no teu feedback (pré-post) fiz metade dessa integração através de javascript assíncrono, mas para limpar o css o iframe aumentou o número de requisições. Como você disse, acho que vale o teste da simplicidade e, caso não seja um caminho interessante para a plataforma, voltamos atrás.

    Enquanto isso, tentar fazer com que todos eles sigam a regra de não ser um ponto de trava do site já ajuda bastante.

    Abraço

  4. Diego 28/08/2012 at 18:53 #

    Porque nao usa jsonp para buscar as coisas no outro servidor e monta os componente usando js?

  5. Alexandre Gama 28/08/2012 at 18:55 #

    A união de sistemas realmente está tomando conta das novas soluções e o interessante é justamente o que você falou Guilherme, especialização de um serviço. Muitas empresas, como a de Badges que você comentou, estão se especializando cada vez mais em ter um serviço que resolva um problema específico mas que pode ser usado por N outros tipos de aplicações.

    Bem lembrado pelo Sérgio que usar de forma impensada as famosas “integrações por iframe” acaba com a otimização de qualquer sistema mas nada como usar com cautela.

    Valeu o post Guilherme!

  6. Alessandro 23/09/2012 at 18:47 #

    Tenho uma curiosidade a nível de db: como vocês tratam os dados? Neste formato por exemplo, vocês possuem dados de usuário na plataforma de ensino e no aplicativo de badges, por exemplo… Tenho dúvidas quanto à redundância…

  7. Guilherme Silveira 24/09/2012 at 11:09 #

    Tudo bem Alessandro?

    A sacada nesse caso é tentar fazer as quebras para minimizar esses problemas. No caso da badge deu certo pois não precisamos de nenhuma informação do usuário fora o ID dele. Quanto mais informação for necessária de maneira duplicada, bem, maior o problema.

    Abraço

    Guilherme

Deixe uma resposta