Salve, das Beleza! Continuando essa saga aqui no Domain Dream Design, agora vamos falar sobre objetos de valores. Como nós já vimos aqui no curso que as marcações vão nos ajudar a transcrever essa linguagem do DDD para o meio do nosso código, nós vamos também ter um tipo ali para os objetos de valores. Mas o objeto de valor tem algumas peculiaridades que nós podemos trabalhar, e isso também vai de encontro à sua linguagem de programação. Cada linguagem de programação tem a sua forma de lidar com orientação a objetos e etc. E no caso do JavaScript, eu tenho um objeto na mão e esse objeto pode ser modificado a qualquer momento. Esses objetos que a gente cria ali sem nenhuma restrição. Então, a ideia com esse objeto de valor é ter uma classe que vai ter ali o valor que vai ser armazenado com esse value, com esse generic, que a princípio, eu não quero ser obrigado a falar qual o tipo de valor que eu quero, pode ser um inteiro, pode ser uma string, ou pode ser um inteiro, pode ser uma string, ou pode ser um objeto mais complexo. Mas eu passo o valor que é do tipo value no construtor e armazeno na variável. Mas o armazenamento não é direto. Está sendo chamado esse deep freeze, que é justamente para poder congelar aquele objeto ali. Então, quando eu tiver um objeto de valor que estende desse aqui, vamos supor que eu vou criar lá o meu VO, Value Object, passando o valor 1 ou passando um objeto mais complexo que eu queira armazenar, ou até uma instância de uma classe, que eu queira armazenar, ou até uma instância de uma classe, se eu tentar fazer V.value, que é onde está o meu objeto, .a igual a 2, ele não vai deixar essa modificação. A gente fez o freeze, o objeto está congelado. Então, isso aqui, na verdade, nem é obrigatório, mas é uma implementação para poder ter a segurança de fato ali. Se alguém acidentalmente ou alguma coisa tentar mudar o objeto de valor, não vai conseguir. Então, como isso aqui é protegido também para evitar que seja acessado diretamente, justamente é mais uma proteção, eu habilitei um getter para poder capturar esse valor quando fosse necessário. Então, com um ponto velho ali, a gente consegue. Já o toString é mais um método conveniente, assim que a gente faz toString em classes no JavaScript. Então, se eu tentar por exemplo, fazer um console.log de um VO, se eu passar ele direto, vai ser mostrado, vai ser renderizado o objeto. Mas se eu fizer uma concatenação, vai ser permitido e ele vai acabar chamando esse método aqui. Então, em qualquer lugar que forçou-se string, acaba mostrando... Porque muitas vezes o objeto de valor é um valorzinho só. E esse método vê se você tem um objeto complexo ou se tem um valor só. Então, ele só mostra aquele valor ali. Então, é interessante que a gente crie nas nossas linguagens de programação. Toda linguagem de programação vai ter um trueString, como eu comentei lá para o caso da entidade também. É interessante para debug, para teste e para várias outras coisas. Show de bola. Sobre esse método equals aqui em cima, é justamente para a gente ter aquela ideia de comparação de objetos de valores. Muitas vezes você vai se deparar com a situação que você quer ver se o objeto de valor novo é igual ao antigo. Mas as referências dos objetos ali na linguagem são diferentes. Para fazer a comparação, a gente precisa pegar cada propriedade e fazer essa devida comparação. Então, esse método aqui serve para poder fazer essa comparação. Em vez de a gente ficar naquela história de if vo1 igual a vo2, se eu puxar esse vo aqui do banco de dados e esse aqui eu acabei de criar, nunca eles vão ser iguais. Então, isso aqui gera muito problema. Então, sempre faça com o equals, porque esse método aqui está preparado para poder analisar o objeto ali, mesmo que ele seja um objeto de objetos de objetos, porque nesse caso aqui eu estou utilizando uma biblioteca externa. Então, olha só, para esse caso, eu preferi aqui no JavaScript, para ter um comportamento dinâmico e completo, utilizar o loadExt, que é bem famoso. E estou utilizando somente, não estou importando ele inteiro. Inclusive, até tenho que ver se eu estou com ele aqui já instalado. Seria interessante, ele já está instalado ali, então ele já é alguma dependência aqui da nossa aplicação. Eu não preciso me preocupar com essa instalação. Então, tem muitos momentos que isso vai acontecer, por vários motivos. Tanto comparação de entidade, quanto comparação de objeto de valor. Beleza. Então, vamos criar aqui um objeto de valor, para que a gente possa entender aqui como que funciona. Imagina lá no caso da nossa entidade. A gente está lidando com o nome como uma string. Mas eu posso ter ali um comportamento no meu nome que eu quero, toda vez que eu for lidar com o nome, tem que ser convertido para uppercase, maiúsculo, tem outras coisas que podem ser feitas. Então, se eu não crio objeto de valor, acabo colocando esse comportamento dentro da própria entidade, fica ruim, porque aí eu não permito o reuse. A minha entidade, meu agregado, vai ficando cada vez com mais responsabilidade. Então, vamos supor que seu objeto de valor para nome fosse mais genérico. Então, eu posso criar ele dentro aqui de uma pasta value object. Aí eu poderia mover esse camaradinha para cá. E aí eu vou criar aqui um name.vo, é assim que eu gosto de fazer. Então, eu vou exportar uma classe name que estende de value object. Então eu vou lidar apenas com o valor do nome que é um string, não tem um objeto complexo, mas se eu tiver um objeto complexo, é só passar aqui com o generic e fica fácil. Aí vamos brincar com esse objeto de valor aqui, vou criar um name.vo.spec, a gente pode trabalhar com testes automatizados, vamos colocar assim, teste deve criar um nome válido. Eu vou aceitar a sugestão dele aqui. E aí a gente vai fazer aqui um name é igual a new name. Na verdade, name, né? Não nome. E aqui eu passo um valor qualquer. Ficou de bola. Então, quero ver se o valor é o mesmo AA que eu passei ali. Vamos rodar esse teste aqui. Estou utilizando uma extensão, para quem tiver dúvidas, que é o Just Runner. Na verdade, eu tenho duas. Eu tenho essa aqui que me permite rodar manualmente e uma extensão feita pelo próprio time do Jest para trabalhar com testes, que é o Octa Jest. Ela é que está mostrando esse verdinho aqui. Se eu quero criar, se eu tenho que modificar o valor, imagina que eu chegue aqui no Customer e eu fale assim aqui, isso aqui na verdade é um tipo Name. Então aqui também eu vou receber um Name. O que faz com que aqui também eu receba um Name. o que faz com que aqui também recebo o name. Então nesse caso, quando eu vou fazer a atribuição de um new customer da vida, passei lá cpf e o nome. Então, eu tenho o meu customer aqui. A princípio, a gente vai evitar alterar as informações diretamente, porque nós perdemos riqueza do nosso domínio. As informações são sempre alteradas por comandos. Comandos é justamente o que a gente está fazendo aqui com create. Mas a regra é que se eu tiver que alterar aqui o name, eu não vou fazer isso aqui. Value é igual a outro valor. Não, inclusive aqui ele vai até falar que a propriedade é sobre leitura. É para poder fazer esse treinamento. Se mudou o valor, você vai gerar um novo objeto de valor, com o valor BBB. Ou seja, o valor antigo é descartado e entrou um novo valor, que é o que a gente faz normalmente com variável. Se a gente tivesse lá o name antigo, não chegaria lá e faria dessa forma aqui? Mas a gente vê que tem um objeto lá, a gente quer sempre mudar aquele objeto. Com isso aqui, nós nos livramos de efeitos colaterais em cima do objeto de valor, porque a gente sabe que foi gerado um novo valor. Lembre-se daquela história que o seu objeto de valor, ele pode ter um método de fábrica, pode ser create with qualquer coisa, XPTO da vida, que você recebe, não para esse caso aqui, mas para o endereço que tem vários, eu poderia ter um objeto de endereço, e aí, tendo aqui os vários valores ali, rua, etc, etc, etc, eu só quero mudar a rua. Então, eu poderia ter algum tipo de operação desse aqui. Aí eu vou devolver um novo new endereço, reaproveitando os valores atuais, acrescentando o novo. Na verdade, nem estático aqui seria, seria um método comum mesmo. Eu posso ter uma operação também dentro do objeto de valor, mas sempre ele tem que ser imutável. Sempre ele tem que ser estável. Ao contrário da entidade, que nós vamos sempre querer mudar os valores ali acompanhando todo o histórico do que está acontecendo. Porque a gente vai manter sempre a identidade, que é a única coisa que não muda, e o restante dos valores vão ser modificados. É como eu já falei lá atrás, que não é necessário que você saia criando objetos de valores para tudo, mas quando você vê que tem algumas regras específicas aqui para poder sempre lidar com esse nome, inclusive até validação, eu poderia chegar aqui no meu construtor, crio um construtor para sobrescrever o construtor antigo e crio um método de validação. Então, quando eu estou criando esse objeto de valor, faço aqui as minhas devidas validações de tamanho ou até mesmo faço filtros. Se tiver qualquer problema, aqui na hora que eu estiver criando, faço um this is valid, ele vai quebrar. Mas todo esse comportamento está abstraído no objeto de valor e ele vai ser replicado em todos os lugares que eu utilizar. Então, você tira essa responsabilidade da entidade, tem uma estrutura mais estável e permite mais o reuso no meio do código. Então é isso aí e até a próxima pessoal. Vamos continuar a nossa saga.