<?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: Pedro Nandi</title>
    <description>The latest articles on DEV Community by Pedro Nandi (@pedronandi).</description>
    <link>https://dev.to/pedronandi</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%2F991626%2Fd53076a4-e15d-4f3b-9461-908a46e0df1a.jpg</url>
      <title>DEV Community: Pedro Nandi</title>
      <link>https://dev.to/pedronandi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pedronandi"/>
    <language>en</language>
    <item>
      <title>Usando helm-secrets e Vals para anonimizar seus dados no deploy!</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Thu, 07 Nov 2024 18:16:24 +0000</pubDate>
      <link>https://dev.to/pedronandi/usando-helm-secrets-e-vals-para-anonimizar-seus-dados-no-deploy-2fme</link>
      <guid>https://dev.to/pedronandi/usando-helm-secrets-e-vals-para-anonimizar-seus-dados-no-deploy-2fme</guid>
      <description>&lt;p&gt;Eai, meu povo! Bão? Aqui, tô bão! Mas faz tempo que não escrevo. Essa semana precisei estudar umas ferramentas para atender uma demanda e pensei que seria bacana compartilhar esse conhecimento!&lt;/p&gt;

&lt;p&gt;Esse texto vai para quem precisa fazer deploy em cluster Kubernetes e utiliza helm charts, no dia-a-dia. Nos values.yml, você possui informações sensíveis como senhas de bancos de dados, de serviços de mensageria, etc? Você anonimiza esses dados, para que eles não fiquem expostos no repositório de controle de versão? Não? Então vem ver como faz de um jeito facinho!&lt;/p&gt;

&lt;p&gt;A seguir, mostrarei como anonimizar dados sensíveis dos helm charts utilizando: &lt;strong&gt;AWS Secrets Manager&lt;/strong&gt;, o plugin &lt;strong&gt;helm-secrets&lt;/strong&gt; e o &lt;strong&gt;Vals&lt;/strong&gt;. Seguinte, imagine que temos que fazer o deploy de um serviço no nosso cluster, com helm charts. No values.yml, temos os dados de acesso ao banco de dados MySQL, e eles estão explícitos. Assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secret:
  spring:
    datasource:
      username: pedro
      password: pedro123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não queremos que todos que tenham acesso ao repositório do projeto, tenham acesso à esses dados assim, tão facilmente. Para isso, decidimos utilizar um cofre de senhas, externo. O AWS Secrets Manager. Porém, precisamos fazer com que, no momento do deploy, o Helm consiga acessar o Secret Manager para buscar as informações. Caso contrário, o deploy nunca vai funcionar.&lt;/p&gt;

&lt;p&gt;Para tal, existem dois caras que nos salvam: O plugin helm-secrets e o Vals. Ambos existem para facilitar a vida de quem usa Helm e precisa lidar com secrets e informações sensíveis. Vamos iniciar instalando o plugin helm-secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm plugin install https://github.com/jkroepke/helm-secrets --version v4.6.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Disclaimer: Todas as versões utilizadas nesse texto são datadas da época em que o mesmo está sendo escrito.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para validar a instalação do helm-secrets, basta digitar no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm plugin list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, para a instalação do Vals, basta seguir esses passos (exclusivamente para Linux):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/helmfile/vals/releases/tag/v0.37.8" rel="noopener noreferrer"&gt;Aqui&lt;/a&gt;, efetuar o download do binário (vals_0.37.8_linux_amd64.tar.gz)&lt;/li&gt;
&lt;li&gt;Descompactar e mover o arquivo &lt;strong&gt;vals&lt;/strong&gt; para &lt;strong&gt;/usr/local/bin&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Conceder permissão de execução à vals: &lt;strong&gt;chmod +x /usr/local/bin/vals&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para validar a instalação do Vals, basta digitar no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vals version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No AWS Secrets Manager, vamos criar as seguintes secrets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;datasource.username : pedro&lt;/li&gt;
&lt;li&gt;datasource.password : pedro123&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos nossos helm charts, precisamos que o arquivo templates/secrets.yml esteja buscando os valores das secrets do nosso arquivo values.yml, assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Secret
metadata:
  name: nosso-secret
data:
  spring.datasource.username: {{ .Values.secret.spring.datasource.username | b64enc }}
  spring.datasource.password: {{ .Values.secret.spring.datasource.password | b64enc }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, no nosso arquivo values.yml, precisamos apontar para as secrets da AWS utilizando a sintaxe disponibilizada pelo Vals. Essa sintaxe está disponível na &lt;a href="https://github.com/helmfile/vals" rel="noopener noreferrer"&gt;documentação&lt;/a&gt; oficial da ferramenta. O values.yml ficará assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secret:
  spring:
    datasource:
      username: ref+awssecrets://datasource.username?region=us-east-2#datasource.username
      password: ref+awssecrets://datasource.password?region=us-east-2#datasource.password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dissecando a sintaxe, temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Termo fixo para integração com AWS Secrets Manager: ref+awssecrets://&lt;/li&gt;
&lt;li&gt;Path para a secret: datasource.username&lt;/li&gt;
&lt;li&gt;Parâmetro indicando a região AWS: ?region=us-east-2&lt;/li&gt;
&lt;li&gt;Apontamento para a key da secret: #datasource.username&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O Vals possui suporte para uma infinidade de secret managers. Agora, com tudo pronto, vamos para o deploy. O Vals precisa de dados de acesso à AWS, para que consiga buscar as secrets ao longo do deploy. Para isso, é necessário que algumas variáveis de ambiente sejam setadas na máquina que realizará o deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export HELM_SECRETS_BACKEND=vals #Faz parta das configurações entre o helm-secrets e o Vals
export AWS_ACCESS_KEY_ID=foo
export AWS_SECRET_ACCESS_KEY=foo
export AWS_SESSION_TOKEN=foo
export AWS_DEFAULT_REGION="us-east-2" #Região AWS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os valores das variáveis referentes à AWS podem ser obtidas no portal de acesso da AWS. O comando para o deploy é o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm secrets install release-name -f values.yaml your-chart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao longo do deploy, o Vals deve informar que conseguiu buscar as secrets da AWS. Ele deve gerar um arquivo temporário contendo os values.yml com as respectivas secrets e, por fim, deve sinalizar que o serviço foi deployado com sucesso!&lt;/p&gt;

&lt;p&gt;Bom, texto rápido e fácil, pra facilitar a vida de todo mundo. Decidi compartilhar, novamente, porque tive dificuldade em reunir toda essa informação através de pesquisas. Encontrei alguns links que me ajudaram muito, mas nada muito claro.&lt;/p&gt;

&lt;p&gt;Através do helm-secrets, também é possível fazer a anonimização dessas informações através de criptografia, sem o uso de um cofre externo. Mas isso, rende um outro texto (que vai vir em breve). A ideia principal é não ter informações sensíveis expostas dentro do repositório de controle de versão do projeto, disponíveis à qualquer um que tiver acesso.&lt;/p&gt;

&lt;p&gt;Aqui, algumas referências e documentações que usei para validar toda essa groselha. Valeu!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.gitguardian.com/how-to-handle-secrets-in-helm/" rel="noopener noreferrer"&gt;https://blog.gitguardian.com/how-to-handle-secrets-in-helm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jkroepke/helm-secrets" rel="noopener noreferrer"&gt;https://github.com/jkroepke/helm-secrets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsops/sops/releases?ref=blog.gitguardian.com" rel="noopener noreferrer"&gt;https://github.com/getsops/sops/releases?ref=blog.gitguardian.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/helmfile/vals" rel="noopener noreferrer"&gt;https://github.com/helmfile/vals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jkroepke/helm-secrets/wiki/Cloud-Integration" rel="noopener noreferrer"&gt;https://github.com/jkroepke/helm-secrets/wiki/Cloud-Integration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>aws</category>
      <category>helm</category>
      <category>vals</category>
    </item>
    <item>
      <title>API simples que gera arquivos de forma assíncrona, com Java e Spring? Aqui tem!</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Fri, 19 Apr 2024 17:48:45 +0000</pubDate>
      <link>https://dev.to/pedronandi/api-simples-que-gera-arquivos-de-forma-assincrona-com-java-e-spring-aqui-tem-6oo</link>
      <guid>https://dev.to/pedronandi/api-simples-que-gera-arquivos-de-forma-assincrona-com-java-e-spring-aqui-tem-6oo</guid>
      <description>&lt;p&gt;E aí, tudo certo?&lt;/p&gt;

&lt;p&gt;Nesse artigo rápido, decidi escrever sobre geração de arquivos assíncronos em APIs, pois vi esse tema sendo debatido no Twitter, onde alguém pediu por alguma forma bacana de contruir uma. Entendi que o tema interessou algumas pessoas e cá estamos.&lt;/p&gt;

&lt;p&gt;Quando falamos sobre uma API responsável por gerar um arquivo (.txt, .csv, etc), as primeiras dúvidas que surgem, geralmente são: Mas a resposta da API vai ser o arquivo? Vai ser um JSON? Se for um JSON, é o front que vai gerar o arquivo? Mas espera... Então a geração vai ser síncrona? Se for, o front vai ter que ficar aguardando? E se o arquivo for gigante? Enfim, many many doubts!&lt;/p&gt;

&lt;p&gt;Vou compartilhar aqui uma estratégia que já usei e gostei, achei simples e dinâmica. Gosto de explicá-la usando a analogia do food truck. Quando você pede um hambúrguer em um food truck, como funciona? Uma das formas é a seguinte:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Você faz o pedido no caixa, paga e recebe uma senha;&lt;/li&gt;
&lt;li&gt;Você fica de olho no painel de senhas e quando chega a sua, vai até a bancada e retira seu hambúrguer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notou que isso é assíncrono? Você não fica no caixa esperando o seu hambúrguer ficar pronto para que o caixa atenda a próxima pessoa. O caixa delega a geração do hambúrguer à alguém para que ele fique livre e atenda o próximo cliente.&lt;/p&gt;

&lt;p&gt;A geração de arquivos através de uma API que eu vou mostrar aqui funciona exatamente da mesma forma. Vamos lá! Primeiramente, eu criei uma API que recebe uma requisição contendo os parâmetros para a geração do arquivo (um intervalo de datas, outros dados relevantes, etc). A única responsabilidade dessa API é responder com um hash, um UUID, ou qualquer código de identificação única. Ou seja, essa API nunca retorna um erro de negócio, sempre retorna um hash, e esse retorno deve ser instantâneo.&lt;/p&gt;

&lt;p&gt;Esse hash é a "senha". Assim, a API já fica livre para antender uma próxima requisição. Aí você pergunta: Tá, mas e o arquivo? Pois bem. A API, antes de retornar o hash na resposta, monta um &lt;strong&gt;evento&lt;/strong&gt; referente à geração do arquivo e publica esse evento através do nosso querido &lt;strong&gt;ApplicationEventPublisher&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspkvn1ww8vj1sqnsnb01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fspkvn1ww8vj1sqnsnb01.png" alt="Image description" width="794" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essa publicação, feita pela API, é capturada por um listener construído especificamente para isso. Esse listener é o responsável por dar seguimento à geração do arquivo. Dessa forma, temos a geração assíncrona. Ou seja, a API monta e publica o evento, logo em seguida devolve o hash como resposta da requisição e encerra seu trabalho. Ela não tem controle sobre quando o listener irá capturar o evento e gerar o arquivo, são processamentos diferentes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2axx8atzx3a5i2zi6bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2axx8atzx3a5i2zi6bd.png" alt="Image description" width="782" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E a pergunta final: Cadê o arquivo? Onde ele vai parar e como o usuário tem acesso a ele? Aqui, eu uso uma tabela de status de geração dos arquivos. Uma tabela simples, no banco de dados, que informa em que pé está a geração requisitada. &lt;/p&gt;

&lt;p&gt;A chave dela é o hash gerado pela API. Antes da geração ser iniciada pelo listener, é inserido um registro referente à essa etapa com o hash e o status "PROCESSING". Caso a geração do arquivo ocorra com sucesso, é possível upar esse arquivo em um servidor, obter um link para download do mesmo e atualizar a tabela pelo hash, trocando o status para "DONE" e adicionando o link para download. Caso ocorra algum erro na geração do arquivo, é possível alterar o status para "ERROR" e adicionar uma descrição do erro que ocorreu. A granularidade desse erro fica a critério de você, querido padawan.&lt;/p&gt;

&lt;p&gt;Por fim, uma boa pedida é ter uma segunda API para consultar o status da geração do arquivo, através do hash, e obter o link de download do mesmo, ou o erro. Não sei se essa é a melhor das melhores estratégias para gerar um arquivo assíncrono, mas veio bem a calhar e trouxe dinamismo à minha aplicação. Espero ter ajudado e até a próxima =)&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>async</category>
      <category>files</category>
    </item>
    <item>
      <title>Vantagens do git commit --amend</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Fri, 21 Jul 2023 00:38:17 +0000</pubDate>
      <link>https://dev.to/pedronandi/vantagens-do-git-commit-amend-1fcm</link>
      <guid>https://dev.to/pedronandi/vantagens-do-git-commit-amend-1fcm</guid>
      <description>&lt;p&gt;Nos últimos tempos, abordei esse tema com algumas pessoas e vi que esse artigo pode servir pra alguém, no futuro. No projeto onde trabalho, os devs decidiram pelo seguinte padrão relacionado ao git:&lt;/p&gt;

&lt;p&gt;Cada pull request (PR) deve ter um único commit. Decidiram isso para facilitar os code reviews. Em pouco tempo, gostei do padrão e decidi adotá-lo até em projetos pessoais. Nesse artigo vou mostrar passo-a-passo como faço:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Criação da branch:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Após rodar um &lt;code&gt;git pull&lt;/code&gt; em cima da branch de develop, eu crio uma branch para o meu desenvolvimento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout -b feature/&amp;lt;card_id&amp;gt;_&amp;lt;card_description&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Criação dos commits:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Após realizar algumas alterações, crio o primeiro commit da branch, com o título:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit -m "&amp;lt;card_id&amp;gt; &amp;lt;commit_title&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A medida que o desenvolvimento avança e julgo necessários novos commits, passo a utiliza o &lt;code&gt;--amend&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git commit --amend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar esse comando, o terminal abre um arquivo texto referente a este commit. Esse arquivo já possui o título do primeiro commit que realizei, na primeira linha. Se eu desejo adicionar mais informação ao commit, eu informo a partir da segunda linha do arquivo. Dessa forma, o commit fica dividido entre título e texto:&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;card_id&amp;gt; &amp;lt;commit_title&amp;gt; #primeira linha (título do commit)
&amp;lt;commit description&amp;gt; #segunda linha em diante (texto)
&amp;lt;commit description&amp;gt;
&amp;lt;commit description&amp;gt;
&amp;lt;commit description&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao terminar de alterar o arquivo, um Ctrl+X salva o commit. Ao término dessa etapa, um &lt;code&gt;git log&lt;/code&gt; vai mostrar apenas um commit referente à branch e assim vou até o final do desenvolvimento. Quando finalizo, posso prosseguir com um &lt;code&gt;git push origin &amp;lt;branch_name&amp;gt;&lt;/code&gt; para criar a branch na ferramenta de versionamento.&lt;/p&gt;

&lt;p&gt;Já na ferramenta (utilizo Github em casa e Bitbucket no trabalho), no momento de abrir o PR, consigo vizualizar o título do commit, o texto com toda a descrição do que foi feito e tudo isso com apenas 1 commit, ao invés de uma lista de commits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bônus 1&lt;/strong&gt;: Quando abro um PR e vejo que tenho algum conflito que precisa ser resolvido (durante meu desenvolvimento, alguém evoluiu a branch de develop e preciso puxar coisas), eu executo um &lt;code&gt;git pull --rebase origin develop&lt;/code&gt;. Dessa forma, o git baixa tudo que a develop da cloud tem que a minha branch (criada com base em uma develop anterior) não tem. Dessa forma, consigo resolver os conflitos (utilizo o VS Code pra isso) e dar um push que normaliza o PR aberto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bônus 2&lt;/strong&gt;: Quando o objetivo é aglutinar muitos commits já realizados dentro de um mesmo PR ou branch, utilizo a técnica de squash, que tá bem explicadinha &lt;a href="https://www.internalpointers.com/post/squash-commits-into-one-git"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Acho essa metodologia de trabalho com o git super tranquila e me evita muitas dores de cabeça. Valeeu!&lt;/p&gt;

</description>
      <category>git</category>
      <category>developer</category>
    </item>
    <item>
      <title>A Fragilidade Sem Ser Frágil</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Tue, 18 Jul 2023 16:20:37 +0000</pubDate>
      <link>https://dev.to/pedronandi/a-fragilidade-sem-ser-fragil-21lo</link>
      <guid>https://dev.to/pedronandi/a-fragilidade-sem-ser-fragil-21lo</guid>
      <description>&lt;p&gt;Eaí, bão?&lt;/p&gt;

&lt;p&gt;Você leu meu outro texto sobre a &lt;a href="https://dev.to/pedronandi/o-objetivo-e-a-mochila-4a7i"&gt;mochila&lt;/a&gt;? Não? Corre lá e lê rapidão que essa groselha aqui tem a ver com aquela lá!&lt;/p&gt;

&lt;p&gt;Recentemente, assisti a maravilhosa Paola Carosella no Podpah #650 e quando perguntada sobre o motivo de ter deixado o MasterChef Brasil, a resposta dela me inspirou a escrever esse texto. Dentro da resposta dela, ela fala que quando está fazendo algo e percebe que aquilo não tem mais nada a agregar, que não a motiva mais, ela encerra o ciclo. Ela diz que ama aprender, ama o sentimento de aprender, ama a sensação de "fragilidade sem ser frágil". E que diabos é isso?&lt;/p&gt;

&lt;p&gt;Quando nos deparamos com algo que não fazemos ideia do que é ou como funciona e precisamos aprender, é natural sentir a fragilidade. Não temos o domínio, estamos vulneráveis em relação àquilo. Mas, ao mesmo tempo, já aprendemos várias outras coisas na vida. A vida é aprender. Chegamos até o presente momento aprendendo e aprendendo. Então, esse algo nada mais é do que mais uma coisa a ser aprendida. Portanto, não somos nada frágeis. É só mais uma coisa. Ou seja, essa é a sensação de fragilidade, sem ser frágil.&lt;/p&gt;

&lt;p&gt;Eu, particularmente, adorei essa síntese. Eu sinto isso também. Lembra quando falei, lá no texto da mochila, que mesmo que não seja possível, no momento, trabalhar com aquilo que desejamos dominar, devemos manter a aprendizagem e a curiosidade vivas?&lt;/p&gt;

&lt;p&gt;Em relação à aprendizagem, entender essa sensação de fragilidade sem ser frágil é um ponto muito importante. Tirar nosso cérebro da inércia, fazê-lo se exercitar, é algo difícil que facilmente perde para qualquer outra coisa. Literalmente. Já viu alguém falar que precisava estudar, mas acabou indo lavar uma louça ou limpando a casa? Pois é, eu não só ouvi como já fui assim em algum momento da vida. &lt;/p&gt;

&lt;p&gt;Nosso cérebro, quando está quieto, tende a querer permanecer quieto. Gasta menos energia, se poupa. Lembre-se disso quando passar por essa situação, racionalize, se organize e meta a mão na massa, nem que seja um pouquinho por vez. Constância vence a empolgação, sempre! E a curiosidade?&lt;/p&gt;

&lt;p&gt;Um vez vi Neil deGrasse Tyson falando sobre sua filha criança, numa entrevista. Ele disse que o que mais o animava era estigar a curiosidade da filha. Responder à ela todos os porquês que ela perguntava, estigar ela a perguntar cada vez mais, estigar ela a experimentar as coisas, a testar, a ver com os próprios olhos os resultados, validar suas pequeninas hipóteses de como o mundo funciona.&lt;/p&gt;

&lt;p&gt;A curiosidade é algo que nasce com a gente. É o que nos move, pois no começo, não sabemos nem temos noção de nada. Sem curiosidade, não passaríamos de amebas. Mas, a medida em que vamos crescendo, aprendendo e entendendo o mundo, tendemos a deixar a curiosidade de lado, como se ela não fosse mais necessária. Aí que mora o perigo.&lt;/p&gt;

&lt;p&gt;A curiosidade, durante toda a nossa vida deve funcionar como o motor que nos faz querer aprender. Afinal de contas, aprender para responder uma pergunta interna é sanar uma dor, a da dúvida. Mas como faço para voltar a sentir curiosidade pelas coisas?&lt;/p&gt;

&lt;p&gt;Talvez o ponto que eu queira chegar aqui é relacionar o fato de entender a si mesmo e encontrar algum propósito profissional. Desse propósito surgem objetivos a serem alcançados. E esses objetivos te exigirão aprender. Se você teve sucesso em entender a si mesmo nisso, o primeiro empurrão da aprendizagem, motivada pelo objetivo planejado, tende a te despertar curiosidade, porque será algo que motiva você. Se não motivar, volte algumas casas.&lt;/p&gt;

&lt;p&gt;Nesse sentido, observamos uma relação de causa e efeito: Aprender gera curiosidade e curiosidade gera vontade de aprender. Zonas de conforto matam a curiosidade e, por consequência a vontade de aprender. O caos, nos força a aprender para voltarmos à tranquilidade. Caos? Sim, estar em busca de algo que te motive, é um certo caos.&lt;/p&gt;

&lt;p&gt;Era isso. Espero ter ajudado e continuo querendo ouvir as opiniões de vocês. Não quero ficar bitolado por apenas esse ponto de vista. É bom ler opiniões diferentes e complementos, exemplos, etc. Valeeu!&lt;/p&gt;

</description>
      <category>career</category>
      <category>developer</category>
    </item>
    <item>
      <title>O Objetivo é a Mochila</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Thu, 13 Jul 2023 14:42:15 +0000</pubDate>
      <link>https://dev.to/pedronandi/o-objetivo-e-a-mochila-4a7i</link>
      <guid>https://dev.to/pedronandi/o-objetivo-e-a-mochila-4a7i</guid>
      <description>&lt;p&gt;Esse é um relato pessoal sobre o que eu aprendi com a minha carreira até aqui, como dev.&lt;/p&gt;

&lt;p&gt;Todo dev carrega uma mochila nas costas, durante o caminho que é a sua carreira. Ela começa vazia. A medida em que vamos caminhando, vamos enchendo ela de conhecimentos e experiências. A medida em que vamos nos deparando com as mais diversas situações, recorremos à nossa mochila para buscar as soluções mais adequadas. Quando a mochila estiver demasiadamente cheia, teremos um repertório tão grande que ficará difícil não termos uma ideia sobre como solucionar algum problema com o qual nos deparamos.&lt;/p&gt;

&lt;p&gt;O objetivo de pensar dessa maneira é fazer com que, lá na frente, uma mochila cheia nos dê segurança para escolher onde e com o que trabalhar, ter um bom salário e uma carreira de sucesso. Mas, para isso, é necessário fugir o tempo todo da zona de conforto.&lt;/p&gt;

&lt;p&gt;Por que eu penso assim? Vamos lá... Faz tempo que eu quero escrever esse artigo sobre a carreira do dev. Nos últimos anos tomei algumas decisões que me fizeram refletir muito sobre minha caminhada profissional e vi que essa experiência toda tinha potencial para ser compartilhada.&lt;/p&gt;

&lt;p&gt;Esse é um texto específico sobre a carreira de desenvolvedor de software. Pode ter coisas aqui que não façam sentido ou se encaixem em outras profissões, e tá tudo certo.&lt;/p&gt;

&lt;p&gt;Comecei minha carreira há muito tempo, em um estágio, há mais de 10 anos. Final de faculdade, primeiro emprego, a vaga era pra dev Oracle PL/SQL. Eu cursei ciência da computação em período integral, então, quando fui para o mercado, não sabia como era. Ciência da computação é um curso muito teórico.&lt;/p&gt;

&lt;p&gt;Minha estratégia na época foi perceber meus novos colegas de trabalho. Notei que aqueles que eram mais valorizados dominavam as regras de negócio. Esses eram deuses. Ninguém se preocupava com stack ou com arquitetura. Era consenso que isso já havia sido escrito em pedra e não iria mudar.&lt;/p&gt;

&lt;p&gt;Foquei crescer naquele ambiente. Por alguns anos, comi regra de negócio com farinha para alçar meu lugar até uma certa estabilidade. Deu certo. Na monotonia, decidi cursar uma pós em engenharia de software, o que eu considero o início da mudança.&lt;/p&gt;

&lt;p&gt;Na pós, conheci pessoas que trabalhavam em outras empresas e entrei em desespero porque as conversas entre eles soavam como grego pra mim. Não conhecia nada das tecnologias que usavam e falavam. Vi que estava estagnado, fiquei triste, perdido.&lt;/p&gt;

&lt;p&gt;Meus sentimentos se explicam porque sempre gostei de tech, sempre gostei de programar. Estar tão para trás me deixou mal. Percebi que meu mundo era só o meu trabalho. Não sabia como era o mundo lá fora.&lt;/p&gt;

&lt;p&gt;Foi então que decidi correr atrás do prejuízo. Fiz cursos, programei, comecei a participar de pequenos eventos da comunidade local de tech. Tudo estava melhorando até que decidi trocar de emprego para trabalhar com stacks mais atuais. A quantidade de negativas que recebi, foi de perder as contas. Os principais motivos: Não ter experiência profissional nas stacks requisitadas e não ter portfólio.&lt;/p&gt;

&lt;p&gt;Foram alguns anos nessa rotina: Dar o meu melhor no trabalho, estudar e participar de processos seletivos por aí. Até que veio a pandemia e a nossa área de tecnologia decolou. Alta demanda, altos salários, muitas vagas, muitas empresas crescendo. Comecei a receber muitas abordagens de recrutadores no Linkedin, até que encontrei uma empresa que topou a parceria comigo.&lt;/p&gt;

&lt;p&gt;Eu entregaria meu conhecimento em PL/SQL e teria a oportunidade de também trabalhar com Java. Pra mim, perfeito! E foi só aí, quando consegui finalmente essa oportunidade, que comecei a refletir sobre toda essa trajetória até então.&lt;/p&gt;

&lt;p&gt;Durante a minha passagem pela empresa onde iniciei estagiário, trabalhei até atingir uma zona de conforto. Minha mochila foi preenchida até um ponto onde eu não tinha mais nada novo para guardar. Tudo que eu tinha nela me era suficiente. Foi quando fui tentar trocar de emprego, que percebi que eu não tinha nada do que era necessário por aí.&lt;/p&gt;

&lt;p&gt;Viu como o processo de encher a mochila é contrário à zona de conforto? Quando me deparo com a expressão "assumir o volante da própria carreira" eu sempre penso que essa visão da mochila é isso. Só você é responsável pela sua própria mochila. Ninguém vai colocar nada nela por você.&lt;/p&gt;

&lt;p&gt;Isso não quer dizer que devemos virar macacos, pulando de galho em galho (empresa em empresa), sugando o que julgamos importante até estarmos satisfeitos. Pode ser, mas não necessariamente. A partir do momento em que você passa a entender a importância de cuidar da própria mochila, você começa a perceber que pode fazer isso de várias maneiras, e com calma.&lt;/p&gt;

&lt;p&gt;Defina objetivos para a sua carreira, observe o que te faz se sentir empolgado o que o mercado oferece. Veja o que você deve correr atrás para aprender e busque uma oportunidade para trabalhar integralmente com aquilo que você quer dominar. É difícil, muitas vezes não é possível, mas não desista. Enquanto tenta, mantenha a aprendizagem e a curiosidade vivas.&lt;/p&gt;

&lt;p&gt;Nessas situações, o "vestir a camisa da empresa" se funde com o famoso "que seja eterno enquanto dure". Faça seu trabalho bem feito, mas se surgir uma oportunidade mais alinhada com os seus objetivos de carreira, siga em frente. Explore as oportunidades. Tente perceber o que a nova empresa pode te oferecer em questão de evolução. É explorando que você vivenciará situações que te darão conhecimentos e experiências novas para você adicionar à sua mochila!&lt;/p&gt;

&lt;p&gt;Percebo que essa visão pode sim nos oferecer um futuro com mochilas bem pesadas. Lá na frente, poder falar que sabe como resolver tal problema porque tem experiência com a ferramenta necessária, ou porque já passou por tal problema semelhante anteriormente, é o objetivo dessa brincadeira toda. É essa segurança que alicerça a carreira bem sucedida.&lt;/p&gt;

&lt;p&gt;Enfim, esse texto foi difícil de escrever porque foi difícil sintetizar tudo isso em um roteiro breve. Espero que tenha contribuído em algo na sua vida e gostaria da sua opinião sobre o assunto! Valeu e até a próxima!&lt;/p&gt;

</description>
      <category>carrer</category>
      <category>developer</category>
    </item>
    <item>
      <title>Spring Container: O que eu considero primordial quando se trata de entender o funcionamento do Spring Framework</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Tue, 04 Jul 2023 14:37:02 +0000</pubDate>
      <link>https://dev.to/pedronandi/spring-container-o-que-eu-considero-primordial-quando-se-trata-de-entender-o-funcionamento-do-spring-framework-4ea4</link>
      <guid>https://dev.to/pedronandi/spring-container-o-que-eu-considero-primordial-quando-se-trata-de-entender-o-funcionamento-do-spring-framework-4ea4</guid>
      <description>&lt;p&gt;Você estuda ou trabalha com Java? Usa o Spring Framework? Você entende como o Spring funciona e como ele faz para conectar tudo por trás dos panos? Caso você entenda, talvez esse artigo não te traga nenhuma novidade. Mesmo assim, você pode usá-lo para relembrar algumas coisas e até para me corrigir, caso eu tenha escrito alguma bobagem.&lt;/p&gt;

&lt;p&gt;Decidi escrever esse artigo porque notei que muita gente utiliza o Spring e não entende muito bem como ele funciona. Ou até entende, porém aprendeu lendo aqui e ali e levou tempo até que as coisas fizessem sentido. É difícil achar algo mais compilado que agrupe explicações e conceitos que se relacionam e sejam tão importantes.&lt;/p&gt;

&lt;p&gt;Pontuado isso, seguimos! O que você lembra ou sabe sobre orientação à objetos em Java? Se você sabe diferenciar uma classe de um objeto, entende o que é e como funciona herança,  polimorfismo e interfaces, ótimo! Sensacional! Se você não sabe, sugiro que procure entender cada uma dessas coisas antes de continuar essa leitura. Porém, decidi começar esse artigo com uma breve revisão sobre o que é e como funciona o polimorfismo. Pois acho um conceito fundamental para entendermos tudo que vem pela frente.&lt;/p&gt;

&lt;p&gt;O que é o polimorfismo dentro da orientação à objetos? Vamos logo com exemplos: Imagine que temos uma aplicação qualquer que cadastra um novo cliente, inicialmente inativo. Após o cadastro é possível ativá-lo e essa ativação dispara uma notificação via e-mail. Uma implementação básica para isso seria a seguinte:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1SzaGWJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esdta3d7eh4ghqfqwh4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1SzaGWJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esdta3d7eh4ghqfqwh4y.png" alt="Image description" width="700" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Funcionalidade entrege, bacana. Agora, o cenário mudou e o cliente precisa ser notificado via SMS, após a ativação. O que você faria? Refatoraria o código trocando a NotificacaoEmail por uma NotificacaoSMS? Ok. Mas e se depois tiver que mudar novamente? Ficaremos reféns disso? Complicado, concorda?&lt;/p&gt;

&lt;p&gt;Aí entra o poderoso uso do polimorfismo através das interfaces. Explico melhor... Imagine que criamos uma interface chamada Notificacao com a declaração de um método notificar(). Toda classe que implementar essa interface será obrigada a fornecer uma implementação deste método. Dito isso, imagine que nossas classes NotificacaoEmail e NotificacaoSMS passem a implementar essa interface. Isso ficaria assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7jTDMtwV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7y02wqedzts45csuci0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7jTDMtwV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7y02wqedzts45csuci0.png" alt="Image description" width="340" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5vryITvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7lmj6og7s1wo079knhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5vryITvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7lmj6og7s1wo079knhp.png" alt="Image description" width="608" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, nossa classe Cliente não precisa mais ter de forma imperativa qual o tipo de notificação a ser utilizada. Cliente pode, simplesmente, possuir um atributo do tipo Notificacao que vai chamar o método notificar():&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SBdmF6mJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7g1uyrztrafluroka8x7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SBdmF6mJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7g1uyrztrafluroka8x7.png" alt="Image description" width="784" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dessa forma, Cliente passa a ser agnóstica quanto ao tipo de notificação a ser utilizada. Quem instancia um objeto cliente poderá decidir qual o tipo de notificação lhe convém:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cliente pedro = new Cliente('Pedro', '123', false, notificacaoSMS);

Cliente joao = new Cliente('João', '456', false, notificacaoEmail);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Através desse exemplo simples, eu consigo trazer aqui 3 conceitos básicos: Polimorfismo, injeção de dependência e inversão de controle. Vamos com calma, um por um:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Polimorfismo&lt;/strong&gt;: Quando uma ou mais classes implementam uma mesma interface, a interface passa a representar a classe. Quando um método tem como parâmetro de entrada uma interface, qualquer objeto de classe que implementa a mesma pode ser passado como sendo esse parâmetro. No exemplo, como declaramos um atributo Notificacao na classe Cliente, o método construtor do Cliente passa a receber uma Notificacao como parâmetro. Ou seja, nos permitindo informar tanto NotificacaoSMS quanto NotificacaoEmail;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Injeção de dependência&lt;/strong&gt;: No exemplo, Cliente passa a ter uma Notificacao como dependência. Ou seja, se na construção de um objeto Cliente não for informada uma forma de notificação, Cliente não poderá ser instanciado. Como essa dependência está vindo via construtor, dizemos que ela está sendo injetada. Ou seja, está ocorrendo uma injeção da dependência;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inversão de controle (IoC)&lt;/strong&gt;: Notificacao é uma dependência do Cliente. Nos nossos primeiros exemplos, Cliente instanciava um NotificacaoEmail. Ou seja, Cliente tinha controle sobre qual o tipo de notificação estava usando. Era via e-mail. Quando passamos a usar o polimorfismo através da interface Notificacao, observamos a classe Cliente e vemos que não tem mais como saber qual o tipo de notificação a mesma utiliza. Agora, depende de quem instancia um cliente. Ou seja, Cliente perdeu o controle sobre o tipo de notificação. Esse controle agora pertence a quem instancia. Ou seja, houve uma inversão de controle da dependência.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note que esses 3 conceitos são amarrados. Não tem como falar de um sem falar dos outros dois. Para que exista inversão de controle, tem que haver injeção de dependência e isso só ocorre, de forma efetiva, via polimorfismo. Como diz um caro colega: Não é magia, é tecnologia.&lt;/p&gt;

&lt;p&gt;E que diabos o Spring tem a ver com isso??&lt;/p&gt;

&lt;p&gt;O coração do Spring funciona através de inversão de controle e injeção de dependências, meu caro. Quando subimos uma aplicação Spring, uma das primeiras etapas executadas pelo framework é a chamada &lt;strong&gt;Component Scanning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O Spring busca todos os beans que deve gerenciar a partir da classe anotada com @SpringBootApplication. Pera, o que significa tudo isso?&lt;/p&gt;

&lt;p&gt;Quando o Spring inicia, ele instancia uma penca de objetos dentro da aplicação. Objetos de todo o tipo que vão auxiliar o spring a ter acesso a informações que ele precisa pra funcionar e se localizar. Esses objetos são chamados de beans. Esses beans podem ser de todas as formas e existem várias anotações dentro do Spring que evidenciam se uma classe vai gerar um bean. Exemplos: @Bean, @Component, @Controller, @Service, @Repository, @Entity, @Configuration... Tudo exemplo de bean.&lt;/p&gt;

&lt;p&gt;Geralmente, a classe que inicia a aplicação, aquela que possui o método main(), é anotada com @SpringBootApplication. Ou seja, quando essa classe executa, o Spring incia o processo de component scanning, buscando todas as classes que possuem anotações que representam beans. Ele instancia objetos de todas essas classes antes de começar a executar a aplicação propriamente dita.&lt;/p&gt;

&lt;p&gt;Aqueles beans que não possuem dependências, ou seja, que não possuem parâmetros no construtor, o Spring sobe com tranquilidade. Quando um bean que precisa subir depende de receber parâmetros via construtor, é necessário que seja implementada uma classe com @Configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H9WdkoKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkc375y8swfjenostjmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H9WdkoKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkc375y8swfjenostjmi.png" alt="Image description" width="634" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8CDhLy4g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0x9klpmrlzlwt7w37ebs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8CDhLy4g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0x9klpmrlzlwt7w37ebs.png" alt="Image description" width="543" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No exemplo acima, o Spring entende que NotificacaoSMS será instanciada a partir do método notificacaoSMS da NotificacaoSMSConfig. Sendo assim, a classe NotificacaoSMS não precisará mais de @Component. &lt;/p&gt;

&lt;p&gt;Quando uma classe possui mais de um método construtor, usamos o @Autowired para informar ao Spring qual é o construtor que deve ser utilizado para instanciar a classe. Curiosidade: @Autowired(required = false) torna a dependência (a ser injetada), opcional. Ou seja, se ela não for instanciada, não ocorrerá NullPointerException.&lt;/p&gt;

&lt;p&gt;O objetivo desse texto foi tentar mostrar que o Spring só consegue performar o component scanning por conta do uso daqueles três conceitos: Polimorfismo, injeção de dependência e inversão de controle. É comum ler em vários lugares que o Spring utiliza muito IoC, mas não é tão comum ler como isso funciona na prática. O component scanning é uma das primeiras etapas executadas pelo Spring ao ser iniciado e é a base para que o Spring tenha controle e noção do que precisa fazer e de onde cada parte da aplicação está localizada e como se relaciona. É parte importante do famoso "por trás dos panos".&lt;/p&gt;

&lt;p&gt;Espero ter ajudado com essa minha explicação fajuta e pretendo voltar com mais textos continuando esse assunto. Podemos falar de ambiguidade de beans, nesse processo, quem sabe. Valeu!&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>springboot</category>
      <category>ioc</category>
    </item>
    <item>
      <title>Subindo Keycloak 20.0.2 via docker-compose</title>
      <dc:creator>Pedro Nandi</dc:creator>
      <pubDate>Sun, 21 May 2023 18:48:00 +0000</pubDate>
      <link>https://dev.to/pedronandi/subindo-keycloak-2002-via-docker-compose-2o4f</link>
      <guid>https://dev.to/pedronandi/subindo-keycloak-2002-via-docker-compose-2o4f</guid>
      <description>&lt;p&gt;Pois bem! Recentemente, precisei subir um server Keycloak na versão 20.0.2 via docker-compose para assegurar autenticação e autorização das APIs da minha aplicação. Notei que tive muita dificuldade em encontrar exemplos concretos na web, na forma que eu precisava. Levei alguns dias até entender tudo e conseguir fazer o que eu queria. Visto isso, decidi que, ao término da tarefa, eu escreveria um artigo descrevendo como fazer o que eu fiz com o intuito de ajudar os próximos caros colegas que precisem de uma ajuda. Vamos lá!&lt;/p&gt;

&lt;p&gt;Inicialmente, deixo aqui dois links que me ajudaram a enteder o que é para que serve o Keycloak. O Keycloack é um servidor de autorização que funciona em cima da especificação do OAuth2, porém que também é capaz de performar autorizações através do protocolo OpenID. Ele provê toda uma estrutura em cima dessas duas principais funções que facilitam demais a vida de quem precisa implementar esses serviços em suas aplicações. O Keycloak provê, por exemplo: Cadastro e gerenciamento de múltiplos realms (que são conjuntos isolados de configurações possíveis e provê multi tenancy ao Keycloak), cadastro e gerenciamento de clients (que representam usuários ou aplicações terceiras que desejam acessar a sua), de roles, e muito mais coisas.&lt;/p&gt;

&lt;p&gt;O primeiro link é um resumão sobre Keycloak feito pelo Wesley, da Full Cycle: &lt;a href="https://www.youtube.com/watch?v=82GIvH0qkJ4"&gt;Aqui!&lt;/a&gt;&lt;br&gt;
O segundo link é um tutorial sobre como integrar o Keycloak com uma aplicação Java feita com Spring feito pelo Pedro, do canal Java Para Iniciantes: &lt;a href="https://www.youtube.com/watch?v=x-6kEIL0RsU"&gt;Aqui!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beleza... Visto isso, acho importante dar um contexto sobre as mudanças que o Keycloak sofreu entre as versões 15 e 20 (não sei dizer especificamente em qual foi). A imagem do Keycloak 15.0.2 era disponibilizada pela JBoss e rodava em cima de Wildfly. A versão 20.0.2 está sendo disponibilizada pela Red Hat e roda em cima do Quarkus. Isso faz uma diferença tremenda na montagem do container via docker-compose. Até as variáveis de ambiente mudam. O Keycloak 20.0.2 inicia através da execução de um script chamado kc.sh. Vamos ao exemplo do container e na sequência eu explico o que é o quê:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; keycloak:
    image: quay.io/keycloak/keycloak:20.0.2
    environment:
      KC_HOSTNAME: localhost
      KC_HOSTNAME_PORT: 7080
      KC_HOSTNAME_STRICT_BACKCHANNEL: "true"
      KC_DB: mysql
      KC_DB_URL: jdbc:mysql://mysqldev:3306/meu_schema?createDatabaseIfNotExist=true&amp;amp;characterEncoding=UTF-8&amp;amp;rewriteBatchedStatements=true&amp;amp;enabledTLSProtocols=TLSv1,TLSv1.1,TLSv1.2
      KC_DB_USERNAME: root
      KC_DB_PASSWORD: root
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
      KC_HEALTH_ENABLED: "true"
      KC_LOG_LEVEL: info
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:7080/health/ready" ]
      interval: 15s
      timeout: 2s
      retries: 15
    command:
      [ "start-dev", "--http-port 7080", "--https-port 7443", "--import-realm" ]
    volumes:
      - ../keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json
    ports:
      - 7080:7080
      - 7443:7443
    depends_on:
      - mysqldev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos por partes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A imagem que estou utilizando é a oficial do Keycloak 20.0.2: quay.io/keycloak/keycloak:20.0.2&lt;/li&gt;
&lt;li&gt;Estou informando que meu servidor vai estar rodando em localhost:7080&lt;/li&gt;
&lt;li&gt;Estou informando que este server Keycloak vai estar consumindo um banco MySQL e informo o endereço do mesmo através da variável KC_DB_URL. Inclusive, no endereço, informo que o schema a ser usado, no banco, é o meu_schema. E se o mesmo não existir, deve ser criado automaticamente&lt;/li&gt;
&lt;li&gt;Informo login e senha do banco (root/root)&lt;/li&gt;
&lt;li&gt;Informo login e senha do console de administração do Keycloak (admin/admin)&lt;/li&gt;
&lt;li&gt;Configuro um endpoint de healthcheck (opcional)&lt;/li&gt;
&lt;li&gt;Em "command" devem ser informados os parâmetros que serão passados para a execução do script kc.sh:

&lt;ol&gt;
&lt;li&gt;"start-dev" é obrigatório ser passado para a execução do script. Porém, é um parâmetro que denota restritamente o ambiente de desenvolvimento. Se fosse produção, seria outro valor. Ex: "start"&lt;/li&gt;
&lt;li&gt;Informo que via HTTP o servidor estará disponível na 7080 e via HTTPS, na 7443&lt;/li&gt;
&lt;li&gt;"--import-realm" é um parâmetro que informa que um arquivo de pré-configuração deverá ser importado pelo Keycloak, na subida do servidor. Esse parâmetro tentará importar todos os arquivos .json que obedeçam a sintaxe esperada pelo Keycloak e que estejam na pasta /opt/keycloak/data/import&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Mapeio um volume para copiar o arquivo realm-export.json para dentro do container. Dessa forma, esse arquivo será importado conforme mencionei. Esse arquivo já cria realm, clients e roles específicas para mim&lt;/li&gt;
&lt;li&gt;Informo as portas internas e externas do container&lt;/li&gt;
&lt;li&gt;Informo que esse container do Keycloak depende de um outro container meu, de MySQL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dessa forma, com a execução do arquivo docker-compose (docker-compose up), teremos um container de Keycloak 20.0.2 rodando tranquilamente. Você poderá acessar o console do Keycloak através do endereço &lt;a href="http://localhost:7080/admin"&gt;http://localhost:7080/admin&lt;/a&gt;. Nesse momento, será exibida uma mensagem "HTTPS is required". Isso porque o primeiro acesso ao console é através do realm "master", que é um realm do próprio Keycloak e o mesmo exige HTTPS. Para contornar essa situação, basta acessar o banco e dar um update na tabela REALM, trocando essa informação de SSL EXTERNAL para NONE.&lt;br&gt;
Com isso, basta reiniciar o Keycloak e tudo deve funcionar normalmente. Bom, espero ter ajudado e ter sido sucinto. Este é o meu primeiro artigo aqui no dev.to. Obrigado por ler :)&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>docker</category>
      <category>dockercompose</category>
      <category>oauth2</category>
    </item>
  </channel>
</rss>
