Cappta / best-practices

2 stars 0 forks source link

Trabalhar com Value Objects Design Patterns #27

Open fernandoseguim opened 6 years ago

fernandoseguim commented 6 years ago

Um pattern muito legal, que as vezes esquecemos de usar o Value Object ou VO, em resumo eles são objetos sem identidade conceitual, eles existem para compor outros objetos, um exemplo disso é o Datetime ou o String ou o próprio Guid.

Existem algumas premissas para Value Objects: :warning:

Algumas vantagens :sparkle:

No nosso contexto um VO interessante seria o Checkout:

public class Checkout
{
        public int CheckoutId { get; set; }
        public int CheckoutCode { get; set; }
        public Guid CheckoutGuid { get; set; }
}

public class MerchantCheckout
{
        public Checkout Checkout { get; set; }
        public string Cnpj { get; set; }  
        ...
}

Value Objects Trabalhando com Value Objects Implement Value Objects

mathnogueira commented 6 years ago

Alguns pontos sobre o exemplo em código:

Então teríamos um exemplo mais ou menos assim:

public class Checkout
{
        public Checkout(int id, int code, Guid token)
        {
            this.CheckoutId = id;
            this.CheckoutCode = code;
            this.Token= token;
        }

        public int CheckoutId { get; }
        public int CheckoutCode { get; }
        public Guid Token { get; }
}

public class MerchantCheckout
{
        public MerchantCheckout(Checkout checkout, string cnpj)
        {
            this.Checkout= checkout;
            this.Cnpj= cnpj;
        }

        public Checkout Checkout { get; }
        public string Cnpj { get; }
}

Uma outra coisa sobre Value Objects:

Estes objetos seriam utilizados para transferir dados do domínio da aplicação para outros pontos da aplicação, ou seriam os objetos mapeados no banco de dados? Caso seja a segunda opção, temos as seguintes premissas:

  1. Um objeto para ser imutável, deve receber seus dados pelo construtor;
  2. Se um ORM (e.g. Entity Framework) for utilizado, é necessário que a classe tenha um construtor padrão;

A combinação destas premissas causam um problema: quando o ORM instanciar o objeto utilizando o construtor padrão, ele não conseguirá popular os dados do objeto, pois estes são readonly.

daniellessio commented 6 years ago

@fernandoseguim, quando você fala de domínios distintos, estamos falando em aplicações distintas ou contextos distintos na mesma aplicação ? Esse padrão me parece exatamente o inverso de DTOs, ou estou enganado ?

Na esteira dos comentários do @mathnogueira, minha dúvida na sua sugestão foi a mesma que surgiu do próprio Matheus, eu e outros colegas sobre a inclusão de um guideline de arquitetura neste repo: o uso desse padrão exige a adoção ou não de outros padrões e tecnologias, e limitar essas escolhas não me parece bom. O que acha?

vinibeloni commented 6 years ago

Sobre o ponto do @mathnogueira em relação a um ORM , eu vi num comentário deste artigo que o cara comenta que no entity framework vc pode utilizar um data annotation Complexytype que ele ja entende como passa os atributos por contrutor, mas não li nada a respeito. Mas assim que tiver um tempinho eu dou uma olhada, ja no NHibernate já tem um esquema da propria biblioteca pra fazer.

daniellessio commented 6 years ago

Dando uma olhada melhor neste tópico vi que um dos pontos para utilização desse cara é a fuga da obsessão por tipos primitivos e então fez mais sentido por mim. Ex.:

Ao inves de : public class Client { public **string** Cnpj {get;set;} } Teriamos : public class Client{ public Cnpj Cnpj {get;set;} }

Cnpj no ultimo é uma classe a parte, com todas as regras de validações que um Cnpj tem que ter, e pode ser reutilizado em toda classe que tem um Cnpj.

O ponto dos ORMs eu realmente não sei dizer.

SammyROCK commented 6 years ago

Gostei do exemplo do Lessio, mas que tal utilizar struct ao invés de classe? Uma das diferenças básicas entre struct e classe é que struct nunca é nula, o que economizaria validações em nosso código.

daniellessio commented 6 years ago

Struct parece ser o ideal mesmo, pensei nisso quando vi a explicação do Baltieri sobre esses caras, mas ele utiliza classe.