Olá, sejam bem-vindos ao canal Engenharia de Software com ênfase UML. Eu sou professor Gilianes Getes e eu já atuo na área de moderagem de software há vários anos. Eu tenho quatro livros publicados sobre o assunto e eu já ministrei diversas palestras e cursos técnicos sobre modagem de software utilizando a linguagem UMR.
Na aula de hoje, eu vou dar continuidade ao tema de padrões arquiteturais, ou seja, arquiteturas de software. Dessa vez enfocando o padrão arquitetural de arquitetura limpa. Ah, lembrando que uma arquitetura ela basicamente estabelece a estrutura do software, como ele está organizado.
Mas vamos dar início à nossa aula. Então, como falei, hoje nós vamos iniciar a falar sobre a o padrão arquitetural de arquitetura limpa ou clean architecture. Então, esse é um padrão que estrutura o código do sistema, o código do software em diversos círculos concêntricos.
por padrão são quatro, em que o círculo mais interno ele contém as regras do negócio mais essenciais para o software. Ã, ele contém as classes de entidade que vão conter a lógica do negócio, enquanto que os círculos mais exteriores, eles contêm detalhes de implementação, então eles vão conter frameworks, eh, bancos de dados, esse tipo de coisa. Ah, o princípio central dessa arquitetura é a regra de dependência, em que ela estabelece que as dependências devem vir de fora para dentro.
Ou seja, os círculos externos eles possuem dependência com os círculos internos, mas nunca o contrário. Vamos continuar. Então, e a arquitetura limpa, ela contém, ela segue um conjunto de boas práticas de projeto de software com objetivo de separar os aspectos da aplicação em diversos círculos que estão bem estabelecidos, claramente definidos e estão organizados em níveis de responsabilidade.
Isso segue o objetivo de tornar o código fácil de manter, testar e evoluir e também de produzir uma arquitetura de software organizada, independente de frameworks e outras tecnologias, simples e fácil de compreender. Um dos elementos principais da arquitetura limpa é a regra da dependência. Isso significa que eh os círculos eles possuem áreas de responsabilidade diferentes e quanto mais interno o círculo, maior é o nível de abstração de de informação que esse código, desculpe, que esse círculo contém.
e mais estáveis são as suas regras, em essência são as regras do negócio. Os circos mais externos, eles representam basicamente tecnologias que são utilizadas para a implementação do sistema, como frameworks, drivers e outros mecanismos, sistemas gerenciadores de banco de dados, a interface com o usuário final, esse tipo de coisa. enquanto que os círculos mais internos, eles contêm, como eu falei, as regras de negócio e políticas de mais alto nível.
Ah, bom, então a regra de negócio é a regra primordial que garante o funcionamento desse padrão arquitetural. Ela ela exige que as dependências do código fonte sempre apontem em direção ao centro, das camadas mais externas, aliás, dos círculos mais externos para os círculos mais internos. Então, sempre na direção das políticas mais fundamentais da aplicação.
Eh, então as camadas externas têm dependência com as camadas internas, mas não o contrário. Ah, os elementos de um círculo interno, eles não devem ter conhecimento sobre quaisquer elementos de um círculo externo, principalmente com relação a nomes que foram declarados em um círculo externo. Eles não devem ser utilizados, não devem ser mencionados no ciclo, no, aliás, no código contido em um círculo, em um círculo interno.
Então isso inclui, entre outras, funções, classes, variáveis e qualquer outras entidades que tenham sido definidos nos círculos externos. Aqui nós temos uma figura que foi tirada, adaptada de do marketing, ã, em que representa as quatro os quatro círculos dessa desse padrão arquitetural, tá? Eventualmente podem haver mais círculos, mas estes são os círculos essenciais, os círculos básicos desse padrão arquitetural.
Então, o círculo mais interno contém as entidades, essencialmente as classes entidades, classes relacionadas diretamente ao domínio do problema, que contém as regras de negócio, a lógica de negócio do sistema. Depois nós temos os casos de uso que contém as regras de negócio da aplicação. Essencialmente representam as funcionalidades principais do software.
Depois nós temos os adaptadores de interface que servem de comunicação entre o círculo externo e os casos de uso. Então aqui nós temos classe de controle, classes de visão, gateways, que são softwares que servem de intermediários entre os casos de uso e a interface com o usuário e fazem conversões. Ei na camada mais externa, nós temos os frameworks e drivers, onde nós vamos ter, como o nome já diz, frameworks, drivers, mas não sentido tradicional de comunicação entre sistema operacional e hardware, mas drivers que eh ajudam a a comunicação entre a camada, o círculo mais externo e os círculos de o círculo de de adaptadores de interface.
Ah, então aqui nós vamos ter também dispositivos e qualquer outro software, qualquer outro framework, qualquer ã qualquer mecanismo que seja necessário para o funcionamento do software e é a camada em que ela é mais fácil de substituir. qualquer uma dessas tecnologias pode no futuro ser ah relativa com relativa facilidade substituída ah desde que a forma de comunicação com os círculos internos seja mantida. Bom, então, seguindo essa mesma lógica, os formatos de dados que são declarados em um círculo externo, eles não podem ser utilizados em um círculo interno, principalmente se esses formatos, se eles foram gerados por um framework em um círculo externo.
Não é desejável que um elemento de um círculo externo tenha qualquer impacto sobre os círculos internos para garantir a independência dos círculos internos e facilitar a mudança de tecnologia. Então isso evita o acoplamento com tecnologias externas e garante que os círculos eh internos da aplicação eles permaneçam independentes, testáveis e duradouros. que não seja necessário tanta manutenção quando houver troca de tecnologia.
Ah, vamos falar um pouquinho de cada um desses círculos. Vamos começar com círculos de com círculo de entidades, que é o círculo mais interno de todos, como já falado, contém as regras de negócio da empresa, a a lógica do negócio. Então, as entidades elas contêm as regras de negócio essenciais e que são independentes da aplicação.
Ah, elas podem, se se utilizar uma linguagem orientada a objetos, serem implementadas como classes com métodos. esses métodos coterão a lógica do negócio. Ou se for utilizado ah uma linguagem funcional, eles podem ser representados como estrutura de dados com funções.
O círculo de caso e uso, ele contém as regras de negócio específicas da aplicação. Então eles implementam fluxo de interação entre os atores e o sistema. Os atores são usuários do sistema, os as pessoas que interagem com o software.
E essencialmente o o círculo de casos de uso, ele contém uma série de classes ã chamadas casos de uso que representam os casos de uso do sistema, ou seja, as funcionalidades que o sistema deve suportar. E eh essas classes elas eh solicitam quando necessário que a objetos das classes entidade executem métodos contendo regras de negócio da empresa. Nós vamos detalhar isso aí.
Ah, então nos casos de uso, eles coordenam o envio e recebimento de dados entre os elementos externos e as entidades. Eles aplicam as regras de negócios fundamentais por meio das entidades, ou seja, solicitam que objetos das classes entidades executem determinados métodos que contém a lógica do negócio da empresa ou do software. e eles executam e essa eles aplicam essas regras de negócio para atingir os objetivos específicos da aplicação.
Basicamente, como já falei, um caso de uso ele é um processo de negócio que durante esse processo pode e muitas vezes solicita a execução de um ou mais um ou mais métodos por parte das entidades e esses métodos representam a lógica do negócio. Então, por exemplo, eu tenho um posso ter um caso de uso, uma classe de caso de uso que represente o processo de abertura de conta pro sistema bancário, que eu já utilizei em vários exemplos eh nesse canal. Então, como pode se lembrar, ã, nesse sistema bancário, eu estabeleci uma regra de negócio que para abrir uma conta comum, eh, é necessário depositar algum valor.
Então, basicamente eh a classe de caso de uso, ela vai conter eh a lógica da aplicação. Então, primeiramente vai se consultar o cliente ou se cadastrar o cliente, caso ele não exista, ou precise modificar o seu cadastro. Hã, depois vai se abrir a conta propriamente dita e aí vai se realizar um depósito.
Então a classe cas de uso, ela vai conter um método que vai ao longo desse método solicitar a execução de métodos mais básicos contidos nas classes de entidade, como a consulta de um cliente, a abertura de uma conta e a realização de um depósito. Ah, as mudanças no círculo de caso de uso não podem afetar as entidades. Os círculos têm um certo grau de independência.
Ah, e da mesma forma o círculo de caso de uso, ele não pode ser afetado por quaisquer mudanças que ocorram na nos círculos externos. Então, a mudança na base de dados, no banco de dados, no sistema a gerenciador de banco de dados, na interface com usuário, ah, qualquer outro framework ou biblioteca que for alterado, ã, não pode afetar o círculo de caso de uso. Então, o círculo de cas de uso, ele precisa estar isolado dessas preocupações externas.
Então, dessa forma, se percebe que isso facilita bastante a manutenção e a evolução do software, permitindo que haja mudanças nos círculos externos sem afetar os círculos internos. E o círculo de adaptadores de interface, ele contém classes controladoras, classe de visão e gateways, que são intermediadores entre a classe mais externa e a e a entre, desculpem, entre o círculo mais externo e o círculo de caso de uso, as conversões de formatos, entre outras funções. Então, o círculo de adaptadores de interface, ele é composto por elementos responsáveis que devem converter os dados entre o formato que é compreendido pelos agentes externos, frameworks, drivers, dispositivos, interface com usuário, banco de dados, etc.
H, e o formato que interno que é compreendido pelas entidades e pelos casos de uso. Então, eh, o círculo de adaptadores de interface, ele atua como um intermediário entre os círculos internos e os mecanismos externos. Ah, esse círculo, ele pode eventualmente implementar padrões como MVC, principalmente quando trabalha com interfaces gráficas.
E como eu falei, nesse círculo se encontra elementos como apresentadores ou eh classe de visão, controladores ou casos classes controladoras, classes responsáveis por interpretar o que ocorre na visão, gateways e repositórios. Como eu falei, gatway são eh uma espécie de conversor eh uma espécie de intermediador entre a camada mais externa, entre, aliás, entre o círculo mais externo e o círculo de caso de uso. E repositórios são, como o nome já diz, repositórios lógicos que armazenam eh coleções de objetos eh que serão utilizados pelo software.
Ah, então, ah, no círculo de adaptadores de interface, os dados eles são convertidos do formato que é utilizado pelos casos de uso e pelas entidades para o formato que é exigido pelos mecanismos externos, tais como frameworks de persistência ou serviços web e vice-versa. Ah, com relação à persistência, lembrando que persistência é o ato de preservar objetos em disco, gravar objetos em disco. O código dos círculos internos, eles não conhecem os detalhes sobre a base de dados, sobre o sistema gerenciador de banco de dados que está sendo utilizado, esse tipo de coisa.
Então, se a aplicação, por exemplo, utilizar a a linguagem Scell, todo o código SQL precisa estar restrito no círculo de adaptadores de adaptadores de interface, principalmente nos componentes que irão implementar o acesso à base de dados, como aqueles que eh implementam repositórios ou gateways. Ah, essa esse círculo ele também é responsável por entregar, integrar serviços externos como APIs, ou seja, application program interfaces de outros softwares e realiza as conversões de dados que são recebidos para o formato interno que é utilizado pelos casos de uso e pelas entidades. E depois nós temos o círculo de frameworks e drivers, que é o círculo mais externo desse padrão arquitetural.
Eh, então ele contém elementos que são externos da lógica do negócio, que não devem afetar a lógica do negócio, como frameworks web, sistema gerenciadores de banco de dados, biblioteca de interface com usuário, user interface, serviços de mensageria, drivers de hardware. Aí são os drivers propriamente ditos, dispositivos físicos e serviços de terceiros. Ah, então esse círculo ele não faz parte da lógica central do sistema.
Na verdade, existe muito pouca programação nesse círculo. Eh, o objetivo, ele está focado na na infraestrutura necessária ao software e ele permite então que o software interaja com o mundo exterior. Como eu falei, esse nesse círculo há muito pouca programação.
E essa programação, ela basicamente se resume ao código necessário para que haja comunicação entre este círculo e o círculo ah de adaptadores, ou seja, o círculo interno. Seguinte. Ah, então no contexto desse círculo, frameworks, eles são ferramentas externas que podem ser reutilizadas, que podem ser adaptadas, que podem ser configuradas e customizadas, que fornecem com estruturas prontas e componentes genéricos que podem ser especializados.
H, então, e esses frameworks eles, eh, auxiliam o desenvolvimento software e principalmente quando se trata de aspectos que são estão fora da lógica de negócio do sistema. H, então os frameworks eles são infraestruturas de apoio que, entre outras funções controlam parte do fluxo de execução do sistema. E por esse motivo, eh, como já fornecem muitas funcionalidades prontas, eles facilitam eh o desenvolvimento dessas funcionalidades.
Essas funcionalidades, elas vêm prontas ou parcialmente prontas. Eh, são funcionalidades como interfaces web ou AP REST, persistência de dados, ou seja, gravação de objetos em disco, gravação e recuperação, ah, comunicação entre serviços, proteção, garantir que não haja invasão indevida, autenticação, entre outros. Ah, no padrão arquitetural, então os frameworks eles precisam, neste padrão arquitetural, os frameworks eles precisam estar fora da lógica de negócio.
Então eles são tratados como detalhes externos, eles devem ser possíveis de serem facilmente substituíveis e o sistema não pode ter uma dependência forte desses frameworks, uma vez que eles podem eles é é uma é uma regra que eles possam ser substituídos de forma fácil. Ahã. E neste padrão arquitetural, a lógica de negócio é que controla o fluxo, não o contrário.
Os frameworks não influenciam no fluxo do sistema. Alguns exemplos de frameworks, nós temos frameworks web, por exemplo, jungleprint ou ASP. net.
Esse tipo de framework, eles controlam rotas, http, requisições, sessões, etc. Nós temos frameworks ORM do tipo como por exemplo o Hbernate, o Torque, o entity framework, que eles fazem o mapeamento objeto relacional, são responsáveis por parte da persistência dos objetos. Nós nós temos frameworks de user interface como Angular, o React e o View, que como já foi falado, né, como já se percebe, auxiliam na construção de interfaces gráficas.
Ah, nós temos frameworks de mensageria como Rabbit, Rabbit, MQ, Client Libs, o Cafka Streams, que são responsáveis por estabelecer o processamento assíncrono e eventos. Nós temos frameworks e testes como J Unit, o P test e o MOSA, que permitem produzir testes automatizados. Ah, e com relação aos drivers, eles são componentes externos.
que são responsáveis por iniciar interações com o sistema não são exatamente os drivers eh relacionados a hardware que serve de comunicação entre o sistema operacional e esse hardware, embora também possam ser. Então, os drives eles funcionam como pontos de entrada, eles recebem eventos ou requisições do mundo externo e solicitam a execução de caso de uso da do software em questão. Ah, e eles são chamados de drivers, não são exatamente os drivers tradicional, podem incluir também, mas em geral não são.
Eles são chamados de drivers porque eles dirigem o fluxo de controle para dentro do sistema. Então, driver quer dizer motorista, né? Então ele invoca, eles invocam a lógica de negócio sem realmente fazer parte dela.
Então, exemplo de drivers, nós temos controladores web que recebem requisições HTTP e encaminham pros casos de uso, interfaces gráficas que capturam ações do usuário e acionam operações internas, consumidores de mensagem que recebem mensagens e executam processos internos. Agendadores tarefas que executam rotinas em horários programados. H bom, a arquitetura limpa, ela recomenda quatro círculos.
No entanto, é possível que possam ser necessários mais círculos, dependendo da aplicação, mas mesmo assim a regra da dependência ela deve se manter. Ou seja, as dependências de código fonte sempre irão aprontar para dentro. Sempre a dependência é dos círculos mais externos em relação aos círculos mais internos.
Ah, então o círculo mais externo, ele consiste em detalhes concretos de baixo nível. Quanto mais interno o círculo, maior nível de abstração e maior nível de políticas. Ah, então o círculo mais interno é o mais geral e de nível mais alto.
E esse padrão arquitetural, ele é relativamente simples e implementar. Eh, no momento que se divide os o software em diversos círculos lógicos e se obedeça à regra de dependência, então se cria um sistema facilmente testável, com todos os benefícios eh dessa eh capacidade de teste. E quando uma das partes externas do sistema se tornar por algum motivo obsoleto, obsoleta, precisar ser substituída, ah, como por exemplo a base de dados, o framework, por exemplo, então pode substituir o elemento que precisa ser trocado com um esforço relativamente pequeno.
Aqui nós temos um exemplo de aplicação do padrão de arquitetura limpa que foi representado por meio de um diagrama de pacotes UML. Então cada um dos pacotes representa um dos círculos dessa arquitetura. Então, o círculo mais externo é o círculo de frameworks e drivers.
Claro que ele poderá conter diversas outras classes, mas aqui por uma questão de espaço, eu tô representando somente as classes de interface do usuário. Então aqui, eh, eu representei as classes de formulário eh necessárias para que o usuário interage com o sistema. Então, tem um formulário para abertura de conta, um formulário para emitir extrato, um formulário para emitir saldo e assim vai.
Depois nós temos o círculo de adaptadores de interface, onde eu coloquei classes controladoras e classe de visão. A classe de visão são classes que h interagem com a interface externa e comunicam os eventos que ocorrem às controladoras e dependendo desses eventos, as controladoras irão solicitar a execução de um caso de uso ou solicitar que a visão apresente determinados eh dados na interface. H, depois nós temos o círculo de casos de uso.
Nesse caso se trata do sistema bancário que eu tenho utilizado como exemplo. Ah, então aqui eu tenho uma classe de caso de uso para cada funcionalidade principal do sistema. Então, eu tenho uma uma classe para abrir uma conta comum, outra para abrir uma conta especial, outra para abrir uma conta poupança, outra para emitir extrato, emitir saldo, outra para encerrar conta e assim vai.
Ah, notem também que eu tenho uma controladora para cada uma dessas funcionalidades e uma visão para cada uma das funcionalidades. Poderiam, obviamente, haver mais visões. E, finalmente, eu não tenho o círculo de entidades, onde eu vou ter as minhas classes de entidades que conterão a lógica do negócio.
Então aqui eu tenho as minhas classes conta comum, conta especial, conta poupança, movimento, pessoa, pessoa física e pessoa jurídica. E são as classes dos exemplos que eu tenho utilizado do sistema bancário em outras áreas. H em outras aulas.
Então, eh basicamente nessa arquitetura, ah, o usuário, por meio de um uma determinada interface, um determinado formulário, faz solicitações ao sistema. Essa solicitação é repassada, recebida por uma classe de visão. Essa classe de visão, se for necessário, repassa por uma classe de controle, para um objeto de uma classe de controle, que irá então solicitar, se achar que é necessário, que eh um objeto de um determinado caso de uso seja executado.
esse ah objeto de caso de uso irá a ao longo da execução do do seu método, se for necessário, solicitar a execução de métodos de objetos de classe entidade que conterão a lógica do negócio. Então, por exemplo, o um objeto da da classe abrir conta comum, quando for executar o seu método, ele irá solicitar que um objeto da entidade conta comum ah execute métodos como eh consultar conta, ah, abrir conta, ah, e realizar depósito, por exemplo. Ah, os resultados serão retornados para a classe abrir conta comum.
A classe abrir conta comum irá retornar os resultados por controladora. a controladora eh poderá solicitar que uma classe de visão, que um objeto de uma classe de visão apresente os resultados e esse objeto classe de visão irá solicitar que o formulário relativo ao processo apresente os dados para eh o usuário que fez a solicitação. Aqui nós temos um exemplo de classes de casos de uso.
Então aqui eu tenho uma classe de casa de uso para cada funcionalidade do sistema. Notem que eu tenho uma classe para cada funcionalidade, né? Eu tenho uma classe abrir conta comum, uma classe abrir conta especial, outra abrir conta poupança, outra classe realizar depósito, outra classe realizar saque, outra classe emitir exrato, outra classe emitir saldo, outra classe encerrar conta e assim vai.
Cada uma delas relacionada a um dos casos de uso do sistema, alguma a uma das funcionalidades principais do sistema. Essas classes elas não possuem atributos e cada uma delas possuem um método que normalmente tem o mesmo nome, tá? que no caso pode ser o método executar ou execute ou handle, depende.
Ah, basicamente esse método ele contém o passo a passo para a execução do processo representado pelo caso de uso. E dentro desse método, normalmente se fazem chamadas a métodos de classes de entidade. Ah, quais são as vantagens do padrão de arquitetura limpa?
manutenibilidade. Uma vez que os círculos eles são claramente separados, isso torna a manutenção mais fácil, uma vez que o código é mais fácil de entender. Testabilidade, já que os círculos eles são separados, então, eh, é possível que cada um seja testado de forma independente, então os testes são mais eficientes e precisos.
flexibilidade, numa vez que é uma arquitetura modular, isso permite que novas funcionalidades sejam adicionadas ou modificadas com facilidade. Normalmente eu tenho que fazer pouco pouco esforço para adicionar novas funcionalidades, relativamente pouco esforço, pouco esforço e normalmente sem afetar o resto da aplicação. escalabilidade que permite que a aplicação ela cresça em termos de ah poder suportar mais recursos, mais usuários, por exemplo.
Ah, esse tipo de arquitetura, ela permite identificar e corrigir pontos de gargalo com mais facilidade. Ah, mas também a desvantagens. Em um primeiro momento, embora seja uma arquitetura relativamente fácil de implementar, pode haver uma complexidade inicial, ã, porque eh esse tipo de padrão arquitetural pode ser mais complexo, mais difícil de implementar do que abordagem mais simples.
o custo de tempo pode ser maior para que principalmente quando a equipe ela é inexperiente nessa arquitetura para que ela compreenda e implemente as boas práticas desse padrão. Tem outro problema que é dificuldade de mudança. Então, se a se a aplicação já estiver em desenvolvimento, se é muito difícil mudar o padrão de arquitetura limpa, sem haver um grande impacto no projeto e no código do sistema, mas na verdade isso é um uma desvantagem comum a qualquer arquitetura.
Sempre que se quer trocar arquitetura do sistema, ah, isso pode ser muito difícil, muito complexo e pode acarretar grandes prejuízos no projeto, grandes atrasos. Ah, quando é mais adequado utilizar arquitetura limpa? Quando domínio de negócio é complexo, quando existe uma separação clara entre a lógica de negócio e a infraestrutura.
Isso permite que haja uma maior controle sobre as regras essenciais do sistema. Quando o projeto de longo prazo, então esse tipo de arquitetura, ela facilita a manutenção, a testabilidade, a evolução do software. Ã, ela permite que mudanças na interface com o usuário, mudanças no banco de dados, mudanças no SGBD, mudanças em qualquer outro tipo de framework não afetem a lógica do negócio, porque os círculos eles são independentes.
Ah, e a e os círculos externos não deve afetar os círcul os círculos internos. também quando se deseja que equipes diferentes possam desenvolver eh parte distinta do sistema. Então, eh, dessa forma é possível alocar, eh, círculos diferentes para equipes diferentes.
Então, posso, isso me permite um desenvolvimento paralelo, onde cada equipe será responsável por um círculo específico. Ah, quando há equipes multidisciplinares, ah, separar as responsabilidades auxilia na organização das equipes com que possuam perfis variados, perfis diferentes. Então, ã, cada membro da equipe pode ser responsável pelo frontend, outro pelo backend, outro pela infraestrutura e assim vai.
Ah, quando se deseja uma arquitetura que seja independente de tecnologia e que seja fácil de testar e reutilizar, quando não é adequado utilizar arquitetura limpa? Quando se trata de um projeto simples, na verdade eu defendo que não existem projetos simples, porque o projeto ele pode começar simples, mas geral eles crescem. Mas em se tratando de projeto simples, o esforço de criar círculos e separações, conforme exigido pela arquitetura limpa, pode não ser compensatório quando existem recursos ou prazos limitados.
Então, pode não ser adequado utilizar arquitetura limpa, porque esse padrão ele exige um tempo maior, eh, e uma estrutura inicial que consome mais tempo. Eh, essa arquitetura, ela pode parecer um pouco burocrática para equipes pequenas ou para desenvolvedores individuais. Podem não achar ela adequada, BR demais.
Ah, quando se exige um autodesempenho? Porque uma vez que nós temos quatro círculos e há esse grau de comunicação entre os círculos, isso pode introduzir uma certa latência e pode afetar o desempenho. Ah, também situações em que a equipe ela possui pouco conhecimento sobre arquitetura.
Então, se a arquitetura ela for mal implementada, isso pode produzir eh um código confuso e muito acoplado. Então, é preciso que a equipe tenha algum treinamento e alguma cultura de boas práticas para que possa implementar esse padrão arquitetural de maneira adequada. E nós concluímos mais essa aula sobre padrões arquiteturais.
Eu espero que vocês tenham considerado essa aula válida. Espero que vocês tenham gostado desse conteúdo. Se vocês gostaram desse conteúdo, eu peço que compartilhem esse vídeo com que possa interessar.
Curtam esse vídeo e se você ainda não estão inscritos, que se inscrevam no canal. Eu agradeço a atenção de todos. Nós nos vemos na próxima aula.
Obrigado pela atenção.