Olá, sejam todos muito bem-vindos a mais uma aula. E na aula de hoje a gente vai começar o módulo prático aqui da arquitetura hexagonal da nossa pós-graduação da MBA de arquitetura. E a gente vai então dar uma olhada, a gente vai explorar aqui o código que a gente vai trabalhar em cima. O código que a gente vai operar. Fomos encarregados de melhorar esse código. A gente entrou aqui nesse projeto, tudo aquilo que a gente falou, Big Ball of Mud, está ruim, não está dando para reaproveitar coisa, tem queries sendo lançadas no controller, não está muito bacana. Então a gente vai corrigir isso aqui e a gente também vai entender melhor um pouco mais do problema que a gente comentou. Então vamos lá, vamos fazer um reconhecimento de campo aqui. Esse projeto, ele foi criado por mim, eu mesmo que bolei ele. Ele já tem, ele segue já o modelo que vocês já estão acostumados aqui no MBA. Então, a gente tem basicamente a entidade de Customer, são os clientes. A gente tem o Partner. O Partner, ele é uma casa de show, por exemplo, alguém que quer fazer um show, um evento, aí a gente tem o evento, que são basicamente os eventos mesmo, e cada evento tem uma lista de tickets. A lista de tickets é o evento, é criado pelo partner e o ticket é comprado pelo customer. Está bem simples, um projeto bem curto mesmo, bem pela didática do que a gente vai ver. Então, a gente já consegue ver aqui, por exemplo, o projeto está usando aquela arquitetura em camadas, como a gente comentou, a gente tem Controllers, que seria um pouco do presentation Y-layer, a gente tem as services Que é onde deveria ter regra de negócio E a gente tem os repositories Que aqui no mundo do Spring Do Java A gente Usa o Spring Data JPA Então a gente expõe uma interface A gente expõe basicamente uma interface E aí o framework, o Spring cria para a gente a implementação para essa interface com todos os métodos que a gente declarou, ele cria para a gente as queries que vão para o banco de dados. De certa forma, o Spring já trabalha com o repository pattern, o repository pattern que é um padrão por agregado mas aqui no caso por tabela do banco de dados mas de certa forma ele já trabalha um pouco com esse padrão, então ele já até tem uma interface, já está um pouco isolado, mas ainda assim não é aquilo que a gente quer, ainda está longe uma interface aqui do JPE ele é obrigado a se acoplar ao framework, então você precisa estender CRUD repository ou alguma outra interface similar, ou então prover uma implementação customizada. A gente fala qual é a entidade que ele vai gerenciar e essa entidade precisa ter as anotações do jpe, né? E depois qual que é o tipo da chave primária, né? Então, no caso, é um long. Vamos ver como é que está a camada de regras de negócio? Vamos ver como é que está aqui o Customer Services, né? Teoricamente, deveria ter regra de negócio aqui do ponto de vista de persistência e a gente já vê que não está. Lembra aquele exemplo que eu mostrei para vocês da startup, contrato a choc, então, olha lá, imagina que caiu no mesmo cenário, o service, ele se tornou, o primeiro que ele se tornou um antipatron chamado middleman, que é um cara que não faz absolutamente nada e está só fazendo um proxy de uma parada para outra. E não, não tem nada a ver com o padrão proxy. Esse cara, de fato, aqui, não faz nada. Ele não agrega nenhuma informação, não decora, não faz nada. Ele nem precisava ter aqui. Quer dizer, semanticamente, ele deveria existir porque aqui é onde deveriam estar centradas as regras de negócio. Só que como não tem, não faz sentido. E aí estar centradas as regras de negócio. Só que como não tem, não faz sentido. E aí, onde estão as regras de negócio? Vamos dar uma olhada no controller. Aqui no controller a gente já consegue ver. Aqui a gente já tem, por exemplo, parece que começa bem, mas depois vai mal. Olha o método create aqui. Faz as validações na mão, instancia, chama o save, retorna, tem um pouco de query, ou melhor, um pouco de chamada para service, que são queries abaixo nível, isso aqui. A gente instancia o customer, seta, e nem tem validação, e-mail, cpf, nada de validação aqui, é simplesmente seta, persiste, e aí retorna aqui qual o status code e a e o path para recuperar esse cara recém criado. Então, olhando assim, você para e pensa, está bom ou está ruim? Quantos códigos que você já trabalhou que você já viu algo parecido? Agora pensa. Quais os tipos de problema que esse tipo de código apresenta? Você consegue alentar? A gente já falou algumas coisas, né? Mas para e pensa. De cara, eu já trago uma reflexão pra você. Se isso aqui tá aqui, como a gente faria, por exemplo exemplo para expor a nossa aplicação para um nosso regras de negócio os casos de uso para um se ela se eu quiser rodar a aplicação de forma como sendo um se ela tem como acho difícil né porque isso é um controle está acoplado ao REST API, às anotações web, está vendo? As anotações web do Spring. Aí você pode estar pensando, putz, mas por que eu ia expor isso aqui como uma CLI? Ok, até o pensamento justo, e eu venho com uma outra provocação. E se eu for expor esse meu código, a minha regra de negócio, via GraphQL? Eu tenho clientes no GraphQL. Isso aqui é um REST Controller, isso aqui é um controller para requisições HTTP REST. Eu precisaria duplicar isso aqui para expor? Complicado, né? Vamos fazer um teste? Vamos fazer um teste? Então, vamos ver se a gente consegue expor isso aqui para um GraphQL. O que a gente precisaria? A gente precisa para um Alt Insert aqui, né? Eu estou usando Linux. E só um detalhe, né? Então, aqui no MBA o conteúdo já é mais avançado, tá, gente? Eu não vou ensinar para vocês como configurar o Java, como configurar a IDE, mas temos já ensinado tanto no YouTube da Fullcycle quanto no curso Fullcycle, a gente tem bonitinho como configurar o Java, como configurar o WSL, como configurar a IDE, como configurar o Docker, a gente tem tudo já bem mastigadinho aqui, então se você ainda não tem o ambiente configurado, dê uma pausa. Vá lá para configurar o seu ambiente. Mas vamos continuar aqui então. O que a gente precisaria aqui? Alt insert, um package. Vamos colocar aqui, GraphQL. E aí vamos, alt insert de novo, uma classe. Customer resolver. Quem que é o customer resolver? E aí vamos, a gente inserta de novo uma classe, CustomerResolver. Quem que é o CustomerResolver? Ele é basicamente um controller que vai fazer a gestão do que está vindo do GraphQL via HTTP para alguma outra regra de negócio. E aí o que a gente colocaria aqui? a regra de negócio. E o que a gente colocaria aqui? Customer, por exemplo, DTO Create Customer e aí esse cara aqui é uma Mutation Mapping do GraphQL. Ah, só a título de explicatório, né? O build.gradle, eu já deixei ele meio pronto, tá? O repositório já está lá no GitHub da Fullcycle dev Fullcycle, é este repositório aqui, o MBA, Exagonal Architecture na branch main é onde está esse código bem vanilo de tic tac, então vocês podem só fazer o fork desse código e continuar aqui comigo na aula, então aqui eu já tenho, por exemplo, o Spring Starter Web, o StarGraphQL e o DataJPA, junto do MySQL. Então eu tenho o MySQL aqui rodando. Então o que a gente precisaria aqui? Aí eu precisaria de um arroba argument, customer.dto, recebe a mesma coisa como um input e agora que a gente vai fazer? A gente pode importar o customer service auto-iried aqui e como a gente já está fazendo aqui, como fomos designados a corrigir esse código, a gente já vai fazer direito. designados a corrigir esse código, a gente já vai fazer direito. A gente sabe que uma boa prática é fazer a injeção via construtor e não daquele jeito, porque assim via construtor permite com que a gente não tenha dependência cíclica. A gente garante isso. Então, vamos fazer via construtor, a gente já está garantindo aqui que esse cara não é nulo, estamos bem seguros aqui do que a gente está fazendo mas e agora, o que a gente vai fazer bom eu tenho que vir copiar, eu tenho que copiar isso aqui, voltar lá colar vou mudar aqui do que é dto para input só pela semântica, response não tem na verdade isso aqui deveria ser deveria ser feito essa validação deveria ser feito lá dentro da service então a grosso modo vamos lançar aqui uma exception aqui também lançamos exception responsiente também não tem a gente vai retornar o customer direto aqui, ou melhor, o customer DTO, retornamos o customer DTO direto aqui e não vou nem mexer em mais muita coisa, é só isso para ficar compliance. O que você achou? Faz sentido? Vamos ver o do evento. Olha o do evento aqui. O do evento já tem mais coisa. O do evento aqui para criar é fácil. Mas para comprar um ticket. Que dá o subscribe aqui. Tem que buscar o customer. Tem que buscar o evento. Tem que buscar. Tem que ver se esse evento tem um ticket para esse customer. Porque ele não pode comprar duas vezes, instanciar o ticket, se adicionar no evento, persistir o evento, copiar e colar tudo isso aqui, testar novamente tudo isso aqui, um para cada um, parece meio inviável, certo? Então o que a gente é obrigado a fazer? A refatorar o Customer Service? Colocar isso aqui tudo para dentro do Customer Service? É uma opção. É uma opção. Mas quem garante que vai continuar assim o código? Quem garante que alguém não vai ver aqui o Partner que está mal feito e vai copiar e colar mal desse jeito? Ninguém garante que alguém não vai ver aqui o partner que está mal feito e vai copiar e colar mal desse jeito? Ninguém garante, porque a nossa arquitetura de aplicação não está impondo esse tipo de coisa. Ela está liberalzona. Então a gente vai corrigir isso. Vamos só continuar aqui no exemplo do GraphQL. A gente tem o nosso CustomerResolver. O que a gente precisa aqui? Vir no Spring, se eu não me engano é GraphQL.graphicl.enable, igual a true. Vamos habilitar o sandbox aqui, o GraphQL. A gente precisa vir aqui e inserir um diretório chamado GraphQL. inserir um diretório chamado GraphQL e a gente vai inserir aqui um arquivo um arquivo chamado schema.gqls GraphQL Language, beleza aqui a gente pode colocar, vamos lá type, customer o customer tem um id ele tem um id, ele tem um name que é do tipo string, ele tem um email que é do tipo string e tem também customer input, que é basicamente isso aqui que a gente precisa, e ele não é type, ele é um input, customer, beleza? E aí depois a gente tem aqui, por exemplo, o type mutation, e também temos o type query, então isso aqui tudo faz parte do GraphQL. Então aqui a gente pode, por exemplo, ou melhor, Customer of ID, e aí ID aqui, e retorna um Customer. Não vou nem falar que é obrigatório porque pode não existir esse customer e de mutation é basicamente createCustomer que recebe um input do tipo customerInput e retorna um customer e aí a gente tem a nossa primeira mutation e a nossa primeira query agora vamos tentar subir a aplicação. Na verdade, a aplicação tem uma dependência, que é o MySQL. Então, eu já deixei até um docker aqui. docker compose-up-d. Vamos rodar o MySQL aqui. o MySQL aqui e aí agora a gente pode a gente pode tentar rodar a aplicação enquanto o MySQL sobe também ó, beleza, se conectou fez os alters, a aplicação está de pé agora a gente pode trazer um trazer um navegador pra cá e localhost 2.8080 barra GraphQL show de bola ó já temos aqui umas variáveis que a gente não vai usar já temos aqui até o teste feito antes vou vou mudar isso para input e vamos enviar enviei uma vez internal error vamos ver o que deu aqui de erro customer already exists então já estou operando em uma base que não está 100% limpa então vamos colocar aqui uma outra coisa de e-mail um outro cpf e tentar enviar agora sim, o Customer.id2 que foi criado. Vamos comentar isso aqui. A gente pode colocar aqui, query Customer.id2 E aí, precisa só falar qual é o parâmetro, né? E aí a gente fala o que a gente quer o nome. Opa, Customer de... Ah, a gente fala o que a gente quer o nome. Opa, customer de... Ah, a gente não implementou a query, óbvio. Então não vai funcionar, mas vamos tentar criar mais um. Já viu que recebemos um erro, né? Recebemos um erro aqui. Uma runtime exception que nem foi tratada, né? No caso, a gente colocou de qualquer forma, mas tá vendo que começa a ficar inviável, né? A gente fez o customer, beleza. Vamos fazer mais um, ó. Vamos fazer a parte do query. O query até que é mais fácil, né? A gente retorna um customer.dto, customer of id, né? Que a gente colocou e aí ele tem um long do tipo id e um argument esse cara é um arroba query mapping, show de bola vamos lá, o que o get faz? faz isso aqui, vamos pegar isso aqui, vamos só pegar isso aqui a gente vai dar um return isso aqui, or else or else vamos retornar nulo e aí, na verdade a gente vai ponto map se tiver valor, a gente vai mapear para customer gto customer gto o que tiver valor a gente vai mapear para customerGTO 2.2.new beleza, se a gente subir agora o getPred vai funcionar mas sabendo que a gente vai ficar copiando e colando, isso que a gente nem foi na dor principal que é lá o do evento, que é maior. Mas, ó, a gente já vê que é inviável, né? Não dá. Não dá pra ter um projeto suscetível a isso, onde você precisaria ficar copiando e colando, precisaria ficar fazendo um grande refactor, onde a regra de negócio tá num lugar errado, totalmente acoplado no controller. Olha como estão os testes, né? Normalmente de projetos como esse, ó, um teste 100% baseado em integração, onde você precisa ficar mandando requests pra simular o sistema, não tô falando que esse teste não tem que ter, tem que ter né, tem que ter mas não é só isso que tem que ter, e não deve ser feito majoritariamente desse tipo de teste né, então, não tá bom, né, e e como eu mostrei pra vocês, como eu já provei pra vocês, não é ladainha. Isso acontece, Big Boss Mud acontece. Inclusive tem cursos na internet que ensinam Java, microserviços, não sei o que. E aí quando você vai ver o código baixo nível que tá sendo produzido e ensinado, é algo parecido com isso, ruim, não escalável. Então, vamos aprender a fazer direito e a gente vai começar na próxima aula.