Olá pessoal, tudo bem? Sejam todos muito bem-vindos a mais uma aula. E, bom, acho que só para a gente encerrar esse módulo de hexagonal na prática, eu gostaria de fazer algumas considerações finais, algumas dicas para você que quer ir além, e alguns outros assuntos. Então, vamos primeiro começar recapitulando o que a gente fez. Eu já subi tudo na branch chamada Hexagonal Arc. A gente saiu lá do main, que estava cheio de spaghetti code, que tinha um monte de middlemen, um monte de services que não faziam nada, a não ser que eles redirecionavam para repositórios, testes só do integrado, quase um edge-to-edge e um escopo bem broad, validações, regras de negócio meio perdidas entre controllers e services para isso aqui, que é a aplicabilidade do hexagonal. Então, dividimos a nossa aplicação em dois principais pacotes, application, onde tem casos de uso, repositórios e o nosso domain, casos de uso, repositórios e o nosso domain e infrastructure, onde a gente tem aí toda a parte de fora do hexágono. A gente tem interface adapters, a gente tem drivers e driven actors. Então, o que era aquele monte de controller virou REST, então aqui a gente tem o customer controller, ele é um adapter, a gente tem um event controller, outro adapter, partner controller, cada um deles trazem consigo casos de uso, então eles não mais estão acoplados e não mais possuem regras de negócio, eles possuem um caso de uso, cada caso de uso, cada controller, cada adapter sabe criar o input do caso de uso, passar para ele executar, pega o seu output e devolve então isso aqui é adaptação está um pouco misturado também com a parte drivers um pouco parado da parte http mas tudo bem fazemos está grossa aqui né além disso a gente adicionou um outro driver a gente adicionou o GraphQL que da forma como estava antes, estava meio complicado da gente adicionar, porque tinha muita regra de negócio aqui na camada de controller, na camada REST e tinha que ficar copiando e colando então a gente extraiu para um caso de uso e começamos a conseguir reutilizar eles nesses dois lugares então são bem enxutos e muito parecidos, só que um vem através do ator GraphQL, um vem do REST, então temos as boas diferenças aí e a gente começou a reutilizar bastante coisa. Falei da DTO, essas DTOs aqui, elas estão sendo compartilhadas entre a camada REST e a camada GraphQL, eu levantei uma bandeira, falei que tem que tomar cuidado com isso, porque se de repente a comunicação via GraphQL precisar adicionar mais ou menos campos, vai refletindo no REST e pode ser algo que não é desejado, então se você não tiver afim mesmo, talvez um sistema end, um sistema final, que está para a produção, que seja da sua empresa, possa fazer sentido deixar DTOs dentro aqui da package de GraphQL e dentro de REST, cada um com seus DTOs aqui. Os use cases foram configurados tudo aqui em configurations, configuração manual. A gente falou que se eu não quisesse fazer configuração manual, eu poderia utilizar da especificação de CDI do Java, tanto a mais moderna do Jakarta, como a antiga Javax Inject, para através dessas annotations, eu colocá-las nos casos de uso e aí é os casos de uso basicamente já seriam inspecionados automaticamente pelo Spring ou por qualquer outro framework que todos suportam a especificação de CDI do próprio Java, da Jakarta no caso. Então são duas abordagens diferentes, aqui eu fui pela de declaração de bins mesmo, mas poderia utilizar ela. Os repositórios aqui não são os repositórios JPA, aqui são as implementações dos repositórios expostos da Camarada de Application, das Out output ports, no caso, das outbound ports, das portas de saída do nosso hexágono. Então, temos Customer Database Repository, que traz consigo, ele é um interface adapter, e traz consigo uma outra interface que dá caminho a um data mapper, um ORM. O que mais? Acho que aqui é isso. Depois a gente vem para a camada de use case, onde a patamar de application, a gente tem os nossos use cases, aqui a gente tem as anatomias dos casos de uso, as abstrações. A gente tem aqui, por exemplo, os use cases de uso, as abstrações a gente tem aqui por exemplo os cases de customer de partner, de event uma das coisas que eu gostaria de ressaltar é sobre esse caso de uso que a gente recém trabalhou nele, a gente ainda vai voltar e vai modificar esse caso de uso a gente vai aplicar domain event aqui que é um conceito que a gente ainda não viu. A gente aplicou algumas coisas de DDD como agregado, como repository para manipular o agregado. A linguagem é obíqua, a gente tem tanto que a linguagem é obíqua aqui para os nossos casos de uso. Mas esse caso de uso ainda está meio esquisito. Ele manipula dois agregados de uma única vez. Existem maneiras, através de eventos de domínio, que a gente consegue manipular um agregado e fazer com que essa manipulação depois dispare uma reação num outro caso de uso que vai manipular outro agregado. Então, eu vou dar a ideia para vocês, se vocês quiserem implementar. A gente vai implementar depois quando for falar de eventos de domínio, depois de falar de Clean Architecture inclusive. Que é basicamente, a gente não precisa criar um ticket aqui agora. Aqui a gente também, esse reserve ticket não precisa necessariamente devolver um ticket. A gente deve sim manter essas validações, esse método deve continuar existindo, só que ao invés de gerar um novo ticket aqui, a gente só vai gerar esse event ticket com o ticket ID nulo, então teria que modificar também depois como esse cara está sendo armazenado, se a chave primária é esse aqui. Não poderia ser, acho que poderia ser uma chave composta ou uma outra chave aleatória só para trace. Então, de repente, esse event ticket passa a ser uma entidade, não só mais um objeto de valor. E aí, o que acontece? A gente vai reservar esse cara, vai devolver o event ticket e vai persistir o nosso event apenas. persistir o nosso event apenas porque daí a gente já vai persistir com esse novo essa nova reserva de ticket já tudo bonitinho e aí vai gerar um evento de domínio que esse evento de domínio é nova reserva de evento que quem vai escutar por exemplo é uma camada de ticket que aí sim através da nova reserva vai ser gerado um ticket para essa reserva. E até pode ser devolvido esse ticket ID para cima, ou mantém o ID como referência de trace que foi gerado ali. Depois dá para pensar melhor. Eu acho que até manter isolado é melhor ainda. Não precisa devolver o ID do ticket gerado. Tem o ID lastro, o well ticket é um outro id que está dentro do serviço de ticket caso depois a gente queira isolar também então o resumo é que a gente vai mexer nisso aqui tá então essa é a parte da consideração final aqui não se preocupe quanto a isso pass, a gente criou, então, aqui os nossos domínios ricos, criamos os nossos agregados, não construímos nenhuma anatomia de agregado, value object, height de agregação, value object, entidade, mas definimos aqui, então, um agregado tem a sua, um agregado é uma entidade, ele é identificado por um ID e apenas isso, esse agregado tem o seu ID de forma imutável, esse ID nunca pode ser mudado, você pode mudar as características dele, mas o ID não, o ID sempre é o mesmo, e sempre precisa ter ter esse cara a gente falou um pouquinho sobre factory methods, para facilitar a construção a gente criou objetos de valor como CNPJ que encapsulam validações e já criamos utilizando o novo padrão record cpf, mail, então já tem algumas coisas bem interessantes o name eu falei que poderia até ser só uma string pura, não precisa necessariamente ser um viés de valor, porque ele não tem uma validação tão interessante assim. Como a gente está, repara que sim, como a ideia de um modelo de domínio e DDD, principalmente da modelagem tática do DDD você redistribuir a complexidade do software entre várias classes é por isso que no construtor e no método público a gente recebe tipos tipos convencionais objetos convencionais e dentro do construtor a gente instancia os objetos de valor. Porque daí, assim, a gente está distribuindo a complexidade de fato. Porque daí, na hora que for instanciar esse cara, por exemplo, você vai retornar um erro de validação de CPF, de e-mail, de nome. E aí, essas complexidades são encapsuladas justamente aqui dentro do Customer. Se você instanciasse o Name fora e passasse o Name, o Customer, por exemplo, já não estaria dentro dele a validação. E uma outra vantagem de deixar aqui dentro é que a gente está retornando o Customer direto ou uma exception, mas poderíamos retornar uma construção como um Either, que é o sucesso que é um customer ou um erro, através do Factory Method aqui. Depois eu posso mostrar para vocês isso quando a gente for implementar CleanArt, por exemplo. Falamos também que, vamos lá no Event, a gente todo agregado, ele só relaciona com IDs de outros agregados, no caso aqui é uma entidade, está relacionada com outro agregado, só relaciona com a igis de outros agregados no caso aqui é uma entidade está relacionada com outro agregado é sempre quando for relacionar com agregada sempre por aí né é que eu vou até uma excepção aqui né e mais certo um performático né eu mencionei para vocês é sobre esses dois parâmetros né que é suppression, enable suppression e readable stack trace esse aqui precisa necessariamente sempre ser falso para ter uma performance boa em output no JVM, porque é muito custoso parar a thread e pegar toda a stack trace para colocar aqui numa exception criamos o nosso GraphQL, nosso esqueminha, então acho que é isso, e como eu já mencionei para vocês, eu particularmente nem uso o Proberts, normalmente eu uso o YAML, eu acho que eu prefiro, ainda estou muito na dúvida sobre isso, mas tenho usado o YAML faz anos, então eu não coloquei as mais boas práticas aqui, nem configurei pool de banco de dados. Então, eu mencionei que lá no curso FC, que é focado em Java, eu ensino isso. Aqui o importante é ensinar arquitetura hexagonal, praticar o DDD, ensinar o CleanArch, e não nas mais boas práticas de Java para uma publicação de alta performance. Então, é um bem de consideração. Ah, falamos um pouquinho também sobre testes, criamos aqui uma abstração de integration test, também criamos os testes mais... criamos os testes unitários, então, estamos testando só aqui o customer, todas as validações, person, criamos esses caras, repositórios, todas as validações, Person, criamos e testamos esses caras. Repositórios, são as complementações de memória e os use cases também. Eu considero casos de uso dessa maneira unitários. Ah não, esses aqui são integrados, mentira. Aqui são casos de uso integrados mesmo, mas poderíamos testar unitariamente esses... Ah, eu entrei em um integrado, porque tem o IT, esse caso é integrado, mas esse aqui, por exemplo, é unitário. Por quê? Porque eu estou testando a unidade que é o meu caso de uso. Eu, na minha leitura e na leitura do Martin Fowler, que tem um artigo dele falando sobre a pirâmide prática de testes, lá do Martin Fowler, ele comenta justamente sobre isso também. Assim, não tem framework aqui, o teste executado absurdamente rápido é unitário. Independente se dentro da minha unidade tem um side effect, tem uma dependência. Ele ainda assim é unitário. Estou testando esse cara aqui. Eu moco esse comportamento, eu vejo esse cara, eu vejo se o resultado de entrada, o resultado final e o script que ele executou de fato estão coerentes com o que ele se propõe. Então, para mim, é um teste aqui unitário. É integrado se você colocou framework Colocou framework Virou integrado Na minha perspectiva E quando você testa uma única parada É um teste integrado mais narrow Com um escopo menor Quando você testa uma parada grande Mais a nível de controller É um teste integrado broad Com um escopo maior Com exceção Quando você está testando vários métodos de controle, então você está criando o mockup, depois chamando a parte do caso de uso que você gostaria, e depois fazendo alguma outra verificação, aí sim eu chamo de end-to-end, porque no conceito de microservice, tipo esses RESTs aqui da vida, esses aqui são end-to-end, Porque no conceito de microservice, tipo esses RESTs aqui da vida, esses aqui são end-to-end. Eu chamo aqui, por exemplo, para criar o primeiro, depois para criar o segundo, o do event também. O do event está mais ou menos, na verdade, porque eu tenho a persistência prévia aqui. Seria mais end-to-end se eu estivesse chamando createCustomer, createPartner, depois createEvent, os três requests aqui. Eu acho que eu consideraria mais enteúente, esse cara que eu criei aqui tá meio que um teste integrado mais broad, mas é isso, então, recapitulando um pouquinho do que a gente fez, o que eu posso lhe dar de dicas e recomendo que vocês façam isso, que eu vou fazer para a parte de CleanArch, que é um pouco mais fácil com isso. No CleanArch a gente vai isolar, a gente vai quebrar isso aqui em módulos, em submódulos do Gradle. Aqui a gente está tudo dentro de pacotes. O problema do pacote é que ele não adiciona travas necessárias para que não aconteça cagadas como implementações, como acoplamentos de frameworks e bibliotecas em camadas de regras de negócio, coisas do gênero. Então, até no hexagonal, eu também recomendo que você faça submódulos. O submódulo de application do Gradle, o submódulo Gradle de application, e o submódulo Gradle de application e o submódulo Gradle de infrastructure. No application você não coloca lá no build.gradle nada que é biblioteca, framework, nada. É puro. No infrastructure sim você coloca e aí você também inclui o application lá pra você poder acessar a camada do hexágono. Então, eu recomendo que vocês façam isso, eu vou ensinar vocês a fazerem lá quando a gente for implementar o CleanArc, porque o CleanArc, sim, é bem mais chato com isso. E qual que é a vantagem de usar submodules? A gente também disse, você adiciona uma trava a mais, que é se o cara quiser adicionar um framework com a biblioteca, ele precisa ir no build.gres o .gres daquele submodo e inclui lá. Então, a chance de você pegar esse tipo de coisa em um pull request é muito maior. Fora que também podemos utilizar de outros meios como o ArcUnit, que é para você testar justamente esse tipo de coisa. Testar pacotes, sacolas em pacotes, sufixo de classes, então todos coerentes com a atividade da aplicação. Também recomendo que tenha isso. Bom, acho que é isso. Espero que vocês tenham gostado. Vejo vocês na próxima aula.