Arquitetura

Design by contract, implementando primeiro um contrato

Design by Contract é um conceito baseado na metáfora de como elementos de um sistema de software interagem uns com os outros, da mesma forma que as empresas colaboram com base em obrigações e benefícios mútuos.

Definindo direitos e responsabilidades da parte do consumidor e do fornecedor, esse modelo é focado na documentação, na aceitação nos direitos e responsabilidade nos módulos ou APIs e pode orientar a descoberta de um design mais robusto e objetivo.

Neste exemplo tentamos fugir um pouco da definição original e trazer esse conceito para o mundo de micro serviços, onde nossos contratos são nossas APIs, métodos, testes, entre outros. 

Aqui, consumidor e fornecedor concordam com um contrato que:

  • O fornecedor deve retornar resultado de dados determinado por ambos;
  • O fornecedor define as condições mínimas para retornar esse resultado;
  • O cliente deve satisfazer essas condições;
  • Ambas as partes devem cumprir determinadas leis e regulamentos gerais, aplicando-se a todos os contratos.

Esses conceitos existem em todos os níveis no desenvolvimento de software, e são muito úteis para a criação de classes e interfaces, podendo auxiliar a definir requisitos, projeto, implementação, teste.

São partes de um contrato:

  • Nome do serviço
  • Operações públicas
  • Comportamento do serviço
  • Entradas de dados
  • Saídas de dados
  • Versão
  • Formato dos dados (XML, JSON)
  • Layout (formato de data dd/mm/yyyy)
  • Protocolo (REST,SOAP,outros)

Essa forma de trabalho (onde é definido o contrato antes da implementação) ajuda a eliminar erros,  antes que eles possam prejudicar o desenvolvimento ou o funcionamento do software.

Iniciando pelo contrato, podemos considerar como benefícios:

  • Documentação automática de qualidade, pois é definida por os ambos participantes;
  • Ideia mínima para se realizar um teste de funcionamento;
  • Capacidade de comunicar seu projeto sem a necessidade de descrever os detalhes da implementação;
  • Guia claro e simples ao longo de todo o processo de desenvolvimento de software.

Partindo dessa ideia de desenvolvimento de software, podemos definir 3 perguntas para definir um contrato:

  • Quais são as entradas da minha API?
  • Quais são as saídas da minha API
  • Qual o comportamento que minha API deve ter?

A definição de uma API iniciando pelo seu contrato possibilita que a especificação seja o mais simples possível, traga clareza para fornecedor e consumidor, traga precisão dos requisitos e permite que o fornecedor ignore detalhes de implementação.

Mas, para que isso aconteça, algumas premissas devem ser seguidas – pois deixando de respeita-las o contrato pode ser quebrado.

Veja o que quebra um contrato:

  • Remover um Endpoint
  • Renomear um serviço
  • Renomear Endpoint
  • Remover um Endoint
  • Adicionar um atributo de impute obrigatório
  • Mudar o formato de dados
  • Mudar o layout de dados

O que NÃO quebra um contrato:

  • Adicionar um novo Endpoint
  • Adicionar um novo atributo que seja opcional no input
  • Adicionar um novo atributo no output

Compatibilidade com versões anteriores

Manter a compatibilidade de um contrato é uma das disciplinas mais importantes Design by Contract, já que descumprir isso causar falta de fornecimento de dados de um serviço na má implementação. Isso pode trazer prejuízo – seja ele de tempo ou financeiro – pois tudo que foi combinado e se acredita que esteja funcionando pode deixar de atuar da maneira correta.

No primeiro passo é definido um contrato, e os consumidores tem o conhecimento das suas entradas e saídas.

Se em um segundo momento for necessário mudar o contrato para atender um consumidor, ele vai consumir uma nova versão deste contrato:

Então, em um X período de tempo, será necessário forçar a migração do consumidor X para a nova versão do contrato.

Este versionamento é muito importante, pois constantemente um serviço/endpoint pode evoluir e ganhar novos consumidores – e provavelmente aquela V1 pode não atender mais a todos eles. Então surge a V2 ou Vx.

Sabendo que há uma versão nova, é dever do fornecedor comunicar a todos os seus consumidores sobre a atualização com melhorias e que a V1 (ou versão mais antiga) será desligada. Assim, passamos a remover esse código, que ficará defasado.

Deixando essas regras básicas claras, nosso Products Owners (que podem ter viés técnico ou não) conseguem ajudar os times de desenvolvimento com as definições, trazendo muito mais velocidade nas entradas.

Esse conceito de implementação de contratos antes mesmo do serviço é uma pratica que vem ajudando muito os times no Agibank! Partindo dessa ideia podemos implementar Mocks funcionais com o comportamento esperado pelos consumidores, de maneira que ambos times (consumidor e fornecedor) possam realizar os seus desenvolvimentos de forma isolada, e sem a pressão de um time ter a dependência do outro para realizar a sua implementação.

%d blogueiros gostam disto: