Caelum | Ensino e Inovação - Cursos de Java, Scrum, Ruby on Rails


Hipermídia e contratos dinâmicos: menor acoplamento

Por Guilherme Silveira em 17/12/09

Nos últimos anos você vem comprando livros em um website: você acessa o site inicial www.amazon.com, procura pelo livro que deseja comprar, adiciona-o ao seu carrinho, escolhe o método de pagamento e finaliza a compra.

Na época do Natal, o site muda: existe agora uma promoção de fim de ano e você se depara com um conteúdo inesperado: existem funcionalidades e informações novas (como um programa de desconto através de cupons). Como reage um humano ao encontrar a mudança com novas possibilidades de iteração em um site?

  • Gritar: “contrato violado! não comprarei mais nada!
  • Ignorar as novas informações e executar o processo
  • Usar o intelecto humano e se aproveitar das novas informações

Como humanos sabemos o quão natural é agir de maneira a ignorar as informações – caso elas não contribuam com meu objetivo – ou tirar proveito delas.

A opção 1 só se concretiza caso existisse um comprometimento total a maneira que o site disponibilizava suas informações e ao processo: se meu acoplamento for alto e o que eu espero seja fixo, imutável. Infelizmente robôs não são ainda capazes de raciocionar como nós e executar a última opção.

O conteúdo hipermídia permite evoluir o servidor com funcionalidades e dados sem quebrar os clientes consumidores por padrão. Ninguém deixaria de comprar pois fornecemos funcionalidades e dados novos em relação aos recursos disponibilizados.

Isso permitiu a evolução de sites por diversos anos sem que usuários enviassem emails para o responsável reclamando da nova função que foi adicionada, dizendo que não utilizarão o sistema pois existe conteúdo extra.

Hipermídia permite um baixo acoplamento entre o cliente e o servidor e pode ser levado para o mundo da automatização: a web dos sistemas. Na web humana, validamos nossos contratos com o usuário final através do uso de testes end-to-end, verificando a existência de funcionalidades como o usuário o faria.

Diversas opções de ferramentas como selenium-rc e webdriver fornecem funcionalidades para garantir que o comportamento esperado não será quebrado com novos releases.

Eles não validam tudo retornado pela requisição, dando espaço para a ::forward-compatibility::, a capacidade de evoluir nosso sistema no servidor sem quebrar o comportamento esperado. Por exemplo, adicionar novas funcionalidades ou campos não relativos ao teste não deve quebrar o mesmo.

Na web para sistemas integrados, a representação mais comum é o xml, que não suporta conteúdo hipermídia, uma vez que uris devem ser tratadas como texto (de acordo com a especificação) então acabamos criando nossos próprios media-types, como vnd/caelum+xml, onde há a definição de como elas devem ser tratadas: o nosso próprio micro formato.

Existem diversas alternativas para criar esquemas forward e backward compatíveis mas infelizmente esse não é o comportamento padrão de arquivos como o formato ::xsd:: e arquitetos não se lembram disso ao definir seus esquemas, o suporte é opcional.

Dentre essas opções, a mais fácil e possivelmente perigosa envolve permitir qualquer tipo de conteúdo em qualquer campo, enquanto outra solução envolve o uso de tipos polimórficos: um perigoso início de schema-hell controlando diversas versões para uma mesma funcionalidade.

Micro formatos como os que podemos criar permitem a definição de uma estrutura fixa e uma dinâmica: um contrato parcialmente fixo, com garantias para validação e compatibilidade, além de parcialmente dinâmico, com liberdade para evolução, diminuindo o acoplamento que seu sistema possuia ao utilizar um esquema totalmente fixo.

Mas a responsabilidade de não quebrar o contrato original fixo ainda é do servidor.

Na web humana, xhtml permite validar a estrutura (o contrato) enquanto é responsabilidade sua (seus testes) não remover o campo de busca de livro, caso contrário o processo não se completa.

Enquanto esquemas permitem a validação de dados, os testes permitem a validação dos processos. Ambos devem ser escritos de maneira a permitir a evolução desacoplada do servidor e do cliente. E quais seriam então as partes dinâmicas do meu contrato?

Os possíveis estados de seu recurso podem variar com o tempo: uma aplicação para empréstimo pode ser só aprovada ou recusada, mas com o passar do tempo a empresa pode decidir a existência de um novo estado: “prolongado”.

As relações entre seu recurso e outros recursos também variam: um cliente pode ter uma lista de serviços contratados atualmente, acessando a sua representação via links. É natural imaginar que surjam novos serviços e que o cliente mude suas contratações.

As transições e operações disponíveis para seus recursos também são dinâmicas: suportando um método HTTP novo ou um novo link não quebra a existência de clientes que consomem as transições e operações existentes até então.

Todo esse dinamismo é guiado através de hiperlinks e conteúdo hipermídia. Como os clientes terão certeza que não quebramos o contrato dinâmico?

Da mesma maneira que implementamos testes para garantir o comportamento esperado, precisamos deles para garantir que o processo não é alterado no servidor.

Os testes end-to-end são a única garantia de que não quebramos os processos junto ao cliente, seja ele humano ou outro serviço.

Esquemas xml podem ser usados de maneira a garantir flexibilidade e compatibilidade, mas não é o comportamento padrão de tal ferramenta: depende muito mais do usuário conhecer e fazer o uso adequado dela.

ATOM é um exemplo que suporta por padrão contratos dinâmicos: ao seguir o Must Ignore, ganhamos forward e backward compatibility. Contratos dinâmicos fornecem dicas para os frameworks, permitindo ao servidor guiar o cliente naquilo que pode executar ou acessar.

A consequência principal de contratos dinâmicos é o baixo acoplamento.

O Restfulie foca no poder do hipermídia como facilitador na evolução a médio e longo prazo: não são URIs elegantes ou a adoção do protocolo HTTP sozinhos que criam sistemas de baixo acoplamento.

  • Share/Bookmark

Livro Arquitetura e Design de Software: mais 4 tópicos liberados!

Por Sérgio Lopes em 04/11/09

arquitetura e design de softwareHá três meses anunciamos o livro Arquitetura e Design Java, um livro que está em seu processo de finalização, fortemente baseado na experiência da Caelum com debates no curso de Arquitetura e Design, a adminstração do GUJ.com.br e esses anos de consultoria.

Os 4 tópicos liberados agora são “Java como plataforma não como linguagem”, “Favoreça imutabilidade e simplicidade”, “Cuidado com o modelo anêmico” e “Considere uma ferramenta de mapeamento objeto relacional”. Eles se juntam aos outros 4 tópicos liberados anteriormente (“Gerenciar memória não é simples”, “Programe voltado a interface, não a implementação”, “Entendendo o NoSuchMethodError e o ClassLoader hell” e “Inversão de Controle: Cadê a minha chave de fenda?”). Confira no site!

Além disso, atualizamos os tópicos do livro com novos temas que estamos finalizando, como REST, Cloud computing, bancos de dados não relacionais, modelos anêmicos e outros.

Este é um livro que aborda desde código até a arquitetura numa visão mais ampla. Como Craig Larman já afirmou: Você deve enfrentar suas batalhas, sejam elas no nível macro-arquitetural ou no humilde campo das instâncias“. Essa distinção, sobre o que é design e o que é arquitetura, não fica muito clara dentro do livro, pois muitas vezes é até difícil separar nessa classificação. Martin Fowler fala o mesmo no âmbito de patterns logo na segunda página de seu livro Patterns of Enterprise Application Architecture: “Alguns dos padrões nesse livro podem ser chamados arquiteturais, já que representam decisões importantes sobre essas partes; outros são mais sobre design e te ajudam a implementar essa arquitetura. Eu não faço nenhuma tentativa forte de separar esses dois, já que é o que é arquitetural ou não é subjetivo.”.

Estamos em processo de finalização do livro e gostaríamos muito de receber feedbacks e opiniões!

  • Share/Bookmark

Bancos de dados não relacionais e o movimento NoSQL

Por Nico Steppat em 30/10/09

Nas grandes aplicações web é cada vez mais comum a quantidade de informações ser enorme, e ainda temos uma certeza: amanhã teremos mais dados para armanezar. Como lidar com isso de maneira eficiente?

Muito se fala ultimamente sobre os novos bancos não relacionais. Houve um encontro inicial e a segunda conferência também já aconteceu. O movimento acabou ganhando o nome de NoSQL, até mesmo por que cada banco de dados tem uma maneira diferente de se escrever queries.

A grande motivação para NoSQL é resolver o problema de escalabildade dos bancos tradicionais. Pode ser muito caro ou/e complexo escalar um banco SQL.

Esse movimento está bastante enraizado no open source. Dá para perceber isso até mesmo pelos curiosos nomes dos projetos: Voldemort, MongoDB, Tokyo Tyrant e CouchDB.

Apesar de grande quantidade desses bancos serem open source, o movimento ganhou muita força com a publicação de dois papers sobre implementações proprietárias: o Google Bigtable (que a Caelum usa atualmente) e o Amazon Dynamo. Não por acaso são duas empresas que lidam com uma quantidade enorme informações. Outros grandes nomes participam do movimento NoSQL: Yahoo! (Hadoop com HBase, Sherpa), Facebook e Digg (Cassandra), LinkedIn (Voldemort), Mixi (Facebook do Japão) (Tokyo Cabinet) e a Engine Yard (MongoDB).

Muitos acham que esses bancos de dados escalam simplesmento por causa da ausência de um schema (schema free), logo não há verificação de integridade e de relacionamentos. Mas seria só isso? O MySQL, nos seus primórdios, quando não fazia tais verificações, ainda assim não era rápido como esses novos competidores. Quais são então os segredos para tanta escalabilidade?

O Amazon Dynamo se destacou por causa da forma como o sistema escala. Cada nó no cluster comunica com outros nós (p2p) e faz ativamente parte da partição/replicação. Não tem um single-point-of-failure, mas essa facilidade de escalar não vem sem custo.

Todos os novos bancos tem em comun que eles são key-value stores, ou seja salvam, como o nome sugere, um conjunto de enradas formadas por uma chave associada a um valor e o valor poderia ser de qualquer tipo, um binário ou string que está sendo salvo de forma denormalizada (schema-free). Diferentemente dos bancos SQL não existe uma esquema forte. Essa abordagem facilita a distribuição dos dados entre vários servidores onde cada servidor possui apenas uma fatia dos dados (shard).

O CouchDB é um dos mais famosos no time dos key-value stores. Ele usa documentos para definir uma estrutura no banco, armazenando uma chave associada ao um documento. Um documento é apresentado como JSON. Por exemplo:

{
  "Subject": "Bancos não relacionais"
  "Author": "Nico Stepat"
  "PostedDate": "10/15/2009"
  "Tags": ["database", "nosql", "rest"]
}

Repare a estrutura dos dados é definido através da aplicação, o CouchDB não exige nada, apenas um documento JSON.

Talvez o CouchDB ficou famoso por causa da simples API REST e do uso do JSON, ou da interface grafica bonita ou por causa dos views interessantes usando Map-Reduce ou da replicação Multi-Master ou por que foi escrito em Erlang (como esse e esse também). Seja que for, a promessa principal do NoSQL – sendo escalável – o CouchDB não compriu ainda. Ele não é distribuído sozinho, e precisa de ajuda externa para tal.

Outra forma de dar alguma estrutura aos dados ficou famosa por causa do Google Bigtable. A idéia é não salvar os dados em linhas como estamos acustomados pelos bancos relacionais. Os dados serão salvos através de colunas. Veja a diferença:

Row-Oriented (3 rows presentes – Nome, Salário, Data):

João,1432.00,15/10/2009
Maria,1511.00,13/10/2009
Pedro,1721.00,01/10/2009

Column-Oriented (mesmo exemplo):

João,Maria,Pedro
1432.00,1511.00,1721.00
15/10/2009,13/10/2009,01/10/2009

No column-oriented vem primeiro TODOS os dados da primeira coluna Nome, depois a segunda coluna Salario e por último a coluna Data.

E isso altera algma coisa? Para o desenvolvedor que vai utilizar o banco de dados, a idéia é que isso seja transparente, mas para que desenvolveu o banco, há enormes melhorias.

Isso não é muito vantajoso quando for salvo apenas um registro, como cada coluna tem que ser accessada separadamente. Também complica mais na recuperação de um registro específico (random-access) pelo mesmo motivo. Aqui a abordagem row-oriented tem vantagens.

Por outro lado, usando colunas, podemos empacotar os dados melhor já que os dados semelhantes, de mesmo formato, estão próximos um do outro. Gravando dados empacotados em BDs traz grandes vantagens, porque podemos recuperar e armanezar mais informações em menos tempo.

Com colunas também podemos aplicar projeções sobre os dados mais fácil. A segunda vantagem é importante principalmente para sistemas OLAP (online analytic process) que usam esse tipo de pesquisas pesadamente.

Banco de dados orientados a coluna vão além de um simples key-value store. Eles representam normalmente um array/hash de 4 ou 5 dimensões, usando ou adaptando o modelo proposto pelo BigTable.

Primeiramente, também temos tabelas só que eles chamem column-families. Como o nome indica um column-family são váras colunas. Quais são essas colunas, a aplicação define.

Cada coluna salva um valor. O grupo de colunas dentro de uma familia é acessível atraves de uma chave (row-key). O esquema fica:

  • columnFamily – parecido com uma tabela (tabela de colunas)
  • rowKey – ID do grupo de colunas
  • column – nome da coluna
  • value – valor a salvar

<columnFamily>.<rowKey>.<column> = <value>

Por exemplo, para apresentar dados sobre um DVD com a ID 234:

    <dvds>.<234>.<nome> = 'Beleza americana'
    <dvds>.<234>.<ator_principal> = 'Kevin Spacey'
    <dvds>.<234>.<ano> = '1999'

ou para apresentar um usuário com joao.silva:

    <usuarios>.<joao.silva>.<nome> = 'Joao Silva'
    <usuarios>.<joao.silva>.<email> = 'joao.silva@foo.com'

e o relacionamento:

   <usuarios_dvds>.<joao.silva>.<234> = ‘data que ele comprou’

Normalmente é salvo uma data automaticamente, ou seja, a estrutura completa fica:

   <columnFamily>.<rowKey>.<column>.<timestamp> = <value>

Os bancos orientados a coluna não oferecem joins entre column-families nem chaves compostas. A Google AppEngine, por exemplo, não aceita chaves compostas porque usa o BigTable por baixo. Existem pequenas diferenças entre implementações orientadas a coluna.

Seria o “início do fim” dos bancos relacionais? Aderindo a um banco de dados não relacional muita da responsibilidade de cuidar dos dados fica a cargo da aplicação. É ela que define como funcionam e como se relacionam os documentos. O banco fica com certeza mais simples, escalavél e rápido, mas perdemos as conhecidas garantias dos bancos relacionais. Como toda decisão arquitetural, escolher por bancos de dados não relacionais apresenta um trade off: ACID ou BASE ou alguma coisa no meio. Vale a pena? Cada caso deve ser estudado com cuidado. Algumas aplicações usam bancos de dados não relacionais para uma leitura e escrita temporária, atualizando um banco relacional de tempos em tempos, tirando vantagem das duas estratégias.

Semana que vem, no Caelum Day in Rio conversaremos sobre muitos outros detalhes do movimento NoSQL. Nos encontramos lá!

  • Share/Bookmark

Livro Arquitetura e Design de Software: 4 tópicos do draft liberados!

Por Paulo Silveira em 17/07/09

arquitetura e design de software Depois de muito trabalho e suor temos o prazer de apresentar um rascunho de alguns tópicos do livro Arquitetura e Design de Software: uma visão sobre a plataforma Java. O livro é resultado de mais de dois anos da nossa experiência em ministrar o treinamento de arquitetura e design Java da Caelum, além de anos de consultoria e desenvolvimento da equipe e de um prefácio de Phillip Calçado e tem lançamento previsto para novembro de 2009, pela Campus / Elsevier.

Os capítulos possuem um formato semelhante ao Effective Java: separado por tópicos que discutem sobre diversos assuntos, de maneira independente porém relacionando-se de forma natural. Neste milestone estamos disponibilizando uma ampla discussão sobre os cuidados com o gerenciamento de memória pelo garbage collector, as vantagens de preferir o uso de interfaces em vez do acesso direto a implementações, o desacoplamento resultado da adoção de inversão de controle através de injeção de dependências e finalmente uma explicação de problemas que costumamos enfrentar com os classloaders. Este último ainda explica os problemas gerados na permgen durante sucessivos redeploys em containers, o NoSuchMethodError, o singleton e até os misteriosos ClassCastExceptions que as vezes ocorrem em servidores de aplicação em linhas de código que nem possuem castings. A bibliografia parcial para estes tópicos também está disponível. Você pode fazer download dos pdfs diretamente no site.

Aguardamos os comentários, críticas e sugestões de todos. Pretendemos assim, através do feedback de vocês, nos alinhar com a expectativa da comunidade para o lançamento do livro.

  • Share/Bookmark

SOA sem tentar vender middleware?

Por Fabio Kung em 17/03/09

Na última sexta-feira, estive junto com o Alexandre Magno em um evento organizado pelo pessoal da Stefanini, no Rio de Janeiro. O Alexandre falou um pouco sobre a sua especialidade, Scrum. Eu dei uma palestra sobre SOA e como sempre a expectativa do pessoal era ouvir mais uma palestra cheia de buzzword, que de alguma forma tenta empurrar algum produto de integração e que tenha ESB (Enterprise Service Bus) no nome.

O público era bem misto, com pessoal técnico e não técnico. Bastante gente veio conversar comigo no fim da palestra e demonstraram surpresa com relação a abordagem diferente sobre SOA. Um pouco na linha do fantástico Guerrilla SOA do Jim Webber, tentei falar sobre o assunto sem tentar vender nenhum produto gigante middleware-de-integração. Se você ainda não viu: veja agora, sério. A minha palestra fala um pouco sobre como SOA não precisa ser buzzword, SOA é integração:


Talvez a palestra não faça tanto sentido para quem não esteve presente, mas fiquem a vontade para dar uma olhada e comentar a respeito.

  • Share/Bookmark



Caelum | Ensino e Inovação
São Paulo: Rua Vergueiro, 3185, cj. 87, próximo ao Metrô Vila Mariana   |   Tel. (11) 5571-2751
Rio de Janeiro: Rua Senador Dantas, 80, cj. 307/308 - Centro   |   Tel. (21) 2220-4156 ou 2297-0033
Brasília: SCS Qd. 8 Bl. B-50, Sala 521 - Ed. Venâncio 2000   |   Tel. (61) 3039-4222