<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Fernando Nagase's blog]]></title><description><![CDATA[Fernando Nagase's blog]]></description><link>https://blog.ngsfer.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 18:48:09 GMT</lastBuildDate><atom:link href="https://blog.ngsfer.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Git: da pedra aos metais — parte 1]]></title><description><![CDATA[Um dos fatores mais importantes para mim ao aprender sobre um novo assunto é estudar a forma como o entendimento sobre ele evoluiu ao longo da história, pois acredito que, ao fazer isso, muito se revela sobre o contexto em que as pessoas passaram a e...]]></description><link>https://blog.ngsfer.com/git-da-pedra-aos-metais-parte-1</link><guid isPermaLink="true">https://blog.ngsfer.com/git-da-pedra-aos-metais-parte-1</guid><category><![CDATA[Git]]></category><dc:creator><![CDATA[Fernando Nagase]]></dc:creator><pubDate>Mon, 08 Jan 2024 19:21:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/EXk6PC7kTiA/upload/0bb87063ad368bc19164016613ebd3c0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Um dos fatores mais importantes para mim ao aprender sobre um novo assunto é estudar a forma como o entendimento sobre ele evoluiu ao longo da história, pois acredito que, ao fazer isso, muito se revela sobre o contexto em que as pessoas passaram a estudá-lo e a utilidade que ele traz para a sociedade.</p>
<p>Nesse sentido, resolvi experimentar uma abordagem nova para mim, que consiste em criar minhas próprias versões de ferramentas de software comumente usadas. Meu intuito com isso não é apenas replicar cada ferramenta em sua "forma final", mas compreender as possíveis escolhas que as levaram a ser como são.</p>
<p>É exatamente esse processo que pretendo relatar na série "Git: da pedra aos metais", que se inicia com esta publicação. Nela, começarei criando a versão mais óbvia que eu conseguir pensar para o versionamento de código e, parte por parte, trarei novas melhorias até atingir um resultado semelhante ao próprio Git.</p>
<p>Ao mesmo tempo em que escrevo cada artigo, planejo realizar a implementação do sistema com a linguagem Rust e disponibilizar o código de cada versão juntamente às publicações. Até o final da série, minha expectativa é que o sistema implemente as funcionalidades a seguir:</p>
<ul>
<li><p>persistência e restauração de versões (commit);</p>
</li>
<li><p>rastreamento de histórico (log);</p>
</li>
<li><p>ramificações do histórico (branching);</p>
</li>
<li><p>staging area (index).</p>
</li>
</ul>
<p>Eu não recomendaria esta série para pessoas que nunca tiveram contato com o Git, pois pretendo implementar o sistema já levando em consideração alguns dos conceitos existentes em Git. Por outro lado, caso você já o tenha utilizado e queira aprender ainda mais sobre seu funcionamento, essa é a oportunidade!</p>
<h2 id="heading-primeira-abordagem-cada-versao-e-uma-copia-completa-do-repositorio">Primeira abordagem: cada versão é uma cópia completa do repositório</h2>
<p>Inicialmente, optei por uma abordagem trivial e que, provavelmente, todos já utilizamos para fazer backup de algum projeto: para cada versão que precisamos guardar, todo o conteúdo presente atualmente no diretório de trabalho é copiado para um novo diretório.</p>
<p>Esse trabalho é automatizado por meio da interação com uma interface de linha de comando (CLI), de forma semelhante ao Git, e essa CLI, nomeada genericamente como <code>vcs</code>, conta com apenas três comandos: <code>init</code>, <code>commit &lt;descricao&gt;</code> e <code>restore &lt;versao&gt;</code>.</p>
<p>Conforme sugerido pelo nome, a responsabilidade do comando <code>init</code> é inicializar um repositório controlado pelo sistema no diretório atual, o que, ao menos por ora, consiste em criar um diretório oculto <code>.vcs</code> para abrigar todos os arquivos relacionados ao controle de versão, de forma análoga ao diretório <code>.git</code> do Git.</p>
<p>O comando <code>commit</code> é responsável por criar o backup do repositório, o que, como discutimos anteriormente, trata-se apenas de copiar todo o conteúdo para um diretório específico dentro de <code>.vcs</code>. Nesse caso, o diretório de cada backup recebe como nome um número sequencial, como 1, 2, 3 etc., indicativo de sua versão.</p>
<p>Para facilitar o trabalho de identificar qual é o número associado à versão atual, utilizei um arquivo <code>version</code> dentro de <code>.vcs</code>, que, a cada execução de <code>commit</code>, tem seu conteúdo substituído pelo número da nova versão.</p>
<p>Finalmente, cada diretório de versão abriga um arquivo extra com o nome <code>README</code>, cujo conteúdo é uma string informada pelo usuário durante o commit (<code>commit &lt;descricao&gt;</code>) para ajudar a identificar as alterações introduzidas por cada um deles.</p>
<p>O último comando, <code>restore &lt;versao&gt;</code>, recebe o encargo de restaurar o repositório para o exato estado em que se encontrava na versão informada, o que, na prática, consiste em apagar todo o conteúdo do diretório raiz do repositório, com exceção de <code>.vcs</code>, e criar uma cópia de todos os arquivos salvos no backup da versão desejada para o diretório atual, com exceção de <code>README</code>.</p>
<p>O conteúdo do diretório <code>.vcs</code> se assemelha ao seguinte:</p>
<pre><code class="lang-bash">ls .vcs/
1 2 3 version
</code></pre>
<p>O conteúdo do diretório de uma versão específica contém uma cópia de todos os arquivos do próprio repositório juntamente a um arquivo <code>README</code> com a descrição do commit:</p>
<pre><code class="lang-bash">ls .vcs/3/
README a.txt b.txt
</code></pre>
<p>Tudo o que fiz até aqui é basicamente o que já fazemos ao copiar backups de um projeto para a nuvem ou para um outro dispositivo de armazenamento local, com a única diferença sendo a automatização desse processo por meio da CLI.</p>
<p>Como já sabemos, essa abordagem é prática, mas carrega consigo alguns problemas. Na próxima parte desta série, vou enumerar e resolver alguns desses problemas para melhorar o sistema. Com isso, encerro a primeira parte por aqui! Até a próxima!</p>
<h2 id="heading-repositorio">Repositório</h2>
<p>O código-fonte desta primeira versão pode ser consultado no <a target="_blank" href="https://github.com/fernandonagase/rust-vcs/tree/v1.0">repositório do GitHub</a>.</p>
<h2 id="heading-atribuicoes">Atribuições</h2>
<ul>
<li>Fotografia da capa por <a target="_blank" href="https://unsplash.com/pt-br/@rouichi">Azzedine Rouichi</a> em <a target="_blank" href="https://unsplash.com/pt-br"><strong>Unsplash</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A história da Inversão de Controle em 10 minutos]]></title><description><![CDATA[Entre o final da década de 1970 e o início da década de 1980, uma equipe de programadores do Xerox PARC (Palo Alto Research Center) trabalhava na criação de um ambiente de ferramentas integradas com o objetivo de facilitar o desenvolvimento e manuten...]]></description><link>https://blog.ngsfer.com/a-historia-da-inversao-de-controle-em-10-minutos</link><guid isPermaLink="true">https://blog.ngsfer.com/a-historia-da-inversao-de-controle-em-10-minutos</guid><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Fernando Nagase]]></dc:creator><pubDate>Fri, 20 Oct 2023 18:12:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_wGnQvptV3U/upload/5bf193b8ea5b120d3034cba5ce49a5a2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Entre o final da década de 1970 e o início da década de 1980, uma equipe de programadores do Xerox PARC (Palo Alto Research Center) trabalhava na criação de um ambiente de ferramentas integradas com o objetivo de facilitar o desenvolvimento e manutenção de software com a <a target="_blank" href="https://www.softwarepreservation.org/projects/mesa">linguagem Mesa</a>.</p>
<p>Um dos componentes centrais do XDE (Xerox Development Environment), como foi denominado o projeto, era o <a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/Tajo_Functional_Specification_Version_6.0_Oct1980.pdf">Tajo</a>, que, resumidamente, oferecia o arcabouço necessário para implementar e executar as ferramentas em questão.</p>
<p>Diferentemente de outros ambientes de desenvolvimento daquela época, que executavam <a target="_blank" href="https://web.archive.org/web/20050206130024/http://apearson.f2s.com/xde.html">uma única tarefa por vez</a>, com o Tajo, era possível interagir com múltiplas ferramentas simultaneamente, pois ele representava cada uma delas como uma <a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_3.0_Nov84/610E00130_XDE_Concepts_and_Principles_Sep85.pdf">janela</a> em uma interface gráfica de usuário.</p>
<p>Para tanto, uma característica especialmente interessante no contexto deste artigo foi adotada no design do Tajo: as ferramentas agregadas "sob o seu guarda-chuva" deveriam funcionar de forma passiva e não podiam iniciar procedimentos por conta própria.</p>
<p>Em outras palavras, o Tajo funcionava de acordo com um <a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_3.0_Nov84/610E00130_XDE_Concepts_and_Principles_Sep85.pdf">sistema de notificações</a>, em que cada ferramenta entraria em ação — por meio de procedimentos de resposta previamente configurados pelo seu desenvolvedor — apenas quando notificadas pelo Tajo de que o usuário realizou alguma interação (com mouse ou teclado, por exemplo) com uma janela pertencente a ela.</p>
<p>Essa característica foi sintetizada pelo nome <strong>lei de Hollywood</strong> ou <strong>princípio de Hollywood</strong> na <a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/Tajo_Functional_Specification_Version_6.0_Oct1980.pdf">especificação funcional do Tajo</a>, aparentemente, em referência à forma como atores e atrizes iniciantes adentravam no mundo de Hollywood. A explicação a seguir é feita por Alexandre Aquiles no livro Desbravando SOLID (2022):</p>
<blockquote>
<p>Há milhares de atores e atrizes tentando a sorte em Hollywood. E todo filme tem uma pessoa responsável por definir quem vai interpretar cada papel. Imagine se os milhares de atores e atrizes ligassem à procura de uma oportunidade. A pessoa responsável pelo elenco não sairia do telefone!</p>
<p>Por isso, em Hollywood, a pessoa responsável pelo elenco obtém uma lista de atores e atrizes com seus telefones e as características de cada um. E essa pessoa comumente diz: "Não me ligue, deixa que eu te ligo". Esse é o Hollywood Principle.</p>
</blockquote>
<p>Ou seja, da mesma forma que a pessoa responsável pelo elenco de um filme se encarregaria de ligar para um ator ou atriz caso houvesse um papel disponível, o Tajo tinha o papel de notificar cada ferramenta quando fosse o momento certo de agir.</p>
<p>No ano de 2004, Martin Fowler publicou um <a target="_blank" href="https://www.martinfowler.com/articles/injection.html#InversionOfControl">exemplo em seu site</a> que parece compatível com o princípio de Hollywood e nos ajuda a entendê-lo melhor:</p>
<blockquote>
<p>As primeiras interfaces de usuário eram controladas pelo programa da aplicação. O que você tinha na interface de um programa era uma sequência de comandos como "Insira seu nome", "Insira seu endereço" etc., e ele conduziria esses prompts para coletar uma resposta para cada um deles. Tratando-se de UIs gráficas (ou mesmo as baseadas em telas), o framework de UI é que conteria o loop principal da aplicação, e o seu programa apenas forneceria <a target="_blank" href="https://en.wikipedia.org/wiki/Event_(computing)#Event_handler">event handlers</a> para cada campo (de um formulário) na tela. O controle principal do programa foi invertido, afastado de você em direção ao framework.</p>
<p>(Traduzido e adaptado por Fernando Nagase)</p>
</blockquote>
<h2 id="heading-desenvolvendo-software-ao-contrario">Desenvolvendo software ao contrário</h2>
<p>Você notou como, no exemplo, Fowler utilizou a expressão "o <mark>controle</mark> do programa foi <mark>invertido</mark>"? Acontece que o comportamento promovido pelo princípio de Hollywood é exatamente o que seria chamado, posteriormente, de <strong>inversão de controle</strong>. Esse era, inclusive, o tema abordado por Fowler no artigo em questão.</p>
<p>Até o momento, discutimos apenas sobre o contexto de interfaces gráficas de usuário, mas a inversão de controle é um princípio ainda mais amplo, que se aplica à matéria de frameworks de software como um todo, conforme seria abordado por alguns autores anos após a concepção do princípio de Hollywood.</p>
<p>De acordo com Fowler (2004), o termo <a target="_blank" href="https://www.martinfowler.com/bliki/InversionOfControl.html">inversão de controle</a> teria aparecido pela primeira vez no artigo <a target="_blank" href="http://www.laputan.org/drc/drc.html"><em>Designing Reusable Classes</em></a><em>,</em> publicado por Ralph Johnson e Brian Foote em 1988, em que os autores discutiam sobre o projeto (<em>design</em>) de classes reutilizáveis em programação orientada a objetos com a linguagem Smalltalk.</p>
<p>Nesse artigo, Johnson e Foote descrevem o fato de que, em frameworks de software, é comum que os métodos implementados pelos usuários do framework para suprir uma aplicação sejam executados e coordenados pelo próprio framework, em vez de serem chamados explicitamente pelo código do usuário.</p>
<p>Essa característica, referenciada pelo artigo de forma tangecial como uma <strong>inversão de controle</strong>, foi considerada importante pelos autores por permitir aos frameworks de software funcionarem como "esqueletos extensíveis", que podem ser adaptados por métodos fornecidos pelos seus consumidores para atender diferentes aplicações.</p>
<p>Em uma publicação de 1996, <a target="_blank" href="https://web.archive.org/web/20070323220916/http://www.research.ibm.com/designpatterns/pubs/ph-feb96.txt">John Vlissides</a> também abordou o tema e afirmou que, por meio do princípio de Hollywood, frameworks de software são capazes de capturar aspectos invariáveis de arquitetura e implementação, enquanto delegam as partes variáveis para o código específico de cada aplicação.</p>
<p>Essa mesma inversão de controle foi tratada por Michael Mattson, também em 1996 (conforme citado por <a target="_blank" href="https://web.archive.org/web/20040202120126/http://www.betaversion.org/~stefano/linotype/news/38/">Stefano Mazzocchi em 2004</a>), como a principal diferença entre frameworks orientados a objetos (que chamam, <em>eles mesmos</em>, o código de uma aplicação) em relação a bibliotecas de classes (que <em>são chamadas</em> pelas aplicações).</p>
<h2 id="heading-mudanca-de-paradigma"><strong>Mudança de paradigma</strong></h2>
<p>Até o final da década de 1990, a expressão "inversão de controle" aparecia frequentemente ao lado de "princípio de Hollywood", mas, diferentemente da forma como a aplicamos atualmente, não parecia ser considerada um termo por si só.</p>
<p>Um evento-chave para essa mudança de interpretação parece ter ocorrido em 1998, quando <a target="_blank" href="https://web.archive.org/web/20040202120126/http://www.betaversion.org/~stefano/linotype/news/38/">Stefano Mazzocchi</a> apresentou o conceito da inversão de controle à comunidade do <a target="_blank" href="https://web.archive.org/web/20030418111752/http://avalon.apache.org/framework/guide-patterns-ioc.html">Apache Avalon</a>, um projeto cujo objetivo era prover um framework para o desenvolvimento de aplicações <em>server-side</em> na linguagem Java.</p>
<p>Um dos princípios adotados pelo Avalon era a <a target="_blank" href="https://web.archive.org/web/20030418120927/http://avalon.apache.org/framework/guide-cop-what-is.html">programação orientada a componentes</a> (COP), que promove a modularização de aplicações por meio do conceito de <strong>componente</strong>, isso é, uma porção delimitada de código exposta sob uma interface padronizada e que resolve uma responsabilidade bem definida.</p>
<p>Em outras palavras, para lidar com cada responsabilidade (como acesso ao banco de dados, caching, autorização etc.) em uma aplicação desenvolvida com o Avalon, era possível escolher diferentes implementações de componentes, que, por funcionarem sob uma interface comum, poderiam ser utilizadas de forma intercambiável.</p>
<p>A IoC era utilizada pelo Avalon no contexto do gerenciamento de dependências entre componentes, pois encorajava que um componente não configurasse suas dependências por conta própria, mas as recebesse já configuradas dos trechos de código onde fossem utilizados, nesse caso, chamados de <strong>contêineres</strong> do componente.</p>
<figure>
    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697822577274/f656e285-51fd-4c97-a574-75349bedbc58.webp" alt />
    <figcaption>Figura 1 - Sem a IoC (à esquerda), o componente A instancia suas próprias dependências. Com a IoC (à direita), ele as recebe de seu "contêiner" (o método main)</figcaption>
</figure>

<p>Ocorre que, em grandes projetos de software, que reúnem um número elevado de componentes, tornaria-se difícil gerenciar manualmente o ciclo de vida de todos eles, já que o próprio desenvolvedor precisaria coordenar as suas rotinas de inicialização e destruição. O exemplo a seguir foi retirado do documento <a target="_blank" href="http://java.coe.psu.ac.th/OpenSource/Apache/Avalon/developing-with-avalon.pdf">"Developing With Avalon"</a> e demonstra a verbosidade desse tipo de gerenciamento.</p>
<pre><code class="lang-java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContainerComponent</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Component</span>, <span class="hljs-title">Initializable</span>, <span class="hljs-title">Disposable</span>
</span>{
    DocumentRepository docs = <span class="hljs-keyword">new</span> DatabaseDocumentRepository();
    GuardianComponent guard = <span class="hljs-keyword">new</span> DocumentGuardianComponent();
    DefaultComponentManager manager = <span class="hljs-keyword">new</span> DefaultComponentManager();

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initialize</span><span class="hljs-params">()</span>
        <span class="hljs-keyword">throws</span> Exception
    </span>{
        Logger docLogger = <span class="hljs-keyword">new</span> LogKitLogger( Hierarchy.defaultHierarchy()
        .getLoggerFor( <span class="hljs-string">"document"</span> ) );

        <span class="hljs-keyword">this</span>.docs.enableLogging( docLogger.childLogger( <span class="hljs-string">"repository"</span> ) );
        <span class="hljs-keyword">this</span>.guard.enableLogging( docLogger.childLogger( <span class="hljs-string">"security"</span> ) );

        DefaultConfiguration pool = <span class="hljs-keyword">new</span> DefaultConfiguration(<span class="hljs-string">"dbpool"</span>);
        pool.setValue(<span class="hljs-string">"main-pool"</span>);
        DefaultConfiguration conf = <span class="hljs-keyword">new</span> DefaultConfiguration(<span class="hljs-string">""</span>);
        conf.addChild(pool);

        <span class="hljs-keyword">this</span>.manager.addComponent( DocumentRepository.ROLE, <span class="hljs-keyword">this</span>.docs );
        <span class="hljs-keyword">this</span>.manager.addComponent( GuardianComponent.ROLE, <span class="hljs-keyword">this</span>.guard );
        <span class="hljs-keyword">this</span>.docs.compose( <span class="hljs-keyword">this</span>.manager );
        <span class="hljs-keyword">this</span>.guard.compose( <span class="hljs-keyword">this</span>.manager );

        <span class="hljs-keyword">this</span>.docs.configure(conf);

        <span class="hljs-keyword">this</span>.guard.initialize();
        <span class="hljs-keyword">this</span>.docs.initialize();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dispose</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">this</span>.docs.dispose();
        <span class="hljs-keyword">this</span>.guard.dispose();
    }
}
</code></pre>
<p>Com isso, uma solução proposta pelo Avalon foi a criação de um "contêiner genérico" (<a target="_blank" href="https://excalibur.apache.org/component.html">Excalibur Component Manager</a>) para automatizar o controle sobre cada componente, que poderia ser configurado por meio de arquivos XML. Desse modo, os componentes poderiam ser facilmente acessados por meio do ECM, removendo-se a necessidade de se preocupar com seus ciclos de vida.</p>
<p>Foi exatamente esse contexto de gerenciamento de dependências que, no início da década de 2000, influenciou o surgimento de outros frameworks, como o <a target="_blank" href="https://web.archive.org/web/20030706235709/http://www.picocontainer.org/introduction.html">PicoContainer</a> e <a target="_blank" href="https://web.archive.org/web/20030814095023/http://www.springframework.org/docs/lightweight_container.html">Spring Framework</a>, chamados de "contêineres baseados em IoC", que ofereciam funcionalidades semelhantes ao Avalon.</p>
<p>Desde então, o termo "inversão de controle" passou a ser cada vez mais utilizado de forma "standalone" no contexto de gerenciamento de dependências e estabeleceu uma nova tendência.</p>
<h2 id="heading-injecao-de-dependencia">Injeção de dependência</h2>
<p>Em 2004, Martin Fowler publicou um <a target="_blank" href="https://martinfowler.com/articles/injection.html#InversionOfControl">artigo</a> em que discutia sobre o surgimento de uma nova onda de <a target="_blank" href="https://web.archive.org/web/20030814095023/http://www.springframework.org/docs/lightweight_container.html">"lightweight containers"</a> e sobre como eles se relacionavam com o princípio da inversão de controle. Um trecho desse artigo nos é especialmente interessante:</p>
<blockquote>
<p>A <a target="_blank" href="https://martinfowler.com/bliki/InversionOfControl.html">Inversão de controle</a> é uma característica comum entre frameworks, logo, dizer que esses "lightweight containers" são especiais por usarem inversão de controle é como dizer que meu carro é especial por ter rodas.</p>
<p>A pergunta é: "qual aspecto do controle eles estão invertendo?"</p>
<p>(Traduzido e adaptado por Fernando Nagase)</p>
</blockquote>
<p>Ou seja, indo ao encontro da definição de Foote e Johnson (1988) sobre como a IoC está inerentemente ligada ao próprio conceito de framework de software, Fowler julgou inadequado o uso desse termo para designar o padrão de projeto  implementado pelos contêineres analisados, por ser muito genérico.</p>
<p>Antes de publicar o artigo, entretanto, Fowler já havia demonstrado um rascunho para outros programadores envolvidos com o assunto, entre os quais Rod Johnson (criador do Spring Framework) e Paul Hammant (co-líder do PicoContainer), com quem discutiu uma nova nomenclatura, chegando ao termo "Injeção de Dependência".</p>
<p>Desde então, a escolha entre um termo ou outro parece ter se tornado confusa, principalmente pelo fato de algumas pessoas terem passado a considerá-los sinônimos, o que foi <a target="_blank" href="https://web.archive.org/web/20040202120126/http://www.betaversion.org/~stefano/linotype/news/38/">refutado por Mazzocchi</a> alguns dias após a publicação original de Fowler.</p>
<p>Com base nas posições de Mazzocchi (2004) e Fowler (2005), assim como a defendida em um artigo no site do PicoContainer sobre a <a target="_blank" href="http://picocontainer.com/inversion-of-control-history.html">história da IoC</a>, considero seguro tratar a inversão de controle como um princípio amplo (conforme abordado por Johnson e Foote, Vlissides e Mattson).</p>
<p>Por outro lado, a injeção de dependência se trata de uma entre diversas formas de se atingir a inversão de controle, tendo seu foco voltado para a coordenação de dependências entre objetos (conforme implementado pelo PicoContainer, Spring Framework e demais contêineres do tipo).</p>
<h2 id="heading-conclusao"><strong>Conclusão</strong></h2>
<p>As primeiras discussões sobre a inversão de controle foram levantadas no contexto de frameworks de software e a tratavam como um princípio amplo, preocupado com a transferência de aspectos reutilizáveis entre aplicações das mãos dos desenvolvedores para as mãos de frameworks.</p>
<p>No entanto, a grande popularização do termo pelos chamados "contêineres baseados em IoC" fez com que o conceito da inversão de controle se confundisse com o que hoje chamamos de "injeção de dependência", isso é, uma forma específica de IoC voltada para o gerenciamento de dependências entre os componentes de uma aplicação.</p>
<h2 id="heading-referencia">Referência</h2>
<ol>
<li><p><a target="_blank" href="https://www.softwarepreservation.org/projects/mesa">Mesa — Software Preservation Group</a></p>
</li>
<li><p><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/Tajo_Functional_Specification_Version_6.0_Oct1980.pdf">Tajo_Functional_Specification_Version_6.0_Oct1980.pdf (</a><a target="_blank" href="http://bitsavers.org">bitsavers.org</a><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/Tajo_Functional_Specification_Version_6.0_Oct1980.pdf">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20050206130024/http://apearson.f2s.com/xde.html">Xerox Mesa Programming - XDE (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20050206130024/http://apearson.f2s.com/xde.html">)</a></p>
</li>
<li><p><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_3.0_Nov84/610E00130_XDE_Concepts_and_Principles_Sep85.pdf">610E00130_XDE_Concepts_and_Principles_Sep85.pdf (</a><a target="_blank" href="http://bitsavers.org">bitsavers.org</a><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_3.0_Nov84/610E00130_XDE_Concepts_and_Principles_Sep85.pdf">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.casadocodigo.com.br/products/livro-desbravando-solid">Livro Desbravando SOLID - Casa do Código (</a><a target="_blank" href="http://casadocodigo.com.br">casadocodigo.com.br</a><a target="_blank" href="https://www.casadocodigo.com.br/products/livro-desbravando-solid">)</a></p>
</li>
<li><p><a target="_blank" href="https://martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern (</a><a target="_blank" href="http://martinfowler.com">martinfowler.com</a><a target="_blank" href="https://martinfowler.com/articles/injection.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.martinfowler.com/bliki/InversionOfControl.html">InversionOfControl (</a><a target="_blank" href="http://martinfowler.com">martinfowler.com</a><a target="_blank" href="https://www.martinfowler.com/bliki/InversionOfControl.html">)</a></p>
</li>
<li><p><a target="_blank" href="http://www.laputan.org/drc/drc.html">Designing Reusable Classes (</a><a target="_blank" href="http://laputan.org">laputan.org</a><a target="_blank" href="http://www.laputan.org/drc/drc.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20070323220916/http://www.research.ibm.com/designpatterns/pubs/ph-feb96.txt">"Pattern Hatching" column for February '96 issue John Vlissides (archive.org)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20040202120126/http://www.betaversion.org/~stefano/linotype/news/38/">Stefano's Linotype ~ On Inversion of Control (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20040202120126/http://www.betaversion.org/~stefano/linotype/news/38/">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20030418111752/http://avalon.apache.org/framework/guide-patterns-ioc.html">Avalon Framework - Guide - Inversion of Control (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20030418111752/http://avalon.apache.org/framework/guide-patterns-ioc.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20030418120927/http://avalon.apache.org/framework/guide-cop-what-is.html">Avalon Framework - Guide - What is COP? (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20030418120927/http://avalon.apache.org/framework/guide-cop-what-is.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://excalibur.apache.org/component.html">Excalibur - ECM (</a><a target="_blank" href="http://apache.org">apache.org</a><a target="_blank" href="https://excalibur.apache.org/component.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20030706235709/http://www.picocontainer.org/introduction.html">PicoContainer - (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20030706235709/http://www.picocontainer.org/introduction.html">)</a></p>
</li>
<li><p><a target="_blank" href="http://web.archive.org/web/20030814095023/http://www.springframework.org/docs/lightweight_container.html">The Spring Framework - A Lightweight Container (archive.org)</a></p>
</li>
<li><p><a target="_blank" href="http://picocontainer.com/inversion-of-control-history.html">PicoContainer - Inversion of Control History</a></p>
</li>
<li><p><a target="_blank" href="http://n327.blogspot.com/2014/01/inversion-of-control.html">Technical Deficit : Inversion of Control (</a><a target="_blank" href="http://n327.blogspot.com">n327.blogspot.com</a><a target="_blank" href="http://n327.blogspot.com/2014/01/inversion-of-control.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Inversion_of_control">Inversion of control - Wikipedia</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20040315090313/http://www.betaversion.org/~stefano/linotype/news/42/">Stefano's Linotype ~ Origin of the Hollywood Principle (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20040315090313/http://www.betaversion.org/~stefano/linotype/news/42/">)</a></p>
</li>
<li><p><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_6.0_Oct88/610E00201_XDE_User_Guide_Oct88.pdf">610E00201_XDE_User_Guide_Oct88.pdf (</a><a target="_blank" href="http://bitsavers.org">bitsavers.org</a><a target="_blank" href="http://www.bitsavers.org/pdf/xerox/xde/XDE_6.0_Oct88/610E00201_XDE_User_Guide_Oct88.pdf">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20050606014557/http://java.sys-con.com/read/38102.htm">Inversion of Control Rocks @ JDJ (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20050606014557/http://java.sys-con.com/read/38102.htm">)</a></p>
</li>
<li><p><a target="_blank" href="http://java.coe.psu.ac.th/OpenSource/Apache/Avalon/developing-with-avalon.pdf">developing-with-avalon.pdf (</a><a target="_blank" href="http://psu.ac.th">psu.ac.th</a><a target="_blank" href="http://java.coe.psu.ac.th/OpenSource/Apache/Avalon/developing-with-avalon.pdf">)</a></p>
</li>
</ol>
<h2 id="heading-atribuicoes">Atribuições</h2>
<ul>
<li>Fotografia da capa por <a target="_blank" href="https://unsplash.com/pt-br/@cedricletsch">Cedric Letsch</a> em <a target="_blank" href="https://unsplash.com/pt-br">Unsplash</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[O que é o padrão Strangler Fig Application?]]></title><description><![CDATA[O padrão de projeto Strangler Fig Application, que também é conhecido como padrão Strangler Application ou simplesmente Strangler, teve seu nome baseado em uma analogia popularizada por Martin Fowler.
Ao meu ver, as analogias compõem um recurso poder...]]></description><link>https://blog.ngsfer.com/o-que-e-o-padrao-strangler-fig-application</link><guid isPermaLink="true">https://blog.ngsfer.com/o-que-e-o-padrao-strangler-fig-application</guid><category><![CDATA[Devops]]></category><category><![CDATA[Microservices]]></category><dc:creator><![CDATA[Fernando Nagase]]></dc:creator><pubDate>Thu, 22 Jun 2023 19:27:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/T49WTav4LgU/upload/2b881006736043200e339415512c44a6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>O padrão de projeto <em>Strangler Fig Application</em>, que também é conhecido como padrão <em>Strangler Application</em> ou simplesmente <em>Strangler</em>, teve seu nome baseado em uma analogia popularizada por <a target="_blank" href="https://martinfowler.com/">Martin Fowler</a>.</p>
<p>Ao meu ver, as analogias compõem um recurso poderosíssimo para facilitar o entendimento de assuntos complexos. Por meio de comparações, elas permitem <a target="_blank" href="https://descomplica.com.br/blog/o-que-e-analogia/">explicar conceitos desconhecidos por meio daqueles que já conhecemos</a>... Isso, é claro, se tivermos primeiramente uma referência com a qual comparar.</p>
<p>Dito isso, eu te faço uma pergunta: você sabe o que são <strong><em>Strangler Figs</em>?</strong> Se, assim como eu, você nunca tinha ouvido falar sobre esse termo até se deparar com o padrão abordado neste artigo, continue lendo, pois vamos começar pelas "raízes" para entender o seu significado e qual a sua relação com desenvolvimento de software.</p>
<h2 id="heading-o-que-sao-strangler-figs">O que são Strangler Figs?</h2>
<p>Em uma publicação feita em seu próprio site, Fowler relata que concebeu uma <a target="_blank" href="https://martinfowler.com/bliki/StranglerFigApplication.html">metáfora sobre a migração de sistemas críticos</a> durante uma viagem que fez para a Austrália, após observar o comportamento de certas árvores que podiam ser encontradas naturalmente por lá.</p>
<p>Essas árvores, que na verdade fazem parte de uma família com várias outras espécies, são denominadas <a target="_blank" href="https://en.wikipedia.org/wiki/Strangler_fig"><em>Strangler Figs</em></a> ou "figueiras estranguladoras", em português, e recebem esse nome devido à forma pela qual normalmente se desenvolvem: elas crescem ao redor de árvores hospedeiras e as "estrangulam".</p>
<p>Para ser mais específico, elas produzem frutos cujas sementes são depositadas nas copas das outras árvores principalmente como resultado da alimentação de pássaros, e quando essas sementes encontram os recursos necessários, elas germinam e suas raízes passam a crescer do alto até se estabelecerem no solo.</p>
<p>O resultado desse processo pode ser, <a target="_blank" href="https://www.naplesgarden.org/strangler-figs-not-always-a-bad-wrap/">ocasionalmente, a morte da árvore hospedeira</a>, visto que a figueira passa a competir tanto pelos nutrientes do solo quanto pela luz solar, nas partes superiores. Você pode ver como esse tipo de árvore se parece assistindo <a target="_blank" href="https://www.youtube.com/watch?v=kVpVbS9CJIk">este vídeo</a> (YouTube).</p>
<details><summary>Strangler Fig Application vs. Strangler Application</summary><div data-type="detailsContent">Originalmente, em 2004, o artigo de Fowler tinha <em>"Strangler Application"</em> como título. O termo <em>strangler</em> ou "estrangulador" não é, por si só, muito claro sobre a origem da analogia, e muitas vezes era usado no sentido violento. Por isso, o autor renomeou sua publicação sobre o padrão para "Strangler Fig Pattern", reforçando a relação com a metáfora original.</div></details>

<h2 id="heading-desenvolvendo-software-como-strangler-figs">Desenvolvendo software como Strangler Figs</h2>
<p>Agora que conhecemos o contexto por trás da analogia de Fowler, finalmente podemos prosseguir para a etapa em que a relacionamos com o contexto de desenvolvimento de software e microsserviços.</p>
<p>A comparação é feita com a migração de uma aplicação monolítica para uma organizada em microsserviços, e pode ser explicada da seguinte forma:</p>
<ol>
<li><p>a aplicação monolítica, pronta e já em funcionamento, serve como uma árvore hospedeira, em torno da qual a nova aplicação organizada em microsserviços será desenvolvida;</p>
</li>
<li><p>aos poucos, desenvolvemos microsserviços "ao redor" da aplicação monolítica (pense neles como as raízes de um <em>Strangler Fig</em>) para substituir responsabilidades individuais e bem definidas do sistema original;</p>
</li>
<li><p>eventualmente — esse processo pode durar anos — o ecossistema de microsserviços desenvolvidos em torno do sistema original terá crescido o suficiente para substitui-lo por completo, sendo assim, ele é "estrangulado".</p>
</li>
</ol>
<p>A principal vantagem de aplicar <em>Strangler Fig Applications</em> decorre da entrega gradual de <em>software</em>, que reduz o risco durante o desenvolvimento. Ao trabalharmos com incrementos, em vez de substituir "tudo de uma vez", não apenas podemos aproveitar cada microsserviço assim que estiver pronto, como também conseguimos acompanhar mais facilmente a evolução da aplicação e verificar se ela está no caminho certo.</p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>O padrão de projeto <em>Strangler Fig Application</em> é comumente lembrado quando se fala na migração de uma aplicação monolítica para a arquitetura de microsserviços, e recomenda que o desenvolvimento e implantação de microsserviços sejam graduais, até o momento em que todo o sistema original possa ser substituído por eles.</p>
<p>O nome dessa abordagem se origina de uma analogia feita por Martin Fowler com o comportamento de uma família de árvores denominadas <em>Strangler Figs</em>, cujas raízes crescem ao redor de árvores hospedeiras e as "estrangulam", de modo a "roubar" os seus nutrientes, em alguns casos, até mesmo causando a morte da árvore original.</p>
<p>Ao implantar microsserviços que substituem responsabilidades pequenas e bem definidas do domínio, as migrações feitas seguindo esse padrão permitem entregar valor ao negócio de forma incremental, e reduzem os riscos dentro do projeto, devido à maior facilidade de monitorar o seu andamento.</p>
<h2 id="heading-referencias">Referências</h2>
<ol>
<li><p><a target="_blank" href="https://martinfowler.com/">martinfowler.com</a></p>
</li>
<li><p><a target="_blank" href="https://descomplica.com.br/blog/o-que-e-analogia/">Analogia: o que é, conceito e exemplos (</a><a target="_blank" href="http://descomplica.com.br">descomplica.com.br</a><a target="_blank" href="https://descomplica.com.br/blog/o-que-e-analogia/">)</a></p>
</li>
<li><p><a target="_blank" href="https://martinfowler.com/bliki/StranglerFigApplication.html">StranglerFigApplication (</a><a target="_blank" href="http://martinfowler.com">martinfowler.com</a><a target="_blank" href="https://martinfowler.com/bliki/StranglerFigApplication.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Strangler_fig">Strangler fig - Wikipedia (wikipedia.org)</a></p>
</li>
<li><p><a target="_blank" href="https://www.naplesgarden.org/strangler-figs-not-always-a-bad-wrap/">Strangler Figs: Not Always a Bad Wrap | Naples Botanical Garden (</a><a target="_blank" href="http://naplesgarden.org">naplesgarden.org</a><a target="_blank" href="https://www.naplesgarden.org/strangler-figs-not-always-a-bad-wrap/">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=kVpVbS9CJIk">Strangler Fig - YouTube (youtube.com)</a></p>
</li>
<li><p><a target="_blank" href="https://www.ibm.com/garage/method/practices/code/chunking-strategy-strangler-pattern/">Break the monolith: Chunking strategy and the Strangler pattern - IBM Garage Practices (www.ibm.com)</a></p>
</li>
<li><p><a target="_blank" href="https://developer.ibm.com/articles/cl-strangler-application-pattern-microservices-apps-trs/">Apply the Strangler Fig Application pattern to microservices applications - IBM Developer (developer.ibm.com)</a></p>
</li>
</ol>
<h2 id="heading-atribuicoes">Atribuições</h2>
<ul>
<li>Fotografia da capa por <a target="_blank" href="https://unsplash.com/@davidclode">David Clode</a> em <a target="_blank" href="https://unsplash.com/"><strong>Unsplash</strong></a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Tratamento de exceções em Java: o que há de especial?]]></title><description><![CDATA[As exceções em Java são um pouco diferentes se comparadas com as de outras linguagens de programação. Eu não sei se esse é o seu caso, mas, quando comecei a estudar Java, eu sentia essa diferença enquanto programava e não sabia explicar qual era o mo...]]></description><link>https://blog.ngsfer.com/tratamento-de-excecoes-em-java-o-que-ha-de-especial</link><guid isPermaLink="true">https://blog.ngsfer.com/tratamento-de-excecoes-em-java-o-que-ha-de-especial</guid><category><![CDATA[Java]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[exceptionhandling]]></category><dc:creator><![CDATA[Fernando Nagase]]></dc:creator><pubDate>Sat, 10 Jun 2023 20:45:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HJckKnwCXxQ/upload/3ca00952e568845992bbfc75445bac43.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As exceções em Java são um pouco diferentes se comparadas com as de outras linguagens de programação. Eu não sei se esse é o seu caso, mas, quando comecei a estudar Java, eu sentia essa diferença enquanto programava e não sabia explicar qual era o motivo.</p>
<p>Por exemplo, por que algumas exceções produzem erros de compilação quando não são tratadas enquanto outras não? E, em relação a esses erros produzidos, por que eles são "magicamente" resolvidos ao especificar os tipos das exceções após a palavra-chave <code>throws</code>, na assinatura do método pelo qual são lançadas?</p>
<p>No final das contas, a resposta é simples (ou nem tanto, conforme explico na última seção). Basta entender como as exceções em Java foram projetadas e a razão pela qual elas foram organizadas da forma que foram. É isso que eu tentarei te explicar até o fim deste artigo.</p>
<h2 id="heading-introducao-as-excecoes">Introdução às exceções</h2>
<p>Por baixo do pano, todo método define uma espécie de contrato com o código que o consome. Nele, especifica-se detalhes como a forma de utilizá-lo (ou seja, seus parâmetros) e o comportamento esperado ao chamá-lo (produz um valor de retorno ou <a target="_blank" href="https://en.wikipedia.org/wiki/Side_effect_(computer_science)">efeitos colaterais</a>).</p>
<p>No entanto, há situações em que um método não é capaz de seguir o seu fluxo padrão, geralmente em decorrência de fatores externos, como o ambiente em que o programa está sendo executado.</p>
<p>Nesse contexto, um exemplo comumente utilizado é o de um método que recebe do usuário o nome de um arquivo e tenta abri-lo: caso o nome informado não exista, o arquivo não pode ser aberto, e o método é impedido de prosseguir da forma esperada.</p>
<p>É esse aspecto que as exceções representam. Por meio delas, é possível sinalizar a ocorrência de <strong>situações excepcionais</strong> que podem acontecer ao invocar um método, e essas situações podem ser detectadas e "tratadas" pelo desenvolvedor por meio de um mecanismo adequado — os famosos <strong>blocos try-catch</strong>.</p>
<pre><code class="lang-java"><span class="hljs-comment">// código omitido</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSomething</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">try</span> {
        doAnotherThing(); <span class="hljs-comment">// potencialmente lança ExampleException</span>
    } <span class="hljs-keyword">catch</span> (ExampleException e) {
        <span class="hljs-comment">// tratamento da exceção</span>
    }
}
<span class="hljs-comment">// código omitido</span>
</code></pre>
<p>Tradicionalmente, o tratamento de uma exceção não é obrigatório e não precisa ser feito pelo método que a lançou (nem mesmo por outros métodos que o tenham invocado!), o que é uma vantagem até certo ponto, pois possibilita que as exceções "borbulhem" (<em>bubble</em>) de baixo para cima na <a target="_blank" href="https://www.baeldung.com/cs/call-stack"><em>call stack</em></a> até o local mais adequado para o tratamento. A figura 1 ilustra esse comportamento.</p>
<figure>
    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686354060784/ead7c1a4-7a2e-4fec-b0a0-c72cb0ca4943.png" alt="Pilha de chamadas (call stack) composta por métodos nomeados de A a D dispostos em ordem crescente de cima para baixo. O método A invoca o método B, que invoca o método C, e este, por fim, invoca o método D. O método D lança uma exceção, que sobe pela pilha de chamadas como se fosse bolhas de ar subindo dentro d'água. Os métodos B e C não sabem ou não querem tratar a exceção, deixando-a passar, ao passo que o método A sabe o que fazer, capturando-a e estourando a bolha." />
    <figcaption>Figura 1 - As exceções "borbulham" na call stack até que um método as capture.</figcaption>
</figure>

<h2 id="heading-checked-vs-unchecked-exceptions">Checked vs. Unchecked Exceptions</h2>
<p>Ocorre que a linguagem Java considera as exceções lançadas por um método uma parte do seu próprio contrato, e sua sintaxe obriga que elas sejam informadas a qualquer código que o invoque. Em outras palavras, as exceções precisam <a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">constar na assinatura do método</a>, da mesma forma que seus parâmetros e valor de retorno.</p>
<p>Esse requisito é justificado pela noção de que o desenvolvedor deve ser capaz de <strong>antecipar</strong> e contornar exceções, seja exibindo uma mensagem de erro ao usuário, seja buscando uma rota alternativa para a ação solicitada. É por esse motivo que especificamos as exceções após a palavra-chave <code>throws</code>.</p>
<pre><code class="lang-java"><span class="hljs-comment">// código omitido</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doAnotherThing</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> ExampleException </span>{
    <span class="hljs-comment">// código omitido</span>
    <span class="hljs-keyword">if</span> (condition) {
        <span class="hljs-comment">/*
            ExampleException representa uma situação que é prevista ao
            invocar o método doAnotherThing, mas que ocorre apenas em
            condições excepcionais (por exemplo, se "condition"
            for verdadeiro). Espera-se que o código consumidor
            antecipe essa situação e a trate de maneira adequada.
        */</span>
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ExampleException()
    }
    <span class="hljs-comment">// código omitido</span>
}
<span class="hljs-comment">// código omitido</span>
</code></pre>
<p>Dessa forma, sempre que lidamos com um código que possivelmente lança exceções, temos duas opções: ou as tratamos imediatamente (com try-catch) ou as tornamos parte do próprio contrato do método no qual trabalhamos (com <code>throws</code> em sua assinatura), esperando que um outro método faça o tratamento. Esse comportamento é denominado <a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html">Catch or Specify Requirement</a>.</p>
<figure>
    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686354121131/b2673326-ed7a-419f-977f-69503fefe36f.png" alt="Pilha de chamadas (call stack) idêntica à da figura 1, contendo métodos nomeados de A a D. Entre o método D, que lança uma exceção, e o método A, que a captura, todos os outros métodos explicitam para o próximo que eles lançam a mesma exceção lançada por D, por meio da cláusula throws." />
    <figcaption>Figura 2 - Todos os métodos que trabalham com uma exceção, mas não a tratam, precisam torná-la parte do seu próprio contrato com <span>"throws"</span>.</figcaption>
</figure>

<p>Para garantir que o desenvolvedor tome conhecimento sobre as exceções possivelmente lançadas por um método, o compilador Java acusa um erro de compilação caso uma exceção não tenha sido tratada (ou, ao menos, postergada com <code>throws</code>). Sendo assim, as exceções em Java são conhecidas como <em>checked exceptions</em> (exceções verificadas).</p>
<p>No entanto, algumas exceções são naturalmente <a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html">internas à aplicação</a> (não devem ser expostas pelo contrato) e não podem ser contornadas de forma satisfatória, pois geralmente decorrem de <a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">defeitos de programação</a> (como uma tentativa de acessar campos em um valor nulo ou realizar uma divisão por zero). Essas exceções são conhecidas como <em>unchecked exceptions</em> (exceções não verificadas).</p>
<details><summary>Unchecked exceptions vs. Runtime exceptions</summary><div data-type="detailsContent">Na realidade, o termo <strong>runtime exception</strong> representaria com maior precisão o tipo de exceções referidas como <em>unchecked exceptions</em> neste artigo, pois <em>unchecked exceptions</em> também englobam o conceito de <strong>erros, </strong>que são causados por <a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html">condições externas às regras de negócio</a>, como falhas de <em>hardware </em>ou do sistema. Porém, optei por utilizar esses termos como sinônimos para fins de simplificação.</div></details>

<p>Como o nome sugere, as <em>unchecked exceptions</em> não são verificadas pelo compilador e, portanto, não é obrigatório tratá-las, o que as torna semelhantes às presentes em outras linguagens de programação. Isso ocorre pois, embora seja possível capturá-las, o ideal seria detectar e corrigir os bugs que as causam o mais rápido possível.</p>
<p>Na prática, <strong>todas</strong> as exceções em Java são derivadas da classe <code>Exception</code> e são verificadas por padrão. Porém, é possível criar exceções não verificadas a partir da classe <code>RuntimeException</code> (que também é uma <code>Exception</code>!). A figura 3 ilustra a hierarquia de exceções em Java.</p>
<figure>
    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686354176087/8420a411-f26d-40ad-85e6-6cd0be004674.png" alt="Todas as exceções derivam da classe Exception, incluindo IOException, SQLException e RuntimeException, entre outras. Todas as exceções são verificadas pelo compilador, exceto por RuntimeException e suas derivadas, como NullPointerException e ArithmeticException, que não são verificadas." />
    <figcaption>Figura 3 - Hierarquia de exceções em Java. As classes Throwable e Error foram omitidas para fins de simplificação.</figcaption>
</figure>

<h2 id="heading-controversia"><strong>Controvérsia</strong></h2>
<p>Os princípios básicos sobre quando utilizar cada tipo de exceção foram abordados até agora, mas há uma controvérsia entre os desenvolvedores Java, que questionam as vantagens e desvantagens de <em>checked</em> e <em>unchecked exceptions</em>.</p>
<p>Em meio a vários outros argumentos, alguns afirmam que <em>checked exceptions</em> dificultam a <a target="_blank" href="https://www.artima.com/articles/the-trouble-with-checked-exceptions">manutenção da base de código</a> em projetos de larga escala, enquanto outros argumentam que elas são essenciais para garantir que desenvolvedores sejam capazes de <a target="_blank" href="https://stackoverflow.com/a/614494">antecipar situações excepcionais</a> ao consumir uma API.</p>
<p>Não entrarei em mais detalhes, pois trata-se de um assunto complexo e que foge do escopo deste artigo, porém, disponibilizarei algumas leituras que encontrei sobre o assunto juntamente às referências.</p>
<p>De modo geral, me parece ser um consenso que as <em>checked exceptions</em> têm, de fato, a sua utilidade, desde que não abusemos do seu uso, sob o risco de dificultar a manutenção do código. Além disso, convém nos lembrarmos de sempre manter a consistência com as convenções já utilizadas dentro de um projeto.</p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>As exceções em Java derivam da classe <code>Exception</code> e são consideradas parte do contrato do método pelo qual são lançadas, devendo ser especificadas em sua assinatura por meio da cláusula <code>throws</code>. Nesse mesmo sentido, essas exceções são chamadas de <em>checked exceptions</em>, pois têm seu tratamento garantido pelo compilador, que acusa um erro caso não sejam tratadas.</p>
<p>No entanto, há exceções especiais — chamadas de <em>unchecked exceptions</em> — que se originam da classe <code>RuntimeException</code> (também derivada de <code>Exception</code>) e não são verificadas pelo compilador, pois são internas ao escopo de um método e, por esse motivo, não são expostas pelo seu contrato.</p>
<h2 id="heading-referencias">Referências</h2>
<ol>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Side_effect_(computer_science)">Side effect (computer science) (wikipedia.org)</a></p>
</li>
<li><p><a target="_blank" href="https://www.baeldung.com/cs/call-stack">The Call Stack | Baeldung on Computer Science (baeldung.com)</a></p>
</li>
<li><p><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">Unchecked Exceptions — The Controversy (The Java™ Tutorials &gt; Essential Java Classes &gt; Exceptions) (</a><a target="_blank" href="http://oracle.com">oracle.com</a><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html">The Catch or Specify Requirement (The Java™ Tutorials &gt; Essential Java Classes &gt; Exceptions) (</a><a target="_blank" href="http://oracle.com">oracle.com</a><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.artima.com/articles/the-trouble-with-checked-exceptions">artima - The Trouble with Checked Exceptions (www.artima.com)</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/613954/the-case-against-checked-exceptions/614494#614494">java - The case against checked exceptions - Stack Overflow (stackoverflow.com)</a></p>
</li>
<li><p><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html">What Is an Exception? (The Java™ Tutorials &gt; Essential Java Classes &gt; Exceptions) (</a><a target="_blank" href="http://oracle.com">oracle.com</a><a target="_blank" href="https://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20220409162401/http://answers.google.com/answers/threadview?id=26101">Google Answers: The origin of checked exceptions (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20220409162401/http://answers.google.com/answers/threadview?id=26101">)</a></p>
</li>
</ol>
<h3 id="heading-discussoes-sobre-o-uso-de-checked-x-uncheckd-exceptions">Discussões sobre o uso de checked x uncheckd exceptions</h3>
<ul>
<li><p><a target="_blank" href="https://www.artima.com/articles/the-trouble-with-checked-exceptions">artima - The Trouble with Checked Exceptions (www.artima.com)</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/613954/the-case-against-checked-exceptions/614494#614494">java - The case against checked exceptions - Stack Overflow (stackoverflow.com)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20180301074914/http://www.mindview.net/Etc/Discussions/CheckedExceptions">Bruce Eckel's MindView, Inc: Does Java need Checked Exceptions? (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20180301074914/http://www.mindview.net/Etc/Discussions/CheckedExceptions">)</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20171109034001/http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html">Java's checked exceptions were a mistake (and here's what I would like to do about it) (</a><a target="_blank" href="http://archive.org">archive.org</a><a target="_blank" href="https://web.archive.org/web/20171109034001/http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html">)</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/27578/when-to-choose-checked-and-unchecked-exceptions">java - When to choose checked and unchecked exceptions - Stack Overflow (stackoverflow.com)</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/499437/in-java-when-should-i-create-a-checked-exception-and-when-should-it-be-a-runti">In Java, when should I create a checked exception, and when should it be a runtime exception? - Stack Overflow (stackoverflow.com)</a></p>
</li>
</ul>
<h2 id="heading-atribuicoes">Atribuições</h2>
<ul>
<li>Fotografia da capa por <a target="_blank" href="https://unsplash.com/@gabriellefaithhenderson">Gabrielle Henderson</a> em <a target="_blank" href="https://unsplash.com/">Unsplash</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Introdução ao Declarative UI em React]]></title><description><![CDATA[O lançamento da nova documentação do React em março de 2023 foi, para mim, uma ótima oportunidade para revisar alguns conceitos básicos para os quais eu nunca havia dado tanta atenção, e, por incrível que pareça, uma das leituras que mais me chamou a...]]></description><link>https://blog.ngsfer.com/introducao-ao-declarative-ui-em-react</link><guid isPermaLink="true">https://blog.ngsfer.com/introducao-ao-declarative-ui-em-react</guid><category><![CDATA[React]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Fernando Nagase]]></dc:creator><pubDate>Sat, 20 May 2023 21:40:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684617253384/6db32a02-e1e5-443e-aa2e-d18dccdd1537.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>O lançamento da <a target="_blank" href="https://web.archive.org/web/20230328114849/https://react.dev/blog/2023/03/16/introducing-react-dev">nova documentação do React</a> em março de 2023 foi, para mim, uma ótima oportunidade para revisar alguns conceitos básicos para os quais eu nunca havia dado tanta atenção, e, por incrível que pareça, uma das leituras que mais me chamou a atenção foi a <a target="_blank" href="https://web.archive.org/web/20230323135831/https://react.dev/learn/reacting-to-input-with-state">dessa seção</a>, que explica sobre dois conceitos presentes <a target="_blank" href="https://youtu.be/x7cQ3mrcKaY?t=916">desde a concepção</a> do React: UI reativa e programação declarativa.</p>
<p>De forma resumida, o React permite criar interfaces de usuário que reagem a mudanças no estado de uma aplicação e disparar as atualizações correspondentes na UI por meio de <strong>descrições</strong> sobre como ela deve se parecer em vez de <strong>comandos</strong> para alterar a interface diretamente. Em outras palavras, o desenvolvedor não se preocupa com <em>como</em> exibir a interface, mas com <em>o que</em> deve ser exibido.</p>
<blockquote>
<p>Em React, você não manipula diretamente a UI — isso é, você não habilita, desabilita, mostra ou oculta componentes diretamente. Em vez disso, você <mark>declara</mark> o que quer mostrar e o React identifica como atualizar a UI. (tradução nossa.)</p>
<p>-- <a target="_blank" href="https://react.dev/learn/reacting-to-input-with-state"><cite>Reacting to Input with State</cite></a></p>
</blockquote>
<p>Trata-se de um tema bem interessante, mas antes de entrar em mais detalhes, eu gostaria de te mostrar o que todo esse assunto tem a ver com <strong>cortar o seu próprio cabelo</strong>. Ficou com curiosidade? Então continue comigo até a próxima seção!</p>
<h2 id="heading-cortes-de-cabelo-podem-ser-complicados-a-ui-tambem">Cortes de cabelo podem ser complicados; a UI também</h2>
<p>Flávio é um rapaz jovem e se preocupa com o seu visual, mas não esteve satisfeito com o seu cabelo nos últimos dias e sente que está na hora de experimentar um novo corte, só que com um detalhe: <em>ele mesmo</em> queria fazê-lo.</p>
<p>A primeira etapa foi comprar as ferramentas necessárias, como uma tesoura, uma máquina de cortar cabelo e um pente. Em seguida, estudou algumas técnicas de barbearia pela internet e, por fim, iniciou o trabalho em sua própria casa.</p>
<p>Após terminar, Flávio limpou o local, tomou um banho, penteou o cabelo e, quando se olhou no espelho, teve uma surpresa infeliz ao perceber que o resultado não o agradou tanto quanto esperava — seria melhor ter ido ao cabeleireiro — ele pensou.</p>
<figure>
<img src="https://media.tenor.com/QFGSG5uW06IAAAAC/oden-annoyed-face.gif" alt="Pessoa fazendo uma expressão caricata de nojo" />
<figcaption>Figura 1 — Flávio após ver o seu cabelo no espelho (GIF via tenor.com)</figcaption>
</figure>

<p>Ao meu ver, essa situação pode ser comparada a de um desenvolvedor front-end implementando uma aplicação web moderna, cuja interface de usuário precisa ser constantemente atualizada para acompanhar as interações com o usuário.</p>
<p>Do mesmo modo que Flávio poderia ter apenas explicado como queria seu cabelo para que um cabeleireiro fizesse o corte, tendo em mãos as ferramentas, técnicas e espaço adequados; um desenvolvedor web poderia ver o seu trabalho facilitado ao dispor de uma biblioteca de código que recebesse descrições da interface de usuário e fizesse os trabalhos de exibi-la e atualizá-la da forma adequada.</p>
<figure>
<img src="https://media.tenor.com/N7w5XyJyPFwAAAAC/kozuki-oden-smile-oden.gif" alt="Pessoa alternando de uma expressão neutra para um sorriso de aprovação" />
<figcaption>Figura 2 — Flávio, caso tivesse ido ao cabeleireiro (GIF via tenor.com)</figcaption>
</figure>

<p>Com isso, não estamos reconhecendo ser impossível realizar todo esse trabalho por conta própria, afinal, era assim que tudo era feito até alguns anos atrás. Acontece que esse processo pode ser complexo, sujeito a erros e nem sempre será feito de forma eficiente quando falamos em grandes aplicações, e é nesse sentido que bibliotecas de UI como o React entram em cena.</p>
<h2 id="heading-mas-como-descrever-uma-interface-de-usuario">Mas como descrever uma interface de usuário?</h2>
<p>Diferentemente de como Flávio poderia simplesmente descrever o seu corte para o cabeleireiro, nós não temos uma forma tão trivial para solicitar ao computador que exiba as interfaces de usuário, pois não falamos a mesma língua. Logo, justifica-se a necessidade de encontrar uma maneira padronizada para descrever a UI, assim como o React utiliza a sintaxe do <a target="_blank" href="https://react.dev/learn/writing-markup-with-jsx">JSX</a> para esse fim.</p>
<p>Ocorre que, além de descrever e exibir os "esqueletos" de componentes da interface com JSX — isso é, apenas as suas estruturas — precisamos gerenciar a exibição de conteúdo dinâmico, que varia conforme as "situações" em que cada componente se encontra. Esse comportamento é abordado e implementado em React por meio do conceito de <a target="_blank" href="https://react.dev/learn/state-a-components-memory"><strong>estado</strong></a> e do hook <code>useState</code>.</p>
<p>Utilizando esses dois recursos — JSX e estado — implementamos componentes em React por meio de funções que, a grosso modo, têm como principal objetivo expor uma forma de obter descrições atualizadas de um componente sempre que houver alterações no seu estado, sendo que a esse evento, em que o React chama uma dessas funções, atribui-se o nome de <a target="_blank" href="https://react.dev/learn/render-and-commit#step-2-react-renders-your-components">"renderização"</a>.</p>
<p>Para ser um pouco mais específico, o fluxo de atualização de um componente se assemelha ao descrito a seguir:</p>
<ol>
<li><p>o estado do componente, que é gerenciado de forma centralizada e interna ao React, sofre uma alteração (por exemplo, devido à chamada de uma função <code>set</code>);</p>
</li>
<li><p>o React invoca a função de renderização do componente em questão e fornece a ela uma <strong>cópia</strong> com os novos valores das suas variáveis de estado. O valor retornado é uma representação válida para o componente <strong>naquele momento</strong>;</p>
</li>
<li><p>com a nova representação do componente em mãos, o React transfere as mudanças necessárias ao <a target="_blank" href="https://developer.mozilla.org/pt-BR/docs/Web/API/Document_Object_Model">DOM</a>, o que provoca uma atualização da interface exibida pelo navegador para corresponder ao estado atual do componente.</p>
</li>
</ol>
<p>A base de conhecimento do React fornece uma explicação ainda mais detalhada sobre esse assunto, mas, de forma geral, podemos sintetizar esse fluxo conforme ilustrado na figura 3.</p>
<figure>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684612929514/984a52de-cd38-4f30-b9db-d0cb420591a8.png" alt="Um componente pode ser visto como uma função matemática que recebe os valores de estado e produz uma descrição da UI" />
<figcaption>Figura 3 — componente visualizado como uma função matemática (baseado na <a href="https://medium.com/everything-full-stack/declarative-ui-what-how-and-why-13e092a7516f#cff6">ilustração de Asaf Varon</a>)</figcaption>
</figure>

<h2 id="heading-bonus-chamadas-cumulativas-de-funcoes-set">Bônus: chamadas cumulativas de funções "set"</h2>
<p>Uma consequência do processo de renderização em React diz respeito a uma limitação sobre como devemos utilizar funções <code>set</code> para alterar variáveis de estado de um componente, mais especificamente, quando tentamos chamá-las "de uma só vez" para aplicar mudanças cumulativas. Para entender melhor o que eu quero dizer, veja o exemplo a seguir:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// trecho de código retirado de https://react.dev/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time</span>

<span class="hljs-comment">// Código omitido</span>
&lt;button onClick={<span class="hljs-function">() =&gt;</span> {
        setNumber(number + <span class="hljs-number">1</span>);
        setNumber(number + <span class="hljs-number">1</span>);
        setNumber(number + <span class="hljs-number">1</span>);
}}&gt;+<span class="hljs-number">3</span>&lt;/button&gt;
<span class="hljs-comment">// Código omitido</span>
</code></pre>
<p>Quando estamos começando em React, é comum chegarmos à conclusão de que o resultado ao clicar no botão descrito acima (ou ao disparar qualquer evento semelhante) seja um incremento de três unidades no valor de <code>number</code>, mas, surpreendentemente, o que ocorre é um incremento de uma única unidade.</p>
<p>O motivo por trás disso é que, uma vez que o JSX é processado pela função de render do componente, a representação resultante sempre "enxerga" os valores de estado (nesse caso, o de <code>number</code>) como estavam no <strong>momento da renderização</strong>, e, até que o componente seja "chamado" novamente pelo React, ele não recebe o estado atualizado.</p>
<p>Como resultado, cada chamada de <code>setNumber</code> enxerga o valor de <code>number</code> somente como ele estava no momento em que <code>onClick</code> foi chamado, pois todas foram feitas antes que o componente fosse renderizado novamente. Logo, cada uma solicita a atualização de <code>number</code> para o mesmo valor (o valor inicial somado a 1).</p>
<h2 id="heading-consideracoes-finais">Considerações finais</h2>
<p>Podemos dizer que o tema tratado neste artigo é introdutório e até mesmo faz parte dos fundamentos do React, mas acredito que ter um entendimento claro sobre ele ajuda a construir uma base sólida, que facilita compreender o funcionamento da biblioteca com mais detalhes, por exemplo, da forma que me ajudou a entender com maior propriedade o fenômeno descrito na seção bônus.</p>
<p>Em suma, você deve se lembrar que o React segue um paradigma declarativo, cuja ideia é descrever a UI em vez de controlá-la diretamente, em contraste com uma abordagem imperativa, e fazemos isso por meio de funções de render, que fornecem descrições atualizadas dos componentes após mudanças em seus estados, sendo utilizadas pelo React para descobrir como ele deve atualizar o DOM.</p>
<p>A figura 4 sintetiza a diferença entre os paradigmas declarativo e imperativo.</p>
<figure>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684612965205/1bcd2480-380a-461d-bfa1-dc18648f0792.png" alt="No paradigma imperativo, o desenvolvedor precisa se preocupar com várias responsabilidades, como o gerenciamento de estado, manipulação da árvore DOM, garantia de performance entre renderizações etc. Já no paradigma declarativo, o desenvolvedor apenas fornece descrições dos componentes, e o restante do trabalho é feito pela biblioteca de UI" />
<figcaption>Figura 4 — Paradigma imperativo vs. paradigma declarativo</figcaption>
</figure>

<p>Finalmente, deixo explícito que vários outros detalhes sobre o funcionamento do React foram omitidos no contexto deste artigo, como o gerenciamento de estado, Virtual DOM e o processo de reconciliação em geral. Sendo assim, sugiro que continue estudando sobre esses assuntos, sendo a base de conhecimento do React a minha principal recomendação (por sinal, foi a maior fonte de informações para a escrita deste texto).</p>
<h2 id="heading-referencias">Referências</h2>
<ol>
<li><p><a target="_blank" href="https://react.dev/blog/2023/03/16/introducing-react-dev">Introducing react.dev (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/learn/reacting-to-input-with-state">Reacting to Input with State (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=x7cQ3mrcKaY&amp;t=916s">Pete Hunt: React: Rethinking best practices -- JSConf EU (YouTube)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/learn/writing-markup-with-jsx">Writing Markup with JSX (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/learn/state-a-components-memory">State: A Component's Memory (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/learn/render-and-commit#step-2-react-renders-your-components">Render and Commit. Step 2: React renders your components (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/pt-BR/docs/Web/API/Document_Object_Model">Modelo de Objeto de Documento (MDN)</a></p>
</li>
<li><p><a target="_blank" href="https://developer.android.com/jetpack/compose/mental-model?hl=pt-br#paradigm">Trabalhando com o Compose. O paradigma de programação declarativa (Android Developers)</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/everything-full-stack/declarative-ui-what-how-and-why-13e092a7516f">Declarative UI — What, How, and Why? - Asaf Varon (Medium)</a></p>
</li>
<li><p><a target="_blank" href="https://react.dev/learn/state-as-a-snapshot">State as a Snapshot (react.dev)</a></p>
</li>
<li><p><a target="_blank" href="https://rauchg.com/2014/7-principles-of-rich-web-applications">7 Principles of Rich Web Applications - Guillermo Rauch (rauchg.com)</a></p>
</li>
</ol>
<h2 id="heading-atribuicoes">Atribuições</h2>
<ul>
<li>Fotografia da capa por <a target="_blank" href="https://unsplash.com/pt-br/@chrisknight">Chris Knight</a> em <a target="_blank" href="https://unsplash.com/pt-br">Unsplash</a></li>
<li>Logo da marca <a target="_blank" href="https://react.dev/">React</a> sob a licença <a target="_blank" href="https://github.com/reactjs/react.dev/blob/main/LICENSE-DOCS.md">Creative Commons Attribution 4.0</a></li>
</ul>
]]></content:encoded></item></channel></rss>