<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Dev On Track!</title><link>https://blog.devontrack.com/pt-br/posts/</link><description>Recent content in Posts on Dev On Track!</description><generator>Hugo -- gohugo.io</generator><language>pt-br</language><lastBuildDate>Sat, 10 Oct 2026 22:28:34 -0300</lastBuildDate><atom:link href="https://blog.devontrack.com/pt-br/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>E era um escritor que não sabia escrever</title><link>https://blog.devontrack.com/pt-br/posts/2025-06-11-escritor-nao-sabia-escrever/</link><pubDate>Sun, 11 May 2025 22:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2025-06-11-escritor-nao-sabia-escrever/</guid><description>&lt;p>&lt;em>O conto que você lê abaixo foi escrito por mim em 2014, para um concurso da faculdade. Infelizmente eu não ganhei nada, só a lembrança de me divertir muito escrevendo hahaah&lt;/em>&lt;/p>
&lt;hr>
&lt;blockquote>
&lt;p>E era um escritor que não sabia escrever.&lt;/p>&lt;/blockquote>
&lt;p>Simplesmente, um belo dia, acordou, como sempre fazia, lavou o rosto e se olhou no espelho, contemplando as persistentes olheiras que estavam entalhadas feito mármore em seu rosto.&lt;/p>
&lt;p>Era um homem relativamente jovem. Seus olhos acompanharam sua fisionomia, passando pelos seus cabelos desgrenhados, seus olhos escuros e seu nariz reto. Parou em seu queixo quadrado.&lt;/p>
&lt;p>É, até que tenho um queixinho bonitinho, pensou.&lt;/p>
&lt;p>Isso lhe deu motivos suficientes para acreditar que o dia seria ótimo. Afinal, não são muitas pessoas que tem o queixo charmoso, ou ao menos era isso que ele pensava. Deu um sorriso forçoso para si mesmo refletido no espelho, como que para reafirmar o pensamento mentalmente. Enxugou o rosto e foi se vestir. Abriu o guarda roupa e se arrependeu logo em seguida, pelo monte de roupas que caiu a seus pés. Pegou a primeira camiseta que estava menos amassada em sua frente.&lt;/p>
&lt;p>Foi até a cafeteira, colocou água, o pó do café, ligou e esperou ansiosamente, tamborilando os dedos na bancada. Tentou assoviar, mas soou estupidamente deprimente. Realmente não estava se sentindo tão contente assim. Cruzou os braços e pensou no que faria naquele dia. Não haveria nada de novo, provavelmente. A busca por algo em sua agenda mental demorou tempo suficiente para o café preencher a pequena garrafa. E ainda assim, nenhuma ideia.&lt;/p>
&lt;p>Suspirou e pegou a garrafa. Procurou sua xícara favorita, aquela que tinha desenhos de pequenos pássaros pretos que voavam sobre uma grama preta e branca, em direção a um por do sol, porém como não estava em seu armário de costume, se dirigiu até a bagunça de louças na pia e procurou até encontrá-la. Lavou rapidamente e serviu seu café. Sentou-se a mesa olhando a xícara. Olhando a fumaça quente sair do café, produzindo aquele efeito de imagem tão bonito que ele tanto gostava.&lt;/p>
&lt;p>Observou a xícara até o café esfriar. E depois, sem perceber, continuou pelo menos quinze minutos ali, estático, com os pensamentos girando em espiral, tal como o vapor do café, como fazia todos os dias. Pensou sobre os pássaros, será que eles possuíam algum objetivo ao voar? Será que eles voavam com algum destino pré-definido, ou simplesmente aproveitavam a sorte de planar nos ares para fazê-lo sem pensar muito, apenas pelo prazer do ato?&lt;/p>
&lt;p>Ele, por breve instantes, desejou ser um daqueles pássaros.
Sorveu o café ainda pensando em tudo aquilo. Estava terrível, sem açúcar. Mas o autor se sentia desanimado demais para se levantar e pegar, de modo que tomou daquela maneira mesmo. Passou as mãos pelo rosto pesarosamente e se levantou, passando pelo calendário pregado ao lado da janela. Voltou de costas e parou de frente ao papel que denotava seus febris e escassos compromissos.&lt;/p>
&lt;p>Havia um post it, de berrante tom alaranjado, fixado na data que ele demorou a reconhecer como sendo o dia seguinte. Nele estava escrito palavras que fizeram seu estômago revirar. “Entrega do tema do livro”. Ele encostou-se à bancada para não cair. &lt;em>Um dia?&lt;/em> Como havia deixado aquilo acontecer?&lt;/p>
&lt;p>Correu de encontro ao seu computador. Havia cabos enrolados se esgueirando para fora da mesa por todo o chão, tal como cipós na floresta tropical, fazendo-o usar toda sua agilidade e perspicácia para não se enroscar e levar ele mesmo e o pobre computador para o chão.&lt;/p>
&lt;p>Sentou na cadeira, estafado pela ansiedade, e pressionou o botão “Power” do computador. A luz de LED acendeu, e ele encarou ansiosamente como se isso ajudasse o computador a se ligar mais rápido. A tela se acendeu e ele desviou o olhar rapidamente, como se estivesse acompanhando um interessantíssimo jogo de ping pong,
ou talvez de tênis, entre o monitor e o gabinete. Seu computador, que era uma relíquia dos anos 2000, gemeu em protesto – e como que para testar a paciência do autor, ele demorou mais do que o de costume a ligar. O homem se pegou tamborilando os dedos novamente na mesa, dessa vez com maior velocidade.&lt;/p>
&lt;p>A tela apresentou sua área de trabalho. Ele gemeu de alivio. Pegou o mouse e abriu seus documentos. Ali estava, o arquivo escrito “Sem título”. Clicou duas vezes com uma impaciência feroz e o arquivo demorou quase trinta segundos para se abrir. Isso o fez passar as mãos no rosto quase como que para arrancar os olhos, tamanha impaciência. Quando a página finalmente se abriu, ele apertou os olhos ao contemplar a página brilhante, que continha vitoriosamente em seu topo os seguintes dizeres: “E era uma vez…”. No resto da página, havia um branco de uma pureza que ao entrar na retina do homem estranhamente se transformou em terror puro. A gota de suor que escorreu em sua têmpora parecia rir de sua cara naquele momento.&lt;/p>
&lt;p>Ele fechou a página. Não era possível. Ele se lembrava de ter escrito vinte ou doze páginas, no mínimo. Era algo com o número dois, tinha certeza absoluta. Talvez fosse seu computador que estava com problemas, talvez se ele atualizasse a pasta e
abrisse de novo…&lt;/p>
&lt;p>E abriu. E durante os trinta segundos de espera, fechou seus olhos com força. Respirou fundo. Contou até trinta. Abriu de novo para encarar o inocente “E era uma vez” ali, acenando para sua burrice. Mas, como aquilo acontecera? A resposta veio como um estalo. O autor recordou-se de estar escrevendo um conto de terror. Havia realmente duas páginas, somente duas. E ele estava discutindo com seu íntimo sobre a chatice de contos de terror e como são fáceis de serem feitos. Basta colocar um fantasma pulando na cara do protagonista e gritando “Buuu” e pronto, estrago feito. Pessoas assustadas com sucesso. Mas detestava esses clichês que, ao escrever, o encaravam e zombavam de seu talento, que, aliás, era impressivo. Mas e aquelas palavras naquela página? Um conto infantil, sério? E onde estava a genialidade que despertaria sentimentos de espanto e profunda admiração nos críticos? Mal podia acreditar. Ele devia estar fora de si quando fez aquilo. Um dia apenas. Ele conseguiria fazer isso. Só precisava entregar no máximo cinco páginas para a editora dar sinal verde para ele continuar escrevendo.&lt;/p>
&lt;p>Estalou os dedos e pegou a garrafa de café, servindo mais da bebida já fria na xícara de pássaros. Os pássaros pareciam acenar pra ele, que resistiu ao impulso de perder tempo observando a xícara novamente, tomando o café quase todo de uma vez ainda sem o açúcar. Em compensação, ficou olhando a página em branco por quase três horas.&lt;/p>
&lt;p>Ok, a situação estava ficando preocupante.&lt;/p>
&lt;p>Respirou fundo novamente e resolveu ir lá fora, tomar um ar. Era assim que as ideias interessantes surgiam, não é? Tentou abrir a porta, mas o bocado de papeis embaixo do carpete dificultou a tarefa. Uma rápida olhada o fez empurrar o monte embolorado, que identificou brevemente como sendo contas, para longe. Quando abriu a porta, a claridade do dia quase o cegou. Se o mundo lá fora costumava ser tão claro assim ele não saberia, com as horas do dia dedicadas em ficar em casa e sair somente à noite.&lt;/p>
&lt;p>Resolveu dar uma volta pelo quarteirão e buscar elementos simples para compor sua narrativa. Olhou um cachorro correndo pela calçada. História sobre um cachorro? Um cachorro falante que discutia política na TV. Ele poderia até ter bigode. Ah não, péssima ideia. Viu um menino correndo e brincando com uma imaginária espada de aço, na realidade feita de madeira. Uma história de heróis, onde eles lutavam na Era Medieval e eram fortes e musculosos. Não, isso é muito raso e fácil. Ele amava um desafio. Ou ao menos quando conseguia fazê-lo.&lt;/p>
&lt;p>E então, subitamente, o autor começou a correr. Não sabia definir o motivo, talvez fosse o desespero falando mais alto. Ele desejou fugir das responsabilidades de ser adulto, ter bagunça no guarda roupa e contas sob o carpete. Correu e correu, até ficar ofegante. Isso aconteceu no fim do quarteirão.
Olhou para trás e viu sua casa a quase 30 metros de distância. Arfando, quase se arrastou de volta para dentro. Iria escrever sobre os pássaros, estava decidido.&lt;/p>
&lt;p>Sentou na frente do computador e começou a digitar, digitou furiosamente, conectando as frases como peças de um incrível quebra cabeça, e continuou digitando até se dar por conta que aquilo estava terrível, e segurando o botão de apagar jogou fora mais quatro horas de trabalho.&lt;/p>
&lt;p>Ele ficou ainda mais desesperado. Olhou para o relógio, sentindo a pressão surda e esmagadora do prazo se esgotando esgueirando-se sobre seus ombros. Levantou-se, lavou o rosto e ao se olhar no espelho não achou seu queixo tão bonitinho assim. Tomou um banho que mal demorou cinco minutos, e praticamente correu até o guarda-roupa. Jogou todas as roupas no chão e começou a dobrá-las, procurando sua camiseta da sorte que possuía a foto de um golfinho. Passou na cozinha e lavou as louças em uma velocidade absurda, refletindo o nervosismo que o atormentava. A aquela altura, a fome também o atormentava. Esquentou coisas indefinidas que moravam em sua geladeira e mastigou impetuosamente, pensando no infortúnio de ser um terrível escritor, com um talento incrível.&lt;/p>
&lt;p>Soou como um tiro. Um estalo em sua mente. Foi como se aparecesse um arco-íris em um céu nublado, como se fosse a luz no fim do túnel, como se ele fosse cego e visse a mais bela flor em sua frente, apenas esperando para ser cheirada. Tropeçou até a mesa novamente, porém, dessa vez sentou-se com a maior calma desse mundo. Agora, ele tinha absoluta certeza que daria certo. Abriu uma nova página, fechou os olhos por trinta segundos, pensando na salvação que sua ideia carregava. Ao abrir os olhos, lá estava a página: branca, imaculada, esperando que ele a preenchesse com todo o seu inenarrável talento.&lt;/p>
&lt;p>Digitou a frase no topo da página, lentamente, letra por letra, apreciando o sabor da vitória:&lt;/p>
&lt;blockquote>
&lt;p>“E era um escritor que não sabia escrever.”&lt;/p>&lt;/blockquote></description></item><item><title>Migrando blog estático do Jekyll para o Hugo</title><link>https://blog.devontrack.com/pt-br/posts/2025-06-06-migrating-jekyll-hugo/</link><pubDate>Tue, 06 May 2025 22:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2025-06-06-migrating-jekyll-hugo/</guid><description>&lt;p>Quando pensei em criar esse blog, um dos pré-requisitos era ter agilidade e facilidade com o setup. Eu queria focar no que realmente importava: escrever. E nada melhor do que escrever em markdown, que é minha linguagem de markup favorita! Adoro a facilidade em ler, a simplicidade em formatar o texto e a leveza do formato.
Com isso em mente, procurei algumas alternativas para colocar meu blog no ar.&lt;/p>
&lt;h2 id="jekyll-vem-para-o-resgate">&lt;a href="#jekyll-vem-para-o-resgate" class="header-anchor">&lt;/a>Jekyll vem para o resgate!
&lt;/h2>&lt;p>Em minhas pesquisas notei que o pessoal gostava muito de usar &lt;a class="link" href="https://en.wikipedia.org/wiki/Jekyll_%28software%29" target="_blank" rel="noopener"
>Jekyll&lt;/a>. O Jekyll, que é escrito em Ruby, inclusive é a engine por trás do Github Pages - que inclusive era um dos caminhos iniciais que eu estava buscando para publicar meu conteúdo. No geral, Jekyll pareceu bem popular e encontrei diversos exemplos e templates já criados para criar meu próprio blog.
Ao configurar a primeira versão do blog, não tive grandes dificuldades. Confesso que a parte mais complicada foi me adaptar com &lt;a class="link" href="https://shopify.github.io/liquid/" target="_blank" rel="noopener"
>liquid&lt;/a>, que é a engine de templates usada pelo Jekyll. Liquid usa uma combinação de objetos, tags e filtros para controlar o conteúdo que será mostrado.
Então, por exemplo, a minha página padrão do blog era um arquivo chamado &lt;code>default.html&lt;/code>com o seguinte conteúdo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>---
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>layout: default
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>permalink: /404.html
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>---
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&amp;lt;!DOCTYPE html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">html&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% include head.html %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">body&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% include header.html %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;page-content&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {{ content }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% include footer.html %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">body&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">html&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Na prática, é aquele tipo de configuração que não é feita múltiplas vezes: configurou uma vez, o dinamismo da ferramenta te possibilita não precisar realizar mais ajustes no template. Com isso, o restante da configuração geral do blog foi bem tranquila, e a medida que eu ia escrevendo novos posts me preocupava somente com o texto em si - ainda mais considerando a engenhosidade de &lt;a class="link" href="https://github.com/actions/jekyll-build-pages" target="_blank" rel="noopener"
>buildar e fazer deploy utilizando o github actions&lt;/a> ⚡️&lt;/p>
&lt;h2 id="algum-tempo-depois">&lt;a href="#algum-tempo-depois" class="header-anchor">&lt;/a>Algum tempo depois&amp;hellip;
&lt;/h2>&lt;p>Com o passar do tempo, percebi algumas peculiaridades do Jekyll. Uma delas foi a incompatibilidade que enfrentei com o Ruby: Lembro que atualizei a versão do Ruby na minha máquina para outro projeto e acabei quebrando o funcionamento do Jekyll local.
Depois de muita pesquisa vi que ocorreu um certo drama com o fato que a principal &lt;em>gem&lt;/em> que sincroniza com o Github Pages &lt;a class="link" href="https://github.com/github/pages-gem/issues/651" target="_blank" rel="noopener"
>não tinha planos de dar suporte para o Jekyll 4&lt;/a>. 👀
Outro ponto que não me agradou foi o quão custoso era instalar o ambiente em Ruby, além do estilo de gerenciamento de dependências que o Jekyll fazia - algo que me soava desnecessariamente complicado.&lt;/p>
&lt;p>Fiquei um bom tempo sem postar - &lt;em>life happens!&lt;/em> 🥸 - mas recebi um lindo incentivo em formato de conta bem salgada para pagar com o valor desse domínio. Fiquei com preguiça em voltar pro Jekyll considerando todos os pontos anteriores, então&amp;hellip;&lt;/p>
&lt;h2 id="hora-de-fazer-a-reforma">&lt;a href="#hora-de-fazer-a-reforma" class="header-anchor">&lt;/a>Hora de fazer a reforma!
&lt;/h2>&lt;p>Pesquisei sobre novos frameworks e encontrei o Hugo - que afirma ser o &lt;a class="link" href="https://gohugo.io/" target="_blank" rel="noopener"
>&amp;ldquo;framework mais rápido do mundo para construção de sites&amp;rdquo;&lt;/a>. Li a documentação e me pareceu bem simples, e ao mesmo tempo, bem similar com o que eu já havia me acostumado com o Jekyll. O Hugo é open source e escrito em Go (&lt;a class="link" href="https://blog.devontrack.com/pt-br/posts/2024-02-25-learning-go-tdd/" target="_blank" rel="noopener"
>que eu até aprendi recentemente&lt;/a>), e promete bastante flexibilidade na criação de conteúdo.&lt;/p>
&lt;p>Então, com muita coragem no coração, decidi encarar a migração. Usei a estratégia de criar uma nova pasta e configurar o novo projeto Hugo do zero, adicionando as funcionalidades que eu mais queria uma por uma. Escolhi um novo tema, configurei e fiz pequenos ajustes até ficar do meu agrado, depois fui adicionando minhas páginas com os posts quase que uma a uma. Como elas já estavam em markdown, foi bem tranquilo - tive que fazer pequenos ajustes convertendo algumas tags &lt;em>liquid&lt;/em> para o novo formato correto.&lt;/p>
&lt;p>Uma das partes mais difíceis desse processo de migração foi configurar as linguagens múltiplas do blog, já que eu escrevo os posts em ambos inglês e português. Mas para resolver esse problema foi até simples: Organizar meu conteúdo e fazer a seguinte configuração no arquivo &lt;code>hugo.toml&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">languages&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [&lt;span style="color:#a6e22e">languages&lt;/span>.&lt;span style="color:#a6e22e">en&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">contentDir&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;content/en/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">languageName&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;🇬🇧 English&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">weight&lt;/span> = &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> [&lt;span style="color:#a6e22e">languages&lt;/span>.&lt;span style="color:#a6e22e">pt-BR&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">contentDir&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;content/pt_BR/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">languageName&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;🇧🇷 Português&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">weight&lt;/span> = &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Com isso e mais alguns ajustes no arquivo de deploy, o meu blog estava &lt;em>on&lt;/em> - e realmente mais rápido do que nunca! 🚀&lt;/p></description></item><item><title>Aplicando Método Cientifico no Desenvolvimento de Software</title><link>https://blog.devontrack.com/pt-br/posts/2024-05-23-scientific-method-software-development/</link><pubDate>Thu, 23 May 2024 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2024-05-23-scientific-method-software-development/</guid><description>&lt;hr>
&lt;p>Às vezes (na verdade, com muita frequência) é fácil ficar preso em um enigma de programação durante a codificação, depuração ou solução mental de um problema. Especialmente nos estágios iniciais de senioridade, as pessoas tendem a encarar um problema de programação (como corrigir bugs ou executar testes&amp;hellip;) de frente, pensando uma solução provável, experimentando-a e verificando se o problema foi resolvido ou não repetidamente.
Nesse sentido, a aplicação de métodos científicos a esse processo de solução de problemas pode ser benéfica na engenharia de software.&lt;/p>
&lt;h1 id="o-que-é-método-científico">&lt;a href="#o-que-%c3%a9-m%c3%a9todo-cient%c3%adfico" class="header-anchor">&lt;/a>O que é método científico?
&lt;/h1>&lt;p>O Método Científico é uma técnica empírica usada para construir uma hipótese científica. Essas palavras bonitas significam simplesmente: usando a lógica, construímos uma hipótese para explicar um ocorrido. Este método envolve observação baseada no &lt;em>ceticismo&lt;/em> (uma vez que suposições cognitivas podem distorcer a interpretação das observações). Após a observação, questões são levantadas e as respostas são coletadas por meio de testes e experimentos. Esta metodologia é útil em vários campos, incluindo investigação científica, ciências naturais e, como veremos a seguir, até engenharia!&lt;/p>
&lt;p>Esta técnica consiste nas seguintes etapas:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Observação/Pergunta:&lt;/strong> O método científico começa com uma pergunta ou questionamento sobre algo.&lt;/li>
&lt;li>&lt;strong>Pesquisa sobre o tópico:&lt;/strong> Antes de começar e buscar uma solução em potencial, são realizadas pesquisas para aprender mais sobre o assunto e coletar referências.&lt;/li>
&lt;li>&lt;strong>Hipótese:&lt;/strong> Crie um palpite fundamentado sobre a resposta esperada da sua observação/questionamento proposto.&lt;/li>
&lt;li>&lt;strong>Testar a hipótese com um experimento:&lt;/strong> Verifique se sua hipótese é válida realizando um teste justo, alterando um fator de cada vez e mantendo as mesmas condições de teste para verificar o resultado final.&lt;/li>
&lt;li>&lt;strong>Analisar dados:&lt;/strong> Analise os dados coletados para determinar se eles apoiam ou refutam a hipótese.&lt;/li>
&lt;li>&lt;strong>Tirar uma conclusão:&lt;/strong> Determine se a hipótese é aceitável com base na análise dos dados.&lt;/li>
&lt;/ol>
&lt;p>Essas etapas são realizadas em ambiente controlado e monitorado, o que significa que somos capazes de observar possíveis variáveis que podem interferir no resultado. Essas variáveis podem ser:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Variáveis de controle&lt;/strong>: Também conhecidas como &amp;ldquo;variáveis constantes&amp;rdquo;, são variáveis que são mantidas iguais durante o experimento.&lt;/li>
&lt;li>&lt;strong>Variáveis independentes&lt;/strong>: Variáveis ou condições que podem ser ajustadas para afetar o resultado do experimento.&lt;/li>
&lt;li>&lt;strong>Variáveis dependentes:&lt;/strong> Essas variáveis são medidas ou observadas em como respondem com base nas alterações feitas nas variáveis independentes.&lt;/li>
&lt;/ul>
&lt;h1 id="ok-mas-o-que-isso-tem-a-ver-com-desenvolvimento-de-software">&lt;a href="#ok-mas-o-que-isso-tem-a-ver-com-desenvolvimento-de-software" class="header-anchor">&lt;/a>OK, mas o que isso tem a ver com desenvolvimento de software?
&lt;/h1>&lt;p>Você deve estar se perguntando o que o método científico tem a ver com o desenvolvimento de software. À primeira vista, pode parecer uma incompatibilidade - afinal, pode-se argumentar que a ciência trata do estudo do mundo natural, enquanto a codificação trata de ficar encurvado na frente de um computador escrevendo&amp;hellip; código. Mas pensa bem! Os princípios do método científico são surpreendentemente relevantes para o trabalho diário dos desenvolvedores de software. Vamos ver como.&lt;/p>
&lt;h2 id="análise-de-erros">&lt;a href="#an%c3%a1lise-de-erros" class="header-anchor">&lt;/a>Análise de erros
&lt;/h2>&lt;p>Usar técnicas do método científico para identificar e resolver bugs em um código é bastante útil.
Aplicando as etapas acima:&lt;/p>
&lt;ol>
&lt;li>Identifique um problema ou bug a ser investigado. Isso representa a hipótese. Por exemplo, “O programa trava e fecha inesperadamente”.&lt;/li>
&lt;li>Se necessário, faça pesquisas adicionais sobre as ferramentas, linguagens, configurações e/ou estruturas utilizadas no programa em questão. Isso lhe dará mais experiências e conhecimento para o próximo passo.&lt;/li>
&lt;li>Projete um experimento controlado para testar sua hipótese. Pensando na hipótese acima, você pode escrever testes unitários ou criar um reprodutor para o bug. O objetivo é coletar mais informações sobre o assunto e descartar possíveis variáveis que possam interferir no resultado.&lt;/li>
&lt;li>Execute o experimento (por exemplo, execute o programa para observar a falha). Colete os resultados, possíveis comportamentos inesperados, variáveis&amp;hellip;&lt;/li>
&lt;li>Analise os dados, tentando correlacionar o resultado com as variáveis.&lt;/li>
&lt;li>Se necessário, repita o experimento, alterando variáveis e/ou ambiente. Quando o potencial culpado for encontrado, a hipótese pode ser considerada resolvida.&lt;/li>
&lt;/ol>
&lt;p>As vezes, realizamos algo semelhante ao processo acima intuitivamente ao resolver um problema e isso é ótimo! A aplicação explícita (e consciente) dessas etapas pode melhorar a precisão da resolução do problema.&lt;/p>
&lt;h2 id="desenvolvimento-baseado-em-hipóteses">&lt;a href="#desenvolvimento-baseado-em-hip%c3%b3teses" class="header-anchor">&lt;/a>Desenvolvimento baseado em hipóteses
&lt;/h2>&lt;p>E se tratássemos cada recurso ou correção de bug como uma hipótese e, em seguida, projetássemos nosso processo de desenvolvimento em torno de testes e verificação dessa hipótese?&lt;/p>
&lt;p>Este é o conceito conhecido como Desenvolvimento Orientado a Hipóteses (Hypothesis-Driven Development - HDD).&lt;/p>
&lt;p>Semelhante às etapas do método científico apontadas acima, começamos definindo uma hipótese clara, como “A implementação deste recurso aumentará o uso do programa pelos dos usuários em 30%”. Depois disso, é criado um plano para testar a hipótese, como:&lt;/p>
&lt;ul>
&lt;li>Implementar e implantar x, y e z como pontos-chave do recurso;&lt;/li>
&lt;li>Realizar testes A/B para comparar a nova funcionalidade com o comportamento anterior;&lt;/li>
&lt;li>Coletar dados sobre interação do usuário, métricas de desempenho, métricas de negócios&amp;hellip;
Com o plano criado, as mudanças são implementadas e o experimento é executado. Em alguns casos, uma simulação pode ser executada para conduzir o experimento, ou o novo recurso pode ser usado por uma pequena parcela de usuários por um período específico de tempo. Depois disso, os resultados são analisados e a hipótese é validada: se os resultados foram alcançados a hipótese foi confirmada e pode ser adotada, caso contrário, novas rodadas de experimento podem ser conduzidas com novas hipóteses.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Esta jeito de desenvolver pode parecer bem semelhante ao Test Driven Development (TDD). No entanto, tenha em mente que o HDD se concentra no desenvolvimento de recursos ou correções de bugs com base em hipóteses específicas e em como eles irão melhorar o sistema ou a experiência do usuário, enquanto o TDD enfatiza a escrita de testes unitários para alterações de código individuais para garantir correção e confiabilidade em menor escala.
&lt;br>&lt;/p>&lt;/blockquote>
&lt;h2 id="experimentação-com-diferentes-algoritmos">&lt;a href="#experimenta%c3%a7%c3%a3o-com-diferentes-algoritmos" class="header-anchor">&lt;/a>Experimentação com diferentes algoritmos
&lt;/h2>&lt;p>Também podemos usar o método científico para comparar diferentes algoritmos para resolver um problema específico – e também determinar qual deles é o mais eficaz. Com uma hipótese como &amp;ldquo;O algoritmo A superará o algoritmo B em termos de precisão quando usado para prever o risco de crédito&amp;rdquo;, podemos projetar um experimento comparando ambas as opções de algoritmo usando dados de entrada, métricas de avaliação e usuários como dados de controle. Também é importante utilizar um ambiente controlado, para evitar que fatores externos influenciem os resultados.&lt;/p>
&lt;p>Após a execução do experimento, o desempenho de cada algoritmo é coletado e analisado para determinar qual algoritmo é o melhor conforme sugerido pela hipótese. Também podemos expandir e refinar a hipótese, identificando limitações ou vieses no experimento e propondo explicações alternativas para os resultados (por exemplo, “O algoritmo A pode ter um desempenho melhor devido à sua capacidade avançada de lidar com dados não agrupados&amp;quot;).&lt;/p>
&lt;h2 id="e-muitos-mais">&lt;a href="#e-muitos-mais" class="header-anchor">&lt;/a>…e muitos mais!
&lt;/h2>&lt;p>Existem muitos outras propostas interessantes que podem se beneficiar do uso do método científico, como:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Revisão de código&lt;/strong>, ao avaliar a eficácia de diferentes soluções para resolver um problema específico&lt;/li>
&lt;li>&lt;strong>Priorização de recursos&lt;/strong>, ao determinar qual recurso tem maior importância e impacto dadas certas restrições&lt;/li>
&lt;li>&lt;strong>Análise de débito técnico&lt;/strong>, utilizando métricas para determinar qual débito técnico terá maior impacto positivo no projeto quando resolvido&lt;/li>
&lt;/ul>
&lt;p>Os benefícios de usar essas técnicas para resolver problemas é poder abordar problemas - e, como mostrado, não apenas preposições científicas! - com uma abordagem sistemática baseada em dados, isolando questões subjacentes e tendo um conhecimento mais completo do problema em questão. Experimente!&lt;/p>
&lt;h1 id="leitura-adicional">&lt;a href="#leitura-adicional" class="header-anchor">&lt;/a>Leitura Adicional
&lt;/h1>&lt;p>&lt;a class="link" href="https://en.wikipedia.org/wiki/Scientific_method" target="_blank" rel="noopener"
>Scientific Method - Wikipedia&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://www.sciencebuddies.org/science-fair-projects/science-fair/steps-of-the-scientific-method" target="_blank" rel="noopener"
>Steps of the Scientific Method - Science Buddies&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://joshpeterson.github.io/the-scientific-method-and-programming" target="_blank" rel="noopener"
>The scientific method and programming - Josh Peterson&lt;/a>&lt;/p></description></item><item><title>Aprendendo GO com TDD</title><link>https://blog.devontrack.com/pt-br/posts/2024-02-25-learning-go-tdd/</link><pubDate>Sun, 25 Feb 2024 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2024-02-25-learning-go-tdd/</guid><description>&lt;hr>
Nos últimos anos, o uso do Desenvolvimento Orientado a Testes (TDD) tornou-se cada vez mais popular no desenvolvimento de software. TDD é um estilo de desenvolvimento que enfatiza a escrita de testes automatizados do seu código antes mesmo de você escrever o código em si. Neste post, vou contar minha jornada aprendendo GO com TDD e como foi aprender uma nova linguagem de programação como uma desenvolvedora experiente.
&lt;h2 id="aprendendo-go-com-tdd-uma-jornada-de-descoberta">&lt;a href="#aprendendo-go-com-tdd-uma-jornada-de-descoberta" class="header-anchor">&lt;/a>Aprendendo GO com TDD: Uma Jornada de Descoberta
&lt;/h2>&lt;p>Como uma desenvolvedora experiente, dá pra perceber a importância de escrever testes automatizados para meu código antes mesmo de colocar a mão na massa. Por mais que eu ainda sinta alguma resistência nesse processo de inverter o fluxo &amp;ldquo;normal&amp;rdquo; de desenvolvimento (mais sobre isso depois), é inegável como escrever testes antes do código melhora o fluxo geral de escrita da lógica em si. Eu também estava ansiosa para aprender um novo linguagem de programação, a fim de manter meu cérebro fresquinho sobre tecnologias além daquelas usadas no meu local de trabalho.
Para conseguir isso, decidi aprender GO com Test-Driven Development (TDD). Nesta postagem do blog, compartilharei minha jornada e os insights que obtive ao longo do caminho.&lt;/p>
&lt;h2 id="contexto-entendendo-rapidamente-o-que-é-go">&lt;a href="#contexto-entendendo-rapidamente-o-que-%c3%a9-go" class="header-anchor">&lt;/a>Contexto: Entendendo rapidamente o que é GO
&lt;/h2>&lt;p>Antes de mergulhar nos detalhes do aprendizado de GO com TDD, irei fazer uma breve introdução à linguagem de programação: GO é uma linguagem de programação de código aberto desenvolvida pelo Google em 2009. Ela foi projetada para ser eficiente, simples e fácil de usar, tornando-o uma escolha popular para o desenvolvimento de aplicações web e backend.&lt;/p>
&lt;h2 id="por-que-aprender-go-com-tdd">&lt;a href="#por-que-aprender-go-com-tdd" class="header-anchor">&lt;/a>Por que aprender GO com TDD?
&lt;/h2>&lt;p>Existem dois principais motivos pelos quais decidi aprender GO com TDD:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Melhor qualidade do código:&lt;/strong> O TDD me ajuda a escrever um código melhor, forçando-me a pensar sobre os testes antes de escrever o código real. Isso garante que meu código seja testável e passível de manutenção, o que é especialmente importante ao trabalhar com uma linguagem como GO, que possui muitas funcionalidades integradas.&lt;/li>
&lt;li>&lt;strong>Compreensão mais profunda do GO:&lt;/strong> Aprender GO com TDD me ajudou a entender melhor a linguagem de programação. GO tem uma sintaxe bem diferentes ao se comparar com outras linguagens de programação, e o uso do TDD me ajudou a obter uma compreensão mais profunda de como esses recursos funcionam juntos.&lt;/li>
&lt;/ol>
&lt;h2 id="um-guia-muito-bem-vindo">&lt;a href="#um-guia-muito-bem-vindo" class="header-anchor">&lt;/a>Um guia muito bem-vindo
&lt;/h2>&lt;p>Para colocar a mão na massa de forma rápida, segui o incrível &lt;a class="link" href="https://quii.gitbook.io/learn-go-with-tests/" target="_blank" rel="noopener"
>Leaning GO with Tests&lt;/a>, que é um excelente recurso para aprender GO com TDD. O site fornece guias com passo-a-passo que te orienta no processo de aprendizagem, desde o básico até tópicos mais avançados. Foi muito útil seguir um tutorial tão bem descrito.&lt;/p>
&lt;h2 id="desafios-e-percepções">&lt;a href="#desafios-e-percep%c3%a7%c3%b5es" class="header-anchor">&lt;/a>Desafios e percepções
&lt;/h2>&lt;p>Mesmo com um caminho claro pela frente, aprender GO com TDD teve seus desafios. Aqui estão alguns dos insights que tive ao longo da minha jornada:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>A sintaxe do Go&lt;/strong>: Um dos maiores desafios que enfrentei foi me acostumar com a sintaxe do Go. Mesmo tendo experiência com sintaxes tipo Java e Python (essa última poderíamos argumentar que é bastante semelhante em certo sentido ao GO), ainda foi um pouco desafiador desligar o conhecimento prévio e se acostumar com a forma como o GO está estruturado. GO tem uma sintaxe única e um conjunto de recursos com os quais pode levar algum tempo para se acostumar. Por exemplo, a linguagem utiliza um estilo de programação funcional, que requer uma forma diferente de pensar sobre o código.&lt;/li>
&lt;li>&lt;strong>TDD te força a pensar em testes antes de escrever código&lt;/strong>: Um dos benefícios mais significativos de aprender GO com TDD é que ele me forçou a pensar em testes antes de escrever código. Isso me ajudou a escrever código mais robusto, modular e fácil de manter.&lt;/li>
&lt;li>&lt;strong>Escrever testes primeiro ajuda a identificar possíveis problemas antecipadamente&lt;/strong>: Ao escrever testes antes de escrever o código real, consegui ficar de olho e identificar possíveis problemas antecipadamente e corrigi-los antes que se tornassem problemas maiores. Isso me economizou uma quantidade significativa de tempo e esforço a longo prazo. Escrever testes antes do código também ajuda a garantir que meu código era sempre simples e fácil de entender.&lt;/li>
&lt;li>&lt;strong>O modelo de concorrência do GO é único&lt;/strong>: GO possui um modelo de concorrência integrado que permite processamentos paralelos. No entanto, isso também pode levar a race conditions (que é quando múltiplos processos concorrentes ou threads acessam e modificam dados compartilhados ao mesmo tempo, gerando comportamento inesperado) se não for tratado adequadamente. Ao escrever testes primeiro, é possível identificar esses casos antecipadamente e escrever um código mais robusto e tolerante a falhas.&lt;/li>
&lt;li>&lt;strong>Testando padrões de design&lt;/strong>: Escrever testes antes de escrever o código real me ajudou a escrever um código melhor, forçando-me a pensar primeiro nos testes. Isso também me permitiu aplicar padrões de design, como Injeção de Dependência (DI), para tornar meu código mais flexível e mais robusto.&lt;/li>
&lt;li>&lt;strong>Testes primeiro podem ser difíceis!&lt;/strong>: Uma limitação pessoal que senti nesta jornada foi o ato de pensar em testar primeiro em vez de codificar a solução inteiramente de uma vez. Foi um esforço muito consciente para combater a vontade de criar a lógica inteira antes dos testes. Parecia errado no começo, mas acho que no final peguei o jeito e ficou mais fácil.&lt;/li>
&lt;li>&lt;strong>Aprendendo novos conceitos&lt;/strong>: Esta foi a primeira vez que aprendi TDD com GO, por isso foi importante para mim aprender a linguagem à medida que avançava. Aprender uma nova linguagem de programação pode ser um desafio no início, mas definitivamente vale a pena o esforço. Os benefícios de aprender uma nova linguagem são muitos, incluindo aumento da produtividade e melhoria da qualidade do código.&lt;/li>
&lt;/ul>
&lt;h2 id="conclusão">&lt;a href="#conclus%c3%a3o" class="header-anchor">&lt;/a>Conclusão
&lt;/h2>&lt;p>Aprender GO com TDD foi uma experiência animadora e gratificante. Se você é um desenvolvedor que deseja melhorar seus conhecimentos, recomendo que experimente usar TDD ao aprender GO ou qualquer outra linguagem de programação.&lt;/p>
&lt;p>Espero que esse post tenha fornecido alguns insights sobre como aprender GO com TDD. Se você tiver alguma dúvida ou comentário, sinta-se à vontade para entrar em contato comigo pelos comentários abaixo ou pelo LinkedIn. Happy coding! 🥳&lt;/p>
&lt;h2 id="referências">&lt;a href="#refer%c3%aancias" class="header-anchor">&lt;/a>Referências:
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://quii.gitbook.io/learn-go-with-tests/" target="_blank" rel="noopener"
>Leaning GO with Tests&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://golang.org/ref/spec" target="_blank" rel="noopener"
>Go Programming Language Specification&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://www.manning.com/books/go-in-action" target="_blank" rel="noopener"
>Go in Action&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="leitura-complementar">&lt;a href="#leitura-complementar" class="header-anchor">&lt;/a>Leitura Complementar
&lt;/h3>&lt;p>Se você estiver interessado em aprender mais sobre TDD e GO, aqui estão alguns recursos adicionais:&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://go.dev/doc/effective_go" target="_blank" rel="noopener"
>Effective GO&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://martinfowler.com/bliki/TestDrivenDevelopment.html" target="_blank" rel="noopener"
>Test Driven Development&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Schematics Python: Visão Geral e Tutorial</title><link>https://blog.devontrack.com/pt-br/posts/2023-06-24-using-python-schematics/</link><pubDate>Sat, 24 Jun 2023 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2023-06-24-using-python-schematics/</guid><description>&lt;h3 id="o-que-é-schematics">&lt;a href="#o-que-%c3%a9-schematics" class="header-anchor">&lt;/a>O que é schematics?
&lt;/h3>&lt;p>&lt;a class="link" href="https://schematics.readthedocs.io/en/latest/" target="_blank" rel="noopener"
>Schematics&lt;/a> é uma lib que auxilia no design, conversão e validação de estruturas de dados em python.
Essa biblioteca elimina a necessidade de criar e manipular diretamente dados de payload para o contexto da aplicação.&lt;/p>
&lt;p>Para começar, &lt;a class="link" href="https://pypi.org/project/schematics/" target="_blank" rel="noopener"
>usamos um pip install&lt;/a> assim:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>pip install schematics
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Neste exemplo, vamos ingerir um esquema de dados complexo usando Schematics. Os dados chegam em um formato json, conforme exemplificado abaixo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;_id&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;641505586f0763093fe5de82&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;index&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">0&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;guid&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3e591c0d-5812-4c1e-9062-91d67db36326&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;isActive&amp;#34;&lt;/span>: &lt;span style="color:#960050;background-color:#1e0010">True&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;balance&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;$3,657.06&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;picture&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://picsum.photos/200&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;age&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">22&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;eyeColor&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;brown&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Whitehead Navarro&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;gender&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;male&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;company&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;ROUGHIES&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;email&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;whiteheadnavarro@roughies.com&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;phone&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;(843) 429-2875&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;address&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;934 River Street, Sparkill, New Mexico, 4866&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;about&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Mollit enim aute sint enim ut eiusmod dolore dolore veniam. Esse ad consequat pariatur &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;cupidatat qui deserunt proident minim irure. Proident labore minim ex voluptate ea ut excepteur &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;duis ad minim quis incididunt labore. Laborum sit aliqua aliqua et ad qui qui quis ullamco. &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Voluptate voluptate consectetur nostrud amet enim. In Lorem voluptate fugiat duis. Ut proident &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;ipsum minim do fugiat sunt laboris voluptate tempor aliqua aliquip deserunt sit.\r\n&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;registered&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;2018-08-26T04:14:49&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;coordinates&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">-0.642558&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">-154.849655&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;tags&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;pariatur&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;consequat&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;et&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;amet&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;fugiat&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;non&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;deserunt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;friends&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">0&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Alejandra Kinney&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Holmes Graves&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">2&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Barbra Dominguez&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;greeting&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Hello, Whitehead Navarro! You have 7 unread messages.&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;favoriteFruit&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;strawberry&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;favoriteMedia&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Better Call Saul&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;year&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;2022&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;network&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;AMC&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="1-recebendo-e-convertendo-dados">&lt;a href="#1-recebendo-e-convertendo-dados" class="header-anchor">&lt;/a>1. Recebendo e Convertendo Dados
&lt;/h3>&lt;p>Para converter os dados usando schematics, a primeira coisa a fazer é criar um modelo que represente uma pessoa:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> datetime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics &lt;span style="color:#f92672">import&lt;/span> Model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.transforms &lt;span style="color:#f92672">import&lt;/span> blacklist, whitelist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> ModelType, StringType, IntType, UUIDType, BooleanType, URLType, EmailType, DateTimeType, \
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> GeoPointType, ListType, serializable, PolyModelType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.friend &lt;span style="color:#f92672">import&lt;/span> Friend
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.game &lt;span style="color:#f92672">import&lt;/span> Game
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.movie &lt;span style="color:#f92672">import&lt;/span> Movie
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.schematics_types.currency_type &lt;span style="color:#f92672">import&lt;/span> CurrencyType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.tv_show &lt;span style="color:#f92672">import&lt;/span> TVShow
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> model.validators &lt;span style="color:#f92672">import&lt;/span> is_uppercase, is_email_valid, is_over_18
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Person&lt;/span>(Model):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> id &lt;span style="color:#f92672">=&lt;/span> StringType(deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;_id&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index &lt;span style="color:#f92672">=&lt;/span> IntType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> guid &lt;span style="color:#f92672">=&lt;/span> UUIDType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> is_active &lt;span style="color:#f92672">=&lt;/span> BooleanType(deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;isActive&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> balance &lt;span style="color:#f92672">=&lt;/span> CurrencyType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> picture &lt;span style="color:#f92672">=&lt;/span> URLType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> age &lt;span style="color:#f92672">=&lt;/span> IntType(validators&lt;span style="color:#f92672">=&lt;/span>[is_over_18])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> eye_color &lt;span style="color:#f92672">=&lt;/span> StringType(deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;eyeColor&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">=&lt;/span> StringType(required&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gender &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> company &lt;span style="color:#f92672">=&lt;/span> StringType(validators&lt;span style="color:#f92672">=&lt;/span>[is_uppercase])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> email &lt;span style="color:#f92672">=&lt;/span> EmailType(validators&lt;span style="color:#f92672">=&lt;/span>[is_email_valid], required&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> phone &lt;span style="color:#f92672">=&lt;/span> StringType(required&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> address &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> about &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> registered &lt;span style="color:#f92672">=&lt;/span> DateTimeType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> coordinates &lt;span style="color:#f92672">=&lt;/span> GeoPointType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tags &lt;span style="color:#f92672">=&lt;/span> ListType(StringType)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> friends &lt;span style="color:#f92672">=&lt;/span> ListType(ModelType(Friend))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> greeting &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> favorite_fruit &lt;span style="color:#f92672">=&lt;/span> StringType(deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;favoriteFruit&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> favorite_media &lt;span style="color:#f92672">=&lt;/span> PolyModelType([
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Movie,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> TVShow,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Game
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ], deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;favoriteMedia&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> created_at &lt;span style="color:#f92672">=&lt;/span> DateTimeType(default&lt;span style="color:#f92672">=&lt;/span>datetime&lt;span style="color:#f92672">.&lt;/span>datetime&lt;span style="color:#f92672">.&lt;/span>now)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@serializable&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">external_id&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">u&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">%s&lt;/span>&lt;span style="color:#e6db74">-&lt;/span>&lt;span style="color:#e6db74">%s&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span> &lt;span style="color:#f92672">%&lt;/span> (self&lt;span style="color:#f92672">.&lt;/span>index, self&lt;span style="color:#f92672">.&lt;/span>id)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Options&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialize_when_none &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">False&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> roles &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;public_person&amp;#39;&lt;/span>: blacklist(&lt;span style="color:#e6db74">&amp;#39;id&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;index&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;guid&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;is_active&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;balance&amp;#39;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;profile_info&amp;#39;&lt;/span>: whitelist(&lt;span style="color:#e6db74">&amp;#39;name&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;greeting&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;gender&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;picture&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;about&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;age&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Muita informação aqui! Vamos entender passo a passo.&lt;/p>
&lt;h4 id="atribuindo-tipos-a-campos">&lt;a href="#atribuindo-tipos-a-campos" class="header-anchor">&lt;/a>Atribuindo tipos a campos
&lt;/h4>&lt;p>Criamos uma classe &lt;code>Person&lt;/code> que estende a classe &lt;code>Model&lt;/code> do Schematics. Nesta classe, todas as variáveis são declaradas com um tipo específico já existente no Schematics ou um tipo customizado criados por nós mesmos. O Schematics fornece tipos prontos para uso (como &lt;code>StringType&lt;/code>, &lt;code>UUIDType&lt;/code>, &lt;code>IntType&lt;/code>; verifique todos os tipos disponíveis usando o &lt;a class="link" href="https://schematics.readthedocs.io/en/latest/api/types.html" target="_blank" rel="noopener"
>as documentações do Schematics&lt;/a>).&lt;/p>
&lt;p>Esses tipos são muito úteis para coagir e converter dados para corresponder ao nosso esquema de classe desejado. Além disso, com um tipo, a validação de campo se torna muito fácil (falaremos mais sobre isso já já).
Como visto acima, é possível criar tipos personalizados para atender às nossas necessidades específicas, como a classe &lt;code>CurrencyType&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> FloatType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CurrencyType&lt;/span>(FloatType):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">convert&lt;/span>(self, value, context&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">None&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> isinstance(value, str):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> number &lt;span style="color:#f92672">=&lt;/span> value&lt;span style="color:#f92672">.&lt;/span>replace(&lt;span style="color:#e6db74">&amp;#39;$&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> float(number&lt;span style="color:#f92672">.&lt;/span>replace(&lt;span style="color:#e6db74">&amp;#39;,&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Neste exemplo, &lt;code>CurrencyType&lt;/code> estende a classe &lt;code>FloatType&lt;/code> do Schematics, o método de conversão recebe um valor - e se tratando de uma string, remove o cifrão e a vírgula para aderir ao formato de moeda desejado.&lt;/p>
&lt;h4 id="lista-de-modelos">&lt;a href="#lista-de-modelos" class="header-anchor">&lt;/a>Lista de Modelos
&lt;/h4>&lt;p>Para representar uma lista/array de itens de um modelo, usamos &lt;code>ListType(ModelType())&lt;/code> e o nome do modelo que compõem essa lista - como no exemplo acima: &lt;code>ListType(ModelType(Friend))&lt;/code>. A classe &lt;code>Friend&lt;/code> representa um modelo da seguinte forma:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics &lt;span style="color:#f92672">import&lt;/span> Model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.transforms &lt;span style="color:#f92672">import&lt;/span> wholelist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> IntType, StringType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Friend&lt;/span>(Model):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> id &lt;span style="color:#f92672">=&lt;/span> IntType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se a lista consistir em um tipo simples, como o parâmetro &lt;code>tags&lt;/code> (uma lista composta apenas de strings), declaramos um &lt;code>ListType()&lt;/code> com o tipo desejado, como &lt;code>ListType(StringType)&lt;/code>.&lt;/p>
&lt;h4 id="renomeando-campos">&lt;a href="#renomeando-campos" class="header-anchor">&lt;/a>Renomeando Campos
&lt;/h4>&lt;p>Schematics faz atribuições automáticas para atribuir as variáveis baseadas no nome do campo recebido com o campo do nosso modelo; quando ambos compartilham o mesmo nome, esse processo acontece por baixo dos panos. Mas o que acontece quando recebemos campos que em nosso contexto possuem nomes diferentes?&lt;/p>
&lt;p>Para resolver isso, é bastante fácil: basta adicionar &lt;code>deserialize_from=&lt;/code> seguido do nome do campo original recebido para realizar a correspondência. No exemplo acima, os campos &lt;code>id&lt;/code>, &lt;code>eye_color&lt;/code> e &lt;code>favorite_fruit&lt;/code> são desserializados usando este atributo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>favorite_fruit &lt;span style="color:#f92672">=&lt;/span> StringType(deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;favoriteFruit&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esta é uma ótima maneira de normalizar facilmente payloads com nomenclatura diferente do snake_case, que é usado pelo python.&lt;/p>
&lt;h4 id="campos-padrão">&lt;a href="#campos-padr%c3%a3o" class="header-anchor">&lt;/a>Campos Padrão
&lt;/h4>&lt;p>Para definir um valor padrão para um campo, use o atributo &lt;code>default=&lt;/code> dentro do tipo de campo desejado. No exemplo acima, o campo &lt;code>created_at&lt;/code> terá como padrão a data/hora em que o modelo foi instanciado.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> created_at &lt;span style="color:#f92672">=&lt;/span> DateTimeType(default&lt;span style="color:#f92672">=&lt;/span>datetime&lt;span style="color:#f92672">.&lt;/span>datetime&lt;span style="color:#f92672">.&lt;/span>now)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="campos-compostos">&lt;a href="#campos-compostos" class="header-anchor">&lt;/a>Campos Compostos
&lt;/h4>&lt;p>Para criar um campo composto de campos existentes na classe, crie uma função com o nome do campo desejado anotado com &lt;code>@serializable&lt;/code> como no campo &lt;code>external_id&lt;/code> do model acima, que é criado concatenando os campos &lt;code>index&lt;/code> e &lt;code>id&lt;/code>. Isso permite que o valor seja acessado como qualquer outro campo da classe.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@serializable&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">external_id&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">u&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">%s&lt;/span>&lt;span style="color:#e6db74">-&lt;/span>&lt;span style="color:#e6db74">%s&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span> &lt;span style="color:#f92672">%&lt;/span> (self&lt;span style="color:#f92672">.&lt;/span>index, self&lt;span style="color:#f92672">.&lt;/span>id)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="definindo-validadores-personalizados">&lt;a href="#definindo-validadores-personalizados" class="header-anchor">&lt;/a>Definindo validadores Personalizados
&lt;/h4>&lt;p>Podemos criar um validador personalizado para verificar se os dados recebidos respeitam regras de negócio. Para isso, crie uma função com a validação desejada que receba um atributo &lt;code>value&lt;/code> como parâmetro e gere uma exceção &lt;code>ValidationError&lt;/code> em um cenário negativo, como este:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> re
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.exceptions &lt;span style="color:#f92672">import&lt;/span> ValidationError
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">is_uppercase&lt;/span>(value):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> value&lt;span style="color:#f92672">.&lt;/span>upper() &lt;span style="color:#f92672">!=&lt;/span> value:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> ValidationError(&lt;span style="color:#e6db74">&amp;#39;Field should be uppercase.&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">is_email_valid&lt;/span>(value):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> regex &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">r&lt;/span>&lt;span style="color:#e6db74">&amp;#39;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> re&lt;span style="color:#f92672">.&lt;/span>fullmatch(regex, value):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> ValidationError(&lt;span style="color:#e6db74">&amp;#39;E-mail address invalid.&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">is_over_18&lt;/span>(value):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> value &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">18&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">raise&lt;/span> ValidationError(&lt;span style="color:#e6db74">&amp;#39;User cannot be underage.&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> value
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Para validar os elementos do modelo, use &lt;code>validators=[]&lt;/code> e o nome da função entre colchetes, assim: &lt;code>validators=[is_email_valid]&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> email &lt;span style="color:#f92672">=&lt;/span> EmailType(validators&lt;span style="color:#f92672">=&lt;/span>[is_email_valid], required&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="campos-obrigatórios">&lt;a href="#campos-obrigat%c3%b3rios" class="header-anchor">&lt;/a>Campos Obrigatórios
&lt;/h4>&lt;p>Para definir um campo como obrigatório, use &lt;code>required=True&lt;/code> na declaração do tipo. Se o valor não estiver presente no momento da validação, a aplicação lançará uma exceção.&lt;/p>
&lt;hr>
&lt;h3 id="2-acessando-e-manipulando-dados">&lt;a href="#2-acessando-e-manipulando-dados" class="header-anchor">&lt;/a>2. Acessando e Manipulando Dados
&lt;/h3>&lt;p>Com nosso modelo criado, é hora de gerar alguns dados carregando o json recebido como um dict e passando como parâmetro ao instanciar classe &lt;code>Person&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>person &lt;span style="color:#f92672">=&lt;/span> Person(json_input)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="validando-dados">&lt;a href="#validando-dados" class="header-anchor">&lt;/a>Validando Dados
&lt;/h4>&lt;p>Para validar se os dados recebidos estão em corretos, usamos o seguinte método:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>person&lt;span style="color:#f92672">.&lt;/span>validate()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Em nosso modelo, criamos um validador que especifica que o valor do campo empresa deve ser maiúsculo. Deixar de informar uma string em letras maiúsculas resulta na seguinte saída quando validado:&lt;/p>
&lt;pre tabindex="0">&lt;code>schematics.exceptions.DataError: {&amp;#34;company&amp;#34;: [&amp;#34;Field should be uppercase.&amp;#34;]}
Process finished with exit code 1
&lt;/code>&lt;/pre>&lt;h4 id="ignorando-campos-não-mapeados">&lt;a href="#ignorando-campos-n%c3%a3o-mapeados" class="header-anchor">&lt;/a>Ignorando Campos Não Mapeados
&lt;/h4>&lt;p>Para ignorar campos não declarados no modelo e presentes na entrada, usamos o seguinte atributo de validação:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>person&lt;span style="color:#f92672">.&lt;/span>validate(strict&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">False&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Se este parâmetro não for especificado, passar um campo na entrada que não está contido no modelo resulta na seguinte saída ao validar:&lt;/p>
&lt;pre tabindex="0">&lt;code>schematics.exceptions.DataError: {&amp;#34;newField&amp;#34;: &amp;#34;Rogue field&amp;#34;}
Process finished with exit code 1
&lt;/code>&lt;/pre>&lt;h4 id="omitindo-campos-sem-valor">&lt;a href="#omitindo-campos-sem-valor" class="header-anchor">&lt;/a>Omitindo Campos Sem Valor
&lt;/h4>&lt;p>Para omitir campos sem valor (atribuídos com &lt;code>None&lt;/code>) ao exportar um modelo, use &lt;code>serialize_when_none = False&lt;/code> dentro da classe interna &lt;code>Options&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Options&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialize_when_none &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">False&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="acessando-campos">&lt;a href="#acessando-campos" class="header-anchor">&lt;/a>Acessando Campos
&lt;/h4>&lt;p>Com o objeto modelo criado, fica fácil acessar os campos:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>print(person&lt;span style="color:#f92672">.&lt;/span>name, &lt;span style="color:#e6db74">&amp;#39;is&amp;#39;&lt;/span>, person&lt;span style="color:#f92672">.&lt;/span>age, &lt;span style="color:#e6db74">&amp;#39;old.&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que gera como resposta:&lt;/p>
&lt;pre tabindex="0">&lt;code>Whitehead Navarro is 22 old.
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;h4 id="exportando-para-json">&lt;a href="#exportando-para-json" class="header-anchor">&lt;/a>Exportando para Json
&lt;/h4>&lt;p>Para exportar o objeto para json, utilizamos o seguinte método:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>json&lt;span style="color:#f92672">.&lt;/span>dumps(person&lt;span style="color:#f92672">.&lt;/span>to_primitive())
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que gera como resposta o json:&lt;/p>
&lt;pre tabindex="0">&lt;code>{&amp;#34;id&amp;#34;: &amp;#34;641505586f0763093fe5de82&amp;#34;, &amp;#34;index&amp;#34;: 0, &amp;#34;guid&amp;#34;: &amp;#34;3e591c0d-5812-4c1e-9062-91d67db36326&amp;#34;, &amp;#34;is_active&amp;#34;: true, &amp;#34;balance&amp;#34;: 3657.06, &amp;#34;picture&amp;#34;: &amp;#34;https://picsum.photos/200&amp;#34;, &amp;#34;age&amp;#34;: 22, &amp;#34;eye_color&amp;#34;: &amp;#34;brown&amp;#34;, &amp;#34;name&amp;#34;: &amp;#34;Whitehead Navarro&amp;#34;, &amp;#34;gender&amp;#34;: &amp;#34;male&amp;#34;, &amp;#34;company&amp;#34;: &amp;#34;ROUGHIES&amp;#34;, &amp;#34;email&amp;#34;: &amp;#34;whiteheadnavarro@roughies.com&amp;#34;, &amp;#34;phone&amp;#34;: &amp;#34;(843) 429-2875&amp;#34;, &amp;#34;address&amp;#34;: &amp;#34;934 River Street, Sparkill, New Mexico, 4866&amp;#34;, &amp;#34;about&amp;#34;: &amp;#34;Mollit enim aute sint enim ut eiusmod dolore dolore veniam. Esse ad consequat pariatur cupidatat qui deserunt proident minim irure. Proident labore minim ex voluptate ea ut excepteur duis ad minim quis incididunt labore. Laborum sit aliqua aliqua et ad qui qui quis ullamco. Voluptate voluptate consectetur nostrud amet enim. In Lorem voluptate fugiat duis. Ut proident ipsum minim do fugiat sunt laboris voluptate tempor aliqua aliquip deserunt sit.\r\n&amp;#34;, &amp;#34;registered&amp;#34;: &amp;#34;2018-08-26T04:14:49.000000&amp;#34;, &amp;#34;coordinates&amp;#34;: [-0.642558, -154.849655], &amp;#34;tags&amp;#34;: [&amp;#34;pariatur&amp;#34;, &amp;#34;consequat&amp;#34;, &amp;#34;et&amp;#34;, &amp;#34;amet&amp;#34;, &amp;#34;fugiat&amp;#34;, &amp;#34;non&amp;#34;, &amp;#34;deserunt&amp;#34;], &amp;#34;friends&amp;#34;: [{&amp;#34;id&amp;#34;: 0, &amp;#34;name&amp;#34;: &amp;#34;Alejandra Kinney&amp;#34;}, {&amp;#34;id&amp;#34;: 1, &amp;#34;name&amp;#34;: &amp;#34;Holmes Graves&amp;#34;}, {&amp;#34;id&amp;#34;: 2, &amp;#34;name&amp;#34;: &amp;#34;Barbra Dominguez&amp;#34;}], &amp;#34;greeting&amp;#34;: &amp;#34;Hello, Whitehead Navarro! You have 7 unread messages.&amp;#34;, &amp;#34;favorite_fruit&amp;#34;: &amp;#34;strawberry&amp;#34;, &amp;#34;created_at&amp;#34;: &amp;#34;2023-06-22T22:09:15.939875&amp;#34;, &amp;#34;external_id&amp;#34;: &amp;#34;0-641505586f0763093fe5de82&amp;#34;}
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;h4 id="roles-e-opções-de-classe">&lt;a href="#roles-e-op%c3%a7%c3%b5es-de-classe" class="header-anchor">&lt;/a>Roles e Opções de Classe
&lt;/h4>&lt;p>Uma role funciona como um &lt;em>filtro&lt;/em> ao exportar dados usando as opções &lt;code>whitelist&lt;/code> e &lt;code>blacklist&lt;/code>. Como no modelo &lt;code>Person&lt;/code> acima, declaramos uma role dentro da subclasse Option e listamos os valores da &lt;code>whitelist&lt;/code> (valores para exportar) ou uma &lt;code>blacklist&lt;/code> (valores para omitir).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Options&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> roles &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;public_person&amp;#39;&lt;/span>: blacklist(&lt;span style="color:#e6db74">&amp;#39;id&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;index&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;guid&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;is_active&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;balance&amp;#39;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;profile_info&amp;#39;&lt;/span>: whitelist(&lt;span style="color:#e6db74">&amp;#39;name&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;greeting&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;gender&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;picture&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;about&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;age&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Este é o comando para imprimir apenas os valores da whitelist:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>print(person&lt;span style="color:#f92672">.&lt;/span>to_primitive(role&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;profile_info&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que imprime os valores de &lt;code>pictures&lt;/code>, &lt;code>age&lt;/code>, &lt;code>name&lt;/code>, &lt;code>gender&lt;/code>, &lt;code>about&lt;/code> e &lt;code>greeting&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code>{&amp;#39;picture&amp;#39;: &amp;#39;https://picsum.photos/200&amp;#39;, &amp;#39;age&amp;#39;: 22, &amp;#39;name&amp;#39;: &amp;#39;Whitehead Navarro&amp;#39;, &amp;#39;gender&amp;#39;: &amp;#39;male&amp;#39;, &amp;#39;about&amp;#39;: &amp;#39;Mollit enim aute sint enim ut eiusmod dolore dolore veniam. Esse ad consequat pariatur cupidatat qui deserunt proident minim irure. Proident labore minim ex voluptate ea ut excepteur duis ad minim quis incididunt labore. Laborum sit aliqua aliqua et ad qui qui quis ullamco. Voluptate voluptate consectetur nostrud amet enim. In Lorem voluptate fugiat duis. Ut proident ipsum minim do fugiat sunt laboris voluptate tempor aliqua aliquip deserunt sit.\r\n&amp;#39;, &amp;#39;greeting&amp;#39;: &amp;#39;Hello, Whitehead Navarro! You have 7 unread messages.&amp;#39;}
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;p>Ao imprimir todos os valores exceto os que estão na blacklist, usamos:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>print(person&lt;span style="color:#f92672">.&lt;/span>to_primitive(role&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;public_person&amp;#39;&lt;/span>))
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que omite os campos &lt;code>id&lt;/code>, &lt;code>index&lt;/code>, &lt;code>guid&lt;/code>, &lt;code>is_active&lt;/code> e &lt;code>balance&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code>{&amp;#39;picture&amp;#39;: &amp;#39;https://picsum.photos/200&amp;#39;, &amp;#39;age&amp;#39;: 22, &amp;#39;eye_color&amp;#39;: &amp;#39;brown&amp;#39;, &amp;#39;name&amp;#39;: &amp;#39;Whitehead Navarro&amp;#39;, &amp;#39;gender&amp;#39;: &amp;#39;male&amp;#39;, &amp;#39;company&amp;#39;: &amp;#39;ROUGHIES&amp;#39;, &amp;#39;email&amp;#39;: &amp;#39;whiteheadnavarro@roughies.com&amp;#39;, &amp;#39;phone&amp;#39;: &amp;#39;(843) 429-2875&amp;#39;, &amp;#39;address&amp;#39;: &amp;#39;934 River Street, Sparkill, New Mexico, 4866&amp;#39;, &amp;#39;about&amp;#39;: &amp;#39;Mollit enim aute sint enim ut eiusmod dolore dolore veniam. Esse ad consequat pariatur cupidatat qui deserunt proident minim irure. Proident labore minim ex voluptate ea ut excepteur duis ad minim quis incididunt labore. Laborum sit aliqua aliqua et ad qui qui quis ullamco. Voluptate voluptate consectetur nostrud amet enim. In Lorem voluptate fugiat duis. Ut proident ipsum minim do fugiat sunt laboris voluptate tempor aliqua aliquip deserunt sit.\r\n&amp;#39;, &amp;#39;registered&amp;#39;: &amp;#39;2018-08-26T04:14:49.000000&amp;#39;, &amp;#39;coordinates&amp;#39;: [-0.642558, -154.849655], &amp;#39;tags&amp;#39;: [&amp;#39;pariatur&amp;#39;, &amp;#39;consequat&amp;#39;, &amp;#39;et&amp;#39;, &amp;#39;amet&amp;#39;, &amp;#39;fugiat&amp;#39;, &amp;#39;non&amp;#39;, &amp;#39;deserunt&amp;#39;], &amp;#39;friends&amp;#39;: [{&amp;#39;id&amp;#39;: 0, &amp;#39;name&amp;#39;: &amp;#39;Alejandra Kinney&amp;#39;}, {&amp;#39;id&amp;#39;: 1, &amp;#39;name&amp;#39;: &amp;#39;Holmes Graves&amp;#39;}, {&amp;#39;id&amp;#39;: 2, &amp;#39;name&amp;#39;: &amp;#39;Barbra Dominguez&amp;#39;}], &amp;#39;greeting&amp;#39;: &amp;#39;Hello, Whitehead Navarro! You have 7 unread messages.&amp;#39;, &amp;#39;favorite_fruit&amp;#39;: &amp;#39;strawberry&amp;#39;, &amp;#39;created_at&amp;#39;: &amp;#39;2023-06-22T22:17:12.004692&amp;#39;, &amp;#39;external_id&amp;#39;: &amp;#39;0-641505586f0763093fe5de82&amp;#39;}
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;h4 id="mockando-a-resposta">&lt;a href="#mockando-a-resposta" class="header-anchor">&lt;/a>Mockando a Resposta
&lt;/h4>&lt;p>Para testar nosso código, podemos usar Schematics para &lt;em>mockar&lt;/em> os valores do modelo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Python" data-lang="Python">&lt;span style="display:flex;">&lt;span>print(Person&lt;span style="color:#f92672">.&lt;/span>get_mock_object()&lt;span style="color:#f92672">.&lt;/span>to_primitive())
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>O mock tem valores aleatórios baseados nos tipos das variáveis:&lt;/p>
&lt;pre tabindex="0">&lt;code>{&amp;#39;index&amp;#39;: 14, &amp;#39;picture&amp;#39;: &amp;#39;http://aiV9Q.ZZ&amp;#39;, &amp;#39;age&amp;#39;: 12, &amp;#39;eye_color&amp;#39;: &amp;#39;N&amp;#39;, &amp;#39;name&amp;#39;: &amp;#39;hgqn8YPvDqLbf&amp;#39;, &amp;#39;company&amp;#39;: &amp;#39;JQ&amp;#39;, &amp;#39;email&amp;#39;: &amp;#39;ER@example.com&amp;#39;, &amp;#39;phone&amp;#39;: &amp;#39;DQVbv9q&amp;#39;, &amp;#39;address&amp;#39;: &amp;#39;61sOKCSGGOkV&amp;#39;, &amp;#39;coordinates&amp;#39;: (-83, 53), &amp;#39;greeting&amp;#39;: &amp;#39;fsxF&amp;#39;, &amp;#39;created_at&amp;#39;: &amp;#39;2127-03-09T03:39:51.357227+1130&amp;#39;, &amp;#39;external_id&amp;#39;: &amp;#39;14-None&amp;#39;}
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;hr>
&lt;h3 id="3-modelagem-avançada-polimorfismo">&lt;a href="#3-modelagem-avan%c3%a7ada-polimorfismo" class="header-anchor">&lt;/a>3. Modelagem Avançada: Polimorfismo
&lt;/h3>&lt;p>Também é possível realizar polimorfismo de tipos usando Schematics! Quando temos um campo que pode ter vários tipos, podemos declará-lo assim:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>favorite_media &lt;span style="color:#f92672">=&lt;/span> PolyModelType([
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Movie,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> TVShow,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Game
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>], deserialize_from&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;favoriteMedia&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As classes &lt;code>Movie&lt;/code>, &lt;code>TVShow&lt;/code> e &lt;code>Game&lt;/code> representam os tipos aceitos do campo &lt;code>favorite_media&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics &lt;span style="color:#f92672">import&lt;/span> Model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> StringType, IntType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Movie&lt;/span>(Model):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> year &lt;span style="color:#f92672">=&lt;/span> IntType()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics &lt;span style="color:#f92672">import&lt;/span> Model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> StringType, IntType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">TVShow&lt;/span>(Model):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> year &lt;span style="color:#f92672">=&lt;/span> IntType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> network &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_claim_polymorphic&lt;/span>(cls, data):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;network&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics &lt;span style="color:#f92672">import&lt;/span> Model
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> schematics.types &lt;span style="color:#f92672">import&lt;/span> StringType, IntType
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Game&lt;/span>(Model):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> name &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> year &lt;span style="color:#f92672">=&lt;/span> IntType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console &lt;span style="color:#f92672">=&lt;/span> StringType()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@classmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_claim_polymorphic&lt;/span>(cls, data):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;console&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Nossos modelos são muito parecidos. Neste caso, devemos implementar o método &lt;code>_claim_polymorphic&lt;/code> que ajuda o Schematics a diferenciar entre os modelos com base no payload recebido. Neste caso, retornamos um &lt;code>data.get&lt;/code> com um atributo que seja único entre todas as classes.&lt;/p>
&lt;p>Para verificar o tipo de mídia favorito escolhido pelos Schematics após a ingestão dos dados recebidos, usamos:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>print(person&lt;span style="color:#f92672">.&lt;/span>favorite_media)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que gera como resposta:&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;TVShow instance&amp;gt;
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;p>A saída é definida como uma instância de &lt;code>TvShow&lt;/code> porque informamos um atributo &lt;code>network&lt;/code> em nosso esquema recebido.&lt;/p>
&lt;p>Para acessar o nome da mídia, podemos acessar diretamente o campo de nome:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>print(person&lt;span style="color:#f92672">.&lt;/span>favorite_media&lt;span style="color:#f92672">.&lt;/span>name)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>que gera como resposta:&lt;/p>
&lt;pre tabindex="0">&lt;code>Better Call Saul
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;p>Se alterarmos a entrada para representar um filme, por exemplo, com uma entrada como esta:&lt;/p>
&lt;pre tabindex="0">&lt;code> &amp;#34;favoriteMedia&amp;#34;: {
&amp;#34;name&amp;#34;: &amp;#34;Everything Everywhere All At Once&amp;#34;,
&amp;#34;year&amp;#34;: &amp;#34;2022&amp;#34;
}
&lt;/code>&lt;/pre>&lt;p>Ao enviar o tipo de mídia favorito, vamos ter:&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;Movie instance&amp;gt;
Process finished with exit code 0
&lt;/code>&lt;/pre>&lt;hr>
&lt;p>É isso! Para acessar esta implementação, &lt;a class="link" href="https://github.com/GracieleDamasceno/python-tips/tree/main/schematics" target="_blank" rel="noopener"
>confira o código-fonte no meu Github&lt;/a>.&lt;/p>
&lt;h3 id="referências">&lt;a href="#refer%c3%aancias" class="header-anchor">&lt;/a>Referências
&lt;/h3>&lt;p>&lt;a class="link" href="https://schematics.readthedocs.io/en/latest/index.html" target="_blank" rel="noopener"
>Documentação Schematics Python&lt;/a>&lt;/p></description></item><item><title>AWS Certifications: An Unexpected Journey</title><link>https://blog.devontrack.com/pt-br/posts/2023-06-12-journey-aws-certifications/</link><pubDate>Mon, 12 Jun 2023 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2023-06-12-journey-aws-certifications/</guid><description>&lt;p>Recentemente, tive a grande conquista de obter duas certificações AWS (Practitioner e Solutions Architect Associate) no intervalo de uma semana. Nesse post irei contar como foi a experiência de estudar para as duas provas ao mesmo tempo.&lt;/p>
&lt;h3 id="o-início-da-jornada">&lt;a href="#o-in%c3%adcio-da-jornada" class="header-anchor">&lt;/a>O Início da Jornada
&lt;/h3>&lt;p>Atualmente eu tenho 5 anos de experiência de desenvolvimento de software e trabalhando diretamente com a AWS, eu tenho pouco mais de dois anos. Nesse período, o escopo do meu conhecimento em AWS se resumia a serviços usados no dia-a-dia como dev (tais como EC2, Dynamo, SQS, Lambdas&amp;hellip;)&lt;/p>
&lt;p>Quando decidi tirar a certificação AWS, pensei em começar a estudar para a Practitioner que é o primeiro nível de certificações, porém, não estava me sentindo muito feliz com os estudos; por eu já ter um conhecimento mais na prática, não gostei muito do fato do conteúdo que eu iria aprender para essa certificação ser raso.&lt;/p>
&lt;p>Com isso me veio a ideia de realizar a SAA, que se alinha melhor no meu planejamento de carreira e tem o conteúdo mais alinhado com o que eu queria aprender. Como bônus, poderia reaproveitar o conhecimento adquirido nesse processo e tirar a Practitioner!&lt;/p>
&lt;h3 id="practitioner-vs-solutions-architect-associate">&lt;a href="#practitioner-vs-solutions-architect-associate" class="header-anchor">&lt;/a>Practitioner vs Solutions Architect Associate
&lt;/h3>&lt;p>É interessante comparar o conteúdo das duas provas para descobrir o quanto o conteúdo é similar. Comparando os guias das provas, deu pra perceber que mais ou menos 70% do conteúdo delas é similar. Os conteúdos da Practitioner que não são abordados na Solutions Architect Associate são alguns serviços, pilares do AWS Well-Architected, melhores práticas e vantagens de usar a cloud, AWS Support e os modelos de responsabilidade compartilhadas, dentre outros.&lt;/p>
&lt;h3 id="mãos-a-obra">&lt;a href="#m%c3%a3os-a-obra" class="header-anchor">&lt;/a>Mãos a Obra!
&lt;/h3>&lt;p>Com o objetivo traçado, chegou a hora de traçar as fontes de estudos. A AWS possui muitos serviços e cada um deles tem suas particularidades, por isso, foi bem importante encontrar um curso que se mantenha no escopo da prova e que entregue um nível interessante de profundidade no conteúdo.&lt;/p>
&lt;p>Baseado nisso, utilizei os cursos do &lt;a class="link" href="https://www.udemy.com/user/stephane-maarek/" target="_blank" rel="noopener"
>Sthephane Maarek no Udemy&lt;/a>. Esses cursos são bem focados em explicar o conteúdo coberto pelas certificações de forma sucinta e didática. Além disso, o Sthephane disponibiliza os slides utilizados no curso, que ajudam bastante para uma revisão rápida do conteúdo ou para relembrar alguns conceitos.
Eu assisti todos os vídeos do SAA, fazendo os quizes no final de cada um dos capítulos. Ao final, quando fui fazer o meu primeiro simulado, me veio o choque: eu fui muito mal! 🫠&lt;/p>
&lt;h3 id="aprendendo-a-aprender">&lt;a href="#aprendendo-a-aprender" class="header-anchor">&lt;/a>Aprendendo a Aprender
&lt;/h3>&lt;p>Como fazia um tempinho que eu não estudava no modo sério, digamos que eu estava enferrujada. Nesse processo de estudos percebi uma coisa curiosa sobre mim mesma que não havia notado antes: eu tenho dificuldades em aprender assistindo vídeos, ou absorver conteúdo de forma oral. Foi um choque pra mim perceber que eu não consegui reter muito do conteúdo - que sim, é extenso por si só, mas tive esse choque de realidade ao perceber que eu tenho essa dificuldade a mais e que teria que mudar minha estratégia de combate.&lt;/p>
&lt;p>Eu utilizei a técnica que os antigos dinossauros usavam: Fiz uma revisão anotando conceitos em um caderninho, que me ajudou a realizar uma síntese de cada um dos tópicos. Outro truque que me ajudou foi formular cenários mentais: Por exemplo, o que eu usaria pra conectar minha infraestrutura on-premises com a AWS? Ter esse lado crítico e fazer associações do conteúdo com a minha realidade diária me ajudou bastante a assimilar os conteúdos. Finalmente, além dos cursos, usei também os &lt;a class="link" href="https://aws.amazon.com/whitepapers/" target="_blank" rel="noopener"
>Whitepapers&lt;/a> e &lt;a class="link" href="https://aws.amazon.com/faqs/" target="_blank" rel="noopener"
>FAQs&lt;/a> da AWS, que me ajudaram a sanar dúvidas que eu nem sabia que tinha!&lt;/p>
&lt;p>Com isso, fiz no total 7 simulados. As notas começaram baixas (estava tirando cerca de 50-60% nos primeiros simulados), mas depois foram gradualmente aumentando, até atingir 70-80% nas últimas tentativas. Outro detalhe interessante que me ajudou foi revisar bem os simulados e entender o motivo da resposta certa ser certa e o motivo das incorretas não funcionarem para o contexto da pergunta. No total, creio ter estudado 1 mês, estudando mais ou menos uma a duas horas diárias.
Foi essencial também tirar pausas e revisar conteúdo já visto no intervalo de cada semana para fixação.&lt;/p>
&lt;h3 id="preparar-apontar-fogo">&lt;a href="#preparar-apontar-fogo" class="header-anchor">&lt;/a>Preparar, Apontar, Fogo!
&lt;/h3>&lt;p>E num piscar de olhos chegou o dia do teste! Eu fiz a SAA primeiro e a Practitioner na semana seguinte como round bônus. Optei por fazer a prova em casa e achei o processo bem tranquilo, contando que eu tinha disponível um espaço tranquilo pra fazer a prova, que marquei para 7h da manhã justamente para não ser distraída por barulhos externos. A prova foi mais fácil do que os simulados, o que é excelente - melhor estar super-bem preparado do que mais-ou-menos preparado. Acho que a pior parte foi o nervosismo pela prova e a espera pelo resultado depois do teste.&lt;/p>
&lt;p>Então, depois de 24h chegou o e-mail com a minha badge e o resultado de aprovação. 🥳🎉&lt;/p>
&lt;p>Com a primeira certificação tirada, tomei o intervalo de 6 dias para estudar o conteúdo da Practitioner. Eu não havia focado nos tópicos antes dessa semana pois achei o conteúdo &amp;ldquo;estudável&amp;rdquo; durante o período de uma semana. Foi tranquilo decorar o conteúdo, mas confesso que estava cansada de estudar 🥲&lt;/p>
&lt;p>Depois da SAA, a Practitioner foi mamão com açúcar! O resultado saiu na hora - sem suspense. E desse jeito eu consegui as minhas duas primeiras certificações AWS!&lt;/p>
&lt;div data-iframe-width="150" data-iframe-height="270" data-share-badge-id="085ca332-2226-461e-b240-23a08016bc8c" data-share-badge-host="https://www.credly.com">&lt;/div>&lt;script type="text/javascript" async src="//cdn.credly.com/assets/utilities/embed.js">&lt;/script>
&lt;div data-iframe-width="150" data-iframe-height="270" data-share-badge-id="4d12a234-3479-47ca-be83-f509bdd41d0b" data-share-badge-host="https://www.credly.com">&lt;/div>&lt;script type="text/javascript" async src="//cdn.credly.com/assets/utilities/embed.js">&lt;/script></description></item><item><title>Padrões de Projeto - Bridge</title><link>https://blog.devontrack.com/pt-br/posts/2023-03-03-design-pattern-bridge/</link><pubDate>Fri, 03 Mar 2023 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2023-03-03-design-pattern-bridge/</guid><description>&lt;p>&lt;em>&lt;strong>Bridge&lt;/strong>&lt;/em> é um padrão de projeto estrutural que visa desacoplar uma abstração de sua implementação, de forma que permita que ambos evoluam de forma independente.&lt;/p>
&lt;p>O uso desse padrão é recomendado ao lidar com classes que possuem muitas implementações diferentes e usam herança para implementar a abstração. Nesses casos, a herança conecta uma implementação à abstração permanentemente, de forma que é difícil modificar, aumentar e reutilizar as abstrações de forma independente.&lt;/p>
&lt;p>Para dar um exemplo ilustrado, vamos fingir que temos um cenário onde queremos criar diferentes tipos de contas bancárias: &lt;code>CheckingAccount&lt;/code> e &lt;code>SavingsAccount&lt;/code>. Queremos que nosso sistema seja flexível para a criação de novos tipos de contas, então criamos uma classe abstrata chamada &lt;code>BankAccount&lt;/code> e estendemos esta classe com as classes &lt;code>CheckingAccount&lt;/code> e &lt;code>SavingsAccount&lt;/code>.&lt;/p>
&lt;p>Ótimo! Mais tarde, queremos dar aos nossos tipos de conta seu próprio tipo de cartão de crédito personalizado. Criamos as classes &lt;code>BasicCreditCard&lt;/code>, &lt;code>SilverCreditCard&lt;/code> e &lt;code>GoldCreditCard&lt;/code>. Ao vincular esses cartões de crédito a cada tipo de conta bancária, o problema fica claro:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/bridge.png"
width="1231"
height="536"
srcset="https://blog.devontrack.com/posts/2023-03-03/bridge_hu_1deed85092858d94.png 480w, https://blog.devontrack.com/posts/2023-03-03/bridge_hu_fab3a7c7328269a9.png 1024w"
loading="lazy"
alt="Implementation without bridge pattern"
class="gallery-image"
data-flex-grow="229"
data-flex-basis="551px"
>&lt;/p>
&lt;p>A abordagem ingênua seria criar uma combinação para cada tipo de conta, uma solução que é cara e cresce exponencialmente (imagine o tanto de trabalho se adicionarmos um novo tipo de conta!). O código também é altamente acoplado, pois estados e comportamentos diferentes estariam contidos em uma única classe.&lt;/p>
&lt;p>O padrão Bridge resolve esse problema mudando de herança para composição e realocando todas as classes &lt;code>CreditCard&lt;/code> para sua própria hierarquia. Ao fazer isso, permitimos que ambos os contextos evoluam e mudem independentemente.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/bridge-success.png"
width="1126"
height="486"
srcset="https://blog.devontrack.com/posts/2023-03-03/bridge-success_hu_f0a83ca38cc0d43c.png 480w, https://blog.devontrack.com/posts/2023-03-03/bridge-success_hu_644cdcc413b57b2b.png 1024w"
loading="lazy"
alt="Implementation with bridge pattern"
class="gallery-image"
data-flex-grow="231"
data-flex-basis="556px"
>&lt;/p>
&lt;p>Com esse design em mente, vamos então criar nossa interface &lt;code>CreditCard&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/CreditCard.png"
width="1564"
height="676"
srcset="https://blog.devontrack.com/posts/2023-03-03/CreditCard_hu_d5321153c8a98a5.png 480w, https://blog.devontrack.com/posts/2023-03-03/CreditCard_hu_662469d28ca078cd.png 1024w"
loading="lazy"
alt="CreditCard.java class"
class="gallery-image"
data-flex-grow="231"
data-flex-basis="555px"
>&lt;/p>
&lt;p>Agora, vamos criar nossos tipos: Basic, Silver e Gold, todos implementando os métodos especificados pela interface &lt;code>CreditCard&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/BasicCreditCard.png"
width="1840"
height="1756"
srcset="https://blog.devontrack.com/posts/2023-03-03/BasicCreditCard_hu_b42616b3ef80b28d.png 480w, https://blog.devontrack.com/posts/2023-03-03/BasicCreditCard_hu_ed51e76969a7f099.png 1024w"
loading="lazy"
alt="BasicCreditCard.java class"
class="gallery-image"
data-flex-grow="104"
data-flex-basis="251px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/SilverCreditCard.png"
width="1840"
height="1710"
srcset="https://blog.devontrack.com/posts/2023-03-03/SilverCreditCard_hu_bf63812951305d27.png 480w, https://blog.devontrack.com/posts/2023-03-03/SilverCreditCard_hu_4311d3bc9e7bd146.png 1024w"
loading="lazy"
alt="SilverCreditCard.java class"
class="gallery-image"
data-flex-grow="107"
data-flex-basis="258px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/GoldCreditCard.png"
width="1840"
height="1756"
srcset="https://blog.devontrack.com/posts/2023-03-03/GoldCreditCard_hu_ddc5195eb59514de.png 480w, https://blog.devontrack.com/posts/2023-03-03/GoldCreditCard_hu_3a910a8a5d5d03b2.png 1024w"
loading="lazy"
alt="GoldCreditCard.java class"
class="gallery-image"
data-flex-grow="104"
data-flex-basis="251px"
>&lt;/p>
&lt;p>Vamos criar a abstração &lt;code>BankAccount&lt;/code>, a classe base para nossos tipos de conta. Esta classe terá um objeto &lt;code>CreditCard&lt;/code>, bem como um método para obter as informações do cartão.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/BankAccount.png"
width="1174"
height="720"
srcset="https://blog.devontrack.com/posts/2023-03-03/BankAccount_hu_bbc15e4578a91e13.png 480w, https://blog.devontrack.com/posts/2023-03-03/BankAccount_hu_e531f164e851551.png 1024w"
loading="lazy"
alt="BankAccount.java class"
class="gallery-image"
data-flex-grow="163"
data-flex-basis="391px"
>&lt;/p>
&lt;p>Com tudo criado, podemos escrever nossos tipos de conta &lt;code>CheckingAccount&lt;/code> e &lt;code>SavingsAccount&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/CheckingAccount.png"
width="1802"
height="1016"
srcset="https://blog.devontrack.com/posts/2023-03-03/CheckingAccount_hu_f8dce44562d45a3b.png 480w, https://blog.devontrack.com/posts/2023-03-03/CheckingAccount_hu_c00d1f2b61b9de9a.png 1024w"
loading="lazy"
alt="CheckingAccount.java class"
class="gallery-image"
data-flex-grow="177"
data-flex-basis="425px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/SavingsAccount.png"
width="1784"
height="972"
srcset="https://blog.devontrack.com/posts/2023-03-03/SavingsAccount_hu_cf1c78deecfc2d17.png 480w, https://blog.devontrack.com/posts/2023-03-03/SavingsAccount_hu_adef77b32cb748bc.png 1024w"
loading="lazy"
alt="SavingsAccount.java class"
class="gallery-image"
data-flex-grow="183"
data-flex-basis="440px"
>&lt;/p>
&lt;p>Para testar nosso projeto, criaremos uma classe principal inicializando cada conta com seus respectivos tipos de cartão de crédito.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/BridgeApplication.png"
width="1840"
height="972"
srcset="https://blog.devontrack.com/posts/2023-03-03/BridgeApplication_hu_dc25a90c10b224a9.png 480w, https://blog.devontrack.com/posts/2023-03-03/BridgeApplication_hu_27096a6468bf459d.png 1024w"
loading="lazy"
alt="BridgeApplication.java class"
class="gallery-image"
data-flex-grow="189"
data-flex-basis="454px"
>&lt;/p>
&lt;p>&amp;hellip;que gera o seguinte conteúdo:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-03-03/Output.png"
width="2594"
height="1212"
srcset="https://blog.devontrack.com/posts/2023-03-03/Output_hu_836e3352a8446eab.png 480w, https://blog.devontrack.com/posts/2023-03-03/Output_hu_5703c3f88097633b.png 1024w"
loading="lazy"
alt="Output.java class"
class="gallery-image"
data-flex-grow="214"
data-flex-basis="513px"
>&lt;/p>
&lt;p>No fim das contas, o padrão Bridge é uma ótima ferramenta para ser utilizada quando queremos dividir e refatorar classes com muitas variantes, e também quando precisamos estender uma classe em dimensões independentes. Um grande benefício em usar esse padrão é que ele segue o &lt;strong>princípio aberto/fechado&lt;/strong> (já que podemos adicionar abstrações e implementações sem afetar as existentes) e o &lt;strong>princípio de responsabilidade única&lt;/strong>.&lt;/p>
&lt;p>Você pode verificar a implementação completa deste exemplo &lt;a class="link" href="https://github.com/GracieleDamasceno/design-patterns" target="_blank" rel="noopener"
>aqui no meu Github: GracieleDamasceno/design-patterns&lt;/a>!&lt;/p>
&lt;h4 id="referências">&lt;a href="#refer%c3%aancias" class="header-anchor">&lt;/a>Referências:
&lt;/h4>&lt;p>&lt;a class="link" href="https://refactoring.guru/design-patterns/bridge" target="_blank" rel="noopener"
>Bridge Pattern - Refactoring Guru&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://www.google.com.br/books/edition/Valuepack_Design_Patterns_Elements_of_Re/VDRePgAACAAJ" target="_blank" rel="noopener"
>Design Patterns&lt;/a> (2005), By &lt;a class="link" href="https://www.google.com.br/search?hl=pt-BR&amp;amp;q=inauthor:%22Erich&amp;#43;Gamma%22&amp;amp;tbm=bks" target="_blank" rel="noopener"
>Erich Gamma&lt;/a>, &lt;a class="link" href="https://www.google.com.br/search?hl=pt-BR&amp;amp;q=inauthor:%22Richard&amp;#43;Helm%22&amp;amp;tbm=bks" target="_blank" rel="noopener"
>Richard Helm&lt;/a>, &lt;a class="link" href="https://www.google.com.br/search?hl=pt-BR&amp;amp;q=inauthor:%22Ralph&amp;#43;Johnson%22&amp;amp;tbm=bks" target="_blank" rel="noopener"
>Ralph Johnson&lt;/a>, &lt;a class="link" href="https://www.google.com.br/search?hl=pt-BR&amp;amp;q=inauthor:%22John&amp;#43;Vlissides%22&amp;amp;tbm=bks" target="_blank" rel="noopener"
>John Vlissides&lt;/a>, &lt;a class="link" href="https://www.google.com.br/search?hl=pt-BR&amp;amp;q=inauthor:%22Craig&amp;#43;Larman%22&amp;amp;tbm=bks" target="_blank" rel="noopener"
>Craig Larman&lt;/a>&lt;/p></description></item><item><title>Padrões de Projeto - Adapter</title><link>https://blog.devontrack.com/pt-br/posts/2023-02-18-design-pattern-adapter/</link><pubDate>Sat, 18 Feb 2023 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2023-02-18-design-pattern-adapter/</guid><description>&lt;p>&lt;em>&lt;strong>Adapter&lt;/strong>&lt;/em> é um padrão de projeto com a finalidade de - como o próprio nome sugere - adaptar um contexto à outro, permitindo que duas interfaces incompatíveis sejam conectadas. O principal benefício de aplicar esse padrão é permitir trocar de uma interface existente para outra sem alterar o comportamento original da interface existente. o Adapter também é usado quando há a necessidade de criar uma classe reutilizável que interaja com interfaces incompatíveis. Vamos ver esse padrão em ação!&lt;/p>
&lt;h2 id="adaptando-a-saída-existente-para-uma-nova">&lt;a href="#adaptando-a-sa%c3%adda-existente-para-uma-nova" class="header-anchor">&lt;/a>Adaptando a saída existente para uma nova
&lt;/h2>&lt;p>Em nosso cenário, temos uma POJO de pessoa que contém alguns atributos.&lt;/p>
&lt;br>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/Person.png"
width="1040"
height="1016"
srcset="https://blog.devontrack.com/posts/2023-02-18/Person_hu_2a6a8e610182fe12.png 480w, https://blog.devontrack.com/posts/2023-02-18/Person_hu_468b9fad6e3b597c.png 1024w"
loading="lazy"
alt="Person.java"
class="gallery-image"
data-flex-grow="102"
data-flex-basis="245px"
>&lt;/p>
&lt;br>
&lt;p>Existe também uma interface que dita qual será o contrato de negócio do objeto Pessoa. Em nosso caso, o contrato existente estabelece que a resposta da classe &lt;code>Person&lt;/code> deve ser uma string formatada em XML.&lt;/p>
&lt;br>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/PersonOutput.png"
width="1040"
height="342"
srcset="https://blog.devontrack.com/posts/2023-02-18/PersonOutput_hu_3fbaab79c1ac57a4.png 480w, https://blog.devontrack.com/posts/2023-02-18/PersonOutput_hu_903d318d5ee261b3.png 1024w"
loading="lazy"
alt="PersonOutput.java"
class="gallery-image"
data-flex-grow="304"
data-flex-basis="729px"
>&lt;/p>
&lt;p>&lt;br>E a classe &lt;code>LegacyPersonService&lt;/code> implementa esse contrato, construindo um objeto da classe &lt;code>Person&lt;/code> e retornando-o em string, formatada em XML.&lt;/p>
&lt;br>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/LegacyPersonService.png"
width="1658"
height="1466"
srcset="https://blog.devontrack.com/posts/2023-02-18/LegacyPersonService_hu_bc13637398cb571e.png 480w, https://blog.devontrack.com/posts/2023-02-18/LegacyPersonService_hu_fe431d41aaa599ec.png 1024w"
loading="lazy"
alt="LegacyPersonService.java"
class="gallery-image"
data-flex-grow="113"
data-flex-basis="271px"
>&lt;/p>
&lt;br>
&lt;p>Essa arquitetura funciona bem por um bom tempo, até que seja necessário redesenhar nosso sistema. Como nesse cenário temos muitas dependências externas e cruciais, a resposta em XML tem que coexistir com a nova solução, que tem como objetivo ter a resposta em string no formato JSON.&lt;/p>
&lt;p>É exatamente aí que o padrão do adaptador é muito útil!&lt;/p>
&lt;p>Vamos adaptar nossa solução anterior para gerar um JSON, seguindo os novos requisitos. Primeiro, vamos implementar uma interface que dite esse novo contrato.&lt;/p>
&lt;br>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/PersonOutputAdapter.png"
width="1040"
height="386"
srcset="https://blog.devontrack.com/posts/2023-02-18/PersonOutputAdapter_hu_7e48ac8c1b4e2ac9.png 480w, https://blog.devontrack.com/posts/2023-02-18/PersonOutputAdapter_hu_4fae8e419e527c35.png 1024w"
loading="lazy"
alt="PersonOutputAdapter.java"
class="gallery-image"
data-flex-grow="269"
data-flex-basis="646px"
>&lt;/p>
&lt;p>&lt;br>Agora, criamos o adapter: implementando a interface criada anteriormente, instanciamos a classe &lt;code>LegacyPersonService&lt;/code> que contém a lógica do contrato antigo e implementamos a nova lógica para transformar a resposta em uma string em JSON.
&lt;br>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/ModernizedPersonAdapter.png"
width="1420"
height="836"
srcset="https://blog.devontrack.com/posts/2023-02-18/ModernizedPersonAdapter_hu_a6bf557d114917ad.png 480w, https://blog.devontrack.com/posts/2023-02-18/ModernizedPersonAdapter_hu_50b990aca4be17b7.png 1024w"
loading="lazy"
alt="ModernizedPersonAdapter.java"
class="gallery-image"
data-flex-grow="169"
data-flex-basis="407px"
>
&lt;br>&lt;/p>
&lt;p>Com a lógica criada, podemos criar tranquilamente uma nova versão do nosso endpoint que atenda à nova especificação, sem alterar a que já existia.&lt;/p>
&lt;br>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2023-02-18/PersonController.png"
width="1840"
height="1286"
srcset="https://blog.devontrack.com/posts/2023-02-18/PersonController_hu_b2a78282c0f1ac84.png 480w, https://blog.devontrack.com/posts/2023-02-18/PersonController_hu_a98c70c1e2a8f098.png 1024w"
loading="lazy"
alt="PersonController.java"
class="gallery-image"
data-flex-grow="143"
data-flex-basis="343px"
>&lt;/p>
&lt;br>
&lt;p>Então, para resumir:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>O padrão de Adapter segue o &lt;strong>princípio aberto-fechado&lt;/strong>. Podemos adicionar novos adaptadores sem alterar o código existente.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>O padrão de Adapter também segue o princípio da &lt;strong>responsabilidade única&lt;/strong>, pois separamos a interface/contrato da lógica de negócios existente.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>No nosso caso, foi utilizada composição na classe &lt;code>ModernizedPersonAdapter&lt;/code> para encapsular o alvo do adaptador (&lt;code>LegacyPersonService&lt;/code>). Esta forma de lidar com a classe &lt;em>adaptada&lt;/em> é chamada de &lt;strong>Object Adapter&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>A outra forma de implementar um adaptador seria usando o estilo &lt;strong>Class Adapter&lt;/strong>, onde ao invés de criar um objeto &lt;code>LegacyPersonService&lt;/code> em &lt;code>ModernizedPersonAdapter&lt;/code>, estenderíamos &lt;code>LegacyPersonService&lt;/code> e implementaríamos &lt;code>PersonOutputAdapter&lt;/code> simultaneamente. Ambas são abordagens válidas, no entanto, é melhor favorecer a composição em detrimento da herança, pois permite que o sistema seja mais fácil de testar, menos complexo e desacoplado.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>A principal desvantagem que esse padrão oferece é o aumento da complexidade ao adicionar novos componentes à aplicação. Dependendo da situação e das restrições externas, é melhor apenas refatorar o código existente para corresponder ao novo contrato.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;br>
&lt;p>Você pode dar uma olhada no código &lt;a class="link" href="https://github.com/GracieleDamasceno/design-patterns" target="_blank" rel="noopener"
>aqui no meu Github: GracieleDamasceno/design-patterns&lt;/a>! Até a próxima!&lt;/p>
&lt;br>
&lt;h2 id="referências">&lt;a href="#refer%c3%aancias" class="header-anchor">&lt;/a>Referências:
&lt;/h2>&lt;p>&lt;a class="link" href="https://en.wikipedia.org/wiki/Composition_over_inheritance" target="_blank" rel="noopener"
>Composition over inheritance - Wikipedia&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://refactoring.guru/design-patterns/adapter" target="_blank" rel="noopener"
>Adapter Pattern - Refactoring Guru&lt;/a>&lt;/p></description></item><item><title>Padrões de Projeto - Prototype</title><link>https://blog.devontrack.com/pt-br/posts/2022-11-04-design-pattern-prototype/</link><pubDate>Fri, 04 Nov 2022 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-11-04-design-pattern-prototype/</guid><description>&lt;p>Continuando nossa série de padrões de projeto, o segundo que iremos revisitar é o Prototype!&lt;/p>
&lt;p>Este padrão visa ter um “planta” para gerar instâncias. Isso é muito útil em situações onde existem vários objetos com propriedades diferentes, onde seja custoso criar novos recursos e quando queremos especificar a instanciação da classe em tempo de execução.&lt;/p>
&lt;p>Basicamente, para implementar um Prototype, temos que adicionar à classe original desejada um método que clona uma instância baseada na original. O próximo passo é criar uma espécie de “registro” que mantenha um cache dos objetos prototipados; seguido por uma classe de fábrica que clona o original e retorna o resultado.&lt;/p>
&lt;p>O processo de clonagem é um dos aspecto mais importantes do Prototype, então, para entender melhor as nuances escondidas na clonagem de um objeto, vamos falar sobre Deep Cloning e Shallow Cloning.&lt;/p>
&lt;h2 id="deep-cloning-versus-shallow-cloning">&lt;a href="#deep-cloning-versus-shallow-cloning" class="header-anchor">&lt;/a>Deep Cloning versus Shallow Cloning
&lt;/h2>&lt;p>&lt;strong>Deep Cloning&lt;/strong> significa que, ao clonar, cada cópia terá sua própria referência. Se alterarmos um atributo da cópia, o original permanecerá intacto.&lt;/p>
&lt;p>O mesmo não acontece com o &lt;strong>Shallow Cloning:&lt;/strong> tanto a cópia quanto o original compartilham a mesma referência. Isso significa que as alterações feitas nos atributos de cópia também serão refletidas nos atributos do objeto original.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-11-04/diagram-shallow-deep-cloning.png"
width="1217"
height="508"
srcset="https://blog.devontrack.com/posts/2022-11-04/diagram-shallow-deep-cloning_hu_eacc1f1d62668ffd.png 480w, https://blog.devontrack.com/posts/2022-11-04/diagram-shallow-deep-cloning_hu_9ab545d7486f9ce2.png 1024w"
loading="lazy"
alt="Deep Cloning vs Shallow Cloning"
class="gallery-image"
data-flex-grow="239"
data-flex-basis="574px"
>&lt;/p>
&lt;h2 id="implementando-o-padrão-prototype-em-java">&lt;a href="#implementando-o-padr%c3%a3o-prototype-em-java" class="header-anchor">&lt;/a>Implementando o Padrão Prototype em Java
&lt;/h2>&lt;p>Existem algumas “&lt;em>pegadinhas&lt;/em>” ao implementar o Prototype em Java: A escolha óbvia, a interface &lt;code>Cloneable&lt;/code> do Java, é comumente conhecida por ser defeituosa. Simplesmente não existe um mecanismo construído em Java para criar &amp;ldquo;deep clones&amp;rdquo; nativamente, o que significa que implementar &lt;code>Cloneable&lt;/code> e chamar &lt;code>super.clone()&lt;/code> sempre criará uma cópia superficial. Pior ainda, a interface &lt;code>Cloneable&lt;/code> é uma classe &lt;em>marker&lt;/em> que apenas marca a classe que a implementa como adequada para clonagem, e não possui um método &lt;code>clone()&lt;/code> próprio (este método existe na classe Object).&lt;/p>
&lt;p>Esses fatores argumentam por ser uma escolha melhor usar cópia via construtores para criar clones ao invés do &lt;code>Cloneable&lt;/code> do Java.&lt;/p>
&lt;p>Com isso em mente, vamos tentar usar o Prototype para resolver um problema. O conceito é o seguinte: Queremos acompanhar algumas Criptomoedas que foram compradas em 1º de janeiro de 2022. Os valores nesse período preenchem a instância original quando o aplicativo é iniciado. O usuário envia sua escolha de criptomoeda e o aplicativo chama um endpoint para obter informações em tempo real sobre essa criptomoeda específica, calcula a diferença entre o antes e o depois e envia de volta em um relatório.&lt;/p>
&lt;p>Esse é o diagrama de arquitetura do aplicativo:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-11-04/diagram-prototype.png"
width="1566"
height="891"
srcset="https://blog.devontrack.com/posts/2022-11-04/diagram-prototype_hu_1ac7681f8a2e6e16.png 480w, https://blog.devontrack.com/posts/2022-11-04/diagram-prototype_hu_c1364acfac621279.png 1024w"
loading="lazy"
alt="Prototype Architecture"
class="gallery-image"
data-flex-grow="175"
data-flex-basis="421px"
>&lt;/p>
&lt;p>A classe de controller da aplicação é a seguinte:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@RestController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@AllArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CryprocurrencyController&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">final&lt;/span> CryptocurrencyService cryptocurrencyService;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@GetMapping&lt;/span>(value &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/crypto/{cryptocurrencyType}&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> CryptocurrencyReport &lt;span style="color:#a6e22e">cryptocurrencyController&lt;/span>(&lt;span style="color:#a6e22e">@PathVariable&lt;/span> CryptocurrencyTypeEnum cryptocurrencyType) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> cryptocurrencyService.&lt;span style="color:#a6e22e">getCryptocurrencyReport&lt;/span>(cryptocurrencyType);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Então, o controller invoca a service:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Service&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@AllArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CryptocurrencyService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">final&lt;/span> CryptocurrencyClient cryptocurrencyClient;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">final&lt;/span> CryptocurrencyLoader cryptocurrencyLoader;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> CryptocurrencyReport &lt;span style="color:#a6e22e">getCryptocurrencyReport&lt;/span>(CryptocurrencyTypeEnum cryptocurrencyTypeEnum){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Get original Cryptocurrency instance&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency cryptocurrencyAtPurchase &lt;span style="color:#f92672">=&lt;/span> cryptocurrencyLoader.&lt;span style="color:#a6e22e">getCryptocurrencyLoaded&lt;/span>(cryptocurrencyTypeEnum);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Get Cryptocurrency cloned with updated values&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency cryptocurrencyNow &lt;span style="color:#f92672">=&lt;/span> getUpdatedCryptocurrencyValues(cryptocurrencyTypeEnum);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Returns the report calculating variation between purshased value and current value&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> CryptocurrencyReport.&lt;span style="color:#a6e22e">builder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">cryptocurrencyCurrentValues&lt;/span>(cryptocurrencyNow)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">cryptocurrencyPurchaseValues&lt;/span>(cryptocurrencyAtPurchase)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">rankVariation&lt;/span>(calculateVariation(cryptocurrencyAtPurchase.&lt;span style="color:#a6e22e">getRank&lt;/span>(), cryptocurrencyNow.&lt;span style="color:#a6e22e">getRank&lt;/span>()))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">priceUSDVariation&lt;/span>(calculateVariation(cryptocurrencyAtPurchase.&lt;span style="color:#a6e22e">getPriceUSD&lt;/span>(), cryptocurrencyNow.&lt;span style="color:#a6e22e">getPriceUSD&lt;/span>()))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">volume24Variation&lt;/span>(calculateVariation(cryptocurrencyAtPurchase.&lt;span style="color:#a6e22e">getVolume24&lt;/span>(), cryptocurrencyNow.&lt;span style="color:#a6e22e">getVolume24&lt;/span>()))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">marketCapUSDVariation&lt;/span>(calculateVariation(cryptocurrencyAtPurchase.&lt;span style="color:#a6e22e">getMarketCapUSD&lt;/span>(), cryptocurrencyNow.&lt;span style="color:#a6e22e">getMarketCapUSD&lt;/span>()))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">build&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> Cryptocurrency &lt;span style="color:#a6e22e">getUpdatedCryptocurrencyValues&lt;/span>(CryptocurrencyTypeEnum cryptocurrencyTypeEnum){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Requests current Crypto&amp;#39;s data &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">final&lt;/span> CryptocurrencyDTO cryptocurrencyDTO &lt;span style="color:#f92672">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyClient.&lt;span style="color:#a6e22e">getCryptocurrency&lt;/span>(cryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">getId&lt;/span>()).&lt;span style="color:#a6e22e">iterator&lt;/span>().&lt;span style="color:#a6e22e">next&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Loads original cripto values&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency cryptocurrencyLoaded &lt;span style="color:#f92672">=&lt;/span> cryptocurrencyLoader.&lt;span style="color:#a6e22e">getCryptocurrencyLoaded&lt;/span>(cryptocurrencyTypeEnum);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Maps the current values to the original Criptocurrency object&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> updateLoadedPrototypeWithCurrentValues(cryptocurrencyDTO, cryptocurrencyLoaded);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> BigDecimal &lt;span style="color:#a6e22e">calculateVariation&lt;/span>(BigDecimal valueBefore, BigDecimal valueNow){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> valueNow.&lt;span style="color:#a6e22e">subtract&lt;/span>(valueBefore);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> Integer &lt;span style="color:#a6e22e">calculateVariation&lt;/span>(Integer valueBefore, Integer valueNow){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> valueNow &lt;span style="color:#f92672">-&lt;/span> valueBefore;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Essa é a classe que realiza o mapeamento do objeto recebido para o clone:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@NoArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CryptocurrencyDTOMapper&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> Cryptocurrency &lt;span style="color:#a6e22e">updateLoadedPrototypeWithCurrentValues&lt;/span>(CryptocurrencyDTO cryptocurrencyDTO, Cryptocurrency cryptocurrencyLoaded){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyLoaded.&lt;span style="color:#a6e22e">setRank&lt;/span>(cryptocurrencyDTO.&lt;span style="color:#a6e22e">getRank&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyLoaded.&lt;span style="color:#a6e22e">setPriceUSD&lt;/span>(cryptocurrencyDTO.&lt;span style="color:#a6e22e">getPriceUSD&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyLoaded.&lt;span style="color:#a6e22e">setVolume24&lt;/span>(cryptocurrencyDTO.&lt;span style="color:#a6e22e">getVolume24&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyLoaded.&lt;span style="color:#a6e22e">setMarketCapUSD&lt;/span>(cryptocurrencyDTO.&lt;span style="color:#a6e22e">getMarketCapUSD&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> cryptocurrencyLoaded;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A classe que carrega a instância de Cryptocurrency:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Component&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CryptocurrencyLoader&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> HashMap&lt;span style="color:#f92672">&amp;lt;&lt;/span>String, Cryptocurrency&lt;span style="color:#f92672">&amp;gt;&lt;/span> cryptocurrencyTable &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> HashMap&lt;span style="color:#f92672">&amp;lt;&amp;gt;&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Returns crypto object based on the enum requested by the user&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Cryptocurrency &lt;span style="color:#a6e22e">getCryptocurrencyLoaded&lt;/span>(CryptocurrencyTypeEnum crypto){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency loadedCryptocurrency &lt;span style="color:#f92672">=&lt;/span> cryptocurrencyTable.&lt;span style="color:#a6e22e">get&lt;/span>(crypto.&lt;span style="color:#a6e22e">getId&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Here the cloning happens!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> Cryptocurrency(loadedCryptocurrency);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">//Loads the crypto information on application startup&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@PostConstruct&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> &lt;span style="color:#a6e22e">loadCryptoInfo1stJanuary2022&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency bitcoin &lt;span style="color:#f92672">=&lt;/span> Cryptocurrency.&lt;span style="color:#a6e22e">builder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">id&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">BTC&lt;/span>.&lt;span style="color:#a6e22e">getId&lt;/span>())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">name&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;BITCOIN&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">symbol&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">BTC&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">rank&lt;/span>(1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">volume24&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;24582667004&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">priceUSD&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;47686.81&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">marketCapUSD&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;902104193385&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">build&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Cryptocurrency ethereum &lt;span style="color:#f92672">=&lt;/span> Cryptocurrency.&lt;span style="color:#a6e22e">builder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">id&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">ETH&lt;/span>.&lt;span style="color:#a6e22e">getId&lt;/span>())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">name&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;ETHEREUM&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">symbol&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">ETH&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">rank&lt;/span>(1)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">volume24&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;9776191466&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">priceUSD&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;3769.70&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">marketCapUSD&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> BigDecimal(&lt;span style="color:#e6db74">&amp;#34;448537615143&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">build&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyTable.&lt;span style="color:#a6e22e">put&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">BTC&lt;/span>.&lt;span style="color:#a6e22e">getId&lt;/span>(), bitcoin);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrencyTable.&lt;span style="color:#a6e22e">put&lt;/span>(CryptocurrencyTypeEnum.&lt;span style="color:#a6e22e">ETH&lt;/span>.&lt;span style="color:#a6e22e">getId&lt;/span>(), ethereum);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finalmente, a classe de Cryptocurrency que realiza a clonagem através do construtor com um parâmetro:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Getter&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Setter&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Builder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@NoArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@AllArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Cryptocurrency&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> String id;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> CryptocurrencyTypeEnum symbol;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> String name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> Integer rank;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@JsonProperty&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;price_usd&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> BigDecimal priceUSD;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@JsonProperty&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;volume_24&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> BigDecimal volume24;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@JsonProperty&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;market_cap_usd&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> BigDecimal marketCapUSD;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Since the clone method from Cloneable class is broken, we use a copy constructor.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#a6e22e">Cryptocurrency&lt;/span>(Cryptocurrency cryptocurrency) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">this&lt;/span>(cryptocurrency.&lt;span style="color:#a6e22e">getId&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getSymbol&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getName&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getRank&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getPriceUSD&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getVolume24&lt;/span>(),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cryptocurrency.&lt;span style="color:#a6e22e">getMarketCapUSD&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Você pode checar a implementação completa do projeto &lt;a class="link" href="https://github.com/GracieleDamasceno/design-patterns/tree/main/prototype" target="_blank" rel="noopener"
>clicando aqui.&lt;/a>&lt;/p>
&lt;h2 id="referências">&lt;a href="#refer%c3%aancias" class="header-anchor">&lt;/a>Referências
&lt;/h2>&lt;p>Discussões interessantes sobre o Cloneable do Java:&lt;/p>
&lt;p>&lt;a class="link" href="https://programming.guide/java/clone-and-cloneable.html" target="_blank" rel="noopener"
>Java: Clone and Cloneable &amp;gt; Programming.Guide&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://www.vojtechruzicka.com/java-cloning-problems/" target="_blank" rel="noopener"
>Java Cloning Problems &amp;gt; Vojtech Ruzicka&amp;rsquo;s Programming Blog&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="http://www.javapractices.com/topic/TopicAction.do?Id=12" target="_blank" rel="noopener"
>Copy constructors &amp;gt; Java Practices&lt;/a>&lt;/p></description></item><item><title>Melhorando a comunicação assíncrona no ambiente de trabalho</title><link>https://blog.devontrack.com/pt-br/posts/2022-09-11-improving-asynchronous-communication/</link><pubDate>Sun, 11 Sep 2022 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-09-11-improving-asynchronous-communication/</guid><description>&lt;p>Trabalhar remotamente pode resultar em alguns desafios inesperados. Quando precisamos de ajuda em um ambiente onde todos estão fisicamente compartilhando o mesmo espaço, podemos simplesmente nos chegar em um colega no intervalo do café e pedir ajuda, apontando freneticamente para a tela enquanto explicamos o que estávamos fazendo antes que não funciona mais agora.&lt;/p>
&lt;p>No entanto, em um ambiente remoto, às vezes pedir ajuda ou tirar dúvidas pode ser um grande desafio. Primeiro, eu iria analisar minuciosamente o chat, procurando alguém que esteja disponível que &lt;em>possa&lt;/em> com sorte saber a resposta para o meu problema, secretamente esperando que a pessoa não mude seu status para &amp;ldquo;ocupado&amp;rdquo; ou &amp;ldquo;não perturbe&amp;rdquo; nos próximos cinco segundos. Ótimo, a pessoa está disponível! Eu vou ligar&amp;hellip; Não, é muito abrupto; melhor enviar uma mensagem.&lt;/p>
&lt;blockquote>
&lt;p>Eu: Bom dia Joe, tudo bem?&lt;/p>&lt;/blockquote>
&lt;p>E&amp;hellip; nada. Joe não me responde imediatamente. Talvez ele não tenha visto minha mensagem, isso pode acontecer de vez em quando. Vamos tentar chamar a atenção dele novamente:&lt;/p>
&lt;blockquote>
&lt;p>Eu: Você está ocupado?&lt;/p>&lt;/blockquote>
&lt;p>Nada. Estou travada! Joe precisa me responder para que eu consiga seguir em frente. Ele é o único que pode. Cada segundo que ele leva para me responder é um tempo perdido que não posso recuperar.&lt;/p>
&lt;blockquote>
&lt;p>Joe: Oi Gracie. Eu estou bem. E você?&lt;/p>&lt;/blockquote>
&lt;p>&lt;strong>AÍ SIM&lt;/strong>! Demorou um pouco para me responder, só que ele só respondeu a minha primeira pergunta. Vamos tentar de novo:&lt;/p>
&lt;blockquote>
&lt;p>Eu: Estou bem, obrigado. Pode me ajudar com uma coisinha?&lt;/p>&lt;/blockquote>
&lt;p>&amp;hellip;&lt;/p>
&lt;p>Joe sumiu de novo. Ele não me respondeu.&lt;/p>
&lt;p>E ainda estou travada.&lt;/p>
&lt;h2 id="qual-é-o-problema-aqui">&lt;a href="#qual-%c3%a9-o-problema-aqui" class="header-anchor">&lt;/a>Qual é o problema aqui?
&lt;/h2>&lt;p>Talvez Joe esteja super ocupado e não tenha atualizado seu status. Talvez ele esteja tentando resolver um problema próprio. Talvez ele esteja ajudando outra pessoa. Talvez ele esteja fazendo uma pausa para o café. Talvez sua conexão com a internet não esteja tão boa agora. Talvez ele se distraiu e esqueceu de responder. Talvez&amp;hellip;&lt;/p>
&lt;p>Nunca dá pra saber o que a outra pessoa está fazendo enquanto trabalhando remoto. Não dá pra dar aquela olhadinha de canto e ver a expressão super concentrada do colega, aquela cara de &lt;em>nem-nem-tente-me-incomodar-que-o-bagulho-ta-feio&lt;/em>. Portanto, justamente por estarmos remoto, uma coisa que devemos ter em mente é que devemos aprender a trabalhar &lt;strong>de forma assíncrona&lt;/strong>.&lt;/p>
&lt;p>Nem sempre o outro estará disponível o tempo todo para você, e &lt;strong>está tudo bem&lt;/strong> (o problema é quando eles nunca estão disponíveis para ninguém, mas isso é discussão para outro tópico&amp;hellip;). Do mesmo jeito como nem você não está disponível para ajudar o tempo todo. Com isso em mente, podemos usar algumas técnicas para aproveitar ao máximo o tempo disponível de todos.&lt;/p>
&lt;p>Voltando ao nosso cenário: Joe me responde três horas depois com:&lt;/p>
&lt;blockquote>
&lt;p>Joe: Sim, desculpe a demora. O que está acontecendo?&lt;/p>&lt;/blockquote>
&lt;p>Aí eu nem sei nem mais por onde começar minha pergunta. Então eu mando:&lt;/p>
&lt;blockquote>
&lt;p>Eu: Posso te ligar para mostrar meu problema?&lt;/p>&lt;/blockquote>
&lt;p>Aqui vêm algumas ramificações deste cenário:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Joe está disponível para conversar agora. Vou ligar para ele e explicar o que estava tentando fazer e o que não está funcionando. Depois de cinco minutos ouvindo, ele vai me perguntar se eu tentei fazer isso ou aquilo, eu vou dizer que não, ainda não tentei, e ele vai esperar na ligação enquanto eu tento aplicar sua sugestão. Funcionou! Excelente.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Joe está disponível para conversar agora. Vou ligar para ele e explicar o que estava tentando fazer, e enquanto explico, percebo que&amp;hellip; Algo não parece certo. Eu me escuto explicando e percebo que agora posso chegar à raiz do meu problema. Percebo algum ponto de falha na minha lógica, ou que eu tinha entendido superficialmente o que estava fazendo. Enquanto falo, minha voz desaparece lentamente e exclamo com orgulho que entendi! Eu rapidamente resolvo o problema, agradeço a Joe por seu tempo e sigo em frente.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Joe não está disponível para conversar agora. Procuro outra pessoa para me ajudar.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Vamos examinar algumas técnicas para melhorar esses cenários.&lt;/p>
&lt;h2 id="1-como-escrever-perguntas-de-forma-eficaz-para-obter-se-comunicar-de-forma-assíncrona-e-precisa">&lt;a href="#1-como-escrever-perguntas-de-forma-eficaz-para-obter-se-comunicar-de-forma-ass%c3%adncrona-e-precisa" class="header-anchor">&lt;/a>1. Como escrever perguntas de forma eficaz para obter se comunicar de forma assíncrona e precisa
&lt;/h2>&lt;p>No primeiro cenário, liguei para Joe e expliquei desde o início o que eu estava tentando fazer. Dá pra notar que muito tempo foi gasto esperando Joe me responder antes de conseguir falar com ele. Existe uma maneira melhorar essas situações?&lt;/p>
&lt;p>Eu poderia tentar explicar meu problema via texto para Joe, para que quando ele veja minha mensagem, ele possa passar algum tempo pensando e me dar a melhor resposta possível. Existem algumas técnicas que podem ser usadas para melhorar a qualidade de nossa comunicação escrita; vamos dar uma olhada no método Pirâmide Minto (você pode ler mais sobre esse método de escrita visitando o site &lt;a class="link" href="https://untools.co/minto-pyramid" target="_blank" rel="noopener"
>untools&lt;/a>.)&lt;/p>
&lt;p>&lt;strong>A Pirâmide Minto&lt;/strong> é uma técnica para escrever melhor e comunicar de forma mais eficiente e clara. Ela se concentra principalmente em compartilhar a essência do problema imediatamente, elaborando os detalhes posteriormente seguindo três etapas:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-09-11/minto-pyramid.png"
width="535"
height="405"
srcset="https://blog.devontrack.com/posts/2022-09-11/minto-pyramid_hu_59a5df5ce261f040.png 480w, https://blog.devontrack.com/posts/2022-09-11/minto-pyramid_hu_b7484c9b6633e5aa.png 1024w"
loading="lazy"
alt="Minto Pyramid"
class="gallery-image"
data-flex-grow="132"
data-flex-basis="317px"
>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Para começar, capture a atenção do espectador imediatamente, contando-lhe a essência do problema logo no início. É um começo bastante eficiente, pois pode envolver o leitor a pensar e realmente focar no problema principal.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Em seguida, apoie sua pergunta fornecendo argumentos e pontos-chave breves, explicando os principais detalhes sobre o problema.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Agora é a hora de dar todos os pequenos detalhes que você tiver: o que você tentou, os detalhes mais finos do problema, coisas que podem estar interferindo no seu resultado final, alguns palpites da sua parte&amp;hellip; Se a pessoa está muito ocupada e já sabem a resposta, podem pular essa parte inconscientemente, mas às vezes ainda é necessário enriquecer o contexto.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Vamos reescrever nossa primeira mensagem para Joe com tudo isso em mente:&lt;/p>
&lt;blockquote>
&lt;p>Eu: Oi Joe! Estou tentando acessar nosso banco de dados, porém, a conexão está sendo recusada.&lt;/p>
&lt;p>Preciso me conectar ao banco de dados para poder verificar os atributos da nossa tabela para finalizar outra tarefa.&lt;/p>
&lt;p>Tentei verificar se meu username e senha estão corretos e também minhas configurações de proxy, e tudo parece estar funcionando bem. Também troquei entre a linha de comando e uma ferramenta GUI, mas ainda não tive sorte.
Isso pode ser um problema de acesso? Talvez eu não esteja autorizada a acessar o banco?&lt;/p>&lt;/blockquote>
&lt;p>Depois de um tempo, Joe responde minha mensagem:&lt;/p>
&lt;blockquote>
&lt;p>Joe: Olá! Acabei de dar uma olhadinha no sistema principal e sim, foi devido a um problema de autorização. Você não tinha uma permissão válida para acessar o banco de dados, mas acabei de corrigir. Agora vai dar bom!&lt;/p>&lt;/blockquote>
&lt;p>Dá pra ver como nossa interação foi bem mais rápida? Com apenas duas trocas de mensagens meu problema foi resolvido. Escrevi todas as partes importantes em apenas uma mensagem, como se fosse enviar um e-mail, onde a outra pessoa poderia demorar um pouco para receber, ler e me responder.&lt;/p>
&lt;p>Essa técnica de escrita também nos leva a&amp;hellip;&lt;/p>
&lt;h2 id="2-a-arte-de-obter-respostas-sem-ao-menos-precisar-perguntar-para-alguém-também-conhecida-como-a-teoria-do-pato-de-borracha">&lt;a href="#2-a-arte-de-obter-respostas-sem-ao-menos-precisar-perguntar-para-algu%c3%a9m-tamb%c3%a9m-conhecida-como-a-teoria-do-pato-de-borracha" class="header-anchor">&lt;/a>2. A arte de obter respostas sem ao menos precisar perguntar para alguém, também conhecida como: a teoria do pato de borracha
&lt;/h2>&lt;p>Na maioria das vezes, apenas o simples ato de organizar nossos pensamentos pode ser muito benéfico para a resolução de problemas. Como um experimento escrevendo a pergunta do cenário acima em um bloco de notas, sem nem ao menos enviar para ninguém, eu poderia facilmente chegar à mesma conclusão que Joe.&lt;/p>
&lt;p>Isso tem correlação direta com o fato de alguém explicar algo complexo para outra pessoa pode aumentar bastante o seu conhecimento próprio sobre a questão em si, as vezes levando diretamente para perceber a solução.&lt;/p>
&lt;p>Tentar analisar o problema com os olhos de outra pessoa também pode melhorar a qualidade de nossas perguntas, eliminando redundância e indo direto ao ponto com maior facilidade.&lt;/p>
&lt;p>No entanto, às vezes, só analisar o nosso problema não é suficiente. Às vezes, não conseguimos encontrar uma resposta nós mesmos e nosso primeiro instinto pode ser perguntar a outra pessoa, mas por que não perguntar a nós mesmos:&lt;/p>
&lt;h2 id="3-você-sabe-google-fu">&lt;a href="#3-voc%c3%aa-sabe-google-fu" class="header-anchor">&lt;/a>3. Você sabe Google-Fu?
&lt;/h2>&lt;p>O último recurso antes de pedir ajuda pode ser pesquisar no Google. A esse ponto, já isolamos o problema e pensamos um pouco sobre ele e o contexto, então por que não procurá-lo na internet? Pode esclarecer ou solidificar alguns pontos de nossa compreensão da situação.&lt;/p>
&lt;p>A experiência de pesquisar no Google pode ser melhorada por:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;a class="link" href="https://support.google.com/websearch/answer/2466433?hl=en" target="_blank" rel="noopener"
>Usando operadores de pesquisa avançada do Google&lt;/a>, como aspas duplas;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Estar atento às palavras-chave escolhidas para pesquisar, procurando focar no objetivo principal da pesquisa;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Se for algo muito específico, tentar pesquisar em vários idiomas, se possível;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Não tenha medo de olhar para vários links e fontes em sua pesquisa! A resposta pode estar em um deles;&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tentando outros motores de busca.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Com tudo isso dito, há também mais uma habilidade a desenvolver - essa sendo mais difícil de equilibrar: em qual ocasião devemos conversar pessoalmente. Às vezes, é melhor ligar para outra pessoa para compartilhar notícias, pedir conselhos ou apenas conversar; isso aumenta o vínculo na equipe, o que é muito importante para melhorar a sinergia geral do time. Outro ponto é que nem todos se sentem confortáveis em se espressar por texto. Nesse caso, a dica de tentar comunicar mais por mensagens no dia a dia pode ser um excelente modo de melhorar as habilidades de comunicação escrita e até falada.&lt;/p></description></item><item><title>Padrões de Projeto - Factory</title><link>https://blog.devontrack.com/pt-br/posts/2022-08-29-design-pattern-factory/</link><pubDate>Mon, 29 Aug 2022 08:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-08-29-design-pattern-factory/</guid><description>&lt;p>Hoje vamos dar uma olhada no Padrão de Projeto &amp;ldquo;Factory&amp;rdquo;.&lt;/p>
&lt;p>Imagine que você tenha que construir uma applicação que envie uma mensagem especificada pelo usuário usando diferentes métodos de entrega. Por exemplo, o usuário poderia enviar sua mensagem usando SMS, uma notificação push para um celular, e-mail&amp;hellip;&lt;/p>
&lt;p>Seria um incômodo construir muitas classes diferentes para receber a mensagem do usuário e entregá-la! Quero dizer, imagine se o usuário tiver que utilizar diferentes endpoints/argumentos para enviar cada tipo de mensagem. Pensando em código, teríamos que criar um método que chamasse cada uma das classes que enviariam uma mensagem de cada maneira específica. Mas e se eu quiser desenvolver outro tipo de método de entrega? Eu teria que alterar a lógica que envia cada mensagem para seu respectivo tipo e, se não tomar cuidado, poderia excluir ou modificar partes importantes dessa lógica. Meu código teria muitas condições e poderia ser altamente acoplado.&lt;/p>
&lt;p>Os Padrões de Projeto sugerem uma maneira bem legal de resolver esse problema. Vamos ver como!&lt;/p>
&lt;h3 id="mãos-a-obra">&lt;a href="#m%c3%a3os-a-obra" class="header-anchor">&lt;/a>Mãos a obra!
&lt;/h3>&lt;p>Primeiro, vamos dar uma olhadinha no nosso diagrama de arquitetura.&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-29/factory-diagram.png"
width="1521"
height="851"
srcset="https://blog.devontrack.com/posts/2022-08-29/factory-diagram_hu_4f2ad58a013a3a08.png 480w, https://blog.devontrack.com/posts/2022-08-29/factory-diagram_hu_6be78175bed7bd.png 1024w"
loading="lazy"
alt="Notification Factory Diagram"
class="gallery-image"
data-flex-grow="178"
data-flex-basis="428px"
>&lt;/p>
&lt;p>A ideia principal é criar uma interface de notificação que terá um método de entrega definido, para que cada uma das classes implemente suas próprias especificidades da entrega. Há cinco métodos de entrega definidos, e esses métodos serão chamados com base em um parâmetro enviado pelo usuário por meio de uma classe de service. Daqui a pouco vamos ver mais detalhes sobre isso.&lt;/p>
&lt;p>Esse projeto usa Java com Spring, e uma chamada &lt;code>REST&lt;/code> para receber a mensagem desejada. Vamos começar criando um controller &lt;code>REST&lt;/code> onde o usuário pode postar sua mensagem e o tipo de entrega selecionado.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Slf4j&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@RestController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@AllArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">NotificationController&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> NotificationService notificationService;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@PostMapping&lt;/span>(value &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;/message&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> DeliveryResponseDTO &lt;span style="color:#a6e22e">sendMessage&lt;/span>(&lt;span style="color:#a6e22e">@RequestBody&lt;/span> MessageRequestDTO message, &lt;span style="color:#a6e22e">@RequestParam&lt;/span> NotificationTypeEnum delivery) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> log.&lt;span style="color:#a6e22e">info&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;Message received. Method of delivery: &amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> delivery &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;. Payload: &amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> message);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> notificationService.&lt;span style="color:#a6e22e">redirectMessage&lt;/span>(message, delivery);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Criamos uma classe &lt;code>MessageRequestDTO&lt;/code> que encapsula uma mensagem de tipo String e uma classe enum chamada &lt;code>NotificationTypeEnum&lt;/code> com todas as nossas opções de entrega.&lt;/p>
&lt;p>A interface que especifica nosso método de entrega padrão para todas as opções de entrega é a seguinte:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">Notification&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DeliveryResponseDTO &lt;span style="color:#a6e22e">deliverMessage&lt;/span>(MessageRequestDTO message);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>E este é um exemplo de nossa classe de entrega implementando a interface &lt;code>Notification&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Slf4j&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CarrierPigeonNotification&lt;/span> &lt;span style="color:#66d9ef">implements&lt;/span> Notification {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">@Override&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> DeliveryResponseDTO &lt;span style="color:#a6e22e">deliverMessage&lt;/span>(MessageRequestDTO message) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> log.&lt;span style="color:#a6e22e">info&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;Carrier Pigeon is the selected choice of delivery! The message to send is: &amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> message);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> DeliveryResponseDTO.&lt;span style="color:#a6e22e">builder&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">delivered&lt;/span>(&lt;span style="color:#66d9ef">false&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">deliveryStatus&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;Delivery method not yet supported!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">build&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Maravilha, agora vamos criar a classe &lt;code>NotificationService&lt;/code> que tratará o envio da nossa requisição de mensagem vinda do controller.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@NoArgsConstructor&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">@Service&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">NotificationService&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> DeliveryResponseDTO &lt;span style="color:#a6e22e">redirectMessage&lt;/span>(MessageRequestDTO message, NotificationTypeEnum methodOfDelivery){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Notification notification &lt;span style="color:#f92672">=&lt;/span> methodOfDelivery.&lt;span style="color:#a6e22e">getInstance&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> notification.&lt;span style="color:#a6e22e">deliverMessage&lt;/span>(message);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Pera aí&amp;hellip; &lt;em>Não tem muita coisa acontecendo aqui.&lt;/em> Criamos um método para redirecionar a mensagem recebendo o próprio DTO de mensagem e o método de entrega, que é um enum. Aparentemente, existe um método dentro do nosso enum para obter a instância do &lt;code>NotificationType&lt;/code>&amp;hellip; Vamos dar uma olhada em como a classe enum foi criada.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">enum&lt;/span> NotificationTypeEnum {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CARRIER_PIGEON {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> CarrierPigeonNotification &lt;span style="color:#a6e22e">getInstance&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> CarrierPigeonNotification();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> EMAIL {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> EmailNotification &lt;span style="color:#a6e22e">getInstance&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> EmailNotification();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MAIL_LETTER {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> MailLetterNotification &lt;span style="color:#a6e22e">getInstance&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> MailLetterNotification();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> MOBILE_PUSH {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> MobilePushNotification &lt;span style="color:#a6e22e">getInstance&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> MobilePushNotification();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> SMS{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> SMSNotification &lt;span style="color:#a6e22e">getInstance&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> SMSNotification();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">abstract&lt;/span> Notification &lt;span style="color:#a6e22e">getInstance&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Essa é a classe mais interessante de todo o projeto, na minha opinião. Estamos aplicando um conceito bem legal aqui - criando um método &lt;code>getInstance&lt;/code> que retorna a classe correta de entrega com base no enum enviado pelo usuário. Dessa forma, evitamos blocos &lt;em>if&lt;/em> e nosso código se torna mais limpo e eficiente.&lt;/p>
&lt;p>É possível notar que não tivemos que chamar nenhuma de nossas classes de entrega - nem as classes de service nem de controller precisaram chamar. Se quiséssemos adicionar um novo tipo de entrega, não teríamos que mexer em nenhuma das outras classes de tipo de entrega, elas nem &amp;ldquo;perceberiam&amp;rdquo; a adição ou remoção de tal método de entrega. Isso acontece porque nossa lógica de construção das instancias das classes é mantida por apenas uma classe usada como &amp;ldquo;fábrica&amp;rdquo;, neste caso, a &lt;code>NotificationTypeEnum&lt;/code>.&lt;/p>
&lt;p>Então, para simplificar, o Factory funciona criando uma interface que é responsável por criar &lt;em>famílias&lt;/em> de objetos que possuem a mesma &amp;ldquo;função&amp;rdquo;, mas com comportamento diferente, sem a necessidade de especificar qual é a classe concreta desses objetos. A parte de ser uma fábrica está na criação de mecanismos que tratam de selecionar a implementação correta para cada caso necessário.&lt;/p>
&lt;p>É isso! Você pode conferir a implementação completa desse exemplo de factory &lt;a class="link" href="https://github.com/GracieleDamasceno/design-patterns/tree/main/factory" target="_blank" rel="noopener"
>clicando aqui.&lt;/a>&lt;/p></description></item><item><title>Opengram - Um gerenciador de albums web e open-source</title><link>https://blog.devontrack.com/pt-br/posts/2022-08-10-opengram/</link><pubDate>Wed, 10 Aug 2022 22:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-08-10-opengram/</guid><description>&lt;h2 id="o-dilema">&lt;a href="#o-dilema" class="header-anchor">&lt;/a>O Dilema
&lt;/h2>&lt;p>Nesses últimos anos tenho tentado fazer um &amp;ldquo;desintoxicação das redes sociais&amp;rdquo;. Mesmo antes da pandemia, estava numa fase de tentar me distanciar das redes sociais simplesmente porque não era mais divertido. Os algoritmos que vieram prometendo melhorar o tempo de qualidade das redes sociais criam bolhas impossíveis de estourar. Desinformação, más notícias, negatividade, pessoas compartilhando demais online&amp;hellip; Tudo isso me afastou de sentir vontade de fazer login.&lt;/p>
&lt;p>No entanto, há um lado das redes sociais que sinto muita falta: compartilhar notícias pessoais com meus amigos mais próximos. Sinto falta de não me preocupar com curtidas, compartilhamentos ou minha timeline sendo inundada por conteúdo que não pedi; sinto falta daqueles bons tempos em que eu logava apenas para conversar e focar em conversas reais com amigos e familiares. Sinto falta de compartilhar minhas fotos de momentos especiais e ter conversas significativas sobre elas.&lt;/p>
&lt;p>Falando em fotos, eu adoraria ter uma ferramenta que me permitisse criar álbuns e escrever descrições com contexto sobre elas, mesmo que fosse apenas uma forma de manter um diário local. Tentei encontrar soluções de código aberto que atendesse minhas necessidades, mas nada realmente se encaixava no que eu estava procurando. Até que&amp;hellip;&lt;/p>
&lt;h2 id="se-você-não-consegue-encontrar-por-que-não-construir-do-zero">&lt;a href="#se-voc%c3%aa-n%c3%a3o-consegue-encontrar-por-que-n%c3%a3o-construir-do-zero" class="header-anchor">&lt;/a>Se você não consegue encontrar, por que não construir do zero?
&lt;/h2>&lt;p>A essa altura, já tinha um tempo não tinha nenhum projeto grande em Node.js. Então eu tive a &amp;ldquo;ótima&amp;rdquo; ideia de combinar o útil com o agradável e construir meu próprio gerenciador de álbuns/fotos usando Node.js e React. Só para deixar claro, eu não sou um grande especialista em tecnologias web/front-end (sofri bastante nesse projeto haha), então essa foi uma maneira de me empurrar para fora da minha zona de experiência também. A ideia era simples: construir um projeto se inspirando no Instagram onde eu pudesse fazer &amp;ldquo;upload&amp;rdquo; de imagens e agrupá-las em álbuns, com descrições.&lt;/p>
&lt;h2 id="mãos-à-obra">&lt;a href="#m%c3%a3os-%c3%a0-obra" class="header-anchor">&lt;/a>Mãos à obra!
&lt;/h2>&lt;p>&lt;strong>Opengram&lt;/strong> foi criado com isso em mente. É um projeto &lt;em>muito&lt;/em> simples com escopo limitado. Aqui estão alguns prints de alguns recursos:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/1.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/1_hu_648b64bb694bd24b.png 480w, https://blog.devontrack.com/posts/2022-08-10/1_hu_3478b286abd887d3.png 1024w"
loading="lazy"
alt="Login page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/2.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/2_hu_5c62c3082c4e2edc.png 480w, https://blog.devontrack.com/posts/2022-08-10/2_hu_d6a9d8a7531cb7c4.png 1024w"
loading="lazy"
alt="Register/sign-up page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/3.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/3_hu_b16847865eb77b42.png 480w, https://blog.devontrack.com/posts/2022-08-10/3_hu_23bac72bbb2767c2.png 1024w"
loading="lazy"
alt="Profile page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/5.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/5_hu_568ab9415dc782e3.png 480w, https://blog.devontrack.com/posts/2022-08-10/5_hu_3ce70e2b5efe5392.png 1024w"
loading="lazy"
alt="Create album page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/6.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/6_hu_e10d0218e99806a9.png 480w, https://blog.devontrack.com/posts/2022-08-10/6_hu_6d8e9aa0d7980d4e.png 1024w"
loading="lazy"
alt="List of albums page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/7.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/7_hu_d643e4ce88a1cbad.png 480w, https://blog.devontrack.com/posts/2022-08-10/7_hu_386f4312570dcf00.png 1024w"
loading="lazy"
alt="Album details page"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/8.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/8_hu_deece999f83fb16f.png 480w, https://blog.devontrack.com/posts/2022-08-10/8_hu_e69c7da84991a3dd.png 1024w"
loading="lazy"
alt="Add photos to album"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/9.png"
width="1366"
height="667"
srcset="https://blog.devontrack.com/posts/2022-08-10/9_hu_26ea491f3456f75c.png 480w, https://blog.devontrack.com/posts/2022-08-10/9_hu_f4444168b982bc.png 1024w"
loading="lazy"
alt="Updated album details"
class="gallery-image"
data-flex-grow="204"
data-flex-basis="491px"
>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-08-10/10.png"
width="1207"
height="768"
srcset="https://blog.devontrack.com/posts/2022-08-10/10_hu_c3ad97f794aa953c.png 480w, https://blog.devontrack.com/posts/2022-08-10/10_hu_2933626156004b78.png 1024w"
loading="lazy"
alt="Updated profile with album"
class="gallery-image"
data-flex-grow="157"
data-flex-basis="377px"
>&lt;/p>
&lt;p>Algumas dependências foram usadas para construir este projeto, como &lt;code>bcrypt&lt;/code>, &lt;code>express&lt;/code>, &lt;code>multer&lt;/code>, &lt;code>bootstrap&lt;/code>, &lt;code>axios&lt;/code>, entre muitas outras, juntamente com o MongoDB como banco de dados. O front-end e o back-end foram divididos em dois repositórios, ambos dockerizados. No começo, tentei emular um aplicativo local do tipo Instagram, com login e vários usuários, mas&amp;hellip; pensando no uso no mundo real, parece meio bobo ter vários usuários em um aplicativo da web local, não é? Ainda assim mantive o sistema de login que já havia implementado. Essa também foi minha primeira experiência com funções assíncronas em Node.js, foi interessante aprender mais sobre &lt;em>Promises&lt;/em>.&lt;/p>
&lt;p>Para saber mais sobre o código-fonte, &lt;a class="link" href="https://github.com/GracieleDamasceno/opengram" target="_blank" rel="noopener"
>clique aqui para conferir o repositório Opengram&lt;/a> e &lt;a class="link" href="https://github.com/GracieleDamasceno/opengram-front" target="_blank" rel="noopener"
>aqui para acessar o Opengram Front.&lt;/a>&lt;/p></description></item><item><title>Arquivo de Exoplanetas da Nasa</title><link>https://blog.devontrack.com/pt-br/posts/2022-07-23-nasa-exoplanet-archive/</link><pubDate>Sat, 23 Jul 2022 05:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-07-23-nasa-exoplanet-archive/</guid><description>&lt;p>Este é um projetinho desenvolvido para aprender mais sobre APIs e gráficos em Python. O principal objetivo aqui foi coletar informações usando um endpoint que oferece dados de exoplanetas (que são planetas fora do nosso sistema solar). Os dados usados na aplicação são provenientes do site do Nasa Exoplanet Science Institute, por meio de uma chamada de API.&lt;/p>
&lt;p>O Nasa Exoplanet Archive é um catálogo de estrelas e exoplanetas que reúne e correlaciona dados e informações sobre exoplanetas. Você pode conferir mais sobre o site e a iniciativa &lt;a class="link" href="https://exoplanetarchive.ipac.caltech.edu/docs/intro.html" target="_blank" rel="noopener"
>aqui&lt;/a>.&lt;/p>
&lt;h2 id="detalhes-do-projeto">&lt;a href="#detalhes-do-projeto" class="header-anchor">&lt;/a>Detalhes do Projeto
&lt;/h2>&lt;p>O projeto usa as seguintes bibliotecas externas:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;code>FastApi&lt;/code> para criar endpoints e expôr dados,&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Requests&lt;/code> para buscar informações do banco de dados do Nasa Exoplanet Archive,&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>MongoClient&lt;/code> para salvar tais dados localmente,&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>Pandas&lt;/code> + &lt;code>MatPlotLib&lt;/code> para criar gráficos bacanas com os dados coletados.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="endpoints-da-api">&lt;a href="#endpoints-da-api" class="header-anchor">&lt;/a>Endpoints da API
&lt;/h2>&lt;p>&lt;code>/sync-database&lt;/code>: endpoint que chama o site do Exoplanets&amp;rsquo; Archive e coleta a resposta, salvando ou atualizando os dados existentes em um banco de dados local.&lt;/p>
&lt;p>&lt;strong>Curl&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/sync-database&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;code&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">200&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;message&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Database successfully updated 32606 elements&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;data&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;total_elements&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">32606&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Observações pessoais:&lt;/strong> este endpoint &lt;em>pode&lt;/em> demorar um pouco para carregar. Tentei pegar leve ao construir a solicitação da API para o site da Nasa, selecionando apenas mais alguns parâmetros mais &amp;ldquo;interessantes&amp;rdquo; para construir meu banco de dados local:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>file_url &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;https://exoplanetarchive.ipac.caltech.edu/TAP/sync?&amp;#34;&lt;/span> \
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;query=select+pl_name,sy_snum,sy_pnum,disc_year,&amp;#34;&lt;/span> \
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;discoverymethod,disc_facility,disc_locale,&amp;#34;&lt;/span> \
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;disc_telescope,pl_orbper,pl_rade,pl_bmasse+&amp;#34;&lt;/span> \
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;from+ps&amp;amp;format=json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Tomei a decisão de salvar tudo em um banco de dados Mongo apenas para testar a integração do &lt;code>MongoClient&lt;/code> com o Pyhton, sem nenhum outro motivo especial além disso. E olha, no momento que fiz essa requisição arquivo da Nasa possui 32606 elementos! Isso é bem legal!&lt;/p>
&lt;hr>
&lt;p>&lt;code>/planets&lt;/code>: Retorna todos os exoplanetas paginados com o uso de filtros (nome do exoplaneta, método de descoberta, onde foi descoberto, ano de descoberta).&lt;/p>
&lt;p>&lt;strong>Curl&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/planets?size=3&amp;amp;page_num=1&amp;amp;ordered=desc&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;code&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">200&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;message&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Planets successfully retrieved&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;data&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;62ddfacf34ec799ba78a342f&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;TOI-1272 c&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_stars&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_planets&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">2&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_year&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">2022&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_method&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Radial Velocity&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_facility&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;W. M. Keck Observatory&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_locale&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Ground&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_telescope&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;10 m Keck I Telescope&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;orbital_period&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">8.689&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_radius&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">null&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_mass&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">26.7&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;link&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://exoplanetarchive.ipac.caltech.edu/overview/TOI-1272 c&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;62ddfacf34ec799ba78a348b&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;TOI-500 d&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_stars&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_planets&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">4&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_year&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">2022&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_method&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Radial Velocity&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_facility&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;La Silla Observatory&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_locale&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Ground&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_telescope&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3.6 m ESO Telescope&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;orbital_period&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">26.233&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_radius&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">null&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_mass&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">33.12&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;link&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://exoplanetarchive.ipac.caltech.edu/overview/TOI-500 d&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;id&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;62ddfacf34ec799ba78a348c&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;TOI-500 e&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_stars&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;number_of_planets&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">4&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_year&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">2022&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_method&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Radial Velocity&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_facility&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;La Silla Observatory&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_locale&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Ground&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;discovery_telescope&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3.6 m ESO Telescope&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;orbital_period&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">61.3&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_radius&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">null&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;planet_earth_mass&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">15.05&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;link&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://exoplanetarchive.ipac.caltech.edu/overview/TOI-500 e&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;total_elements&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">32606&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Notas Pessoais:&lt;/strong> A resposta vem paginada e ordenada por ano de descoberta. Na resposta, todos os elementos possuem um link que leva ao site do Arquivo, para verificar mais informações sobre o exoplaneta em questão.&lt;/p>
&lt;hr>
&lt;p>&lt;code>/plot/planet/discovery-year&lt;/code>: Produz um gráfico com todos os planetas agrupados por ano de descoberta.&lt;/p>
&lt;p>&lt;strong>Curl:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/plot/planet/discovery-year&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta:&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-year.png"
width="1179"
height="951"
srcset="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-year_hu_14355806b2aceff5.png 480w, https://blog.devontrack.com/posts/2022-07-23/plot-discovery-year_hu_90bb008d2f4d10b3.png 1024w"
loading="lazy"
alt="Chart with number planets by year"
class="gallery-image"
data-flex-grow="123"
data-flex-basis="297px"
>&lt;/p>
&lt;p>&lt;strong>Notas pessoais:&lt;/strong> É muito louco concluir que o número de planetas descobertos foi expressivamente maior em 2014 e 2016. Tive que ajustar o gráfico para exibir o número de planetas usando a notação científica, já que a discrepância era tão grande que os valores dos outros anos quase não apareceram!&lt;/p>
&lt;hr>
&lt;p>&lt;code>/plot/planet/discovery-method&lt;/code>: Produz um gráfico com todos os planetas agrupados por método de descoberta.&lt;/p>
&lt;p>&lt;strong>Curl:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/plot/planet/discovery-method&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta:&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-method.png"
width="1504"
height="908"
srcset="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-method_hu_be34ceba7e00b12c.png 480w, https://blog.devontrack.com/posts/2022-07-23/plot-discovery-method_hu_1ee53d2f6d3a7db4.png 1024w"
loading="lazy"
alt="Chart with number planets by discovery method"
class="gallery-image"
data-flex-grow="165"
data-flex-basis="397px"
>&lt;/p>
&lt;p>&lt;strong>Notas pessoais:&lt;/strong> Mais uma vez, descobrir planetas por trânsito (confira a &lt;a class="link" href="https://exoplanets.nasa.gov/faq/31/whats-a-transit/" target="_blank" rel="noopener"
>explicação desse método de descoberta&lt;/a>) parece ser a maneira mais popular de se descobrir exoplanetas. A visualização também foi ajustada à notação científica.&lt;/p>
&lt;hr>
&lt;p>&lt;code>/plot/planet/discovery-facility&lt;/code>: Produz um gráfico com todos os planetas agrupados por estação de descoberta.&lt;/p>
&lt;p>&lt;strong>Curl&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/plot/planet/discovery-facility&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta:&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-facility.png"
width="2818"
height="1744"
srcset="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-facility_hu_596d8c8910bcbf8a.png 480w, https://blog.devontrack.com/posts/2022-07-23/plot-discovery-facility_hu_a1e87dd11dd53ae7.png 1024w"
loading="lazy"
alt="Chart with number planets by discovery facility"
class="gallery-image"
data-flex-grow="161"
data-flex-basis="387px"
>&lt;/p>
&lt;p>&lt;strong>Notas Pessoais:&lt;/strong> &lt;a class="link" href="https://exoplanets.nasa.gov/keplerscience/" target="_blank" rel="noopener"
>Kepler&lt;/a> ganha o prêmio como &amp;ldquo;estação&amp;rdquo; que mais descobriu exoplanetas!&lt;/p>
&lt;hr>
&lt;p>&lt;code>/plot/planet/discovery-locale&lt;/code>: Produz um gráfico com todos os planetas agrupados por local de descoberta.&lt;/p>
&lt;p>&lt;strong>Curl&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/plot/planet/discovery-locale&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta&lt;/strong>:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-locale.png"
width="1313"
height="908"
srcset="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-locale_hu_551fc4015fc3c8ed.png 480w, https://blog.devontrack.com/posts/2022-07-23/plot-discovery-locale_hu_25d39a53ec24608b.png 1024w"
loading="lazy"
alt="Chart with number planets by discovery locale"
class="gallery-image"
data-flex-grow="144"
data-flex-basis="347px"
>&lt;/p>
&lt;p>&lt;strong>Notas Pessoais:&lt;/strong> O espaço é um ponto de vista bem privilegiado (Kepler que o diga!) para ver outros planetas. Há duas instâncias de &amp;ldquo;Multiple Locale&amp;rdquo; que poderiam ter sido mescladas, no entanto, achei divertido que uma possui S e a outra não e acabei deixando assim.&lt;/p>
&lt;hr>
&lt;p>&lt;code>/plot/planet/discovery-telescope&lt;/code>: Produz um gráfico com todos os planetas agrupados por telescópio usado na descoberta.&lt;/p>
&lt;p>&lt;strong>Curl&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X &lt;span style="color:#e6db74">&amp;#39;GET&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> &lt;span style="color:#e6db74">&amp;#39;http://localhost:8000/plot/planet/discovery-telescope&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#39;accept: application/json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Resposta&lt;/strong>:&lt;/p>
&lt;p>&lt;img src="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-telescope.png"
width="2831"
height="1744"
srcset="https://blog.devontrack.com/posts/2022-07-23/plot-discovery-telescope_hu_8538a57cfd6409eb.png 480w, https://blog.devontrack.com/posts/2022-07-23/plot-discovery-telescope_hu_f495c63ea0c3cfb1.png 1024w"
loading="lazy"
alt="Chart with number planets by discovery telescope"
class="gallery-image"
data-flex-grow="162"
data-flex-basis="389px"
>&lt;/p>
&lt;p>&lt;strong>Notas pessoais:&lt;/strong> Foi um choque descobrir que em segundo lugar atrás do Kepler em número de exoplanetas descobertos estava a Canon 200mm f1.8, uma câmera com mais de 30 anos de idade!&lt;/p>
&lt;hr>
&lt;h2 id="conclusão">&lt;a href="#conclus%c3%a3o" class="header-anchor">&lt;/a>Conclusão
&lt;/h2>&lt;p>Esta foi uma das minhas primeiras oportunidades de trabalhar com &lt;code>pandas&lt;/code> e construir gráficos em Python e eu não poderia estar mais feliz! Eu gostei bastante de construir uma API e me diverti muito descobrindo mais sobre exoplanetas, que é um dos meus interesses pessoais. Você pode verificar o &lt;a class="link" href="https://github.com/GracieleDamasceno/nasa-exoplanet-archive" target="_blank" rel="noopener"
>repositório com todo o código fonte aqui&lt;/a>.&lt;/p></description></item><item><title>Criando uma skill de audio local na Alexa</title><link>https://blog.devontrack.com/pt-br/posts/2022-07-20-creating-alexa-skill/</link><pubDate>Wed, 20 Jul 2022 22:00:00 +0000</pubDate><guid>https://blog.devontrack.com/pt-br/posts/2022-07-20-creating-alexa-skill/</guid><description>&lt;p>Tutorial que mostra como criar uma Alexa Skill facilmente, chamando um arquivo de áudio externo para impressionar seus amigos e família.&lt;/p>
&lt;h2 id="primeiros-passos">&lt;a href="#primeiros-passos" class="header-anchor">&lt;/a>Primeiros passos
&lt;/h2>&lt;p>Para começar, você precisa de uma conta de desenvolvedor da Amazon. Você pode criar clicando &lt;a class="link" href="https://developer.amazon.com/" target="_blank" rel="noopener"
>aqui&lt;/a> e fazendo login com sua conta Amazon já existente, se já tiver uma, ou criando uma nova conta. No entanto, é importante observar que para &amp;ldquo;testar&amp;rdquo; sua habilidade em seu dispositivo, você deve usar a mesma conta do seu dispositivo Alexa.&lt;/p>
&lt;p>Após o login, você deve acessar o &lt;a class="link" href="https://developer.amazon.com/alexa/console/ask" target="_blank" rel="noopener"
>Alexa Development Console&lt;/a>, onde criaremos a primeira skill.&lt;/p>
&lt;h2 id="criando-uma-skill">&lt;a href="#criando-uma-skill" class="header-anchor">&lt;/a>Criando uma skill
&lt;/h2>&lt;p>Para criar uma nova habilidade, basta clicar no botão &lt;code>Create Skill&lt;/code>. Crie um nome para sua habilidade e selecione seu idioma padrão.
Nas primeiras configurações &lt;code>Choose a model to add to your skill&lt;/code>, deixe marcado no padrão como está (Custom) e selecione &amp;ldquo;Alexa-hosted (Node.js)&amp;rdquo; como opção na configuração &lt;code>Choose a method to host your skill's backend resources&lt;/code>, se já não estiver selecionado.
Quando tudo estiver pronto, clique em &lt;code>Create Skill&lt;/code>. A próxima página pedirá que você escolher um novo template (&lt;code>Choose a template to add to your skill&lt;/code>), e devemos selecionar a opção de começar do zero&amp;quot;Start from Scratch&amp;quot; e clicar em &lt;code>Continue with template&lt;/code>. Voilà! Temos nossa habilidade criada e pronta para ser personalizada.&lt;/p>
&lt;h2 id="adicionando-um-nome-de-invocação-e-interface-de-áudio">&lt;a href="#adicionando-um-nome-de-invoca%c3%a7%c3%a3o-e-interface-de-%c3%a1udio" class="header-anchor">&lt;/a>Adicionando um nome de invocação e interface de áudio
&lt;/h2>&lt;p>Com a habilidade criada, a primeira etapa é criar um nome de invocação. Esta é a frase/duas palavras que o Alexa usará para invocar nosso código. Para configurar isso, precisamos clicar em &lt;code>Invocation Name&lt;/code> digitar a invocação desejada no campo abaixo de &lt;code>Skill Invocation Name&lt;/code> e clicar em &lt;code>Save Model&lt;/code>. Com isso configurado e pronto, há mais uma configuração que precisa ser feita: ativar nossa interface de áudio. Para fazer isso, clique na opção &lt;code>Interfaces&lt;/code> que está localizada no menu à esquerda. Depois disso, marque o botão chamado &lt;code>Audio Player&lt;/code> e salve a interface e o modelo de construção.
A mensagem &lt;code>Quick build in progress&lt;/code> será exibida. Aguarde até que a compilação esteja pronta e vamos para a próxima etapa!&lt;/p>
&lt;h2 id="editando-o-código">&lt;a href="#editando-o-c%c3%b3digo" class="header-anchor">&lt;/a>Editando o código
&lt;/h2>&lt;p>O próximo passo é editar o código adicionando nosso arquivo de áudio! Precisamos especificar um URL que contém um áudio que se reproduz. Você pode auto-hospedar o áudio na AWS ou em qualquer host de sua escolha, ou pesquisar na web para encontrar um. No meu exemplo, usarei um áudio do &lt;a class="link" href="https://www.myinstants.com" target="_blank" rel="noopener"
>My Instants&lt;/a>.&lt;/p>
&lt;p>Para editar o código, clique em &lt;code>Code&lt;/code> no menu. Um editor de código no navegador aparecerá com vários arquivos. O que vamos editar é o &lt;code>index.js&lt;/code>, e já deve estar aberto.&lt;/p>
&lt;p>A próxima parte é fácil: substitua o seguinte código:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">speakOutput&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;Welcome, you can say Hello or Help. Which would you like to try?&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">handlerInput&lt;/span>.&lt;span style="color:#a6e22e">responseBuilder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">speak&lt;/span>(&lt;span style="color:#a6e22e">speakOutput&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">reprompt&lt;/span>(&lt;span style="color:#a6e22e">speakOutput&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">getResponse&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>por esse aqui:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">speakOutput&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;Its me, Mario!&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">handlerInput&lt;/span>.&lt;span style="color:#a6e22e">responseBuilder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">speak&lt;/span>(&lt;span style="color:#a6e22e">speakOutput&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">addAudioPlayerPlayDirective&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;REPLACE_ALL&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;*&amp;#39;&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#66d9ef">null&lt;/span>, &lt;span style="color:#66d9ef">null&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">getResponse&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Explicando brevemente, o &lt;code>speakOutput&lt;/code> corresponde à linha que o Alexa dirá para você quando nosso código for invocado. Você pode mudar o &lt;code>It's me, Mario!&lt;/code> para o que você quiser, apenas certifique-se de escrever entre aspas simples.
A mágica acontece assim: na linha &lt;code>.addAudioPlayerPlayDirective('REPLACE_ALL', '*', 1, 0, null, null)&lt;/code>, o &lt;code>'*'&lt;/code> é o espaço reservado para nosso link de áudio. Troquei para ficar assim:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">speakOutput&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;Its me, Mario!&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">handlerInput&lt;/span>.&lt;span style="color:#a6e22e">responseBuilder&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">speak&lt;/span>(&lt;span style="color:#a6e22e">speakOutput&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">addAudioPlayerPlayDirective&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;REPLACE_ALL&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;https://www.myinstants.com/media/sounds/its-me-mario.mp3&amp;#39;&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#66d9ef">null&lt;/span>, &lt;span style="color:#66d9ef">null&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">getResponse&lt;/span>();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Depois de adicionar seu arquivo de áudio ao código, você precisa &lt;code>Save&lt;/code> e &lt;code>Deploy&lt;/code> seu código, espere até que a implantação seja feita e pronto! Pera, falta testar 🤔&lt;/p>
&lt;h2 id="ativando-o-modo-de-teste">&lt;a href="#ativando-o-modo-de-teste" class="header-anchor">&lt;/a>Ativando o modo de teste
&lt;/h2>&lt;p>Para finalmente chamar a habilidade em sua Alexa pessoal, há uma última etapa: ativar o modo de teste de habilidade. Para isso, basta clicar em &lt;code>Test&lt;/code> localizado no menu acima do seu código, e alterar a opção &lt;code>Test is disabled for this skill.&lt;/code> para &lt;code>Development&lt;/code>. Agora você pode chamar sua Alexa e dizer seu nome de invocação para testar sua habilidade!&lt;/p>
&lt;h2 id="notas-finais">&lt;a href="#notas-finais" class="header-anchor">&lt;/a>Notas finais
&lt;/h2>&lt;p>Esta é apenas uma opção para criar facilmente uma habilidade de uso pessoal, para ser usada localmente sempre no estágio de desenvolvimento. Não vamos aprofundar na publicação da habilidade para todo mundo neste tutorial.&lt;/p></description></item></channel></rss>