Pequenos ajustes, grandes mudanças!

Uma das decisões arquiteturais que tomamos no desenvolvimento do novo site lançado no dia 1º de Março, foi deixar o site de vendas separado da plataforma de curso e também sem acesso ao banco de dados.

Devido a decisão de retirar o acesso do site de vendas ao banco de dados, precisávamos passar as informações necessárias para o site de alguma forma. Optamos então por expor uma API que é consumida pelo site.

Como nossa API foi modelada? Vamos pegar um endpoint da API como exemplo:

Um dos endpoints da nossa API é responsável por listar apenas o nome (nome do curso na plataforma) e o slug (nome da url do curso formatado para efeito de SEO) de todos os cursos.

Já tínhamos uma classe que representa um curso com as informações necessárias:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Vetoed @Entity
public class Course implements Identifiable,Product {
   @Id
   @GeneratedValue
   private Long id;

   @NotNull
   @Length(min = 3, max = 255)
   private String name;
   private String urlName;
   
  // Um monte de outras informações
}

Porém, repare que a classe Course tem informações que não precisávamos expor neste endpoint.

A princípio, era só excluir os campos desnecessários na hora de montar o JSON para a API. Porém, havia um detalhe nessa abordagem: todas as vezes que acrescentássemos um campo novo na classe Course, teríamos que lembrar de excluir esse novo campo nos endpoints desnecessário, ou seja, uma solução problemática… Percebendo que a nossa API iria ficar muito sensível a qualquer alteração no nosso modelo de curso, resolvemos criar uma classe nova que conteria somente informações necessárias para o endpoint.

@Vetoed
public class SimpleCourse {

   @SerializedName("slug")
   private final String urlName;

   @SerializedName("nome")
   private final String name;

   @SerializedName("quantidade_aulas")
   private final long totalSections;

   @SerializedName("minutos_video")
   private final int duration;
}

Com esse pequeno ajuste, conseguimos gerar o nosso JSON com apenas os campos necessários. E se for necessário adicionar/modificar algum campo no endpoint?
Basta apenas ajustar o campo na classe SimpleCourse que o JSON será construído apenas com os campos dessa classe! Uma solução simples que nos livra de toda responsabilidade de ficar se preocupando com qualquer tipo de modificação!

Essa solução é um Design Pattern chamado DTO (Data Transfer Object), que tem apenas a finalidade de armazenar os dados necessários que precisamos transferir, ou seja: uma classe sem qualquer regra de negócio que será utilizada apenas para transferir os dados que queremos!

O que acharam da nossa solução? É a primeira vez que viu sobre o DTO? Deixe seu comentário sobre o que achou dessa abordagem para resolver esse endpoint.

Você pode aprender isso e mais com nossos cursos de programação.

Fique por dentro

(Última atualização em: 7 de março de 2016)

  • Marco Nicolodi

    Bacana a solução.

    Mudando de assunto, tem como implementar comentários pelo Disqus aqui no blog? Fica bem mais fácil de comentar. Abraços

    • Opa Marco, beleza?

      Valeu pela sugestão, vamos dar uma pesquisada e ver se vale a pena para nós trocar 🙂

  • Anna

    Eu tenho uma pequena dúvida sobre o uso de DTO’s. A boa prática de uso deles é só nestes casos de transferência por JSON ou teria algum outro caso em que eles seriam recomendados? (É pq eu já vi um sistema com DTOs espalhados para todos os lados e nem sempre eles faziam sentido pra mim)

    • Felipe Oliveira

      Oi Anna,

      Isso mesmo. Os DTOs são recomendados em qualquer situação onde há mudança de contexto entre aplicações, que geralmente são feitas por JSON.

  • Edwi Feitoza

    Alguns desenvolvedores não são simpáticos ao uso de DTOs. Como argumentos para fundamentar essa não simpatia argumentam que consumiria mais espaço em memória (já que teria mais um objeto em memória) e principalmente por promover o modelo anêmico. Poderia comentar a respeito, por gentileza?

    Obrigado

    • Felipe Oliveira

      Oi Edwi,

      Como toda solução, está solução dos DTOS tem seus pros e seus contras.

      Um dos beneficios de se usar DTOS é quando estamos expondo um serviço, pois usando DTOS podemos evoluir nossos modelos sem medo de quebrar a compatibilidade da API ou que alguma infirmação que não queremos expor seja exposta conforme nosso modelo vai evoluindo.

      DTOS como esses precisam ser estáveis, apenas expõe dados da API, por isso você não deveria se preocupar com o caso de modelos anêmicos.

      Quanto ao consumo de memória, seria o mesmo que dizer que usar design patterns são ruins, pois sugerem, por exemplo, que você crie um strategy de 4 classes no lugar de 4 ifs em uma classe só.

      Abraços
      Felipe

  • Leandro Bianchini Nascimento

    Olá Felipe,

    Como é feito mapeamento e preenchimento dos campos do DTO de acordo com os campos de sua Entity?
    Por exemplo, uso JPA e faço uma consulta ao banco que me traz meu objeto que foi anotado como Etity e desejo transferir somente alguns campos desse meu objeto para meu WebService. Existe alguma melhor prática de fazer isso, incluindo quando o retorno da consulta é uma lista de Entities?

    Obrigado.

Próximo Artigo3 práticas de como aprendi muito