Olá pessoal, tudo bem? Sejam todos muito bem-vindos a mais uma aula. E na aula de hoje a gente vai falar um pouquinho sobre os use cases e as suas controvérsias. Também vamos sanar muitas dúvidas que vocês ficam e é importante justamente a gente conversar sobre, tá bom? Então vamos lá. Primeiro de tudo, quem deve ser responsável pela criação dos casos de uso? Bom, os casos de uso, ou melhor, as aplicações modernas, elas normalmente contam com um container IOC, um container de inversão de controle e injeção de dependência. Então, nesse caso das aplicações que utilizam inversão de controle, que utilizam um container de injeção de dependência, quem vai criar os casos de uso é justamente este container. A gente até pode gerar a instância na mão, mas eles vão ser injetados justamente pelo container. E, do contrário, pode sim ser utilizado outros padrões como o main controller que cria na mão os casos de uso eu já vi também aplicações que os casos de uso são instanciados na camada de interface adapter no controller mais precisamente o controller instancia o caso de uso e utiliza ele, justamente pelo fato de muitas vezes implementar o padrão command também deve ser já vi também na camada de fora frameworks and drivers que normalmente é onde fica mesmo são vários lugares que podem ser usados para a criação do caso de uso. Normalmente, você vai ver dentro de um container IOC mesmo, de uma gestão de dependência da vida. Qual deve ser o ciclo de vida de um caso de uso? Bom, os casos de uso normalmente são usados uma única vez para um contexto de um ator, da intenção de um ator então chega uma requisição de um ator web, por exemplo é instanciado ou é utilizado o caso de uso é injetado o caso de uso por sua vez, passa pela sua entrada, pela sua saída a forma como é gerado e uma vez finalizado, acabou o ciclo de uso para aquela intenção, para aquele caso de uso. O caso de uso deve interagir com outros? Essa é uma pergunta bastante polêmica e bem interessante. e bem interessante. No capítulo 16, o Uncle Bob recomenda fortemente que não acople um caso de uso a outro. Ou seja, ele recomenda que seja feita uma análise dos porquês que você está querendo acoplar um caso de uso ao outro. E normalmente o porquê é para evitar duplicidade de código. Você tem um caso de uso que, por exemplo, cria uma nota fiscal e um caso de uso que imprime essa nota fiscal ou então que envia a nota fiscal para o comprador. imprime essa nota fiscal ou então que envia a nota fiscal para o comprador e aí, pô, por que eu não poderia chamar o caso de uso de enviar para o comprador dentro do caso de uso de criar a nota fiscal? Eu teria que replicar a chamada ou teria que replicar a lógica dentro do caso de uso? Normalmente, é para esse tipo de coisa que o pessoal pensa em um caso de uso deveria utilizar, interagir com outros. E no cenário de duplicidade de código, você deve refletir sobre os conceitos de duplicidade que é o conceito de duplicidade através de intenção ou através acidental. Ou seja, é uma duplicidade real ou é uma duplicidade acidental? Qual é a diferença entre os dois? Uma duplicidade real é de fato uma fragilidade do sistema onde quando uma mudança acontece você precisa modificar em vários lugares. Em todos os lugares, você escolhe que está duplicado. Uma duplicidade acidental, ela, na verdade, é uma duplicidade onde, sim, tem código duplicado em algumas partes, ou duas partes, mas este código está duplicado temporariamente. Porque é sabido que, em questão de tempo, o código vai evoluir de maneira independente. Então, muitas vezes a duplicidade é acidental. O código tende a evoluir. é acidental, o código tende a evoluir. Nesse cenário que eu mencionei, por exemplo, pode ser que seja uma duplicidade real, só que na verdade não é. Aí quando você desconfia que é uma duplicidade real, eu convido você para pensar se na verdade não tem uma casualidade de ação e reação entre os dois casos de uso. Que nesse caso que eu mencionei, sim tem. Ou seja, eu tenho o caso de uso de emitir nota fiscal, e aí depois de emitir nota fiscal, em caso de emitir nota fiscal com sucesso, ou seja, o caso de uso finalizar com sucesso, eu deveria enviar um e-mail para o comprador. Então eu tenho uma casualidade de ação e reação aqui. E quando isso acontece, a gente também não deve acoplar um caso de uso ao outro e fazer eles interagirem entre si de maneira desacoplada através de eventos. Aí a gente pode introduzir o conceito de eventos de domínio aqui de DDD, por exemplo. Ou então não usar eventos de domínio e só introduzir o conceito de eventos normal onde o caso de uso tem um gateway, sei lá, um Kiwi Gateway, por exemplo, ou um Invoices News Gateway da vida, que ele simplesmente publica essa novidade, esse evento de que foi alterado, e aí o outro caso de uso de enviar e-mail, por exemplo, escuta esse evento, de enviar e-mail, por exemplo, escuta esse evento e aí sim você está tendo uma interação entre os dois casos de uso sem gerar um acoplamento entre eles. Se não for nenhum desses dois casos, aí você pode, de repente, estudar. Mas você tem que sempre lembrar que acoplar casos de uso, assim como qualquer outro código, outra classe, acoplamento pode gerar fragilidade no seu sistema. Ainda mais que casos de uso, pela própria semântica do caso de uso, de representar regras de negócio, eles são os componentes que na vida útil do sistema, são os componentes que mais tendem a sofrer alterações para justamente refletir regras de negócio. Então, justamente ter esse acoplamento pode ser com que, para um caso de uso, faça sentido a regra de negócio A, para outro, a regra de negócio é B. Momentaneamente, era parecido, mas uma regra de negócio vai evoluir independente da outra, e quando isso acontecer, você pode ser introduzido em uma fragilidade no seu sistema e um bug, onde você atualizou o caso de uso lá para controlar a regra de negócio e refletiu no B sem que de fato tivesse sido necessário ou que fosse desejado. Então, tem que tomar muito cuidado com esse tema aqui. Como o caso de uso deve trabalhar com múltiplos repositórios? Na minha visão, ou múltiplos gateways, na minha visão, isso aqui tem um pouco a ver com o passo de cima. Lá no Port and Adapters, na última aula, nas aulas dos casos de uso, das entidades de evento, lá no nosso caso de uso Subscribe Customer to Event, lá a gente tem dois agregados dois repositórios a gente manipula o evento, manipula um ticket e a gente persiste esses dois caras e aí eu te pergunto, você pode ter refletido será que essa implementação é a melhor, será que faz sentido e eu já te respondo que não inclusive a gente vai mexer naquilo mais pra frente Pô, será que essa implementação é a melhor? Será que faz sentido? E eu já te respondo que não, e inclusive a gente vai mexer naquilo mais pra frente. Assim que a gente produzir os domain events, na prática a gente vai melhorar aquele código. Eu vou mostrar uma outra abordagem de como fazer aquilo lá, só que através de eventos e através de consistência eventual. Então, aqui se aplica justamente essa resposta. Como o caso de uso deve trabalhar com múltiplos repositórios? Se esses múltiplos repositórios, esses múltiplos gators, forem para obtenção de dado, não tem problema. Obtenção de dado está tudo bem. Mas quando é para persistência, obtenção de salto, tudo bem mas quando é para persistência aí temos que levantar uma bandeira e refletir se de fato esse caso de uso não está com muita responsabilidade e ir virando um big ball of mud virando um spaghetti cold se não deveriam ser casos de uso diferentes que por exemplo tem uma interação com base em eventos. Então, precisa refletir bastante sobre isso quando você tem múltiplas escritas em gators diferentes em um mesmo caso de uso. Até para manter a consistência entre os dois é complicado, porque você precisaria abrir uma unit of work, que não é todas as linguagens ou frameworks que implementam, ou você precisaria abrir uma transação a nível de framework and driver, então tem que tomar muito cuidado com isso. E posso utilizar libres externas nos meus casos de uso, novamente, depende. Qual biblioteca é essa? Eu faço vista grossa para bibliotecas, como eu já mencionei, Lombok, Vavr, coisas que a linguagem carece. Essas bibliotecas que pouco mudam, oferecem para a gente essas construções. Então, temos que analisar o caso a caso aí. Casos de uso e interactors são a mesma coisa? Essa é uma pergunta bastante feita também. Na verdade, o termo é use case interactor, o termo cunhado pelo Uncle Bob. O termo que ele usa no livro é esse, Use Case Interactor. Dentro da arquitetura limpa, quando a gente fala justamente ou só Use Case ou só Interactor, sim, a gente está falando da mesma coisa, a gente está falando da classe que implementa o caso de uso, a gente está falando do nosso caso de uso e da regra de negócio daquele caso de uso. É a mesma coisa. Semanticamente, são coisas diferentes. Semanticamente, caso de uso é aquilo que eu já expliquei, que define uma entrada, define uma saída e define os meios de chegar até aquela saída. Interactor, na literatura, se não me engano, foi muito falado no livro do Eivar Jacobson, é lá que é introduzido esse conceito, mas eu vi algumas pessoas comentando que Interactor, na verdade, é uma especificação, é um outro nome para o padrão Command, e por isso que é usado em conjunto na literatura do Uncle Bob. Use case interactors. Então, evidencia sua característica de ser um comando, naquele caso de uso. Ou seja, o comando tem um único método público, chamado execute. E carrega semântica no nome da classe. Então, quando eu falo de maneira isolada, sim, são as mesmas coisas, mas semanticamente uma coisa diferente da outra. Bom, é isso sobre use cases. Espero que vocês tenham gostado. Vejo vocês na próxima aula.