<?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: Mattheus Cassundé</title>
    <description>The latest articles on DEV Community by Mattheus Cassundé (@cassunde).</description>
    <link>https://dev.to/cassunde</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%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png</url>
      <title>DEV Community: Mattheus Cassundé</title>
      <link>https://dev.to/cassunde</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cassunde"/>
    <language>en</language>
    <item>
      <title>Como automatizar resumos de notícias com IA: Um guia prático usando Jina e Gemini</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sun, 17 Aug 2025 18:55:49 +0000</pubDate>
      <link>https://dev.to/cassunde/getcontent-enviando-resumo-de-noticias-por-e-mail-1mic</link>
      <guid>https://dev.to/cassunde/getcontent-enviando-resumo-de-noticias-por-e-mail-1mic</guid>
      <description>&lt;p&gt;Fala pessoal, tudo certo? Hoje vamos falar sobre como podemos usar a IA para nos ajudar no dia a dia, esse projeto chamado de &lt;a href="https://github.com/cassunde/getContent" rel="noopener noreferrer"&gt;getContent&lt;/a&gt; é um projeto que visa capturar informações de alguns portais de notícia, resumir e mandar direto para seu e-mail&lt;/p&gt;

&lt;h2&gt;
  
  
  O Problema
&lt;/h2&gt;

&lt;p&gt;Mantermo-nos informados sobre as principais notícias do Brasil e do Mundo sem gastar muito tempo é um desafio constante, entrar nos portais tradicionais, é ser soterrado por propagandas ou incentivos, pensando em melhorar a experiência de ler notícias esse projeto vem para resumir as principais notícias e envia-os por email.&lt;/p&gt;

&lt;h2&gt;
  
  
  O GetContent
&lt;/h2&gt;

&lt;p&gt;GetContent é um projeto feito em Python que usa duas IA para fazer a parte trabalhosa, usa a IA Jina para capturar o conteúdo e o gemini para fazer os resumos. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxc5qd3hy8seqbtvwps82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxc5qd3hy8seqbtvwps82.png" alt=" " width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos executar esse projeto de algumas forma, via Docker ou diretamente no seu terminal, vamos ver como executar as duas formas, primeiro vamos executar diretamente no terminal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fazer clone do projeto
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:cassunde/getContent.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Instalar as dependências.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Agora precisamos criar um arquivo .env com as nossas credencias
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOGLE_API_KEY=...
JINA_API_KEY=...
SENDER_EMAIL=...
SENDER_PASSWORD=...
RECIPIENT_EMAIL=...
SMTP_SERVER=...
SMTP_PORT=587
TYPE_GETCONTENT=daily
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para obter as chaves necessárias, siga estes passos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Chave Gemini:&lt;/strong&gt; Acesse o seguinte link para gerar sua chave: &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;https://aistudio.google.com/app/apikey&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Chave Jina:&lt;/strong&gt; Cadastre-se na plataforma Jina através deste link: &lt;a href="https://jina.ai/api-dashboard/" rel="noopener noreferrer"&gt;https://jina.ai/api-dashboard/&lt;/a&gt; Após o cadastro, você receberá uma chave gratuita.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Além disso, você precisará de um endereço de e-mail para ser utilizado como remetente. Se você utiliza o Gmail como seu e-mail principal, considere criar uma conta no Outlook. Para configurar o Outlook como remetente, você pode encontrar as informações de SMTP necessárias neste guia: &lt;a href="https://support.microsoft.com/pt-br/office/configura%C3%A7%C3%B5es-pop-imap-e-smtp-para-outlook-com-d088b986-291d-42b8-9564-9c414e2aa040" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executando o GetContent via Terminal
&lt;/h2&gt;

&lt;p&gt;Após clonar o repositório. instalar as dependências e criar o arquivo &lt;code&gt;.env&lt;/code&gt; na raiz do projeto com suas credenciais. Execute o script principal do GetContent via terminal usando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 news.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso iniciará o processo de coleta de notícias, resumo usando as APIs Jina e Gemini, e envio do resumo por e-mail para o destinatário especificado.  Observe que o sucesso da execução depende da configuração correta do arquivo &lt;code&gt;.env&lt;/code&gt; e da disponibilidade das APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executando a aplicação &lt;code&gt;getcontent&lt;/code&gt; com Docker
&lt;/h2&gt;

&lt;p&gt;Este sessão explica como executar a aplicação &lt;code&gt;getcontent&lt;/code&gt;, disponível no Docker Hub em &lt;code&gt;cassunde/getcontent&lt;/code&gt;, utilizando o comando &lt;code&gt;docker run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pré-requisitos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker instalado e configurado em seu sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Execução:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm --name getcontent -e TYPE_GETCONTENT=daily --env-file ./.env getcontent:0.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;com as seguintes opções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--rm&lt;/code&gt;: Remove o contêiner após a sua execução.  Isso limpa o ambiente após o término da aplicação, evitando a acumulação de contêineres desnecessários.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--name getcontent&lt;/code&gt;: Atribui o nome &lt;code&gt;getcontent&lt;/code&gt; ao contêiner.  Isso facilita a identificação e a gestão do contêiner em execução.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-e TYPE_GETCONTENT=daily&lt;/code&gt;: Define a variável de ambiente &lt;code&gt;TYPE_GETCONTENT&lt;/code&gt; com o valor &lt;code&gt;daily&lt;/code&gt;.  Esta variável dis quais urls serão capturadas, resumidas e enviadas por e-mail&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--env-file ./.env&lt;/code&gt;: Lê as variáveis de ambiente a partir do arquivo &lt;code&gt;.env&lt;/code&gt; localizado no diretório atual.  Este arquivo contém todas as credencias para executar a integrações com as IAs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;getcontent:0.0.2&lt;/code&gt;: Especifica a imagem Docker a ser executada.  A tag &lt;code&gt;0.0.2&lt;/code&gt; indica a versão da imagem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verificando a execução:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Após executar o comando, verifique se a aplicação funcionou corretamente.  Você precisa observar os logs que serão exibidos logo no final&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Buscando conteúdo de: https://techcrunch.com/
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
Buscando conteúdo de: https://www.bbc.com/portuguese/topics/cz74k717pw5t
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
Buscando conteúdo de: https://cearaagora.com.br/ultimas/
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agendamento Automático com Crontab
&lt;/h2&gt;

&lt;p&gt;Para automatizar a execução do &lt;code&gt;getcontent&lt;/code&gt; via Docker usando o Crontab, siga estes passos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abra o Crontab:&lt;/strong&gt; Execute o comando &lt;code&gt;crontab -e&lt;/code&gt; no seu terminal. Isso abrirá o editor de texto padrão do seu sistema para editar o arquivo Crontab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adicione uma nova tarefa:&lt;/strong&gt; Adicione uma linha com o comando para executar o Docker, seguindo a estrutura abaixo.  Substitua &lt;code&gt;* * * * *&lt;/code&gt; pela programação desejada (veja exemplos abaixo) e certifique-se de que o caminho para o arquivo &lt;code&gt;.env&lt;/code&gt; esteja correto.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * * docker run --rm --name getcontent -e TYPE_GETCONTENT=daily --env-file /caminho/para/.env getcontent:0.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemplos de programação:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Diariamente às 8h:&lt;/strong&gt; &lt;code&gt;0 8 * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cada hora:&lt;/strong&gt; &lt;code&gt;0 * * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diariamente às 8h e 20h:&lt;/strong&gt; &lt;code&gt;0 8,20 * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Somente aos dias úteis às 8h:&lt;/strong&gt; &lt;code&gt;0 8 * * 1-5&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observações:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O caminho &lt;code&gt;/caminho/para/.env&lt;/code&gt; deve ser substituído pelo caminho absoluto para o seu arquivo &lt;code&gt;.env&lt;/code&gt;.  Use o comando &lt;code&gt;pwd&lt;/code&gt; no terminal para descobrir o caminho do diretório atual, se necessário.&lt;/li&gt;
&lt;li&gt;Certifique-se de que o usuário que executa o Crontab tenha permissão para executar o comando &lt;code&gt;docker&lt;/code&gt;.  Pode ser necessário adicionar o usuário ao grupo &lt;code&gt;docker&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Após salvar as alterações no Crontab, a tarefa agendada será executada de acordo com a programação definida.&lt;/li&gt;
&lt;li&gt;Monitore os logs do Docker para identificar e solucionar quaisquer problemas que possam ocorrer durante a execução automatizada.  Você pode usar o comando &lt;code&gt;docker logs getcontent&lt;/code&gt; para visualizar os logs do contêiner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerações Adicionais
&lt;/h2&gt;

&lt;p&gt;Este projeto é uma excelente demonstração de como a IA pode simplificar tarefas cotidianas.  No entanto, é importante considerar alguns pontos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limites das APIs:&lt;/strong&gt; As APIs Jina e Gemini possuem limites de uso.  Monitore o consumo para evitar exceder os limites gratuitos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tratamento de Erros:&lt;/strong&gt; Implemente um mecanismo robusto de tratamento de erros para lidar com falhas nas APIs, problemas de conexão de rede e outras situações inesperadas.  Isso garantirá a confiabilidade do sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidade:&lt;/strong&gt; Para um maior volume de notícias ou usuários, considere a escalabilidade da solução, possivelmente utilizando um serviço de agendamento mais robusto e gerenciamento de filas de tarefas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segurança:&lt;/strong&gt; Proteja suas credenciais de API e e-mail adequadamente.  Evite armazená-las diretamente no código e utilize variáveis de ambiente como demonstrado.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>jina</category>
      <category>python</category>
    </item>
    <item>
      <title>GetContent - Enviando resumo de notícias por e-mail</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sun, 17 Aug 2025 18:55:49 +0000</pubDate>
      <link>https://dev.to/cassunde/getcontent-enviando-resumo-de-noticias-por-e-mail-50k3</link>
      <guid>https://dev.to/cassunde/getcontent-enviando-resumo-de-noticias-por-e-mail-50k3</guid>
      <description>&lt;p&gt;Fala pessoal, tudo certo? Hoje vamos falar sobre como podemos usar a IA para nos ajudar no dia a dia, esse projeto chamado de &lt;a href="https://github.com/cassunde/getContent" rel="noopener noreferrer"&gt;getContent&lt;/a&gt; é um projeto que visa capturar informações de alguns portais de notícia, resumir e mandar direto para seu e-mail&lt;/p&gt;

&lt;h2&gt;
  
  
  O Problema
&lt;/h2&gt;

&lt;p&gt;Mantermo-nos informados sobre as principais notícias do Brasil e do Mundo sem gastar muito tempo é um desafio constante, entrar nos portais tradicionais, é ser soterrado por propagandas ou incentivos, pensando em melhorar a experiência de ler notícias esse projeto vem para resumir as principais notícias e envia-os por email.&lt;/p&gt;

&lt;h2&gt;
  
  
  O GetContent
&lt;/h2&gt;

&lt;p&gt;GetContent é um projeto feito em Python que usa duas IA para fazer a parte trabalhosa, usa a IA Jina para capturar o conteúdo e o gemini para fazer os resumos. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxc5qd3hy8seqbtvwps82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxc5qd3hy8seqbtvwps82.png" alt=" " width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos executar esse projeto de algumas forma, via Docker ou diretamente no seu terminal, vamos ver como executar as duas formas, primeiro vamos executar diretamente no terminal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fazer clone do projeto
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:cassunde/getContent.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Instalar as dependências.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Agora precisamos criar um arquivo .env com as nossas credencias
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GOOGLE_API_KEY=...
JINA_API_KEY=...
SENDER_EMAIL=...
SENDER_PASSWORD=...
RECIPIENT_EMAIL=...
SMTP_SERVER=...
SMTP_PORT=587
TYPE_GETCONTENT=daily
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para obter as chaves necessárias, siga estes passos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Chave Gemini:&lt;/strong&gt; Acesse o seguinte link para gerar sua chave: &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;https://aistudio.google.com/app/apikey&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Chave Jina:&lt;/strong&gt; Cadastre-se na plataforma Jina através deste link: &lt;a href="https://jina.ai/api-dashboard/" rel="noopener noreferrer"&gt;https://jina.ai/api-dashboard/&lt;/a&gt; Após o cadastro, você receberá uma chave gratuita.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Além disso, você precisará de um endereço de e-mail para ser utilizado como remetente. Se você utiliza o Gmail como seu e-mail principal, considere criar uma conta no Outlook. Para configurar o Outlook como remetente, você pode encontrar as informações de SMTP necessárias neste guia: &lt;a href="https://support.microsoft.com/pt-br/office/configura%C3%A7%C3%B5es-pop-imap-e-smtp-para-outlook-com-d088b986-291d-42b8-9564-9c414e2aa040" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Executando o GetContent via Terminal
&lt;/h2&gt;

&lt;p&gt;Após clonar o repositório. instalar as dependências e criar o arquivo &lt;code&gt;.env&lt;/code&gt; na raiz do projeto com suas credenciais. Execute o script principal do GetContent via terminal usando o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 news.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso iniciará o processo de coleta de notícias, resumo usando as APIs Jina e Gemini, e envio do resumo por e-mail para o destinatário especificado.  Observe que o sucesso da execução depende da configuração correta do arquivo &lt;code&gt;.env&lt;/code&gt; e da disponibilidade das APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executando a aplicação &lt;code&gt;getcontent&lt;/code&gt; com Docker
&lt;/h2&gt;

&lt;p&gt;Este sessão explica como executar a aplicação &lt;code&gt;getcontent&lt;/code&gt;, disponível no Docker Hub em &lt;code&gt;cassunde/getcontent&lt;/code&gt;, utilizando o comando &lt;code&gt;docker run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pré-requisitos:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker instalado e configurado em seu sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Execução:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm --name getcontent -e TYPE_GETCONTENT=daily --env-file ./.env getcontent:0.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;com as seguintes opções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--rm&lt;/code&gt;: Remove o contêiner após a sua execução.  Isso limpa o ambiente após o término da aplicação, evitando a acumulação de contêineres desnecessários.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--name getcontent&lt;/code&gt;: Atribui o nome &lt;code&gt;getcontent&lt;/code&gt; ao contêiner.  Isso facilita a identificação e a gestão do contêiner em execução.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;-e TYPE_GETCONTENT=daily&lt;/code&gt;: Define a variável de ambiente &lt;code&gt;TYPE_GETCONTENT&lt;/code&gt; com o valor &lt;code&gt;daily&lt;/code&gt;.  Esta variável dis quais urls serão capturadas, resumidas e enviadas por e-mail&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--env-file ./.env&lt;/code&gt;: Lê as variáveis de ambiente a partir do arquivo &lt;code&gt;.env&lt;/code&gt; localizado no diretório atual.  Este arquivo contém todas as credencias para executar a integrações com as IAs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;getcontent:0.0.2&lt;/code&gt;: Especifica a imagem Docker a ser executada.  A tag &lt;code&gt;0.0.2&lt;/code&gt; indica a versão da imagem.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verificando a execução:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Após executar o comando, verifique se a aplicação funcionou corretamente.  Você precisa observar os logs que serão exibidos logo no final&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Buscando conteúdo de: https://techcrunch.com/
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
Buscando conteúdo de: https://www.bbc.com/portuguese/topics/cz74k717pw5t
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
Buscando conteúdo de: https://cearaagora.com.br/ultimas/
Conteúdo obtido com sucesso.
Gerando resumo...
Resumo gerado com sucesso.
Email sent successfully!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agendamento Automático com Crontab
&lt;/h2&gt;

&lt;p&gt;Para automatizar a execução do &lt;code&gt;getcontent&lt;/code&gt; via Docker usando o Crontab, siga estes passos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abra o Crontab:&lt;/strong&gt; Execute o comando &lt;code&gt;crontab -e&lt;/code&gt; no seu terminal. Isso abrirá o editor de texto padrão do seu sistema para editar o arquivo Crontab.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adicione uma nova tarefa:&lt;/strong&gt; Adicione uma linha com o comando para executar o Docker, seguindo a estrutura abaixo.  Substitua &lt;code&gt;* * * * *&lt;/code&gt; pela programação desejada (veja exemplos abaixo) e certifique-se de que o caminho para o arquivo &lt;code&gt;.env&lt;/code&gt; esteja correto.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* * * * * docker run --rm --name getcontent -e TYPE_GETCONTENT=daily --env-file /caminho/para/.env getcontent:0.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Exemplos de programação:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Diariamente às 8h:&lt;/strong&gt; &lt;code&gt;0 8 * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A cada hora:&lt;/strong&gt; &lt;code&gt;0 * * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diariamente às 8h e 20h:&lt;/strong&gt; &lt;code&gt;0 8,20 * * *&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Somente aos dias úteis às 8h:&lt;/strong&gt; &lt;code&gt;0 8 * * 1-5&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observações:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O caminho &lt;code&gt;/caminho/para/.env&lt;/code&gt; deve ser substituído pelo caminho absoluto para o seu arquivo &lt;code&gt;.env&lt;/code&gt;.  Use o comando &lt;code&gt;pwd&lt;/code&gt; no terminal para descobrir o caminho do diretório atual, se necessário.&lt;/li&gt;
&lt;li&gt;Certifique-se de que o usuário que executa o Crontab tenha permissão para executar o comando &lt;code&gt;docker&lt;/code&gt;.  Pode ser necessário adicionar o usuário ao grupo &lt;code&gt;docker&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Após salvar as alterações no Crontab, a tarefa agendada será executada de acordo com a programação definida.&lt;/li&gt;
&lt;li&gt;Monitore os logs do Docker para identificar e solucionar quaisquer problemas que possam ocorrer durante a execução automatizada.  Você pode usar o comando &lt;code&gt;docker logs getcontent&lt;/code&gt; para visualizar os logs do contêiner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerações Adicionais
&lt;/h2&gt;

&lt;p&gt;Este projeto é uma excelente demonstração de como a IA pode simplificar tarefas cotidianas.  No entanto, é importante considerar alguns pontos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limites das APIs:&lt;/strong&gt; As APIs Jina e Gemini possuem limites de uso.  Monitore o consumo para evitar exceder os limites gratuitos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tratamento de Erros:&lt;/strong&gt; Implemente um mecanismo robusto de tratamento de erros para lidar com falhas nas APIs, problemas de conexão de rede e outras situações inesperadas.  Isso garantirá a confiabilidade do sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidade:&lt;/strong&gt; Para um maior volume de notícias ou usuários, considere a escalabilidade da solução, possivelmente utilizando um serviço de agendamento mais robusto e gerenciamento de filas de tarefas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segurança:&lt;/strong&gt; Proteja suas credenciais de API e e-mail adequadamente.  Evite armazená-las diretamente no código e utilize variáveis de ambiente como demonstrado.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>jina</category>
      <category>python</category>
    </item>
    <item>
      <title>Implementando software seguindo problemas de negócio</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sat, 31 May 2025 19:52:17 +0000</pubDate>
      <link>https://dev.to/cassunde/implementando-software-seguindo-problemas-de-negocio-497j</link>
      <guid>https://dev.to/cassunde/implementando-software-seguindo-problemas-de-negocio-497j</guid>
      <description>&lt;p&gt;Nesta imersão sobre &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt;, desvendamos como essa metodologia se estabelece como um pilar fundamental para o desenvolvimento de sistemas complexos, priorizando, de forma inegociável, os &lt;strong&gt;problemas de negócio&lt;/strong&gt; acima de qualquer consideração técnica. O DDD não é meramente um conjunto de padrões arquiteturais; é uma abordagem filosófica que orienta o desenvolvimento de software a partir de uma compreensão contínua do domínio de negócio.&lt;/p&gt;

&lt;p&gt;A essência da nossa discussão girou em torno da premissa de que a tecnologia, por mais avançada que seja, deve ser um meio para um fim – e esse fim é resolver os desafios e impulsionar as oportunidades do negócio. Ao invés de começarmos com a pilha tecnológica ou a arquitetura de banco de dados, o DDD nos convida a iniciar a jornada de desenvolvimento com um mergulho no universo do cliente, entendendo suas operações, seus desafios e seus objetivos estratégicos. É essa compreensão que irá, em última instância, moldar a arquitetura e as soluções técnicas que emergem.&lt;/p&gt;

&lt;p&gt;Um dos pilares conceituais que exploramos foi o &lt;strong&gt;Domínio de Negócio e seus Subdomínios&lt;/strong&gt;. O domínio de negócio representa a área de expertise e conhecimento sobre a qual o software será construído. No entanto, raramente um domínio é monolítico; ele é, na maioria das vezes, composto por diversos &lt;strong&gt;Subdomínios&lt;/strong&gt;, cada um com suas particularidades, regras e responsabilidades. A importância de identificar e mapear esses subdomínios é crucial, pois eles nos permitem segmentar a complexidade e gerenciar o desenvolvimento de forma mais eficaz.&lt;/p&gt;

&lt;p&gt;Dentro dessa estrutura de subdomínios, há uma distinção vital entre subdomínios "core", de suporte e genéricos. Os &lt;strong&gt;subdomínios "core"&lt;/strong&gt; são aqueles que representam o diferencial competitivo da empresa, as funcionalidades que realmente a destacam no mercado. São eles que entregam o maior valor de negócio e, consequentemente, devem ser os mais maleáveis, adaptáveis e fáceis de evoluir. A discussão na call enfatizou que a prioridade de investimento em tempo, recursos e talentos deve ser direcionada para esses subdomínios "core", garantindo que eles permaneçam na vanguarda da inovação e da relevância de mercado. Subdomínios de suporte, embora necessários, não são o cerne da vantagem competitiva, enquanto subdomínios genéricos são aqueles que podem ser adquiridos como soluções prontas (prateleira) ou desenvolvidos com menor investimento, pois não representam um diferencial.&lt;/p&gt;

&lt;p&gt;A colaboração e a comunicação foram outros temas centrais abordados, destacando o papel indispensável dos &lt;strong&gt;Especialistas de Domínio&lt;/strong&gt;. Essas são as pessoas que possuem um conhecimento aprofundado do negócio, suas regras, processos e exceções. No DDD, a parceria entre especialistas de domínio e desenvolvedores é fundamental. Não se trata apenas de o especialista de domínio "passar" os requisitos para o desenvolvedor, mas sim de uma colaboração contínua e bidirecional, onde ambos aprendem uns com os outros. Essa interação constante é a base para a construção de uma &lt;strong&gt;Linguagem Ubíqua&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Linguagem Ubíqua&lt;/strong&gt; é muito mais do que um glossário de termos; é um vocabulário comum e consistente que é usado por todos os membros da equipe – desde os especialistas de negócio até os desenvolvedores, passando por testers, gerentes de produto e qualquer outra pessoa envolvida no projeto. A importância da Linguagem Ubíqua reside em sua capacidade de eliminar ambiguidades e garantir que todos estejam falando a mesma "língua" ao discutir o domínio. Se um especialista de domínio usa um termo com um significado e o desenvolvedor o interpreta de forma diferente, o resultado pode ser um software que não atende às expectativas do negócio. A Linguagem Ubíqua atua como um sistema de verdade único, onde os termos, conceitos e regras do negócio são expressos de forma clara e inequívoca, tanto na comunicação oral quanto no código do software.&lt;/p&gt;

&lt;p&gt;A discussão prosseguiu abordando como essa compreensão profunda do domínio e a Linguagem Ubíqua são traduzidas em artefatos de desenvolvimento, como &lt;strong&gt;Casos de Uso e Modelos&lt;/strong&gt;. Os Casos de Uso nos ajudam a descrever as interações dos usuários com o sistema, detalhando as funcionalidades sob a perspectiva do negócio. Eles são uma ponte crucial entre os requisitos de negócio e o design do software. Os &lt;strong&gt;Modelos&lt;/strong&gt;, por sua vez, são as representações abstratas do domínio, que podem se manifestar de diversas formas – desde diagramas de classes e entidades até fluxos de processo e diagramas de estado. A beleza do DDD é que esses modelos não são apenas documentos estáticos; eles são a representação viva da Linguagem Ubíqua e são constantemente refinados e ajustados à medida que a compreensão do domínio evolui. A clareza e a precisão desses modelos são vitais para que o software reflita fielmente as regras e o comportamento do negócio.&lt;/p&gt;

&lt;p&gt;A call ressaltou a importância de mapear esses subdomínios cruciais para que os modelos de software reflitam a essência do negócio. Isso significa que as classes, os serviços, os repositórios e todos os outros componentes do sistema devem ser nomeados e estruturados de acordo com a Linguagem Ubíqua e a lógica do domínio, e não com base em convenções técnicas genéricas. Por exemplo, se o negócio tem o conceito de "Pedido", o software deve ter uma entidade &lt;code&gt;Pedido&lt;/code&gt;, com métodos e atributos que representem o comportamento e as características de um pedido no mundo real.&lt;/p&gt;

&lt;p&gt;A grande vantagem de se focar nos problemas de negócio com o DDD é a capacidade de construir sistemas que são inerentemente mais alinhados aos objetivos estratégicos da empresa. Ao invés de se adaptar a um software inflexível, o negócio pode, com o DDD, guiar a evolução do sistema de forma orgânica e eficiente. Essa abordagem permite que as empresas se mantenham ágeis, adaptáveis e, o mais importante, continuem relevantes no mercado. A arquitetura de software, quando guiada pelo domínio, torna-se uma aliada poderosa na busca por inovação e competitividade, e não um obstáculo. Em suma, o DDD nos oferece um framework robusto para garantir que o desenvolvimento de software seja uma extensão natural e precisa da estratégia de negócio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vídeo
&lt;/h2&gt;

&lt;p&gt;Quem quiser assistir o vídeo segue abaixo&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/IxqKk1fqtIM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>architecture</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Estratégias de Paralelismo e Divisão de Responsabilidades em Sistemas Complexos</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sat, 04 Nov 2023 19:18:22 +0000</pubDate>
      <link>https://dev.to/cassunde/maximizando-eficiencia-e-tolerancia-a-falhas-estrategias-de-paralelismo-e-divisao-de-responsabilidades-em-sistemas-complexos-o9k</link>
      <guid>https://dev.to/cassunde/maximizando-eficiencia-e-tolerancia-a-falhas-estrategias-de-paralelismo-e-divisao-de-responsabilidades-em-sistemas-complexos-o9k</guid>
      <description>&lt;p&gt;Paralelismo é extremamente funcional quando temos algumas responsabilidades bem definidas dentro do nosso sistema, a divisão de responsabilidade entendo que é o principal ponto de partida.&lt;/p&gt;

&lt;h2&gt;
  
  
  Escopo
&lt;/h2&gt;

&lt;p&gt;Vamos imaginar um sistema que fará o fechamento da folha de pagamento dos funcionários.&lt;/p&gt;

&lt;p&gt;Nesse fechamento hipotético precisamos identificar quantidade de horas extras dos funcionários, multiplicar o resultado pelo valor da hora do funcionário e adicionar o valor encontrado ao salário para assim chegarmos ao valor final a ser pago.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quebrando responsabilidades
&lt;/h2&gt;

&lt;p&gt;Como podemos dividir as responsabilidades nesse cenário? existe uma ordem de acontecimento ?&lt;/p&gt;

&lt;p&gt;Primeiro vamos pensar, nesse cenário não podemos fazer o fechamento sem as horas extras previamente calculadas, com isso entendido fica claro que o cálculo de horas extras não depende de nada mas o fechamento depende do cálculo das horas extras, agora vamos pensar mais um pouco, vamos iniciar com a rotina de calcular as horas extras, será que conseguimos quebrar essa rotina ? será que a rotina precisa mesmo processar todos os funcionários de uma vez ? &lt;/p&gt;

&lt;p&gt;Vamos imaginar que todos os meses esse sistema fará o cálculo de horas extras para 2mil funcionários, nessa nossa primeira implementação faremos um &lt;code&gt;select&lt;/code&gt; na base de dados, pegaremos os 2mil funcionários e para cada funcionário encontrado calcularemos o valor de hora extra.&lt;/p&gt;

&lt;p&gt;Um dos problemas com a abordagem acima é que caso um único funcionário falhe, faremos o reprocessamento de todos os funcionários pois tudo está acoplado dentro de uma única rotina.&lt;/p&gt;

&lt;p&gt;Beleza, para mitigar esse problema, vamos dividir nosso problema em duas partes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identificação de cada Funcionário.&lt;/li&gt;
&lt;li&gt;Execução do calculo de hora extra dado um funcionário.
## Identificando todos os Funcionários&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Abaixo temos um simples diagrama que representa a primeira parte da implementação, vamos identificar todos os funcionários que estão aptos e enfileirá-los.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fjh12s4nrdcavoil0a0u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjh12s4nrdcavoil0a0u5.png" alt=" " width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em nosso exemplo estamos utilizando o RabbitMQ para controlar nossas mensagens&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Podemos implementar controles de status ou outro mecanismo que de alguma forma ajude a identificar se um Funcionário está ou não apito para ter suas horas extras calculas.&lt;/p&gt;

&lt;p&gt;Quando lidamos com eventos temos o benefício do desacoplamento mas temos que nos preocupar com outros fatores, como por exemplo, lidar com mensagens duplicadas, caso por qualquer motivo chegue uma mensagem que já foi processada essa mensagem precisa ser descartada para evitar sobrescrita ou desperdício de recursos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executando o cálculo de hora extra
&lt;/h2&gt;

&lt;p&gt;Agora vamos implementar um &lt;code&gt;Listener&lt;/code&gt; que receberá esse único funcionário e realizará todo o processo de cálculo de hora extra, com o RabbitMQ, conseguimos configurar a quantidade de &lt;code&gt;Consumers&lt;/code&gt; que um determinado &lt;code&gt;Listener&lt;/code&gt; produzirá, ou seja, podemos fazer com que processemos vários Funcionários ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Vale observar que a nossa rotina de cálculo de hora extra é totalmente isolada entre os funcionários, podemos processar com segurança todos em paralelo, pois nesse momento não existe recurso em concorrência.&lt;/p&gt;

&lt;p&gt;Com essa abordagem temos o processo de cálculo de hora extra sendo executado por funcionário e caso algum funcionário falhe conseguiremos reprocessar apenas o funcionário que falhou.&lt;/p&gt;

&lt;h2&gt;
  
  
  DLQ
&lt;/h2&gt;

&lt;p&gt;Com nosso &lt;code&gt;Listener&lt;/code&gt; implementado podemos tirar proveito das DLQs (Dead Letter Queue) que nada mais é do que o local para onde as mensagem que não conseguiram ser processadas vão ser armazenadas, é indicado que sempre que uma mensagem for direcionada para DLQ, seja disparado algum tipo de alarme para que a equipe responsável possa fazer suas análises, isso lembra um post que falo sobre &lt;a href="https://dev.to/cassunde/a-importancia-dos-logs-23c9"&gt;a importância dos logs&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  O Processo de fechamento
&lt;/h2&gt;

&lt;p&gt;E sobre o processo de fechamento? será que conseguimos fazer da mesma forma? a resposta é sim, todos os processos serão por funcionário, quando o funcionário sair da fila de &lt;code&gt;cálculo de hora extra&lt;/code&gt; ele irá para a fila de &lt;code&gt;fechamento de folha de pagamento&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhylggmgtujvl1687s7zd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhylggmgtujvl1687s7zd.png" alt=" " width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse fluxo fica explicito que para um funcionário chegar na &lt;code&gt;Fila de Fechamento&lt;/code&gt; ele precisará passar na fila de &lt;code&gt;Calculo de Hora Extra&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Para alcançar o paralelizar com segurança e escalabilidade, é crucial isolar adequadamente os processos, só isso já é bem difícil principalmente em sistemas monolíticos onde existe muito acoplamento, tolerância a falhas não é coisa de microservice e sim de qualquer sistemas. &lt;/p&gt;

&lt;p&gt;Temos cenários mais complexos, como por exemplo, receber mensagem para descontar valor de um saldo único, isso gera concorrência ou seja, dois processos querendo descontar do mesmo saldo, mas nesse post vou abordar a forma mais simples do paralelismo.&lt;/p&gt;

&lt;p&gt;Espero que tenha ajudado a pensar em alternativas antes de tentar paralelizar um processo já existente ou no desenho de um novo processo, qualquer dúvida ou comentário é só chamar ;)&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/implementando-paralelismo-com-virtual-threads-no-java-21-3om8" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Implementando Paralelismo com Virtual Threads no Java 21&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Oct 30 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#braziliandevs&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#virtualthread&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>java</category>
      <category>eventdriven</category>
      <category>rabbitmq</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Implementando Paralelismo com Virtual Threads no Java 21</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Mon, 30 Oct 2023 03:30:52 +0000</pubDate>
      <link>https://dev.to/cassunde/implementando-paralelismo-com-virtual-threads-no-java-21-3om8</link>
      <guid>https://dev.to/cassunde/implementando-paralelismo-com-virtual-threads-no-java-21-3om8</guid>
      <description>&lt;p&gt;Neste exemplo, veremos como implementar o paralelismo usando Java 21. Anteriormente, para alcançar paralelismo, utilizávamos e ainda usamos o &lt;code&gt;CompletableFeature&lt;/code&gt;, que funciona muito bem, mas ainda é um pouco verboso.&lt;/p&gt;

&lt;p&gt;Para começar, criaremos dois métodos que retornam uma String. Dentro de cada método, faremos a Thread esperar por alguns segundos para simbolizar uma operação de I/O.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;executeTask1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"task 1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"task1"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O primeiro método espera 1 segundo antes de retornar a String, e o segundo método é semelhante, também aguardando 1 segundo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;executeTask2&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"task 2"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"task2"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Agora, criaremos um método que chamará esses dois métodos de forma paralela.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;startVirtualThreads&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExecutionException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;AppThreadPerTask:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;executeTask1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;AppThreadPerTask:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;executeTask2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;task2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ao analisar o código acima, observaremos a criação do &lt;code&gt;executor&lt;/code&gt; usando o utilitário &lt;code&gt;Executors&lt;/code&gt;. No Java 21, foi adicionado o método que cria um &lt;code&gt;ExecutorService&lt;/code&gt; usando &lt;code&gt;VirtualThreads&lt;/code&gt;: o &lt;code&gt;newVirtualThreadPerTaskExecutor()&lt;/code&gt;. Com esse método, podemos criar uma Virtual Thread para cada tarefa. Observamos a separação das tarefas nas linhas 4 e 5 do exemplo.&lt;/p&gt;

&lt;p&gt;O método &lt;code&gt;submit&lt;/code&gt; recebe &lt;code&gt;Callable&amp;lt;V&amp;gt;&lt;/code&gt;, que é uma interface funcional do Java, e retorna um &lt;code&gt;Future&lt;/code&gt;. O &lt;code&gt;Future&lt;/code&gt; entrega o retorno do método quando este é finalizado com sucesso, funcionando de forma similar às &lt;code&gt;Promises&lt;/code&gt; do JavaScript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;É importante observar que utilizamos o método &lt;code&gt;.get()&lt;/code&gt; para recuperar os valores dos métodos que estão sendo processados de forma paralela. Se algum dos métodos retornar uma exceção, podemos capturá-la facilmente no método principal.&lt;/p&gt;

&lt;p&gt;Agora podemos chamar o método principal, que fará tudo funcionar. É recomendável monitorar os tempos de execução para visualização os tempos.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ExecutionException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"init"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;tasksConcatenated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;startVirtualThreads&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasksConcatenated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Duration&lt;/span&gt; &lt;span class="n"&gt;timeElapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;between&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Time taken: "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timeElapsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" milliseconds"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;Após a execução, teremos um log mais ou menos como o seguinte:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;2023-10-29 23:03:12 INFO  AppThreadPerTask:26 - trace=121212 - init
2023-10-29 23:03:12 INFO  AppThreadPerTask:64 - trace= - task 1
2023-10-29 23:03:12 INFO  AppThreadPerTask:58 - trace= - task 2
2023-10-29 23:03:17 INFO  AppThreadPerTask:29 - trace=121212 - task1task2
2023-10-29 23:03:17 INFO  AppThreadPerTask:33 - trace=121212 - Time taken: 5018 milliseconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Observamos nos logs que os métodos são registrados imediatamente, ou seja, estão sendo executados em paralelo. Isso significa que o método mais lento determinará o tempo de execução do método principal.&lt;/p&gt;

&lt;p&gt;Repositório com código de exemplo: &lt;a href="https://github.com/cassunde/java/blob/main/src/main/java/br/com/cassunde/AppThreadPerTask.java" rel="noopener noreferrer"&gt;Repositório&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você já utilizou alguma dessas funcionalidades em produção? Se sim, o que achou?&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/reduzindo-acoplamento-2ofm" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Reduzindo acoplamento no desenvolvimento de software&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Sep 17 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#architecture&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#braziliandevs&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>java</category>
      <category>braziliandevs</category>
      <category>virtualthread</category>
    </item>
    <item>
      <title>Proxy Reverso com Apache2</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Fri, 20 Oct 2023 12:11:26 +0000</pubDate>
      <link>https://dev.to/cassunde/proxy-reverso-com-apache2-3a22</link>
      <guid>https://dev.to/cassunde/proxy-reverso-com-apache2-3a22</guid>
      <description>&lt;h3&gt;
  
  
  O Problema
&lt;/h3&gt;

&lt;p&gt;Muitas vezes quando estamos iniciando uma aplicação web deixamos os usuários acessarem nosso sistema direto do servidor que nossa app está instalada. A imagem abaixo ilustra essa abordagem, agora imagina quantas informações sobre nosso sistema estamos entregando para um atacante?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ff3x7myci3svbxanx9p3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ff3x7myci3svbxanx9p3f.png" alt="Teste de imagem" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Aumentando a segurança
&lt;/h3&gt;

&lt;p&gt;Expor detalhes da nossa aplicação como IP e porta não é uma boa alternativa principalmente quando começamos a aumentar o fluxo de acesso, um atacante pode usar essas informações para derrubar nosso serviço.&lt;/p&gt;

&lt;p&gt;Pensando em como resolver esse problema uma alternativa é usar um proxy reverso e tentar dificultar a vida do atacante, agora, ele não terá acesso direto ao servidor e sim a um proxy que internamente vai chamar um ou vários outros servidores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0vc65sf09qct44es65bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0vc65sf09qct44es65bq.png" alt="Teste de Imagae 2" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Na imagem a cima nosso usuário não acessa mais servidor da aplicação direto, ele agora acessa um proxy que a partir do subdomínio que chegou ele vai redirecionar para o servidor correto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comandos
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Vamos rodar o camando abaixo para resincronizar os arquivos que guardam os repositórios disponíveis do SO
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Vamos instalar a aplicação apache2 que será usada como nosso proxy reverso.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Vamos instalar todos os módulos que o apache precisa para que possamos configurar o proxy reverso
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2enmod proxy proxy_http proxy_connect proxy_html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Após a instalação dos módulo será necessário realizar um reload da aplicação para aplicar todas as instalações acima.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;service apache2 restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Agora vamos criar o arquivo que representa a configuração de um subdomínio que usaremos para fazer o proxy.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/apache2/sites-available/subdominio.dominio.com.br.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Aqui temos um exemplo do conteúdo desse arquivo onde precisamos apenas alterar algumas configurações.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
       ServerName subdominio.dominio.com.br
       DocumentRoot /var/www/html

       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined

       ProxyPass / http://192.121.122.12:8080/
       ProxyPassReverse / http://192.121.122.12:8080/

&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Sobre esse arquivo podemos fazer sobre alguns pontos como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ServerName&lt;/strong&gt;: Tem que ser exatamente o mesmo do subdomínio que configuramos para apontar para IP da máquina que estamos instalando o apache2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ProxyPass&lt;/strong&gt;: Configuração que diz para o apache2 como ele redirecionará as solicitações que chegarem em um determinado &lt;code&gt;path&lt;/code&gt;. Em nosso exemplo a cima nosso primeiro parâmetro é o "/"  que diz que redirecionaremos apartir da raiz do domínio e o segundo é para onde essas requisções serão redirecionadas, em nosso exemplo &lt;a href="http://192.121.122.12:8080/" rel="noopener noreferrer"&gt;http://192.121.122.12:8080/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ProxyPassReverse&lt;/strong&gt;: Configuração para ajustar os cabeçalhos http da resposta do servidor de destino antes de chegar no cliente, assim deixando totalmente oculto o servidor real onde a resposta foi produzida.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Voltando para nossa instalação vamos continuar habilitando o site que acabamos de configurar.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;a2ensite subdominio.dominio.com.br
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Por fim vamos recarregar o servidor com as novas configurações
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Pronto com as configurações a cima tudo deve está funcionando corretamente.&lt;/p&gt;
&lt;h3&gt;
  
  
  Apresentação
&lt;/h3&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/26d947a9b35f4a5ab8c5ffe5afbc4cc4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;h3&gt;
  
  
  Outros posts
&lt;/h3&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/a-potencia-do-jenkinsfile-6p4" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Jenkins Pipeline com Jenkinsfile&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Mar 13 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ci&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#jenkins&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cd&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#braziliandevs&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>devops</category>
      <category>apache2</category>
      <category>opensource</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Jenkins Pipeline com Jenkinsfile</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Mon, 13 Mar 2023 13:44:27 +0000</pubDate>
      <link>https://dev.to/cassunde/a-potencia-do-jenkinsfile-6p4</link>
      <guid>https://dev.to/cassunde/a-potencia-do-jenkinsfile-6p4</guid>
      <description>&lt;h3&gt;
  
  
  O Problema
&lt;/h3&gt;

&lt;p&gt;O time está gastando muito tempo com implantações e atualizações de sistemas nos ambientes de homologação e produção, esse time faz essas operações de forma manual ou seja acessando o servidor e rodando todos os comandos necessários, vale lembrar que esse processo é repetido diversas vezes durante o mês.&lt;/p&gt;

&lt;p&gt;Precisamos de alguma forma melhorar esse processo dando mais agilidade e deixando o time livre para trabalhar em outras tarefas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quais práticas existem para ajudar ?
&lt;/h3&gt;

&lt;p&gt;Em uma situação como essa podemos tirar proveito dos conceitos de CI/CD. Antes de entrar no significado dessas siglas, vamos deixar claro que DevOps não é CI/CD, DevOps é sobre pessoas, um desenvolvedor não pode simplesmente avisar que terminou e esperar que o time de Operação faça a implantação, o time de Operação quando se depara com um erro após a implantação não pode simplesmente abrir um card de erro e encerrar sua parte. Em caso de falhas sistêmicas logo após a implantação quem é o profissional mais apto para resolver o problema ? um profissional de Operações ou o desenvolvedor que criou determinada feature ?&lt;/p&gt;

&lt;p&gt;Vamos imaginar agora que o time de operação não faz mais implantações, quem vai fazer agora é o próprio time de desenvolvimento. Mas por que isso? “Quem pariu Mateus que o balance” ou "cachorro com muitos donos morre de fome”, essas frases falam de responsabilidade, quando atualizamos uma aplicação no servidor do cliente não estamos apenas trocando o &lt;code&gt;.jar&lt;/code&gt; ou &lt;code&gt;exe&lt;/code&gt; , estamos entregando uma solução para resolver um problema, o acompanhamento dessa solução desde a implantação até está em uso diário deve ser do time que planejou e desenvolveu essa solução. Estruturas como Servidores, Sistema operacional, versão de libs e etc depois de configurados é muito difícil dar problema, o que está mais propício a dar problema é código desenvolvido, é aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ok, como podemos melhorar isso?
&lt;/h3&gt;

&lt;p&gt;Vamos falar sobre como o Jenkins e Jenkinsfile conseguem ajudar na criação de um pipeline, a sintaxe que precisamos usar para conseguir escrever um pipeline é baseada em duas formas uma chamada de Declarativa e outra chamada de Script, nesse nosso papo vamos usar a forma Declarativa.&lt;/p&gt;

&lt;p&gt;A Arquitetura ficará mais ou menos assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Feizuw5qa39oi54bvzlcb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Feizuw5qa39oi54bvzlcb.jpg" alt=" " width="651" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iniciando com Jenkinsfile
&lt;/h3&gt;

&lt;p&gt;Um jenkinsfile nada mais é do que um arquivo com código que será interpretado pelo Jenkins, esse código é baseado em &lt;a href="https://groovy-lang.org/" rel="noopener noreferrer"&gt;Groovy&lt;/a&gt; uma linguagem de programação bastante usada no mercado e roda na JVM do Java. Um Jenkinsfile é como qualquer outro código do software,precisa ser versionado, pode evoluir e que provavelmente precisará de manutenções.&lt;/p&gt;

&lt;p&gt;Vamos rapidamente voltar nos passos básicos para entregar um software em produção ou homologação. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Devemos rodar testes de unidade&lt;/li&gt;
&lt;li&gt;Devemos rodar build&lt;/li&gt;
&lt;li&gt;Devemos armazenar artefato&lt;/li&gt;
&lt;li&gt;Devemos implantar artefato no servidor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pronto, agora que mapeamos os passos básicos que fazemos para entregar um software, podemos começar a pensar em como automatizar e deixar uma máquina fazendo esse trabalho.&lt;/p&gt;

&lt;p&gt;Para iniciarmos vamos criar um arquivo na raiz do projeto chamado Jenkinsfile, não precisa de extensão, basta Jenkinsfile, vamos colocar o conteúdo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Testando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Compilando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Armazenando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;DeploY&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Implantando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Analisando o conteúdo que colamos, vamos observar algumas palavras reservadas como, pipeline, agent, stages, stage e steps, vamos conhecer um pouco mais sobre eles nos blocos abaixo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quando estamos montando um Pipeline de forma Declarativa todo o conteúdo fica dentro desse &lt;code&gt;nó&lt;/code&gt; principal que chamamos de  &lt;code&gt;pipeline {}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Define o &lt;code&gt;Executor&lt;/code&gt;que será responsável por executar os comando dos pepiline, no formato Declarativo essa definição é obrigatória pois sem não saberá como executar. Podemos definir um &lt;code&gt;agent&lt;/code&gt;de forma global como em nosso exemplo, no topo do arquivo, ou dentro de cada &lt;code&gt;stage&lt;/code&gt;dando mais possibilidades para nosso pipeline.&lt;/p&gt;

&lt;p&gt;Temos alguns &lt;a href="https://www.jenkins.io/doc/book/pipeline/syntax/#agent" rel="noopener noreferrer"&gt;tipos de Agent&lt;/a&gt;, mas para não alongar muito vamos focar em none, any e Docker.&lt;/p&gt;

&lt;p&gt;Tipo &lt;code&gt;none&lt;/code&gt; é bem simples, não será executado por nenhum &lt;code&gt;Executor&lt;/code&gt; mas obriga a definição nos &lt;code&gt;stage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tipo &lt;code&gt;any&lt;/code&gt;diz que será executado por qualquer &lt;code&gt;Executor&lt;/code&gt;disponível, em nosso exemplo até o momento estamos usando esse valor.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Tipo &lt;code&gt;Docker&lt;/code&gt;diz que o &lt;code&gt;Executor&lt;/code&gt;usará uma imagem docker especificada para que ele execute seu trabalho, essa forma é a que usaremos em nossos exemplos, usando esse tipo de agent conseguimos realizar várias operações bastando ter uma imagem docker que contenha o que precisamos e pronto, não precisaremos "encher” nosso Jenkins com Plugins.&lt;/p&gt;

&lt;p&gt;Confira mais detalhes &lt;a href="https://www.jenkins.io/doc/book/pipeline/syntax/#agent" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stages e Stage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agrupa um ou vários &lt;code&gt;stage&lt;/code&gt;cada stage representa uma etapa do nosso pipeline, como test,build, deploy e etc.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Testando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Compilando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Armazenando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;DeploY&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Implantando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Define como o stage será executado, em nosso caso estamos apenas executando o comando &lt;code&gt;echo&lt;/code&gt;mas podemos ter vários outros comando para executar o objetivo do &lt;code&gt;stage&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Evoluindo colunas
&lt;/h3&gt;

&lt;p&gt;Agora vamos evoluir mais ainda nosso Jenkinsfile preenchendo algumas colunas para entender como o Jenkins vai executar os passos que definimos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evoluindo coluna de Teste&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos ver como podemos evoluir a &lt;code&gt;stage&lt;/code&gt;de teste, atualmente está super simples, apenas exibindo um texto no console, veja abaixo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Testando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nosso projeto foi escrito em java usando maven como gerenciador, para rodarmos os testes unitários executamos o comando:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mvn&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Mas a partir de agora quem vai executar esse comando será o Jenkins, nesse nosso papo usaremos um &lt;code&gt;agent&lt;/code&gt; do tipo &lt;code&gt;docker&lt;/code&gt; com uma imagem contendo o Java já configurado, primeiro vamos mudar o &lt;code&gt;agent&lt;/code&gt;global que está como &lt;code&gt;agent any&lt;/code&gt;para &lt;code&gt;agent none&lt;/code&gt; dessa forma vamos definir o &lt;code&gt;agent&lt;/code&gt; apenas dentro do &lt;code&gt;stage&lt;/code&gt; como no exemplo abaixo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt;
    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;adoptopenjdk&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;openjdk11:&lt;/span&gt;&lt;span class="n"&gt;jdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;11.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;9.1_1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;            
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;agora basta implementar o &lt;code&gt;steps&lt;/code&gt; passando o comando para rodar os testes, veja como fica:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;adoptopenjdk&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;openjdk11:&lt;/span&gt;&lt;span class="n"&gt;jdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;11.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;9.1_1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
          &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;mvnw&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Se observar usamos o comando &lt;code&gt;sh&lt;/code&gt;   dentro da chave &lt;code&gt;steps&lt;/code&gt;, pronto com isso finalizamos nossa primeira coluna, nosso arquivo está fincando assim:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;none&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;adoptopenjdk&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;openjdk11:&lt;/span&gt;&lt;span class="n"&gt;jdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;11.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;9.1_1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;mvnw&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; 
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
        &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Compilando&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Store&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
        &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Armazenando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;DeploY&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
        &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Implantando&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;observe que nos demais &lt;code&gt;stage&lt;/code&gt; adicionei um &lt;code&gt;agent&lt;/code&gt; do tipo &lt;code&gt;any&lt;/code&gt; pois como comentei, se colocarmos no &lt;code&gt;agent&lt;/code&gt; global o tipo &lt;code&gt;none&lt;/code&gt; seremos obrigados a definir um &lt;code&gt;agent&lt;/code&gt; em cada &lt;code&gt;stage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evoluindo coluna de Build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Como na coluna de teste, vamos definir um &lt;code&gt;agent&lt;/code&gt; do tipo &lt;code&gt;docker&lt;/code&gt;, passar uma imagem com java e executar um outro comando para fazer o build da aplicação.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;adoptopenjdk&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nl"&gt;openjdk11:&lt;/span&gt;&lt;span class="n"&gt;jdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;11.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;9.1_1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;            
    &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;mvnw&lt;/span&gt; &lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
    &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;pronto agora o Jenkins saberá empacotar toda nossa aplicação em um arquivo &lt;code&gt;jar&lt;/code&gt; que ficará disponível para a próxima etapa que pode ser por exemplo criar uma imagem docker.&lt;/p&gt;
&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;Vimos com é simples criar um arquivo Jenkinsfile e começamos a entender como o Jenkins vai usa-lo para automatizar os passos das nossas entregas de Software.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/a-importancia-dos-logs-23c9" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;A importância dos logs na sua aplicação&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Oct 1 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#log&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#kibana&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>ci</category>
      <category>jenkins</category>
      <category>cd</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>A importância dos logs na sua aplicação</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sat, 01 Oct 2022 18:34:44 +0000</pubDate>
      <link>https://dev.to/cassunde/a-importancia-dos-logs-23c9</link>
      <guid>https://dev.to/cassunde/a-importancia-dos-logs-23c9</guid>
      <description>&lt;h3&gt;
  
  
  Introdução
&lt;/h3&gt;

&lt;p&gt;As vezes não damos aos logs a importância que eles tem e com isso não conseguimos usar a capacidade que eles tem em ajudar no dia a dia de uma aplicação em produção.&lt;/p&gt;

&lt;p&gt;Nada sabe mais sobre a falha do que a própria aplicação que falhou, por tanto podemos usar os logs para saber o que estava se passando na aplicação quando ela falhou.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Quando podemos usar os logs?
&lt;/h3&gt;

&lt;p&gt;Podemos usar o poder dos logs em diversos aspectos vou listar alguns como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validação de novas funcionalidades&lt;/li&gt;
&lt;li&gt;Análise de erros&lt;/li&gt;
&lt;li&gt;Criação de alarmes e visualizações&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Validação de novas funcionalidades&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;É legal sempre que lançarmos alguma funcionalidade nova, sabermos se ela está sendo usada ou se está atendendo o objetivo para qual ela foi implementada, com base nisso podemos lançar os logs sempre que uma rotina for finalizada com sucesso.&lt;/p&gt;

&lt;p&gt;Um exemplo, foi lançada uma funcionalidade que cria prontuário de paciente sempre que ele faz seu primeiro atendimento no hospital, até pouco tempo na aplicação não era possível fazer isso de formal automática, que tal lançar um log sempre que essa funcionalidade rodar com sucesso? dessa forma saberemos que funcionalidade entregue em produção funcionou com sucesso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Análise de erros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tão importante quanto sabermos quando uma funcionalidade nova roda com sucesso é saber quando essa mesma falha, sempre vai existir a possibilidade de algum cenário não mapeado acontecer e literalmente quebrar sua funcionalidade, é importante que saibamos o mais rápido possível para entender e corrigir esse cenário não mapeado.&lt;/p&gt;

&lt;p&gt;O log poderá nos ajudar exibindo o máximo possível de informações sobre o cenário que ocorreu, informações como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classe&lt;/li&gt;
&lt;li&gt;Método&lt;/li&gt;
&lt;li&gt;Variáveis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pois essas informações certamente ajudarão a entender o cenário e agilizar a definição da solução.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Criação de alarmes e visualizações&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Existe no mercado diversos centralizadores de logs onde um dos principais objetivos é facilitar a visualização dos mesmos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fcqbwjgfu9i0qx2sd8eab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcqbwjgfu9i0qx2sd8eab.png" alt=" " width="792" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ferramentas como Splunk e Kibana permitem criar alarmes a partir de consultas em logs, por exemplo, sempre que chegar um log de &lt;strong&gt;"erro ao salvar paciente"&lt;/strong&gt; deve ser disparado um alarme para que time de desenvolvimento/sustentação possam agir para corrigir o mais rápido possível o problema em produção.&lt;/p&gt;

&lt;h3&gt;
  
  
  Existe algum framework para logs?
&lt;/h3&gt;

&lt;p&gt;No mundo java um dos Frameworks mais populares é o &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4J&lt;/a&gt;, com ele podemos deixar nossos logs mais eficientes e programáveis, podemos definir também um padrão de log como por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="s1"&gt;"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;com essa configuração nosso log será mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;17:13:01.540 &lt;span class="o"&gt;[&lt;/span&gt;main] ERROR com.foo.Bar - Did it again!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observa que temos a palavra &lt;strong&gt;ERROR&lt;/strong&gt;, com o log4j temos níveis de log que poderemos relacionar com a gravidade do que aconteceu.&lt;/p&gt;

&lt;p&gt;Vamos fazer um exemplo, imagine que temos o método abaixo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;salvar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paciente&lt;/span&gt; &lt;span class="n"&gt;paciente&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para deixar claro que esse método foi executado com sucesso, ele ficaria mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"br.com.MinhaClasse"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;salvar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paciente&lt;/span&gt; &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
  &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"paciente salvo com sucesso"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observe que agora temos uma linha de logger do tipo &lt;strong&gt;INFO&lt;/strong&gt; logo após o passo que salva o paciente, seu log ficaria mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17:13:01.540 [main] INFO com.foo.Bar - Paciente salvo com sucesso
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora que entendemos um pouco de como podemos usar o Log4j vamos ver como podemos lidar com erros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;salvar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paciente&lt;/span&gt; &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;    
   &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
       &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nessa classe acima podemos melhora-la deixando-a com logs para ajudar a entender o que aconteceu quando esse método executou.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;salvar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Paciente&lt;/span&gt; &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;INFO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"paciente salvo com sucesso, paciente={}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCodigo&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
       &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"problema para salvar paciente, paciente={}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;paciente&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCodigo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observando o método a cima, agora é possível saber quando um paciente foi salvo com sucesso e quando um paciente teve problema. Para facilitar mais ainda o entendimento quando analisarmos os logs é a possibilidade de saber qual paciente deu erro.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dados sensíveis
&lt;/h3&gt;

&lt;p&gt;Hoje em nosso país temos a lei &lt;a href="http://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm" rel="noopener noreferrer"&gt;LGPD&lt;/a&gt; que visa melhorar a segurança dos nossos dados na Internet. primordialmente não devemos logar nenhum dado que possa identificar unicamente uma pessoa como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPF&lt;/li&gt;
&lt;li&gt;Data de Nascimento&lt;/li&gt;
&lt;li&gt;e-mail&lt;/li&gt;
&lt;li&gt;Nome completo&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então observe sempre o que estamos logando para não expor dados pessoais.&lt;/p&gt;

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

&lt;p&gt;É fácil começar a usar os logs para ajudar no entendimento do que acontece dentro da sua aplicação, então use e faça proveito dessa vantagens.&lt;/p&gt;

</description>
      <category>log</category>
      <category>java</category>
      <category>kibana</category>
      <category>devops</category>
    </item>
    <item>
      <title>Reduzindo acoplamento no desenvolvimento de software</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Sat, 17 Sep 2022 15:14:11 +0000</pubDate>
      <link>https://dev.to/cassunde/reduzindo-acoplamento-2ofm</link>
      <guid>https://dev.to/cassunde/reduzindo-acoplamento-2ofm</guid>
      <description>&lt;p&gt;Existem vários princípios que ajudam na implementação de códigos mais desacoplados e tudo mais, aqui a ideia e exemplificar como podemos fazer isso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo
&lt;/h3&gt;

&lt;p&gt;Imagine que estamos implementando um código que vende jornal, teremos uma entidade que representa a Banca e outra que representa a Carteira de um cliente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementação acoplada&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pagaJornal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorJornal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Carteira&lt;/span&gt; &lt;span class="n"&gt;carteira&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;carteira&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSaldo&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorJornal&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;cateira&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debitaSaldo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorJornal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// exception SaldoInsuficiente&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nessa primeira abordagem a Banca pega a carteira do cliente verifica se tem o valor necessário e caso sim tira o valor do jornal de dentro da certeira do cliente, talvez isso não seja tão legal pois a Banca sabe muito sobre a carteira do cliente. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementação desacoplada&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agora vamos implementar uma solução de uma forma mais desacoplada.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Carteira&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;paga&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorADebitar&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;SemSaldoException&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorADebitar&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saldo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saldo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorADebitar&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SemSaldoException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Banca&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pagaJornal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;valorJornal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Carteira&lt;/span&gt;   &lt;span class="n"&gt;carteira&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;carteira&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paga&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valorJornal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="c1"&gt;// exception SaldoInsuficiente&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nessa segunda abordagem a regra de saldo fica dentro da própria carteira, dessa forma a entidade Carteira está mais livre para cuidar da sua responsabilidade, caso seja necessário incluir essa mesma funcionalidade em outra parte do projeto agora será mais simples. &lt;/p&gt;
&lt;h3&gt;
  
  
  Referência
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Principio de Demeter&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://pt.wikipedia.org/wiki/Lei_de_Demeter" rel="noopener noreferrer"&gt;https://pt.wikipedia.org/wiki/Lei_de_Demeter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Engenharia Moderna&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.amazon.com.br/Engenharia-Software-Moderna-Marco-Valente/dp/6500019504" rel="noopener noreferrer"&gt;https://www.amazon.com.br/Engenharia-Software-Moderna-Marco-Valente/dp/6500019504&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Conheça outros papos
&lt;/h3&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/observer-com-propertychangelistener-dhf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Observer com PropertyChangeListener&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Jun 21 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#pattern&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>java</category>
      <category>architecture</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Subindo imagens para Harbor</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Mon, 12 Sep 2022 16:57:38 +0000</pubDate>
      <link>https://dev.to/cassunde/subindo-imagens-para-harbor-2b73</link>
      <guid>https://dev.to/cassunde/subindo-imagens-para-harbor-2b73</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introdução&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Harbor é uma ferramenta simples para armazenar suas imagens docker.&lt;/p&gt;

&lt;p&gt;Em nosso exemplo vamos fazer a entrega de um site simples, onde os arquivos estão dentro da pasta &lt;code&gt;/dist&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pré Requisitos&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Sua máquina deve ter o Docker instalado, aqui você pode ver &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04-pt" rel="noopener noreferrer"&gt;como&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sua aplicação deve ter um &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;Dockerfile&lt;/a&gt; com as configurações necessárias para realizar o build da sua imagem com sucesso.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM httpd:2.4

ENV IP_API=192.0.0.1

COPY ./dist/ /usr/local/apache2/htdocs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Criando sua imagem&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dentro a pasta do site digite o seguinte comando
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;nome-sua-app&lt;span class="o"&gt;}&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;versao&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; site-sample:0.0.1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Criando tag&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Precisamos criar tag para cada versão da nossa aplicação, podemos usar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker tag &lt;span class="o"&gt;{&lt;/span&gt;nome-sua-app&lt;span class="o"&gt;}&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;versao&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;url-registry&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;projeto&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;nome-sua-app&lt;span class="o"&gt;}&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;versao&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker tag site-sample:0.0.1 registry.inlinesoft.com.br/test/site-sample:0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Push para repositório&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para enviar uma image para o repositório devemos executar o comando &lt;code&gt;push&lt;/code&gt; seguindo o seguinte template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker push &lt;span class="o"&gt;{&lt;/span&gt;url-registry&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;projeto&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;nome-sua-app&lt;span class="o"&gt;}&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;versao&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker push site-sample:0.0.1 registry.inlinesoft.com.br/test/site-sample:0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se tiver dado tudo certo, ao acessar seu registry você verá sua imagem disponível.&lt;/p&gt;

&lt;p&gt;Agora é só colocar para rodar no seu servidor.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/LdOzXocLvEY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>harbor</category>
      <category>devops</category>
      <category>docker</category>
    </item>
    <item>
      <title>Critérios de Aceite + Cenários de Teste + Teste Unitário</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Fri, 02 Sep 2022 16:00:19 +0000</pubDate>
      <link>https://dev.to/cassunde/criterios-de-aceite-cenarios-de-teste-teste-unitario-2gp4</link>
      <guid>https://dev.to/cassunde/criterios-de-aceite-cenarios-de-teste-teste-unitario-2gp4</guid>
      <description>&lt;h3&gt;
  
  
  Gestão de projetos
&lt;/h3&gt;

&lt;p&gt;Para ajudar no entendimento e definição de estimativa, podemos usar um princípio visto em Gestão de projetos chamado de  &lt;a href="https://support.microsoft.com/pt-br/office/o-tri%C3%A2ngulo-do-projeto-8c892e06-d761-4d40-8e1f-17b33fdcf810" rel="noopener noreferrer"&gt;Triângulo do Projeto&lt;/a&gt;, que requer que o gerente tente manter um equilíbrio entre três pontos fundamentais, Escopo, Tempo e Custo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqey5rfnmggcrz2v5q06x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqey5rfnmggcrz2v5q06x.png" alt=" " width="151" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Segundo essa ideia em Gestão de projetos, não é possível Modificar nenhum desses pilares sem afetar ao menos um outro pilar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triângulo do Projeto de forma Ágil
&lt;/h3&gt;

&lt;p&gt;Nossa ideia é explorar como podemos aplicar esse princípio, primeira coisa a entender que a responsabilidade de manter o equilíbrio entre os pontos é do time e não exclusivamente de uma pessoa.&lt;/p&gt;

&lt;p&gt;Cada ponto pode ser explorado para ajudar na estimativa e refinamento das histórias, vamos ver como podemos explora-los. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escopo:&lt;/strong&gt; &lt;br&gt;
O uso de critérios de aceite podem ajudar a deixar claro esses limites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tempo:&lt;/strong&gt;&lt;br&gt;
O uso de técnicas como &lt;a href="https://asana.com/pt/resources/t-shirt-sizing" rel="noopener noreferrer"&gt;t-shirt&lt;/a&gt; ou &lt;a href="https://blog.betrybe.com/carreira/planning-poker/" rel="noopener noreferrer"&gt;Planning Poker&lt;/a&gt; para definir o tempo que será necessário para atender os critérios de aceite.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custo:&lt;/strong&gt;&lt;br&gt;
Nesse ponto podemos avaliar o custo em "R$", demonstrando a necessidade de usar um recurso da AWS ou a necessidade de levantar mais uma máquina em produção e entre outros.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resumo sobre BDD
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://twitter.com/tastapod" rel="noopener noreferrer"&gt;Daniel Terhorst&lt;/a&gt; apresentou uma técnica para juntamente com TDD busca melhorar a qualidade dos nossos produtos, priorizando o foco em comportamento e nunca em processos.&lt;/p&gt;

&lt;p&gt;Essa técnica auxilia no compartilhamento de informações entre membros do time independentemente se for um membro de negócio ou um membro técnico.&lt;/p&gt;

&lt;p&gt;Parte importante da técnica está na escrita nos &lt;strong&gt;Cenários de Teste&lt;/strong&gt;, esses cenários usam a seguinte estrutura base:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Descreve o Contexto em que nosso usuário está&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Descreve o comportamento que nosso usuário irá realizar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Descreve o resultado gerado pelo comportamento do nosso usuário&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Estrutura pode chegar a usar outras palavras chaves como:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;th&gt;Obrigatório&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;Descreve a HST em uma linha&lt;/td&gt;
&lt;td&gt;Não&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cenário&lt;/td&gt;
&lt;td&gt;Descreve cenário em uma linha&lt;/td&gt;
&lt;td&gt;Não&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Descreve o contexto&lt;/td&gt;
&lt;td&gt;Sim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;Detalha o contexto&lt;/td&gt;
&lt;td&gt;Não&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Descreva o &lt;strong&gt;Comportamento&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Sim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entao&lt;/td&gt;
&lt;td&gt;Descreva o resultado&lt;/td&gt;
&lt;td&gt;Sim&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;Detalha o resultado&lt;/td&gt;
&lt;td&gt;Não&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Ideia central
&lt;/h3&gt;

&lt;p&gt;A ideia central e relacionar os critérios de aceite, cenários de teste e testes unitários, dessa forma unindo e ajudando na padronização da comunicação entre os membros do time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo
&lt;/h3&gt;

&lt;p&gt;Vamos imaginar que nosso time é composto por um Product Owner (PO), um Analista de Qualidade (QA) e Desenvolvedores, nesse contexto a PO escreverá os critérios de aceite para que o time possa estimar, e o time, juntamente com o QA vão criar os cenários de teste, tentando montar os cenários em cima de cada critério de aceite descrito pela PO.&lt;/p&gt;

&lt;p&gt;Quando time começa a pensar nos cenários de teste com um "escopo limitado" isso tende a facilitar no planejamento técnico e definição de esforço.&lt;/p&gt;

&lt;p&gt;Em nosso exemplo vamos criar uma história e passaremos pelos seguintes pontos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Critérios de Aceite&lt;/li&gt;
&lt;li&gt;Cenários de Teste&lt;/li&gt;
&lt;li&gt;Teste Unitário&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Criaremos uma história usando o seguinte modelo, QUEM, O QUE e POR QUÊ&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Obs:&lt;/strong&gt; Sempre criar história com base no &lt;strong&gt;PROBLEMA&lt;/strong&gt; e não da Solução.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  História de Usuário
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Eu, enquanto&lt;/strong&gt; Comprador &lt;strong&gt;quero&lt;/strong&gt; utilizar meu cartão de crédito no pagamento dos livros escolhidos &lt;strong&gt;para&lt;/strong&gt; ter praticidade e segurança no pagamento.&lt;/p&gt;




&lt;h4&gt;
  
  
  Critério de Aceite
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Somente podemos aceitar cartões de crédito com bandeiras &lt;strong&gt;VISA&lt;/strong&gt; e &lt;strong&gt;MASTERCARD&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Somente podemos aceitar cartões de crédito com data de expiração no futuro&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  Cenários de Teste
&lt;/h4&gt;

&lt;p&gt;A ideia aqui é relacionar os critérios de aceite com os cenários de teste, para deixar nossa entrega mais simples e focada no que realmente foi solicitado pelo negócio.&lt;/p&gt;

&lt;p&gt;Vamos criar quantos cenários forem necessários para cada critério de aceite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critério de Aceite1&lt;/strong&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Somente podemos aceitar cartões de crédito com bandeiras VISA e MASTERCARD*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;agora vamos montar os cenários de teste focado nesse critério de aceite.&lt;/p&gt;

&lt;p&gt;Cenário 1:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Comprador de Livro utilizando cartão de crédito Visa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Tenta finalizar compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Recebe mensagem de sucesso&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cenário 2:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Comprador de Livro utilizando cartão de crédito diferente de Visa ou Mastercard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Tenta finalizar compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Recebe mensagem de Falha&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cenário 3:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Comprador de Livro utilizando cartão de crédito Mastercard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Tenta finalizar compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Recebe mensagem de sucesso&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;obs:&lt;/strong&gt;&lt;br&gt;
No critério de aceite não referencia nada de saldo, então devemos nos preocupar apenas com o que está no critério de aceite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critério de Aceite2&lt;/strong&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Somente podemos aceitar cartões de crédito com data de expiração no futuro&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cenário 1:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Comprador de Livro utilizando cartão de crédito com expiração 01/01/2020&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Tenta finalizar compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Recebe mensagem de falha&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cenário 2:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Descrição&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dado&lt;/td&gt;
&lt;td&gt;Comprador de Livro utilizando cartão de crédito com expiração 01/01/2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quando&lt;/td&gt;
&lt;td&gt;Tenta finalizar compra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Então&lt;/td&gt;
&lt;td&gt;Recebe mensagem de sucesso&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h3&gt;
  
  
  Teste Unitário
&lt;/h3&gt;

&lt;p&gt;Aqui vamos fazer a última parte do nosso fluxo, escrever os teste unitários, a ideia aqui é escrever um teste unitário para cada cenário de teste definido anteriormente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critério de Aceite 1 | Cenário de Teste 1&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mustAllowPaymentWithCreditCardVisa&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;//create the saleMock&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCardVisa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreditCard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"VISA"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;creditCardVisa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFlag&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

    &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finlizeSale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardVisa&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Critério de Aceite 1 | Cenário de Teste 2&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mustNotAllowPaymentWithCreditCardOtherCreditCard&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;//create the saleMock&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCardHiper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreditCard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finlizeSale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardHiper&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Critério de Aceite 1 | Cenário de Teste 3&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mustAllowPaymentWithCreditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;//create the saleMock&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCardMastercard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreditCard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finlizeSale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Aqui vamos começar a fazer os testes para o Critério de aceite 2&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Critério de Aceite 2 | Cenário de Teste 1&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mustAllowPaymentWithCreditCardValidDate&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;//create the saleMock&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCardMastercard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreditCard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExpirationDate&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isAfter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

    &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finlizeSale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Critério de Aceite 2 | Cenário de Teste 1&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mustNotAllowPaymentWithCreditCardInvalidDate&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;

    &lt;span class="c1"&gt;//create the saleMock&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCardMastercard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleMock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreditCard&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getExpirationDate&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isBefore&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

    &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;saleService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;finlizeSale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCardMastercard&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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

&lt;p&gt;Finalizamos nosso fluxo entregando uma tarefa focada na necessidade de negócio, com qualidade pois os teste unitário estão cobrindo todos os cenários de teste e consequentemente cobrindo os Critérios de aceite definidos por negócio.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/cassunde" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880638%2F0dfe8eec-5940-4695-8ae2-ae0341044d7d.png" alt="cassunde"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/cassunde/reduzindo-acoplamento-2ofm" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Reduzindo acoplamento no desenvolvimento de software&lt;/h2&gt;
      &lt;h3&gt;Mattheus Cassundé ・ Sep 17 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#architecture&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#braziliandevs&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>test</category>
      <category>bdd</category>
    </item>
    <item>
      <title>[Dica rápida de CDI] - Observando o início</title>
      <dc:creator>Mattheus Cassundé</dc:creator>
      <pubDate>Tue, 30 Aug 2022 11:11:00 +0000</pubDate>
      <link>https://dev.to/cassunde/dica-rapida-de-cdi-observando-o-inicio-3cp1</link>
      <guid>https://dev.to/cassunde/dica-rapida-de-cdi-observando-o-inicio-3cp1</guid>
      <description>&lt;p&gt;As vezes precisamos executar alguns comandos quando nossa aplicação é iniciada, portanto quem usa algum framework moderno consegue saber quando sua app subiu e com o CDI não é diferente.&lt;/p&gt;

&lt;p&gt;CDI contém uma funcionalidade de ajuda na implementação do padrão de projeto Observer.&lt;/p&gt;

&lt;p&gt;A Própria especificação usa esse padrão em suas rotinas internas, vamos usar umas dessas chamadas para observarmos quando o CDI for carregado ao levantar o servidor de aplicação, com o código abaixo fica fácil:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ApplicationScoped&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StartSchedule&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Observes&lt;/span&gt; &lt;span class="nd"&gt;@Initialized&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CDI Iniciado"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Observes&lt;/span&gt; &lt;span class="nd"&gt;@Destroyed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CDI Finalizado"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto agora podemos fazer alguma ação pois o contexto do CDI foi levantado e podemos usar todo o seu poder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cuidados
&lt;/h3&gt;

&lt;p&gt;Quando usamos o método acima para observar a inicialização do CDI outros passos da inicialização só iram continuar após a conclusão deste ou seja o uso errado pode atrapalhar a inicialização completa da sua APP.&lt;/p&gt;

&lt;p&gt;Podemos diminuir um pouco esse efeito se colocarmos toda a implementação de negócio para ser executada em outra thread, como no exemplo abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;....&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Observes&lt;/span&gt; &lt;span class="nd"&gt;@Initialized&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationScoped&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;@Override&lt;/span&gt;
            &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
                &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CDI Iniciado"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;CDI é uma poderosa ferramenta para ajudar na produtividade do desenvolvimento de soluções usando JavaEE/&lt;a href="https://jakarta.ee/" rel="noopener noreferrer"&gt;JarkataEE&lt;/a&gt; , essa é apenas uma das diversas funcionalidades que o CDI pode oferecer.&lt;/p&gt;

</description>
      <category>java</category>
      <category>cdi</category>
      <category>javaee</category>
      <category>jakartaee</category>
    </item>
  </channel>
</rss>
