Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trabalhar com Value Objects Design Patterns #27

Open
fernandoseguim opened this issue Jun 29, 2018 · 6 comments
Open

Trabalhar com Value Objects Design Patterns #27

fernandoseguim opened this issue Jun 29, 2018 · 6 comments
Labels
enhancement New feature or request

Comments

@fernandoseguim
Copy link

fernandoseguim commented Jun 29, 2018

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: ⚠️

  • Eles devem ser imutáveis
  • Devem agrupar informação em um único conceito
  • Tem sua igualidade baseada no valor e não na identidade do objetivo

Algumas vantagens ❇️

  • Proporciona o uso da POO no seu mais primordial fundamento que é o encapsulamento
  • Garante o princípio de responsabilidade única
  • Reduz o primitive obsession (Obsessão por tipos primitivos), que é quando caímos no vício de usar tipos primitivos int, long, bool, string... para atribuir propriedades a objetos de domínio. É mais preferível encapsular os tipos primitivos em pequenos objetos.
  • São facilmente testáveis
  • São livres de domínio, ou seja, podem ser compartilhados entre domínios
  • E claro, torna o código mais legível 😜

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

@fernandoseguim fernandoseguim added the enhancement New feature or request label Jun 29, 2018
@mathnogueira
Copy link
Contributor

Alguns pontos sobre o exemplo em código:

  • Checkout e MerchantCheckout não são imutáveis, pois eles têm o set em suas propriedades;
  • Se não houver set das propriedades, serão necessários construtores que recebem os atributos da classe;
  • O que seria o CheckoutGuid? Talvez um nome mais sugestivo deveria ser utilizado, como IdentificationToken. Mas como não sei a razão da existência desta propriedade, não consigo dar um bom nome também.

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
Copy link
Contributor

daniellessio commented Jul 10, 2018

@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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

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
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants