Olá pessoal, meu nome é Leonardo Leite, sou doutorando ciência da computação pelo IME-USP e hoje vamos conversar sobre arquitetura limpa. Ou mais precisamente é sobre o livro Arquitetura Limpa, que é escrito pelo Robert C. Martin, também chamado de Uncle Bob. E uma motivação ai, é que você estudar, conhecer os grande livros da área, os livros de referência é uma das formas de você se tornar grande desenvolvedor de software e esse é desses livros. Então, antes de falar de arquitetura limpa, a gente precisa se situar nesse contexto, que que a gente entende por Arquitetura. Então, pegando uma definição do próprio livro, o autor vai dizer: que a arquitetura de sistema de software é a forma dada a esse sistema pelos seus criadores. Essa forma está na divisão desses sistemas componentes e na organização desses componentes e nos modos como os componentes se comunicação entre si. Então, falando de uma forma mais geral, a arquitetura de sistema é a organização desses sistema. Como você divide ele componentes, classes e como esses elementos se comunicam. E pra que isso? Bom, segundo o autor também: O propósito da arquitetura é facilitar o desenvolvimento, a implantação, a operação e principalmente a manutenção do sistema. Por que a manutenção que vai sair mais caro. [TOSSE] [TOSSE] E a arquitetura limpa vai entrar ai, para melhorar a testabilidade e a manutenibilidade do sistema. A testabilidade aqui tá até subordinado a manutenibilidade. Por que? Pra que você quer uma boa testabilidade? Quando você fazer uma manutenção no sistema, você vai querer executar os testes, pra saber se está tudo ordem, se a manutenção não regrediu, não quebrou nada no sistema. Então, como que a gente vai fazer aqui pra explicar o que é uma arquitetura limpa? A gente primeiro vai mostrar uma arquitetura não limpa, vamos projetar sistema com uma arquitetura não limpa, explicar porque, qual que são os problemas, porque que não é limpo e depois limpar. Como exemplo, a gente vai pegar exemplo da indústria musical, imagina que a gente está desenvolvendo tipo Spotify ou sistema de uma gravadora e a gente vai fazer cadastro de álbuns musicais, no contexto ai de serviço REST, API que é uma comunicação máquina-máquina. Vai ter uma sistema que vai ficar disparando e alimentando uma base de dados com álbuns musicais. Então, essa API REST, como que ela funciona? A ideia é que você tem sistema cliente, que vai trafegar dado para nosso sistema, esse dado que é conjunto de dados sobre álbum, tem o segunte formato, que é formato JSON e ai, vai ter aqui, cada álbum vai ter título, artista, ano de lançamento do álbum, a lista de canções do álbum e uma foto, essa foto é o seguinte, se a gente pegar uma imagem qualquer, uma imagem no disco, é sequência, uma Rede Bits, mais no contexto de API REST, pra gente trafegar esses BITS dentro desse texto que é JSON, como que a gente faz? A gente transforma esse Rede Bits na representação base64 desses Bits, então, essa imagem que acabei de mostrar esse Check verde, eu posso rodar aqui o comendo base64 e pegar a representação base64 dessa foto, transformou ai a foto, a imagem uma String. Então, a gente pega essa representações essa Stringona e coloca aqui nesse campo do JSON e assim se trafega esses dados. Então, vamos lá, eu vou criar aqui diagrama, diagrama de classe, pra gente projetar esse sistema. [RUÍDO] E aqui, quando a gente está falando de uma. Primeira coisa então, a gente está falando de uma Pay Rest que vai trafegar esses dados. E esses dados quando chegar no sistema, de imaginar que é sistema JAVA isso aqui vai ser mapeado pra objeto JAVA. Então, a gente precisa de uma classe que represente esses atributos, então vamos começar por isso. Eu vou chamar ela simplismente, essa classe de álbum, e vai ter que ter aqueles atributos lá. [RUÍDO] Então, são título, [RUÍDO] artista, [RUÍDO] ano, as canções [RUÍDO] e a capa Vou por base64 e a gente coloca os tipos aqui. [RUÍDO] String, String As canções aqui é uma lista de String. O Ano é INT, coloquei aqui sem querer. [RUÍDO] Então é isso, esse aqui é o nosso álbum. E quando, é uma Pay Rest aqui, vai ter os Frameworks que vão ser utilizados que vão receber a requisição e vão jogar isso pra alguma classe JAVA que vai processar. Essa classe a gente chama de Controller, então vou chamar aqui de Álbum Controller e a operação aqui principal, o ponto de entrada do sistema, vai tá mapeando uma operação REST. Então, vou chamar aqui de POST álbums que é a parte REST E essa operação vai estar recebendo álbum, então eu vou colocar aqui como o atributo, o parâmetro. [RUÍDO. Então a gente tem uma dependência Então, aqui to falando de algumas coisas que talvez você possa não conhecer: API REST, POST, BASE64, mas tudo isso não precisa de preocupar muito, porque são detalhes da tecnologia, que a gente está usando de interação. Então, eu vou colocar tudo isso daqui num pacote chamado API, que representa a parte da tecnologia REST, poderia chamar o pacote de REST também. Porque é algo como o mundo externo vai interagir com o nosso sistema, poderia interagir de outras formas, como o sistema WEB, através de mensageria e por aí vai. Mas o quanto importante é que depois que o nosso sistema foi de alguma forma invocado que tá muito ligado a uma determinada tecnologia, a gente vai chamar código, que é o código do negócio, então vou chamar aqui o pacote de ''Domínio''. E esse pacote ele tende a ser mais independente de tecnologia. Então, esse pacote aqui, ele vai ter aqui principalmente aqui as regras de negócios e a implementação dos casos de uso. E ai que que isso quer dizer? Que o Álbum Controller vai delegar pra uma outra classe, que eu vou chamar aqui de Álbum Service. Aqui a nomeclatura não é tão importante, mas o importante que a gente tem uma operação aqui, que eu vou chamar de Insert Álbum, que é o que de fato vai implementar o caso de uso de inserir novo álbum, contendo regras de negócios, validações. Totalmente Validações aqui é uma forma de entender ta aqui nesse pacote, nesta classe. E ele vai receber esse álbum aqui que foi passado pela interface. Então, aqui também vai ter álbum. [RUÍDO] Então, essa classe aqui, Álbum Service, também depende desse Álbum que tá na fronteira do sistema. E após as validações, as regras de negócios, algum momento o álbum service, vai querer gravar esse álbum no banco de dados. O banco de dados é outro detalhe tecnológico, então não convém ficar aqui no pacote do domínio. Então, a gente cria outro pacote, a gente poderia chamar o pacote de DB (DataBase), mas outro lado possível é a Infraestrutura (INFRA). E ai normalmente, que que a gente faz? A gente tem uma classe aqui, que é o Álbum DAO. DAO, que significa Data Access Object, que geralmente é padrão usado pra interação com banco de dados. Então, o importante aqui é que essa classe, que vai entender de SQL, então, o domínio não pode saber nada de SQL, é muito detalhe para ele. Então, o Álbum Service vai chamar o Álbum DAO, que vai ter uma operação aqui, que também vai ser algo do tipo New Álbum. que vai receber também, aquele álbum vai ser passado a diante. Então, o service recebe o álbum, aplica as regras de negócio, faz validações, está tudo certo, vamos inserir no banco, passa esse álbum e o Álbum DAO inseri no banco. Só que na hora de inserir no banco, tem algumas questões. Primeiro, que esse Base64 aqui, está errado aqui ''cover''. Normalmente no banco, a gente vai guardar o arquivo de fato como a a Rede Bits que é o que ele é. Então, tem que ter uma conversão. Além disso na hora de gravar no banco, a gente pode querer gravar uns campos adicionais como por exemplo: quando que esse registro foi inserido. Então, eu vou criar outra classe que representa essas conversões o que de fato vai para o banco. Esse aqui, vai ser o Álbum Record. Record remete a registros no banco de dados. Então, aqui vai ter o título do Álbum, opa, não é uma operação aqui. Atributo, Então aqui a gente vai ter: título, autor, ano, [RUÍDO] canções, campo que vai dizer quando que foi criado, quando foi criado aqui vai ser do tipo ''Date Time'' e a capa. [RUÍDO] [RUÍDO] E aqui não vai ser mais capa base64, vai ser só capa, que vai ser uma Rede Bits. E aqui eu só vou acertar o tipo dos atributos de cima. [RUÍDO] Então tá, então o álbum DAO vai receber ele depende aqui, desse álbum aqui da interface e converte esse álbum num álbum record criando CreatedAt convertendo [INCOMPREENSÍVEL] num bit que é o que vai ser salvo no banco. E assim temos aqui o projeto da nossa aplicação. Funciona, mas tem algumas questões. Por que que isso não é uma arquitetura limpa? Então, pra isso ficar claro, vou criar diagrama de pacotes. Então aqui a gente tem o pacote API, a gente tem aqui o pacote do Domínio e temos também aqui o pacote da Infra. E ai, dependências, então, a gente tem aqui que o Domínio né? Depende aqui desse álbum, então o domínio depende disso. Mas o álbum, o controle chamasse Service, então o API também depende do domínio. A Infra, o DAO, depende da definição desse Álbum, então a Infra depende aqui do pacote da API e o domínio chama Infra. Então a gente também tem essa dependencia do domínio a Infra. Então, essa aqui é a estrutura de dependência do nosso sistema. Qual que é o problema? Então, o primeiro problema aqui, que a gente tem ciclos. Está fora do escopo do vídeo explicar porque que isso é problema, o livro explica mais detalhes, mas da para você guardar que ciclos é mal cheiro ai para manutenção do sistema. Que ciclos são esses? Olha só, o pacote API ele depende do pacote domínio, o pacote domínio depende do pacote Infra, o pacote Infra depende do API, então a gente tem ciclo aqui. E tem outro ciclo, o pacote API depende do domínio, domínio depende do API então, tem esse ciclo, isso é mal sinal. Outra coisa que acontece, o domínio está dependendo dos detalhes, então, alguém trabalhando nos detalhes, já houve aqui uma otimização do banco de dados, eu vou mexer pouco aqui no Pay Rest, ou vez na Pay Rest, eu vou mudar, fazer outra coisa aqui para receber dados pro sistema interagir com o mundo externo e mexendo nessas coisas que não deveriam ter a saída de negócios, sem querer pode afetar, porque o pacote o domínio depende desses outros pacotes. E uma outra questão é que como o domínio depende desses detalhes, talvez seja complicado testar o domínio de forma isolada, no teste do domínio você vai ter que lhe dar com essas, esses outros detalhes, o que não é legal. O ideal é testar o domínio de forma isolada. Então, essa conversa estou falando bastante de detalhes, isso aqui é ponto chave do livro. Na visão aqui do autor, o livro, sistema ele é composto de políticas e detalhes. As políticas são os elementos mais essenciais do sistema que é principalmente os casos de uso e regras de negócio e os detalhes tem que ser irrelevantes para essa política. Então, a ideia é que uma boa arquitetura vai fazer com que as decisões sob esses detalhes importem menos, e isso é interessante, porque é muito comum numa reunião de início de projeto, os arquitetos, os desenvolvedores está todo mundo preocupado querendo discutir qual banco de dados vai ser usado, qual versão, qual framework, mas essas coisas, numa boa arquitetura importam menos. Então, reforçando que que são esses detalhes. A web é detalhe! Poderiamos vez da web usar sistema de terminal leve, como o [INCOMPREENSÍVEL] usa, que é algo muito diferente. A base de dados é detalhe! Poderiamos gravar tudo banco, arquivos texto por exemplo. E os Frameworks são detalhes também! Então, agora chegando no ponto de arquitetura limpa. Primeiro, retomando o que é arquitetura. Ela é definida por conjunto de componentes e pelo limites que separam esses componentes, então, a arquitetura limpa é uma proposta ai, ou melhor, primeiro assim o autor também coloca, que a arquitetura ela é a arte de estabelecer esses limites entre os componentes. Então, dessa forma a arquitetura limpa é uma proposta de como estabelecer limites entre coisas que importam e não importam. E o que importa aqui que são políticas, a gente pode também dizer que outro motivo importante para separar as políticas dos detalhes, é que essas coisas, elas muda ritmos diferentes, por razões diferentes. Então é interessante que mexendo numa, não afete a outra, principalmente não mexendo nos detalhes não afete a política, que é o mais importante, é o que faz a empresa ganhar dinheiro. Então, agora a gente vai fazer alterações naquele projeto, pra fazer com que a arquitetura fique limpa. Então, vamos lá. Então a primeira coisa que incomoda aqui, é que o domínio ele ta dependendo aqui de detalhe, que é a definição desse álbum que contém até detalhe bem tecnológico, que é esse Base64. Isso não deveria acontecer. O que a gente precisa é de uma outra definição aqui que vai ser independente de tecnologia. Então, na prática que parece interessante de se fazer aqui, é o seguinte, vou criar uma outra classe chamada álbum, que vai ser a classe de negócio, a entidade. Que até eventualmente pode ter regras de negócios nela. Ela vai ter aqui, título, string, vai ter o artista, string, vai ter o ano, vai ter a lista de canções, e aqui na área da capa, que ela vai ter, vai ser: a capa, que é uma Rede Bits. Não tem nada de detalhe tecnológico de Base64. Então, que que vai acontecer? vai ser que o Controller vai receber esse álbum, que até vou mudar de nome, poderia ser por exemplo, álbum JSON, porque ele está mapeando aquele JSON, aquela estrutura de dados, mas outro nome que se dá também que eu vou usar aqui é o DTO, que é o Data Transfer Object, Transfer é transferência, porque é o objeto que representa os dados que são transferidos de sistema pro outro, o dado que está na fronteira do sistema. Então, o álbum controller, ele recebe DTO, ele converte esse DTO nessa classe aqui do domínio e ele vai passar esse objeto da classe do domínio pro álbum Service, então o service não recebe mais DTO, vamos mudar aqui pra ele receber álbum. Então, o service passa a depender dessa álbum e não depende mais aqui do DTO. Fazendo iss, pronto, já temos avanço. O Domínio não depende mais do pacote API, só o pacote API é que depende do pacote Domínio. Mas, tem uma outra questão aqui, porque tem esse campo CreatedAT, geral esses campos adicionais, que é como você recebe alguns campos na fronteira do sistema e a entidade vai ter vários campos a mais, por exemplo, campo estado, pode independer do que é passado, nasce naquele estado pronto. E a criação desses campos, é uma definição muitas vezes do negócio. Então aqui, eu vou representar que esses campos a mais são criadas na camada do domínio, então, eu vou trazer esse álbum record aqui pra dentro, e aí que que vai acontecer. Isso que o álbum service tá recebendo, isso aqui é como se fosse formulário que são os dados pra criação de novo álbum, não com o novo álbum si. Então, eu vou chamar essa classe aqui de ''NewÁlbum'' e esse Álbum Record, ele com esses atributos vai passar a ser de fato o Álbum entidade do sistema, que tem aqui, tudo aqui campos convenientes, tipos convenientes, como o byte array e tem os campos adicionais que são criados. Então, o Álbum Service recebe o New Álbum, cria o álbum e passa esse álbum pro DAO já pronto para ser gravado no banco. Então, o DAO ele vai receber algo do tipo Álbum. E também não tem mais essa dependencia maluca, da Infra lá pro pacote API. Já tá melhorando. Agora tem detalhe aqui, a parte mais difícil que tem pulo do gato, que é essa dependência aqui do domínio pro pacote Infra, o domínio dependendo de detalhe. Como é que o Uncle Bob, o autor do livro instrui a gente pra eliminar essa dependência, na verdade a gente vai inverter essa dependência. Se a gente vê, pelo menos na interface essa classe aqui, ela tá falando aqui a linguagem do negócio, vou inserir novo álbum, vou persistir esse álbum. Então, vou trazer esse aqui para dentro, pra ficar com mais cara de negócio, vez de falar de data, algo que remete a banco, aqui até parece, aqui é a coleção de álbuns, então algum momento o caso de uso de inserir novo álbum vai decidir, vou persistir isso daqui na minha coleção de álbuns e vai chamar o método New Álbum passando o álbum na coleção de álbuns. E isso aqui que está definido aqui é na verdade apenas uma interface definida aqui de acordo com as necessidades do negócio. E aqui no pacote de Infra, aqui sim a gente vai ter uma classe que seria lá o Álbuns DAO que vai conhecer o SQL conhecer uma tecnologia por exemplo, posso até colocar aqui, ÁlbunsMySql vai saber persistir esses dados num banco de dados, mas seguindo essa interface. Então aqui, a gente vai pegar aqui. Isso aqui pra dizer que essa classe implementa essa interface. E é esse cara aqui que entende de SQL. Então, como é que ficou agora aqui a nossa dependência, nossa estrutura. Então, o pacote domínio não depende mais do pacote API. Então, só nessa direção, ao contrário. A API depende do domínio. O domínio não depende mais da 'infra', a gente inverteu. Agora aqui, é a 'infra' que depende do domínio. Claro, tempo de execução, esse 'albumservice' vai chamar esse 'albumsmysql', mas o código fonte... Olha só! O pacote domínio não depende de nada do pacote Infra, ao contrário. Essa classe aqui é que implementa essa interface, então, o pacote infra é que depende do pacote domínio. E não tem mais essa dependência aqui da infra para a API. Então, esse aqui é a nova versão do nosso projeto, do nosso serviço 'S' agora com uma arquitetura limpa para cadastrar álbuns. Então o que muda agora nessa estrutura de pacotes? A primeira coisa mais importante é agora são os detalhes que dependem das políticas da alto nível. Então, você pode mexer na API, mexer na Infra que isso não vai afetar diretamente o domínio. E, por causa disso, agora, é mais tranquilo dizer que o domínio é testável de forma isolada. Dá para testar o domínio sem se preocupar com os detalhes. Uma coisa que vale notar que a gente fez aqui que é a inversão de dependência. Então, o domínio dependia da infra e, com o que a gente fez agora, a infra depende do domínio. A gente também chama isso de 'inversão de dependência', porque, embora tempo de execução, a dependência está no sentido. O domínio vai chamar o 'albumsmysql', isso tempo de execução. Mas, estatisticamente, no código fonte, a dependência é invertida, é o contrário. É o pacote infra que depende do domínio. E essa inversão de dependência... É bonito falar assim alto nível. Mas como é que faz na prática? Então, explicar como isso é feito na prática está fora também do escopo desse vídeo, mas algumas dicas, alguns ponteiros, primeiro, da questão de depender de abstrações. Então aqui a gente tem uma abstração de alto nível que é esse 'álbuns'. Essa interface que representa uma coleção de álbuns, não importa se é banco de dados. A questão do polimorfismo, que é você ter uma interface com implementação que pode variar tempo de execução. E segundo o autor do livro esse polimorfismo é o verdadeiro poder da Orientação ao objeto, porque sem ser polimorfismo, uma linguagem de como ser, a gente teria que usar ponteiros de função que trazem os seus próprios riscos, dificuldades e conveniências. Outra questão é que para fazer com que o service não dependa do 'álbunsmysql', no código, a gente não pode fazer a instanciação, usar o 'new' do 'álbunsmysql' aqui dentro. A gente tem que evitar o new. E para evitar o new, aí vai entrar a técnica da injeção de dependência. Então, nesse contexto todo a 'injeção de dependência' é uma técnica para a gente implementar a inversão de dependência que é o que importa mais. Outro ponto do livro, sobre 'frameworks', ele coloca vários alertas, mas você pode usar o frameworks. Tente apenas não se acoplar demais a ele. Então, exemplo que é mais fácil falar do que fazer, mas os objetos do negócio lá no 'spring boot' não deveriam ter a anotação 'autowired' que é detalhe do framework. Outro exemplo bem recorrente são os sistemas 'ORM´s' que convertem objetos, Java, por exemplo, redes de banco de dados; e vice e versa. Então, tudo menos essa tecnologia, mas ela deveria estar restrita ao pacote infra, não deveria contaminar o pacote do domínio. O problema é que, tipicamente, a gente acaba, os desenvolvedores acabam notando as entidades do negócios com anotações JPA. Então eu vou mostrar aqui código. Então a gente tem aqui os atributos de uma classe Java e tem essas anotações que são anotações do JPA, ou do Hibernate. Algum nível, a gente, normalmente, costuma imaginar que isso não é tanto problema, porque se algum contexto diferente e algum componente for utilizar essa classe álbum, e esse novo componente não sabe nada de Hibernate, tudo bem porque essas anotações serão ignoradas. Então, isso, primeiro momento, não parece tão ruim. Mas eu vou mostrar exemplo aqui que isso acaba sendo problema. Então, eu guardei outro diagrama já pronto que é exemplo real. Amigo me contou. Então, havia sistema e esse sistema tinha componente 'core', que tem as entidades com as regras de negócio, e, também, as classes que faziam a persistência no banco da dados, que é o 'dao'. Mas tinha duas portas de entrada aqui, WS e o sistema online, os dois usando tecnologia JavaEE. E o importante é que a parte tecnológica de entrada estava separada das entidades que tem as regras de negócio. E, assim, tinha o WS, tinha o sistema web, poderia ter mensageiro e até que passou tempo e nasceu, de fato, novo componente para acessar o sistema que é uma nova API, que era uma API rest. E isso aqui, como já tinha passado tempo, vez de usar a tecnologia JAVAEE, foi usada uma tecnologia mais nova, que foi, no caso, o 'Springboot'. E qual era a idéia? A idéia era que esse novo componente fosse utilizar essas classes aqui já existentes. Só que isso aqui não funcionou, isso aqui não deu certo. Por quê? Porque essas entidades que estavam aqui usavam algumas anotações mais avançadas, mais complicadas, do Hibernate. E a versão nova do 'hibernate' que o 'springboot' trazia era incompatível com essas anotações antigas. Então, esse reuso não deu certo justamente por causa do ponto que se coloca, porque foi misturado as entidades do negócio com anotações que são detalhes tecnológicos dos frameworks. Então, essa história ilustrada aqui é sim interessante, uma arquitetura que separa bem essas coisas o que aumenta o reuso do core do seu sistema que contém as saídas de negócios dos casos de uso. Bom, finalizando... Retomando então, a arquitetura de sistema é a arte de estabelecer limites entre os componentes desse sistema. A arquitetura infra é, então, uma proposta para estabelecer limites entre as coisas que importam e coisas que não importam. Para saber mais claro, leiam o livro. É livro tranquilo de ler, é bem fluente, dá para ler relativamente rápido. Mas outro livro muito importante e que tem tudo a ver com a nossa conversa aqui é o livro 'Domain-driven Design'. Esse livro já é mais pesado, mais denso, provavelmente, você vai demorar mais para ler, mas é muito importante. E como, talvez, você vá demorar mais para conseguir terminar a ler, é interessante você ler aqui resumo que eu já escrevi sobre o livro. É resumo curto, então, você pode rapidamente ter uma idéia sobre o livro, dialogar sobre o livro antes mesmo de terminar de lê-lo. Mas vale muito conferir. Então, era essa a conversa. Muito obrigado pela atenção. Valeu pessoal! Tchau!