<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Caio Flavio</title>
    <description>The latest articles on DEV Community by Caio Flavio (@caioflavio).</description>
    <link>https://dev.to/caioflavio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F836842%2Fbdb0c809-baf9-4acb-8e7c-2eef5f425068.jpeg</url>
      <title>DEV Community: Caio Flavio</title>
      <link>https://dev.to/caioflavio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/caioflavio"/>
    <language>en</language>
    <item>
      <title>D do SOLID - Inversão de dependências no Laravel</title>
      <dc:creator>Caio Flavio</dc:creator>
      <pubDate>Tue, 07 Mar 2023 17:33:26 +0000</pubDate>
      <link>https://dev.to/caioflavio/d-do-solid-inversao-de-dependencias-no-laravel-5e4o</link>
      <guid>https://dev.to/caioflavio/d-do-solid-inversao-de-dependencias-no-laravel-5e4o</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2800%2F1%2An-mRpCbekpAIhaeizu7XCA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2800%2F1%2An-mRpCbekpAIhaeizu7XCA.png" alt="capa da publicacao"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  D do SOLID — Inversão de dependências no Laravel
&lt;/h2&gt;

&lt;p&gt;Bom, você deve estar se perguntando por que a &lt;strong&gt;inversão de dependências&lt;/strong&gt; é o &lt;strong&gt;D&lt;/strong&gt; do &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; e não o &lt;strong&gt;I&lt;/strong&gt;. Pra começar, quase tudo em programação é derivado do inglês assim como essa definição que vem de &lt;strong&gt;Inversion Principle&lt;/strong&gt;. Um conceito que foi definido por &lt;a href="https://pt.wikipedia.org/wiki/Robert_Cecil_Martin" rel="noopener noreferrer"&gt;Robert C. Martin&lt;/a&gt; que diz:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A teoria sempre parece complicada, principalmente quando não entendemos todos os termos da definição. O ponto chave aqui é entender o que são módulos de alto e baixo nível, mas, também, o conceito de abstração. Vamos usar duas classes abaixo pra ilustrar esses conceitos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserRepository.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;UserService.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;No caso acima, ambas as classes são de alto nível, pois a &lt;strong&gt;UserService&lt;/strong&gt; depende da classe &lt;strong&gt;UserRepository&lt;/strong&gt; que, por sua vez, depende da classe &lt;strong&gt;Module\Database\DBConnection&lt;/strong&gt; que é a nossa classe de baixo nível. Então, temos definido que:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Classe de alto nível&lt;/strong&gt;: uma classe que possui dependências de outras classes pra ser executada.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Classe de baixo nível&lt;/strong&gt;: uma classe que não possui dependências de outras classes.&lt;/p&gt;

&lt;p&gt;Normalmente, utilizamos as classes de alto nível para descrever a nossa regra de negócio, e as classes de baixo nível para resolver detalhes da infraestrutura, como, por exemplo, a implementação da conexão com o banco de dados e/ou com o servidor de e-mail.&lt;/p&gt;

&lt;p&gt;Nesse caso, estamos usando alguns &lt;a href="https://pt.wikipedia.org/wiki/Padr%C3%A3o_de_projeto_de_software" rel="noopener noreferrer"&gt;&lt;u&gt;padrões de projeto&lt;/u&gt;&lt;/a&gt; como o &lt;a href="https://en.wikipedia.org/wiki/Service_layer_pattern" rel="noopener noreferrer"&gt;&lt;u&gt;Service Pattern&lt;/u&gt;&lt;/a&gt; e o &lt;a href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design" rel="noopener noreferrer"&gt;&lt;u&gt;Repository Pattern&lt;/u&gt;&lt;/a&gt; que nos ajudam a separar as responsabilidades da nossa aplicação, onde a &lt;strong&gt;service&lt;/strong&gt; tem a responsabilidade de encapsular parte da nossa regra de negócio e a &lt;strong&gt;repository&lt;/strong&gt; tem a responsabilidade de persistir os dados de um contexto específico. &lt;/p&gt;

&lt;p&gt;Não iremos entrar em detalhes sobre esses padrões de projeto porque não é o objetivo desse artigo, mas os princípios de &lt;a href="https://pt.wikipedia.org/wiki/SOLID#:~:text=No%C3%A7%C3%B5es&amp;amp;text=%22uma%20classe%20deve%20ter%20apenas,a%20especifica%C3%A7%C3%A3o%20da%20classe" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; são sempre utilizados em conjunto e é quase impossível falar do conceito de inversão de dependência sem utilizar os outros princípios, principalmente o &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle" rel="noopener noreferrer"&gt;princípio da responsabilidade única&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Então, de maneira bem resumida, quando falamos que as classes de alto nível &lt;strong&gt;não devem&lt;/strong&gt; ser dependentes das classes de baixo nível estamos dizendo que a nossa regra de negocio &lt;strong&gt;não deve&lt;/strong&gt; ser dependente de detalhes de infraestrutura.&lt;/p&gt;

&lt;p&gt;Tá, mas e aí? O que são as abstrações? E qual problema há em depender de uma classe de alto nível?&lt;/p&gt;

&lt;p&gt;Abstração é um conceito importante da &lt;a href="https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_orientada_a_objetos" rel="noopener noreferrer"&gt;Programação Orientada a Objetos&lt;/a&gt; e nós costumamos utilizar esse conceito quando pegamos um problema do mundo real, extraímos o seu contexto para nossas classes e descrevemos esse problema através de métodos e atributos que compõe a nossa classe.&lt;br&gt;
Ou seja, nós criamos uma relação direta entre o comportamento do mundo real com a modelagem da nossa classe de modo que essa classe consiga lidar com o máximo de casos possíveis sem depender dos detalhes do problema. Para ilustrar isso, vamos criar a classe que realiza uma conexão com o banco de dados utilizando a extensão &lt;a href="https://www.php.net/manual/pt_BR/intro.pdo.php" rel="noopener noreferrer"&gt;PDO&lt;/a&gt; nativa do PHP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App/Modules/Database/DBConnection.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Bom, nossa classe cumpre o requisito de conectar com o banco de dados, mas aqui temos o primeiro problema, nossa classe depende de muitos detalhes como: tipo de banco, nome de usuário, senha e o &lt;em&gt;host&lt;/em&gt;. &lt;br&gt;
E se o nosso sistema precisa se conectar em dois bancos diferentes? Pra evitar duplicarmos o código podemos &lt;strong&gt;abstrair&lt;/strong&gt; esses dados pra que possamos reaproveitar nossa classe sempre que precisarmos conectar com um banco de dados sem ficarmos dependentes dos detalhes da implementação.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App/Modules/Database/DBConnection.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Pronto, agora nossa classe não depende mais de detalhes de implementação, pois eles foram abstraídos em atributos da nossa classe. Bom, mas e quanto a depender de classes de alto nível?&lt;/p&gt;

&lt;p&gt;O exemplo acima estamos fazendo uma implementação bem básica de conexão com o banco de dados, ainda seria necessário implementarmos muita coisa pra ter um módulo realmente funcional, como a consulta, a inserção, filtros etc.&lt;/p&gt;

&lt;p&gt;No entanto, pra nossa sorte hoje existem muitas bibliotecas mantidas pela comunidade que já fazem a maior parte de abstração das operações com banco de dados. E, por isso, não precisamos ficar reinventando a roda, podemos apenas utilizar uma dessas bibliotecas pra facilitar e abstrair esse trabalho pra gente.&lt;/p&gt;

&lt;p&gt;Quando trabalhamos com o &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel Framework&lt;/a&gt;, normalmente utilizamos uma biblioteca já inclusa chamada &lt;a href="https://laravel.com/docs/9.x/eloquent" rel="noopener noreferrer"&gt;Eloquent&lt;/a&gt; para realizar as operações com banco de dados. O Eloquent é um &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping" rel="noopener noreferrer"&gt;ORM&lt;/a&gt; que r̶e̶s̶o̶l̶v̶e abstrai muitos desses problemas relacionados ao banco de dados pra gente.&lt;/p&gt;

&lt;p&gt;A principal vantagem de utilizar um ORM é que eles criam uma camada que abstrai os detalhes da implementação dos banco de dados, ou seja, ele não é dependente dos detalhes da implementação do banco de dados. Em um mundo perfeito, onde seguimos todas as recomendações e boas práticas do componente de ORM, caso seja necessário mudar de um banco &lt;a href="https://www.mysql.com/" rel="noopener noreferrer"&gt;MYSQL&lt;/a&gt; para um &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PGSQL&lt;/a&gt;, por exemplo, não precisaríamos nos preocupar em reescrever nada, pois os métodos do ORM se encarregariam de transformar as ações que são realizadas em um formato que o novo banco de dados é capaz de entender. Tá vendo aí a importância de não depender de detalhes de implementação? Quando menos dependemos dos detalhes mais abrangente é nosso código.&lt;/p&gt;

&lt;p&gt;Bom, então vamos trocar a nossa implementação de banco de dados simples pelo Eloquent e ver como as coisas ficam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App/Modules/User/Models/User.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Utilizando poucas linhas de código temos uma classe que é responsável por representar a nossa tabela de usuários. Além disso podemos fazer inúmeras ações como &lt;a href="https://laravel.com/docs/9.x/eloquent#inserts" rel="noopener noreferrer"&gt;criar usuários&lt;/a&gt;, &lt;a href="https://laravel.com/docs/9.x/eloquent#updates" rel="noopener noreferrer"&gt;atualizar usuários&lt;/a&gt;, &lt;a href="https://laravel.com/docs/9.x/eloquent#retrieving-models" rel="noopener noreferrer"&gt;consultas simples&lt;/a&gt; e &lt;a href="https://laravel.com/docs/9.x/eloquent#building-queries" rel="noopener noreferrer"&gt;complexas&lt;/a&gt;, mesmo que você não esteja familiarizado, é só seguir a &lt;a href="https://laravel.com/docs/9.x/eloquent" rel="noopener noreferrer"&gt;documentação&lt;/a&gt; que é bem completa e repleta de exemplos.&lt;/p&gt;

&lt;p&gt;Agora, vamos criar a &lt;a href="https://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o_orientada_a_objetos)" rel="noopener noreferrer"&gt;interface&lt;/a&gt; e a &lt;strong&gt;classe&lt;/strong&gt; que será responsável pela persistência de dados, para inversão de dependência precisamos definir o &lt;a href="https://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o_orientada_a_objetos)" rel="noopener noreferrer"&gt;contrato&lt;/a&gt; da nossa classe, que será a abstração da qual vamos depender.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Modules\User\Repositories\UserRepositoryInterface.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Tests\Unit\App\Modules\User\Repositories\UserRepositoryTest.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A &lt;a href="https://pt.wikipedia.org/wiki/Interface_(ci%C3%AAncia_da_computa%C3%A7%C3%A3o)" rel="noopener noreferrer"&gt;interface&lt;/a&gt; é a camada de abstração da qual nós vamos depender, lembra que no início falamos que devemos depender de abstrações e não de implementações? É exatamente isso que estamos fazendo, mas ainda não estamos prontos, se você tentar executar o teste nesse ponto provavelmente vai se deparar com o seguinte erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target [App\Modules\User\Repositories\UserRepositoryInterface] is not instantiable while building [App\Modules\User\Services\UserService]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Por que não podemos instanciar as interfaces diretamente, eles funcionam apenas como um maneira de criar um "&lt;a href="https://pt.wikipedia.org/wiki/Interface_(programa%C3%A7%C3%A3o_orientada_a_objetos)" rel="noopener noreferrer"&gt;contrato&lt;/a&gt;", que diz como a nossa classe vai se comportar, e nesse contrato declaramos os métodos que ela possui e o retorno esperado de cada método. Por isso, agora iremos fazer a implementação desse nosso contrato.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Modules\User\Repositories\UserRepositoryEloquent.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Agora que temos a nossa camada de persistência podemos criar nossa camada de serviço que será responsável pelas regras de negócio da nossa aplicação.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Modules\User\Services\UserService.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Agora que chegamos nesse ponto, ao rodar o teste novamente ainda nos depararemos com o mesmo erro, pois precisamos dizer ao Laravel qual a classe concreta da nossa interface, e ele nos permite fazer esse mapeamento por meio dos &lt;a href="https://laravel.com/docs/9.x/providers" rel="noopener noreferrer"&gt;Service Providers&lt;/a&gt;. Ou seja, ele se encarrega de criar uma referência entre a nossa camada de abstração e a implementação, para isso basta apenas adicionar uma linha no arquivo abaixo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Providers\AppServiceProvider.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Com o código adicionado na linha 18, o Laravel se encarrega de toda vez que instanciamos a nossa interface ele faz a referência entre a abstração e a implementação. Mas qual a vantagem desse trabalho todo?&lt;/p&gt;

&lt;p&gt;Deixar nosso código flexível e bem definido. Vamos supor que as necessidades da sua aplicação tenham evoluído a um ponto que as ferramentas que o Eloquent oferece não são suficientes para resolver algum desafio encontrado, nosso código não é dependente do Eloquent e com poucas linhas de código seriamos capazes de trocar o ORM da nossa aplicação.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Modules\User\Models\UserOtherORM.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;App\Modules\User\Models\UserRepositoryORM.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Com as classes criadas, agora basta apenas alteramos a referências de service provider.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App\Providers\AppServiceProvider.php&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Inclusive, nosso teste não depende da classe concreta, precisaríamos apenas executar os testes unitários, e, uma vez que eles nos digam que está tudo ok, podemos prosseguir com a substituição do ORM sem tanta preocupação em quebrar o nosso sistema.&lt;/p&gt;

&lt;p&gt;Nesse nosso cenário temos apenas uma classe dependendo da nossa lógica de usuários, mas imagine em um sistema complexo onde quase tudo dependeria da classe de usuários, imagine ter que procurar arquivo por arquivo pra fazer essa alteração? Sem ter a certeza que realmente trocou onde deveria trocar? A inversão de dependência facilita muito a manutenção da nossa aplicação!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Você pode estar pensando, mas quais as chances de eu precisar trocar meu ORM ou qualquer outra biblioteca que eu esteja utilizando? Pra ser sincero, em projetos pequenos, são bem baixas. Mas mesmo pra projetos pequenos se seu objetivo é criar um &lt;em&gt;software&lt;/em&gt; de qualidade, de fácil entendimento, escalável e de fácil manutenção, a inversão de dependências junto com as demais letras do SOLID e demais boas práticas de desenvolvimento de software podem ser uma luz no seu caminho. E como você chegou até aqui acredito que seja esse o seu objetivo.&lt;/p&gt;

&lt;p&gt;A inversão de dependência é um conceito muito importante para manter nosso &lt;em&gt;software&lt;/em&gt; escalável e com fácil manutenção, mas como diz o ditado popular, uma andorinha só não faz verão, ele precisa sempre estar acompanhado dos outros princípios da &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se você ficou com alguma dúvida sobre o conceito e/ou implementação da inversão de dependências ou de qualquer outro conceito utilizado nesse artigo, fique à vontade pra comentar aqui!&lt;/p&gt;

</description>
      <category>php</category>
      <category>design</category>
      <category>programming</category>
      <category>laravel</category>
    </item>
    <item>
      <title>CQS Pattern - Quando, como e por quê utilizar?</title>
      <dc:creator>Caio Flavio</dc:creator>
      <pubDate>Fri, 29 Apr 2022 17:29:54 +0000</pubDate>
      <link>https://dev.to/caioflavio/cqs-pattern-quando-como-e-por-que-utilizar-4d2h</link>
      <guid>https://dev.to/caioflavio/cqs-pattern-quando-como-e-por-que-utilizar-4d2h</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Este post tem como objetivo fazer um resumo sobre o que aprendi sobre Command Query Separation (CQS) e compartilhar com outras pessoas que estejam pesquisando sobre esse assunto. &lt;br&gt;
Eu particularmente tenho uma certa dificuldade em definir a responsabilidade de cada uma da minhas classes quando estou levando em consideração o &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle" rel="noopener noreferrer"&gt;Principio da Responsabilidade Única&lt;/a&gt; e o que tem me ajudado a organizar melhor essas responsabilidades é entender como outros programadores mais experientes fazem isso. E durante uma sessão de estudos fui apresentado ao Command Query Segregation (CQS) um pattern que foi introduzido por &lt;a href="https://en.wikipedia.org/wiki/Bertrand_Meyer" rel="noopener noreferrer"&gt;Bertrand Meyer&lt;/a&gt; que tem como princípio que todo método deve executar uma ação ou retornar dados, mas nunca os dois ao mesmo tempo. É importante frisar que como todo &lt;a href="https://en.wikipedia.org/wiki/Design_pattern" rel="noopener noreferrer"&gt;design pattern&lt;/a&gt; ele não é uma bala de prata que vai resolver todos os nossos problemas e por isso iremos discutir um pouco sobre como e quando podemos aplicar esse padrão de desenvolvimento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikm965rbk1b1uojmbdrm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikm965rbk1b1uojmbdrm.gif" alt="Wanted bullet shot film gif"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Definições
&lt;/h2&gt;

&lt;p&gt;O autor definiu que todo método deve executar uma ação ou retornar dados, mas nunca os dois aos mesmo tempo. Nesse momento você pode estar pesando: "mas retornar dados não é uma ação?". Quando falamos em CQS &lt;strong&gt;ações&lt;/strong&gt; ou &lt;strong&gt;Commands&lt;/strong&gt; são operações que possuem &lt;a href="https://en.wikipedia.org/wiki/Side_effect_(computer_science)" rel="noopener noreferrer"&gt;efeitos colaterais&lt;/a&gt;, ou seja, alteram o estado de uma variável, um registro no banco, etc... quando há alguma alteração envolvida estamos estamos executando uma &lt;strong&gt;ação&lt;/strong&gt; ou &lt;strong&gt;Command&lt;/strong&gt;. E quando estamos apenas consultando um dado de onde quer que seja sem causar efeitos colaterais no sistema estamos executando uma &lt;strong&gt;consulta&lt;/strong&gt; ou &lt;strong&gt;Query&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Casos de uso
&lt;/h2&gt;

&lt;p&gt;É sempre bom lembrar que o uso de CQS é uma escolha de arquitetura e não quer dizer que realizar ação e retornar dados na mesma função seja errado. Existem os prós e contras quando utilizamos um determinado padrão e com CQS não é diferente. &lt;br&gt;
Um exemplo clássico e amplamente utilizado pela comunidade PHP que não faz uso do CQS é o &lt;a href="https://laravel.com/docs/9.x/eloquent" rel="noopener noreferrer"&gt;Eloquent ORM&lt;/a&gt;. Como podemos ver abaixo, quando criamos um objeto a classe nos retorna um instância contendo os dados do objeto criado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Domain\Users\UserTypes\BaseUser\Entities\UserEntity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createEloquentUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;UserEntity&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;UserEntity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O retorno dessa função é uma instância de &lt;code&gt;UserEntity&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fk5wb6tsku5wx9r1zlf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fk5wb6tsku5wx9r1zlf.png" alt="Retorno da função createEloquentUser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando pensamos em principio da responsabilidade única, nossa  função &lt;strong&gt;createEloquentUser&lt;/strong&gt; acaba tendo duas responsabilidades: &lt;strong&gt;Criar o usuário&lt;/strong&gt; e &lt;strong&gt;Retornar os dados do usuário&lt;/strong&gt; em projetos pequenos isso acaba não sendo um problema, mas, quando nosso projeto começa a crescer o CQS pode nos oferecer as seguintes vantagens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Performance: A maioria das aplicações executam mais leitura do que escrita então quando separamos as &lt;strong&gt;Queries&lt;/strong&gt; e os &lt;strong&gt;Commands&lt;/strong&gt; temos um ganho de perfomance, pois só executaremos essas ações onde é realmente necessário.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mantenabilidade: Como cada classe e método terão apenas uma a responsabilidade de ler com as &lt;strong&gt;Queries&lt;/strong&gt; ou escrever com os &lt;strong&gt;Commands&lt;/strong&gt; torna o código mais legível pois temos mais clareza do que está sendo executado apenas ao olhar o código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fácil de testar: Como as responsabilidades das classes e métodos estão bem definidos acaba facilitando o processo de criação de testes unitários.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fácil de implementar: É fácil de implementar, pois basta lembrar que se é uma consulta criaremos uma classe &lt;strong&gt;Query&lt;/strong&gt; se é ação que cria ou altera alguma parte do nosso sistema criaremos uma classe de &lt;strong&gt;Command&lt;/strong&gt;. O exemplo abaixo mostra as classes necessárias para um &lt;a href="https://developer.mozilla.org/pt-BR/docs/Glossary/CRUD" rel="noopener noreferrer"&gt;CRUD&lt;/a&gt; de usuários:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementação
&lt;/h2&gt;

&lt;p&gt;A criação, atualização e deleção de usuários são considerados ações, pois, elas causam efeitos colaterais ao alterar o estado de onde estão armazenamos os dados dos nossos usuários. Então, para esses casos devemos criar classes de &lt;strong&gt;Command&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserCreateCommand.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Infrastructure\User\Commands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Infrastructure\Database\DatabaseORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCreateCommand&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$creationParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DatabaseORM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$creationParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UserUpdateCommand.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Infrastructure\User\Commands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Infrastructure\Database\DatabaseORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserUpdateCommand&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$updateParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DatabaseORM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$creationParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UserDeleteCommand.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Infrastructure\User\Commands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Infrastructure\Database\DatabaseORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDeleteCommand&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;DatabaseORM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$creationParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como nossas classes tem responsabilidades únicas e bem definidas então nesse caso optei por utilizar o método mágico &lt;a href="https://www.php.net/manual/pt_BR/language.oop5.magic.php#object.invoke" rel="noopener noreferrer"&gt;__invoke&lt;/a&gt;. Note também que nossas funções sempre retornam &lt;code&gt;void&lt;/code&gt; pois utilizando CQS o &lt;strong&gt;Command&lt;/strong&gt; deve apenas executar uma ação e nada além disso.&lt;/p&gt;

&lt;p&gt;Agora, para retornar os dados que foram armazenados vamos criar nossas classes de &lt;strong&gt;Query&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserFindOneByIdQuery.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Infrastructure\User\Queries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Infrastructure\Database\DatabaseORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFindOneByIdQuery&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;DatabaseORM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UserFindByQuery.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Infrastructure\User\Queries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Infrastructure\Database\DatabaseORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFindByQuery&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$queryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;DatabaseORM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;findBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queryParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas nem tudo são flores, como você pode ver pra executar uma tarefa simples de CRUD de usuários foi preço criar &lt;strong&gt;5 classes&lt;/strong&gt; distintas e em um cenário com mais ações para cada outra ação ou consulta precisaríamos de mais classes, ou seja, apesar de termos um código mais limpo e organizado, temos um aumento na complexidade que nem sempre faz sentido em projetos pequenos. Por isso é importante ter em mente se as vantagens como ganho de perfomance e mantenabilidade a longo prazo realmente farão diferença invés de aplicar somente por estética.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;O Command Query Separation é um padrão de projeto que como qualquer outro tem seus prós e contras, ele nos ajuda a compreender melhor como separar as responsabilidades das nossas ações e consultas. E como os outros padrões deve ser utilizado com sabedoria em casos onde as vantagens compensam as suas desvantagens. Quando mais nos aprofundamos em padrões de projeto e arquitetura de software mais ferramentas teremos pra enfrentar os problemas do dia-a-dia e escolher a melhor ferramenta para cada problema.&lt;/p&gt;

</description>
      <category>php</category>
      <category>beginners</category>
      <category>design</category>
      <category>programming</category>
    </item>
    <item>
      <title>Melhorando a observabilidade: Boas práticas na escrita de LOGS</title>
      <dc:creator>Caio Flavio</dc:creator>
      <pubDate>Fri, 25 Mar 2022 19:17:41 +0000</pubDate>
      <link>https://dev.to/caioflavio/melhorando-a-observabilidade-boas-praticas-na-escrita-de-logs-1f5a</link>
      <guid>https://dev.to/caioflavio/melhorando-a-observabilidade-boas-praticas-na-escrita-de-logs-1f5a</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Esse artigo tem como objetivo dismitificar o uso de logs nas nossa aplicações. E para nos guiarmos nesse processo tentaremos responder algumas perguntas como: &lt;strong&gt;O que são logs? Para que servem? Como escrever logs relevantes?&lt;/strong&gt;. Esse é um tema pode parecer simples mas grande parte dos engenheiros de software apesar de conhecerem não são familiarizados com o conceito, segundo  &lt;a href="[www.linkedin.com](https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying)"&gt;esse artigo&lt;/a&gt; da equipe de engenharia do linkedin e nos iremos mudar isso hoje!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2F8SwMrENO6AEAAAAM%2Fpikachu-togepi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fc.tenor.com%2F8SwMrENO6AEAAAAM%2Fpikachu-togepi.gif" alt="Pokemons rolling on a log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Definição
&lt;/h2&gt;

&lt;p&gt;Uma possível definição técnica que eu particularmente gosto é de que talvez os logs sejam a forma mais simples possível de abstração de armazenamento, eles são sequências de registros ordedenados pela data de criação e possuem duas propriedades, todo arquivo de log deve ser &lt;a href="https://en.wikipedia.org/wiki/Append-only" rel="noopener noreferrer"&gt;&lt;em&gt;append-only&lt;/em&gt;&lt;/a&gt; e &lt;a href="https://mathworld.wolfram.com/TotallyOrderedSet.html" rel="noopener noreferrer"&gt;&lt;em&gt;totally-ordered&lt;/em&gt;&lt;/a&gt;. De modo simples, &lt;em&gt;append-only&lt;/em&gt; significa que o arquivo de log suporta apenas inserção de dados e os dados já existentes devem ser imutáveis e &lt;em&gt;totally-ordered&lt;/em&gt; é uma propriedade que nos grante que existe uma ordem em todos elementos do conjunto (nesse caso nosso arquivo de log) e que pegando quaisquer dois elementos desse conjunto conseguimos dizer qual veio primeiro e qual veio por último.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.dribbble.com%2Fusers%2F6319642%2Fscreenshots%2F14533255%2Fsorting.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.dribbble.com%2Fusers%2F6319642%2Fscreenshots%2F14533255%2Fsorting.gif" alt="Ordenando itens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Principais finalidades
&lt;/h2&gt;

&lt;p&gt;Existem diversos tipos e finalidades de logs como os &lt;a href="https://www.ibm.com/docs/en/db2/11.5?topic=strategies-database-logging" rel="noopener noreferrer"&gt;transaction logs&lt;/a&gt; que são utilizados por diversos bancos de dados para realizar um fallback dos dados em caso de falha de uma transação. Existem também os logs utlizados por &lt;a href="https://www.rapid7.com/blog/post/2018/01/16/taking-a-message-based-approach-to-logging/" rel="noopener noreferrer"&gt;serviços de mensageria para criação de tópicos e mensagens&lt;/a&gt; apesar de ser bom saber que um mesmo conceito pode ser aplicado em situações diferentes nosso objetivo aqui é focar na utilização de logs para monitoramento e auxilio na solução de possíveis problemas na nossa aplicação e esses logs são popularmente conhecidos como &lt;a href="https://www.xplg.com/application-logs-what-how" rel="noopener noreferrer"&gt;application logs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observabilidade
&lt;/h2&gt;

&lt;p&gt;Os logs são comumente utilizados para auxiliar no diágnostico de problemas e no processo de observação do comportamento de uma aplicação, principalmente em sistemas de &lt;a href="https://pt.wikipedia.org/wiki/Aplica%C3%A7%C3%A3o_monol%C3%ADtica" rel="noopener noreferrer"&gt;arquitetura monolitica&lt;/a&gt;. Porém com a popularização da &lt;a href="https://www.redhat.com/pt-br/topics/microservices" rel="noopener noreferrer"&gt;arquitetura de microsserviços&lt;/a&gt; apesar de eles continuarem sendo utilizados para esse fim eles passaram a ser considerados como parte de um conceito mais amplo a &lt;a href="https://aws.amazon.com/pt/products/management-and-governance/use-cases/monitoring-and-observability/" rel="noopener noreferrer"&gt;observabilidade&lt;/a&gt;. Os pilares da observabilidade segundo &lt;a href="https://www.linkedin.com/pulse/import%C3%A2ncia-da-observabilidade-em-aplica%C3%A7%C3%B5es-modernas-felipe-neves/?originalSubdomain=pt" rel="noopener noreferrer"&gt;este artigo&lt;/a&gt; são as métricas, eventos, traces e &lt;strong&gt;logs&lt;/strong&gt;. Neste texto iremos abordar boas práticas na escrita de logs focando no objetivo de melhorar a observabilidade de nossas aplicações e os outros pilares serão abordados em posts futuros.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Freev.co%2Fwp-content%2Fuploads%2F2016%2F07%2Fgifs-contam-uma-historia.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Freev.co%2Fwp-content%2Fuploads%2F2016%2F07%2Fgifs-contam-uma-historia.gif" alt="logs não são coisa do passado"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Como escrever LOGs relavantes?
&lt;/h2&gt;

&lt;p&gt;Tendo em mente o conceito de observabilidade e como os logs funcionam reuni algumas dicas de como escrever logs para que eles nos forneçam informações detalhadas sobre o que acontece na nossa e de fato nos ajudar no processo de monitoramento e correção de problemas no fluxo da nossa aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Padronize a escrita de logs
&lt;/h3&gt;

&lt;p&gt;Os &lt;a href="https://www.php-fig.org/psr/" rel="noopener noreferrer"&gt;PSRs (PHP Stardard Recommendation)&lt;/a&gt; tem uma &lt;a href="https://www.php-fig.org/psr/psr-3/" rel="noopener noreferrer"&gt;seção especifica&lt;/a&gt; para como devemos escrever nossas classes de logs. Mas nem sempre precisamos reinventar a roda, existem diversos pacotes mantidos pela comunidade e amplamente utilizados que podemos utilizar em nossos projetos sem nos precuparmos em implementar essas diretrizes, mas é sempre importante entender o que estamos fazendo.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.1. Pacotes populares para logs em php
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/Seldaek/monolog" rel="noopener noreferrer"&gt;Monolog&lt;/a&gt; - É uma das bibliotecas mais utilizadas no mercado e é utilizada nativamente pelos principais frameworks PHP da atualidade como: Laravel, Symphony, Lumen, CakePHP, Slim, entre outros...&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jbroadway/analog" rel="noopener noreferrer"&gt;Analog&lt;/a&gt; - Apesar de não ser tão popular essa biblioteca tem a premissa de ser otimizada para criação de logs de forma simples, configurável e extensível.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/katzgrau/KLogger" rel="noopener noreferrer"&gt;KLogger&lt;/a&gt; - Essa biblioteca também mantida pela comunidade é utilizada em algumas universades dos EUA e assim como as outras segue as especificações da PSR-3.
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Sempre use os níveis de log
&lt;/h3&gt;

&lt;p&gt;Os &lt;a href="https://www.php-fig.org/psr/psr-3/" rel="noopener noreferrer"&gt;PSRs&lt;/a&gt; especificam oito níveis de mensagens de log que não são arbitrários, eles seguem o protocolo &lt;a href="https://datatracker.ietf.org/doc/html/rfc5424" rel="noopener noreferrer"&gt;RFC-5424&lt;/a&gt; que faz parte de um conjunto de regras definidas para padrozinar o que é implementado na internet. E por esse motivo temos oito níveis de logs, que são eles em ordem de criticidade:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;emergency&lt;/strong&gt;: Deve ser utilizado quando o sistema está completamente não utilizavel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;alert&lt;/strong&gt;: Deve ser utilizado quando uma ação precisa ser tomada imediatamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;critical&lt;/strong&gt;: Deve ser utilizado quando algum componente está indisponível, normalmente quando é uma exceção não esperada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;error&lt;/strong&gt;: Deve ser utilizado para erros de execução que normalmente não precisam de uma ação no momento em que ocorrem mas precisam ser monitorados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;warning&lt;/strong&gt;: Deve ser utilizado para comportamentos anormais no sistema que não necessáriamente sejam erros, como por exemplo, uso de API's desafadas ou mal uso de uma API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;notice&lt;/strong&gt;: Deve ser utilizado para eventos que ocorrem normalmente mas que são siginificantes para o monitoramento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;info&lt;/strong&gt;: Deve ser utilizado para eventos que são interessantes de serem observados no fluxo da aplicação, como por exemplo: "Usuário {id} logou no MYSQL".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;debug&lt;/strong&gt;: Deve ser utilizado para salvar informação detalhada de depuração de erros e/ou um determinado fluxo do sistema.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Escreva mensagens descritivas e contextualizadas
&lt;/h3&gt;

&lt;p&gt;Os logs precisam nos ajudar a entender o fluxo da nossa aplicação então messagens como os exemplos abaixo dificilmente irão nos ajudar nisso:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Algo deu errado"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Banco de dados não esta funcionando"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As mensagens acima não nos dão um caminho de o que e nem onde está acontecendo o problema Um exemplo de mensagem que nos ajuda a entender problemas no fluxo precisa espeficar &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[Atualização Usuário] Não foi foi possível atualizar dados do usuário de id: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[App\Services\ExternalApiService] Protolo número &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$protocolNumber&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; atualizado com sucesso."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[App\Services\ExternalApiService] Não foi possível atualizar o protolo número &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$protocolNumber&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: API Indisponível."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  4. Não logue apenas exceções
&lt;/h3&gt;

&lt;p&gt;Caso haja a necessidade de criar logs para determinadas exceções evite logar somente a stacktrace pois ela normalmente devolve apenas quais linhas de código geraram aquela exceção e díficilmente tem os dados geraram aquele problema, por isso evite fazer como no exemplo abaixo:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'some'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;apiService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\AnErrorException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Caiu em uma excessão."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'exception'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Lembre-se que os logs são uma parte importante da observabilidade e é preciso que ele forneça um contexto que possa ajudar a quem está monitorando a situação a entender aquele determinado fluxo para sanar eventuais problemas.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'some'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;br&gt;
  &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;apiService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\AnErrorException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nc"&gt;LoggerLibrary&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"[Serviço de API XPTO] Falha ao receber dados de cliente da API XPTO. Os seguintes dados foram utilizados."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'exception'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'data'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Isso é realmente necessário?
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h3&gt;


&lt;p&gt;Quando vamos escrever mensagens de log para nossa aplicação precisamos lembrar que estamos descrevendo um fluxo do nosso sistema que precisa ser monitorado. Então antes de sair criando mensagens de log para cada trecho do código precisamos compreender o contexto e se a criação dessas mensagens irá colaborar de maneira positiva para o monitoramento do funcionamento da nossa aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Padronize, mas tenha em mente que as coisas podem mudar
&lt;/h3&gt;

&lt;p&gt;Sabemos que os logs podem ser feitos para serem lidos por humanos e por máquinas e além disso conforme a nossa aplicação evolui novas necessidades surgem e utilizar &lt;a href="https://en.wikipedia.org/wiki/Plain_text" rel="noopener noreferrer"&gt;textos planos&lt;/a&gt; pode deixar de ser uma boa opção. Por isso é importante a outras maneiras de realizar o parsing de nossos logs como por exemplo em JSON. A biblioteca &lt;a href="https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/JsonFormatter.php" rel="noopener noreferrer"&gt;Monolog&lt;/a&gt; possui um parser pronto pra você salvar seus logs em JSON e neste &lt;a href="https://www.loggly.com/use-cases/json-logging-best-practices/" rel="noopener noreferrer"&gt;link&lt;/a&gt; você encontra algumas dicas de como criar bons logs em JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Os logs são um dos pilares da observabilidade e quanto mais entendemos da nossa aplicação mais fácil se torna escrever fluxos que nos ajudem a entender a saúde de nossos serviços. Essas dicas são um caminho para a escrita de logs que podem contribuir para melhorar a observabilidade dos nossos sistemas. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>php</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
