<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://nfo94.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://nfo94.github.io/" rel="alternate" type="text/html" /><updated>2026-01-18T15:04:39+00:00</updated><id>https://nfo94.github.io/feed.xml</id><title type="html">Natália Oliveira</title><subtitle>Um blog sobre desenvolvimento de software e ciência da computação em geral.</subtitle><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><entry><title type="html">Leituras técnicas de 2025</title><link href="https://nfo94.github.io/2025/12/26/Leituras-t%C3%A9cnicas-de-2025.html" rel="alternate" type="text/html" title="Leituras técnicas de 2025" /><published>2025-12-26T00:00:00+00:00</published><updated>2025-12-26T00:00:00+00:00</updated><id>https://nfo94.github.io/2025/12/26/Leituras-t%C3%A9cnicas-de-2025</id><content type="html" xml:base="https://nfo94.github.io/2025/12/26/Leituras-t%C3%A9cnicas-de-2025.html"><![CDATA[<p>Desde 2024 me propus a trocar tempo inútil de tela por leitura, não importando o tipo, e confesso
que o resultado foi fenomenal! Em 2024 li por completo 4 livros técnicos e 2 não-técnicos,
e <a href="https://nfo94.github.io/2024/12/31/leituras-t%C3%A9cnicas-de-2024.html">publiquei sobre os técnicos aqui</a>.
Como não publiquei sobre os não-técnicos de 2024 irei listá-los aqui:</p>

<ul>
  <li><a href="https://www.amazon.com.br/pacto-branquitude-Cida-Bento/dp/6559212327/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=2YPSEPCUFRNJ8&amp;dib=eyJ2IjoiMSJ9.5YLM0-x3QLWrDfMdPFTNNSiCcBIJfTSLmRqBqYtoNIknSdd40PmEsjRI67JeDRBT5tsa5z84JlPrBiY2vLh-tOg503Li9BfwtnHe8m9lib05Qm5zMQcYfm8qxggKW5nmNIRwmAZ3K6cVDfViY3A9X7jFvBhXUwhoFhfZjn_k0KCEVwbHYQqUtU-LjlSBBbxoo7FCL1hogvqdW8JKwpZ1_w.se9XHg-owxYEHzlfQZcLMqKojycaJlAB-WlDUBzu_C8&amp;dib_tag=se&amp;keywords=cida+bento&amp;qid=1766570000&amp;sprefix=cida+bento%2Caps%2C388&amp;sr=8-1">O Pacto da Branquitude, por Cida Bento</a>:
na minha opinião leitura essencial para nós, pessoas brancas, para refletirmos e compreendermos
como já nascemos com as estatísticas (e outras pessoas brancas) trabalhando a nosso favor;</li>
  <li><a href="https://www.amazon.com.br/vida-n%C3%A3o-%C3%A9-%C3%BAtil/dp/8535933697/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=2QOCB4RC9QCBO&amp;dib=eyJ2IjoiMSJ9.0fi9RgSuqoxmlj7v8Xk8Nuqe9SNbJRI6jOuGAz9gRmhPfYr0h_HPqcNMZvZFNT3NqB7KEDA5-EKLM7hVuTzqXP2nvnEx2hzQ_JlWEmZt63olCclXcbiahG_cXKt19E9bt344p4sW5Ha9JuP84ybvfcbiwH3gLxQnat_6w4ZSsgVgQM03o3pDKyTRI-9l6PDs7AVR3vHtMXTPYHxiGAB_XqgS-HtCwd2jYtlLweQktnxlfX3GnrlrEwX_ERT64GG40Tj2kR4rfeO19uJw9mmfFce6CSio8nJRV_hyTcL_WR4.oJ_Vx-0wCm0McKOijm_L1m7zjaQHwvjJe7whADDw_EI&amp;dib_tag=se&amp;keywords=a+vida+n%C3%A3o+%C3%A9+%C3%BAtil&amp;qid=1766570043&amp;sprefix=a+vida+n%C3%A3o+%C3%A9+%C3%BAtil%2Caps%2C264&amp;sr=8-1">A Vida Não É Útil, por Ailton Krenak</a>:
esse livro me fez pensar, além de várias outras coisas, em todas as bobagens contadas no LinkedIn,
<em>tech brows</em> e a sana em destruir tudo para satisfazer investidores.</li>
</ul>

<p>Esse ano de 2025, para minha própria surpresa, li 15 livros completos e foi bem interessante
notar como fui de realizar uma atividade meio chata e forçada para um hábito como escovar os dentes.
Estes foram os livros técnicos que li em 2025:</p>

<ul>
  <li><a href="#1">Domain Driven Design Distilled</a></li>
  <li><a href="#2">How AI Works</a></li>
  <li><a href="#3">Software Architecture Patterns</a></li>
  <li><a href="#4">Artificial Intelligence, a guide for thinking humans</a></li>
  <li><a href="#5">Product Management in Practice</a></li>
  <li><a href="#6">Prompt Engineering for LLMs</a></li>
  <li><a href="#7">Identity Security for Software Development</a></li>
  <li><a href="#8">Concurrency in Go</a></li>
  <li><a href="#9">Web Security for Developers</a></li>
</ul>

<h2 id="domain-driven-design-distilled"><a name="1"></a>Domain Driven Design Distilled</h2>

<p>Já ouvi falar que o livro clássico Domain Driven Design é muito denso e difícil de ler,
então achei melhor começar por esse. É um livro enxuto, rápido de ler e sumariza os
principais conceitos de DDD.</p>

<p>Acredito que vale a leitura, porém, creio que faltou um pouco de revisão. Exemplo: em um
único parágrafo o autor repete a mesma coisa três vezes, uma atrás da outra, além de
apontar uma coisa óbvia de uma imagem. Essa percepção de escrita meio enrolada me
acompanhou em alguns momentos, mas foi uma percepção pessoal, creio que não invalida a importância
desse livro. Em algum momento irei ler outras alternativas como “Learning Domain-Driven
Design”, que é um livro com bons <em>reviews</em> e parece ter uma proposta parecida.</p>

<p>Recomendo a leitura, porém, como é apenas teoria, estou fazendo o projeto prático do “Domain-Driven
Design with Golang” para consolidar melhor os conceitos. DDD definitivamente não é simples (deveria
ser?).</p>

<div align="center">
<img width="55%" alt="domain driven design distilled" src="../../../assets/images/9/dddd.webp" />
</div>

<h2 id="how-ai-works"><a name="2"></a>How AI Works</h2>

<p>Não se engane, esse é um livro técnico apesar da capa fofinha da No Starch Press. Inicialmente
achei que encontraria algo parecido com o “Artificial Intelligence Basics” que li ano passado,
mas esse livro passa por conceitos bem profundos e complexos, apesar de evitar fórmulas
matemática (mas falando de conceitos dela). Apesar disso é extremamente didático de uma forma
muito engajante.</p>

<p>Eu não tinha intenção de ler esse livro esse ano, acontece que eu folheei algumas página no
Kindle e simplesmente fui fisgada. Como a intenção dessas leituras é principalmente filosófica,
ser fisgada por um livro técnico é tudo que eu queria mesmo. Acredito que ajudou a, de certa
forma, acalmar meus nervos com relação a inteligência artificial.</p>

<p>Por fim: altamente recomendado. Leia 5 páginas, se você não for fisgado(a) por esse livro, você
está morto(a) por dentro 😆</p>

<div align="center">
<img width="55%" alt="how ai works" src="../../../assets/images/9/haiw.webp" />
</div>

<h2 id="software-architecture-patterns"><a name="3"></a>Software Architecture Patterns</h2>

<p>Este é um <em>report</em> da O’Reilly, o que significa que é um livro pequeno, um relatório mesmo, focado
em falar sobre padrões de arquitetura de software. Achei bem enxuto e direto ao ponto, porém,
não sei se houve algum valor real ao ler esse livro. Talvez seja interessante para quem só quer
manter um hábito saudável de leitura, ou apenas quer revisar alguns pontos dos tipos de
arquitetura. Mas vale frisar que escolhi esse livro por causa do autor Mark Richards, que é
quem escreveu juntamente com Neal Ford o “Fundamentals of Software Architecture”. Achei que
seria uma boa começar por esse reporte, assim como fiz com o Domain Driven Design Distilled.</p>

<div align="center">
<img width="55%" alt="software architecture patterns" src="../../../assets/images/9/sap.webp" />
</div>

<h2 id="artificial-intelligence-a-guide-for-thinking-humans"><a name="4"></a>Artificial Intelligence, a guide for thinking humans</h2>

<p>Que livro fantástico! Tem um pouco de “How AI Works” nos quesitos históricos e de funcionamento,
mas não vai tão a fundo tecnicamente quanto ele, no lugar da profundidade técnica tem um quê
filosófico, de questionamentos críticos, e tons pessoais da autora cuja história está
entrelaçada com o tema. Melanie Mitchell é professora de ciência da computação e em 1990 já
estava escrevendo teses sobre inteligência artificial.</p>

<p>Recomendo fortemente.</p>

<div align="center">
<img width="55%" alt="artifitiall intelligence, a guide for thinking humans" src="../../../assets/images/9/aiagfth.webp" />
</div>

<h2 id="product-management-in-practice"><a name="5"></a>Product Management in Practice</h2>

<p>Não, não tenho interesse no cargo, mas decidi ler esse livro por curiosidade para entender um
pouco melhor sobre esse papel, e reponder a pergunta “por que alguém faria isso a si mesmo?”.</p>

<p>O livro começa bem filosófico, o que não era minha expectativa. Minha expectativa inicial era ler
um livro recheado de termos técnicos com muita informação sobre frameworks para
o trabalho de gerenciamento de produto em si, mas não foi sobre isso. Na realidade, uns 90%
desse livro é só sobre comunicação, interna, externa, entre diferentes camadas de atuação e
liderança, com colaboradores e clientes, e sobre gerenciamento de expectativas e de egos, dos
nossos e dos outros. Uma verdadeira terapia.</p>

<p>O autor Matt LeMay dá dicas de padrões de comportamentos comuns, tanto
positivos quanto negativos, no contexto de produto de uma empresa, e sugere comunicações,
frases prontas mesmo, para lidar com diversas situações.</p>

<div align="center">
<img width="55%" alt="product management in practice" src="../../../assets/images/9/pmip.webp" />
</div>

<h2 id="prompt-engineering-for-llms"><a name="6"></a>Prompt Engineering for LLMs</h2>

<p>No início do ano, por ignorância, eu achava que prompt engineering descrevia apenas a
situação de escrever bons prompts para um LLM em um chat na web, porém, entendi que o termo não
se refere apenas a essa situação. Esse livro foca em prompt engineering do ponto de vista de
uma aplicação intermediária, que manipula o prompt escrito pelo usuário, o adequa para o caso
de uso, otimiza para um resposta eficiente e o modela num JSON para realizar uma chamada para
um modelo de LLM, como o GPT-4.1. Aborda vários aspectos, tanto de otimização do prompt, como
alguns parâmetros de exemplo da API da OpenAI, como atenta para questões de preço pelo token,
etc.</p>

<p>No geral achei bem interessante a leitura, importante para sair da completa ignorância no
assunto. Não tenha vergonha, somos todos burros, só no LinkedIn todo mundo parece ter mestrado
em inteligência artificial.</p>

<div align="center">
<img width="55%" alt="prompt engineering for llms" src="../../../assets/images/9/pefl.webp" />
</div>

<h2 id="identity-security-for-software-development"><a name="7"></a>Identity Security for Software Development</h2>

<p>Esse é um livro focado em práticas de segurança em gerenciamento de identidades, tanto humana
(como autenticação, autorização, ciclo de vida de usuário, acesso privilegiado, etc) quanto
máquina (secrets, certificates, mecanismo de autenticação e autorização para acessar outras
máquinas, etc). Esse é o tipo de assunto que ainda está meio amorfo na minha mente, mas esse
livro serviu para me dar uma visão mais macro sobre isso: segurança de identidades no código,
soluções de gerenciamento, na cloud, no Kubernetes e pipelines de CI/CD.</p>

<div align="center">
<img width="55%" alt="identity security for software development" src="../../../assets/images/9/issd.webp" />
</div>

<h2 id="concurrency-in-go"><a name="8"></a>Concurrency in Go</h2>

<p>A autora tem uma escrita excelente e engajante, o que eu não esperava de um livro técnico e
prático. É necessário ir rodando e testando os exemplos do livro pois concorrência é assunto
muito desconfortável e não-natural, é o típico “só acredito vendo; eu vendo: não acredito”.</p>

<p>Os primeiros capítulos já entregam muito conteúdo e exemplos, e fica claro que este livro é mais
adequado a quem já tem conhecimento em programação e na linguagem Go.</p>

<div align="center">
<img width="55%" alt="concurrency in go" src="../../../assets/images/9/cg.webp" />
</div>

<h2 id="web-security-for-developers"><a name="9"></a>Web Security for Developers</h2>

<p>Como andei preocupada com temas de segurança em tempos de AI peguei também esse livro para ler.
É bastante acessível, sumarizando do zero conceitos basilares, como funcionamento de browsers e
protocolos de internet. É um equilíbrio interessante entre dar contexto e depos explicar os
tipos de ataques. São 18 capítulos e na parte II vemos com detalhes os tipos.</p>

<p>No geral, um livro excelente e recomendado.</p>

<div align="center">
<img width="55%" alt="web security for developers" src="../../../assets/images/9/wsd.webp" />
</div>

<p><br /></p>

<hr />

<p><br /></p>

<p>Esse ano farei diferente e irei listar os não-técnicos também, afinal, ler apenas conteúdos
técnicos é a forma mais rápida para ficar bitolado e sem diversidade de assuntos. Eis os livros:</p>

<ul>
  <li><strong>Babel</strong>: vou ser honesta, não achei esse livro grande coisa, mas creio que estava tão faminta por
livros de ficção que devorei em pouco tempo. A melhor parte do livro para mim foi o tópico
de linguística, diretamente entrelaçado com a trama fantasiosa. A autora é a R. F. Kuang;</li>
  <li><strong>Watchmen</strong>: um clássico do Alan Moore e Dave Gibbons, porém nunca havia lido. Li a edição
DC Campact, que tem o mesmo formato que um livro comum, é muito <em>cozy</em> para ler;</li>
  <li><strong>Leviathan Wakes</strong>: já havia lido, então esse foi o segundo <em>round</em> e, nossa, que série fantástica.
O Daniel Abraham e Ty Franck sabem como te envolver na trama e fazer um filme na sua cabeça. Ainda
irei tatuar a Enterprise, a Serenity e a Rocinante juntas, as melhores naves de ficção de todos os
tempos;</li>
  <li><strong>Calibans War</strong>: começa mais devagar do que o primeiro livro, mas a construção até a ação é muito
boa, com muito mais partes de política internacional, e Avasarala e Bobbie são sensacionais;</li>
  <li><strong>Hipocritões e Olhigarcas</strong>: excelente livro do Rui Tavares. Fala sobre guerras culturais (assuntos
que exaltam os ânimos, dividem as opiniões com polarização extrema, centrado em temas de identidades,
valores e narrativas), coisa diretamente interligada com o desenvolvimento tecnológico da humanidade.
Extremamente recomendado;</li>
  <li><strong>Abbadon’s Gate</strong>: também começa devagar, com menos tempo com a equipa, mas depois que amarra os fios
fica brutal, com muita ação e decisões que são a carinha da humanidade.</li>
</ul>

<p>Atualmente estou lendo <strong>Cibola Burn</strong>, pensando nos conflitos internacionais que a colonização de
Marte irá causar no nosso mundo. De livro técnico estou lendo <strong>Tidy First</strong>, mas estou na parte
menos interessante, sem código (hehe!).</p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="livros" /><summary type="html"><![CDATA[leituras feitas em 2025]]></summary></entry><entry><title type="html">SOLID: open/closed principle em Go e Python</title><link href="https://nfo94.github.io/2025/08/11/SOLID-open-closed-principle-em-Go-e-Python.html" rel="alternate" type="text/html" title="SOLID: open/closed principle em Go e Python" /><published>2025-08-11T00:00:00+00:00</published><updated>2025-08-11T00:00:00+00:00</updated><id>https://nfo94.github.io/2025/08/11/SOLID:-open-closed-principle-em-Go-e-Python</id><content type="html" xml:base="https://nfo94.github.io/2025/08/11/SOLID-open-closed-principle-em-Go-e-Python.html"><![CDATA[<p>Esse é o segundo artigo de uma série sobre SOLID explicado com exemplos nas linguagens de
programação Python e Go, da forma mais simples posssível, utilizando dois livros como base, um do
Corey Scott e outro do Mariano Anaya:</p>

<ul>
  <li><a href="https://www.amazon.com.br/Hands-Dependency-Injection-Corey-Scott/dp/1789132762">Hands-On Dependency Injection in Go</a></li>
  <li><a href="https://www.amazon.com.br/Clean-Code-Python-maintainable-efficient/dp/1800560214">Clean Code in Python</a></li>
</ul>

<p>Para atualizar os exemplos de Python do “Clean Code in Python” utilizaremos também o artigo do <a href="https://realpython.com/solid-principles-python/#open-closed-principle-ocp">Real Python</a>.
Aqui iremos falar sobre o <strong>open/closed principle</strong>, ou <strong>princípio aberto/fechado</strong> em português.
Perguntas para guiar nosso estudo:</p>

<ul>
  <li><a href="#1">O que é e para que serve o open/closed principle?</a></li>
  <li><a href="#2">Como aplicar o open/closed principle em Python?</a></li>
  <li><a href="#3">Como aplicar o open/closed principle em Go?</a></li>
</ul>

<h2 id="o-que-é-e-para-que-serve-o-openclosed-principle"><a name="1"></a>O que é e para que serve o open/closed principle?</h2>

<p>Você já deve ter ouvido a frase <strong>“aberto para extensão, fechado para modificação”</strong>, mas talvez não
tenha entendido perfeitamente o que isso quer dizer. Quando estamos escrevendo uma classe, um módulo,
etc, queremos que seja possível extendê-lo porque <strong>requisitos mudam</strong> e ao longo do tempo sempre surgem
novas features, novas funcionalidades e comportamentos para o nosso software. Quando extender um
software é muito difícil <s>ou parece impossível de ser feito</s>, temos um problema. Em outras palavras,
queremos que seja fácil adicionar comportamentos, mas não queremos modificar o que já existe (podendo
quebrar funcionalidades), e é justamente para isso que serve o princípio open/closed.</p>

<p>Corey Scott sobre esse princípio:</p>

<blockquote>
  <p>Essas duas características podem parecer contraditórias, mas a peça que falta no quebra-cabeça é o
escopo. Quando falamos em ser aberto, estamos falando do design ou da estrutura do software. Dessa
perspectiva, ser aberto significa que é fácil adicionar novos pacotes, novas interfaces ou novas
implementações de uma interface existente.</p>
</blockquote>

<p>Como bem sublinha Mariano Anaya, o princípio open/closed é aplicável a diversas abstrações de software,
podendo ser uma classe, módulo, função, etc, a ideia é a mesma.</p>

<h2 id="como-aplicar-o-openclosed-principle-em-python"><a name="2"></a>Como aplicar o open/closed principle em Python?</h2>

<p>O Mariano Anaya dá um exemplo interessante em seu livro, acompanhe meus comentários no código dele:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>

<span class="c1"># O decorator `dataclass` dá a classe Python uma série de métodos e atributos básicos built-in
# sem que a gente precise escrevê-los na mão, como um `__init__(self, raw_data: dict)`, por exemplo
</span><span class="o">@</span><span class="n">dataclass</span>
<span class="k">class</span> <span class="nc">Event</span><span class="p">:</span>
    <span class="s">"""`Event` é uma classe que define um evento"""</span>
    <span class="n">raw_data</span><span class="p">:</span> <span class="nb">dict</span>

<span class="c1"># Cada classe abaixo herda do `Event` e especifica um tipo de evento. Imagine uma implementação
# hipotética do que cada uma faz ou tem
</span><span class="k">class</span> <span class="nc">UnknownEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">LoginEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">LogoutEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">SystemMonitor</span><span class="p">:</span>
    <span class="s">"""`SystemMonitor` identifica eventos na aplicação"""</span>

    <span class="c1"># Inicializando o `SystemMonitor` com um atributo `event_data`
</span>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event_data</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span> <span class="o">=</span> <span class="n">event_data</span>

    <span class="c1"># Método para identificar um evento: se é um `LoginEvent`, `LogoutEvent` ou `UnknownEvent`
</span>    <span class="k">def</span> <span class="nf">identify_event</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="p">(</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">[</span><span class="s">"before"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
            <span class="ow">and</span> <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">[</span><span class="s">"after"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
        <span class="p">):</span>
            <span class="k">return</span> <span class="n">LoginEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">)</span>
        <span class="k">elif</span> <span class="p">(</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">[</span><span class="s">"before"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
            <span class="ow">and</span> <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">[</span><span class="s">"after"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
        <span class="p">):</span>
            <span class="k">return</span> <span class="n">LogoutEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">UnknownEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">)</span>
</code></pre></div></div>

<p>Agora, imagine que queremos adicionar mais 3 eventos a essa aplicação. Você diria que o <code class="language-plaintext highlighter-rouge">SystemMonitor</code>
está “aberto para extensão, fechado para modificação”? Pense bem na parte de “modificação”. Para extender
o monitoramento, além da inevitável adição de um novo evento (nova subclasse) precisaríamos modificar o
<code class="language-plaintext highlighter-rouge">SystemMonitor</code> com um novo <code class="language-plaintext highlighter-rouge">elif</code>. Para conseguir cumprir o princípio precisamos, de alguma forma,
fazer com que a lógica do <code class="language-plaintext highlighter-rouge">SystemMonitor</code> “seja uma só” e que a “responsabilidade” da nova feature
seja justamente do novo código, do novo evento. Uma forma de fazer isso é como no código abaixo:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>

<span class="c1"># A classe `Event` é a nossa classe "genérica"
</span><span class="o">@</span><span class="n">dataclass</span>
<span class="k">class</span> <span class="nc">Event</span><span class="p">:</span>
    <span class="n">raw_data</span><span class="p">:</span> <span class="nb">dict</span>

    <span class="c1"># Queremos abstrair a identificação do evento, e aqui exemplificamos uma interface comum para
</span>    <span class="c1"># todos os eventos seguirem
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">meets_condition</span><span class="p">(</span><span class="n">event_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">False</span>

<span class="k">class</span> <span class="nc">UnknownEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">LoginEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="c1"># Agora cada nova subclasse de `Event` implementa seu próprio `meets_condition`. Esse método
</span>    <span class="c1"># recebe um dicionário `event_data` e computa uma lógica para definir se é o tipo de evento em
</span>    <span class="c1"># questão ou não
</span>    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">meets_condition</span><span class="p">(</span><span class="n">event_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="n">event_data</span><span class="p">[</span><span class="s">"before"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
            <span class="ow">and</span> <span class="n">event_data</span><span class="p">[</span><span class="s">"after"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
        <span class="p">)</span>

<span class="k">class</span> <span class="nc">LogoutEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">meets_condition</span><span class="p">(</span><span class="n">event_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="n">event_data</span><span class="p">[</span><span class="s">"before"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span>
            <span class="ow">and</span> <span class="n">event_data</span><span class="p">[</span><span class="s">"after"</span><span class="p">][</span><span class="s">"session"</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
        <span class="p">)</span>

<span class="c1"># Novo evento. Repare em como basta implementar sua lógica, seguindo a "interface" da classe genérica
</span><span class="k">class</span> <span class="nc">TransactionEvent</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="o">@</span><span class="nb">staticmethod</span>
    <span class="k">def</span> <span class="nf">meets_condition</span><span class="p">(</span><span class="n">event_data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">event_data</span><span class="p">[</span><span class="s">"after"</span><span class="p">].</span><span class="n">get</span><span class="p">(</span><span class="s">"transaction"</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span>

<span class="k">class</span> <span class="nc">SystemMonitor</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event_data</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">event_data</span> <span class="o">=</span> <span class="n">event_data</span>

    <span class="k">def</span> <span class="nf">identify_event</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c1"># Agora para identificar o evento usamos o método mágico (dunder/magic method)
</span>        <span class="c1"># `__subclasses__()` para "olhar" as subclasses do `Event`
</span>        <span class="k">for</span> <span class="n">event_cls</span> <span class="ow">in</span> <span class="n">Event</span><span class="p">.</span><span class="n">__subclasses__</span><span class="p">():</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="c1"># Chamando a implementação de clada subclasse passando o `event_data`, e a partir
</span>                <span class="c1"># daí a lógica é responsabilidade de cada evento
</span>                <span class="k">if</span> <span class="n">event_cls</span><span class="p">.</span><span class="n">meets_condition</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">):</span>
                    <span class="c1"># Se satisfaz a condição para ser o evento, retorne a subclasse com os dados do
</span>                    <span class="c1"># evento
</span>                    <span class="k">return</span> <span class="n">event_cls</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">)</span>
            <span class="k">except</span> <span class="nb">KeyError</span><span class="p">:</span>
                <span class="k">continue</span>
        <span class="k">return</span> <span class="n">UnknownEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event_data</span><span class="p">)</span>
</code></pre></div></div>

<p>Com o exemplo acima não precisamos ficar alterando o <code class="language-plaintext highlighter-rouge">SystemMonitor</code> toda vez que um evento novo
for criado, bastará apenas criar uma nova subclasse e implementar a interface da classe genérica
<code class="language-plaintext highlighter-rouge">Event</code>.</p>

<blockquote>
  <p><em>Poxa, mas não tem um exemplo mais moderno e mais simples não, sem usar <code class="language-plaintext highlighter-rouge">__subclasses__()</code>?</em></p>
</blockquote>

<p>Exatamente o que pensei ao ler o código, e pensei logo no pacote <code class="language-plaintext highlighter-rouge">abc</code> do Python. Logo em seguida o
autor Mariano Anaya citou a possiblidade de fazer de outras formas, justamente com o <code class="language-plaintext highlighter-rouge">abc</code>. Vejamos
o exemplo do site Real Python:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">pi</span>

<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
    <span class="c1"># Inicializamos a class recebendo um `shape_type` e `kwargs`
</span>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shape_type</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">=</span> <span class="n">shape_type</span>
        <span class="c1"># Para definir `height` e `width` vamos de `if` e `elif` até dizer chega
</span>        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">==</span> <span class="s">"rectangle"</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">width</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s">"width"</span><span class="p">]</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">height</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s">"height"</span><span class="p">]</span>
        <span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">==</span> <span class="s">"circle"</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s">"radius"</span><span class="p">]</span>

    <span class="c1"># Método para calcular a área a depender do tipo de forma
</span>    <span class="k">def</span> <span class="nf">calculate_area</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">==</span> <span class="s">"rectangle"</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">height</span>
        <span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">==</span> <span class="s">"circle"</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">pi</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">radius</span><span class="o">**</span><span class="mi">2</span>
</code></pre></div></div>

<p>Consegue ver o padrão se repetir aqui? Adicionar mais tipos de formas, de shapes, faz com que tenhamos
que modificar a classe com mais <code class="language-plaintext highlighter-rouge">if</code>. Podemos utilizar essa classe para criar diferentes formas, e
ela funciona, mas não segue o princípio open/closed. Uma possível solução:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span>
<span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">pi</span>

<span class="c1"># Finalmente, estamos usando o pacote `abc`! Na nossa classe genérica, `Shape`, também chamada de
# classe abstrata, e herdamos de `ABC`
</span><span class="k">class</span> <span class="nc">Shape</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shape_type</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">shape_type</span> <span class="o">=</span> <span class="n">shape_type</span>

    <span class="c1"># E aqui criamos um método abstrato com o `abstractmethod`. Quem quiser que implemente 😒💅
</span>    <span class="o">@</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">calculate_area</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>

<span class="c1"># `Circle`, um tipo de `Shape`, herda de `Shape`, nossa classe abstrata
</span><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">radius</span><span class="p">):</span>
        <span class="c1"># Chamando o construtor da superclasse, passando o tipo de forma
</span>        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">(</span><span class="s">"circle"</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">radius</span>

    <span class="c1"># Implementando o `calculate_area` do `Circle`
</span>    <span class="k">def</span> <span class="nf">calculate_area</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">pi</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">radius</span><span class="o">**</span><span class="mi">2</span>

<span class="k">class</span> <span class="nc">Rectangle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">(</span><span class="s">"rectangle"</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">width</span> <span class="o">=</span> <span class="n">width</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">height</span> <span class="o">=</span> <span class="n">height</span>

    <span class="c1"># Implementando o `calculate_area` do `Rectangle` e por aí vai. Quem pegou o bonde andando não
</span>    <span class="c1"># senta na janela: implemente sua poha
</span>    <span class="k">def</span> <span class="nf">calculate_area</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">width</span> <span class="o">*</span> <span class="bp">self</span><span class="p">.</span><span class="n">height</span>
</code></pre></div></div>

<p>Agora podemos dizer que nosso <code class="language-plaintext highlighter-rouge">Shape</code> aberto para extensão e fechado para modificação.</p>

<h2 id="como-aplicar-o-openclosed-principle-em-go"><a name="3"></a>Como aplicar o open/closed principle em Go?</h2>

<p>Agora vamos ver como isso funciona em Go. Vejamos um exemplo do autor Corey Scott de uma função que
formata um output a depender do tipo do arquivo:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">BuildOutput</span><span class="p">(</span><span class="n">r</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">format</span> <span class="kt">string</span><span class="p">,</span> <span class="n">p</span> <span class="n">Person</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">var</span> <span class="n">err</span> <span class="kt">error</span>
	<span class="k">switch</span> <span class="n">format</span> <span class="p">{</span>
	<span class="k">case</span> <span class="s">"csv"</span><span class="o">:</span>
		<span class="n">err</span> <span class="o">=</span> <span class="n">outputCSV</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
	<span class="k">case</span> <span class="s">"json"</span><span class="o">:</span>
		<span class="n">err</span> <span class="o">=</span> <span class="n">outputJSON</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="n">r</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">)</span>
		<span class="k">return</span>
	<span class="p">}</span>

	<span class="n">r</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// Função específica hipotética para csv</span>
<span class="k">func</span> <span class="n">outputCSV</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
	<span class="c">// TODO: implementar</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="c">// Função específica hipotética para json</span>
<span class="k">func</span> <span class="n">outputJSON</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
	<span class="c">// TODO: implementar</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Person</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Name</span>  <span class="kt">string</span>
	<span class="n">Email</span> <span class="kt">string</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Se quisermos trabalhar com outro formato, <code class="language-plaintext highlighter-rouge">xml</code>, por exemplo, teremos que fazer algumas coisas
nesse código acima:</p>

<ul>
  <li>Adicionar mais um <code class="language-plaintext highlighter-rouge">case</code> para cada novo formato;</li>
  <li>Adicionar novas funções de output específicas;</li>
  <li>Os métodos que chamam essa função precisam ser adaptados;</li>
  <li>Novos testes precisarão ser adicionados.</li>
</ul>

<p>Geralmente, quanto mais coisas precisamos modificar no código para abarcar a mudança, mais difícil
fica de não quebrar algo. Existe uma outra forma de escrever esse código:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">BuildOutput</span><span class="p">(</span><span class="n">r</span> <span class="n">http</span><span class="o">.</span><span class="n">ResponseWriter</span><span class="p">,</span> <span class="n">pf</span> <span class="n">PersonFormatter</span><span class="p">,</span> <span class="n">p</span> <span class="n">Person</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">err</span> <span class="o">:=</span> <span class="n">pf</span><span class="o">.</span><span class="n">Format</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span> <span class="c">// Chamamos um método hipotético Format de uma interface PersonFormatter</span>
  <span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
    <span class="n">r</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">)</span>
    <span class="k">return</span>
  <span class="p">}</span>

  <span class="n">r</span><span class="o">.</span><span class="n">WriteHeader</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// Definindo comportamento/contrato através de uma interface</span>
<span class="k">type</span> <span class="n">PersonFormatter</span> <span class="k">interface</span> <span class="p">{</span>
	<span class="n">Format</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">CSVPersonFormatter</span> <span class="k">struct</span><span class="p">{}</span>

<span class="c">// Implementação do Format para csv</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">CSVPersonFormatter</span><span class="p">)</span> <span class="n">Format</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
	<span class="c">// TODO: implement</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">JSONPersonFormatter</span> <span class="k">struct</span><span class="p">{}</span>

<span class="c">// Implementação do format para JSON</span>
<span class="k">func</span> <span class="p">(</span><span class="n">j</span> <span class="o">*</span><span class="n">JSONPersonFormatter</span><span class="p">)</span> <span class="n">Format</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
	<span class="c">// TODO: implement</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>

<span class="k">type</span> <span class="n">Person</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Name</span>  <span class="kt">string</span>
	<span class="n">Email</span> <span class="kt">string</span>
<span class="p">}</span>
</code></pre></div></div>

<p>No código acima abstraímos o <code class="language-plaintext highlighter-rouge">switch</code> por uma “caixa preta”: definimos um comportamento e quem
quiser implementar esse comportamento basta criar seu código específico, seguindo as “regras” da
interface. No fim das contas, cortamos a necessidade de ficar adicionando uma lista enorme de <code class="language-plaintext highlighter-rouge">switch</code>
e precisamos alterar um lugar a menos no código. Quanto menos lugares para alterar, melhor.</p>

<p>O Corey Scott menciona um benefício interessante do open/closed principle: ajudar a reduzir o escopo
de novos bugs para apenas o novo código, o que faz bastante sentido já que se adicionarmos um novo
formato, como o <code class="language-plaintext highlighter-rouge">xml</code>, já sabemos onde precisamos olhar se os testes quebrarem:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span>
<span class="k">type</span> <span class="n">XMLPersonFormatter</span> <span class="k">struct</span><span class="p">{}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">XMLPersonFormatter</span><span class="p">)</span> <span class="n">Format</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">,</span> <span class="n">person</span> <span class="n">Person</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
	<span class="c">// Se passou a quebrar depois do PR que implementa isso aqui, estamos diante de uma implementação</span>
    <span class="c">// safada com bug</span>
	<span class="k">return</span> <span class="no">nil</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<p>Flash da Jequiti para lembrar os princípios:</p>

<div align="center">
<img alt="solid" src="../../../assets/images/8/solid.webp" />
</div>

<hr />

<p>Fontes:</p>

<p>ANAYA, Mariano. <a href="https://www.amazon.com.br/Clean-Code-Python-maintainable-efficient/dp/1800560214">Clean Code in Python</a>.
Packt, 2021.</p>

<p>SCOTT, Corey. <a href="https://www.amazon.com.br/Hands-Dependency-Injection-Corey-Scott/dp/1789132762">Hands-On Dependency Injection in Go</a>.
Packt, 2018.</p>

<p><a href="https://realpython.com/solid-principles-python/#open-closed-principle-ocp">SOLID Principles: Improve Object-Oriented Design in Python - Real Python</a></p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="solid," /><category term="open/closed" /><category term="principle" /><summary type="html"><![CDATA[explicando o que é o open/closed principle do SOLID, com exemplos em Python e em Go]]></summary></entry><entry><title type="html">SOLID: single responsibility em Go e Python</title><link href="https://nfo94.github.io/2025/06/23/SOLID-single-responsibility-em-Go-e-Python.html" rel="alternate" type="text/html" title="SOLID: single responsibility em Go e Python" /><published>2025-06-23T00:00:00+00:00</published><updated>2025-06-23T00:00:00+00:00</updated><id>https://nfo94.github.io/2025/06/23/SOLID:-single-responsibility-em-Go-e-Python</id><content type="html" xml:base="https://nfo94.github.io/2025/06/23/SOLID-single-responsibility-em-Go-e-Python.html"><![CDATA[<p>Esse é o primeiro artigo de uma série sobre SOLID explicado com exemplos nas linguagens de
programação Python e Go, da forma mais simples posssível, e iremos utilizar dois livros como base,
um do Corey Scott e outro do Mariano Anaya:</p>

<ul>
  <li><a href="https://www.amazon.com.br/Hands-Dependency-Injection-Corey-Scott/dp/1789132762">Hands-On Dependency Injection in Go</a></li>
  <li><a href="https://www.amazon.com.br/Clean-Code-Python-maintainable-efficient/dp/1800560214">Clean Code in Python</a></li>
</ul>

<p>Aqui iremos falar sobre o <strong>single responsibility principle</strong>, ou <strong>princípio de responsabilidade
única</strong> em português. Perguntas para guiar nosso estudo:</p>

<ul>
  <li><a href="#1">O que é e para que serve o single responsibility principle?</a></li>
  <li><a href="#2">Como aplicar o single responsibility principle em Python?</a></li>
  <li><a href="#3">Como aplicar o single responsibility principle em Go?</a></li>
</ul>

<h2 id="o-que-é-e-para-que-serve-o-single-responsibility-principle"><a name="1"></a>O que é e para que serve o single responsibility principle?</h2>

<p>De todos os princípios SOLID esse é provavelmente o mais simples de entender. A ideia do single
responsibility principle é <strong>reduzir complexidade decompondo o código em partes menores, mais fáceis
de entender, constatando que um componente de software, uma classe, por exemplo, deve ter apenas uma
responsabilidade</strong>.</p>

<p>Esse princípio também está relacionado ao <strong>separation of concerns</strong>, onde temos a ideia de manter a
coesão do código definindo bem quais são as “preocupações”, ou responsabilidades, que determinado
componente possui.</p>

<p>Uma outra forma de pensar sobre o single responsibility principle (por vezes abreviado para <strong>SRP</strong>)
é que, caso uma classe não siga esse princípio e apresente várias responsabilidades, isso também
significa que essa classe tem vários motivos para acarretar mudanças. Se tivesse uma única
responsabilidade, caso fosse necessário mudar algo isso seria feito de uma vez só.</p>

<p>Além do já citado, o <strong>SRP possivelmente aumenta a reusabilidade de código</strong> uma vez que as
responsabilidades estão bem separadinhas e desacopladas de um componente específico. E na linha do
desacoplamento até escrever testes é potencialmente mais simples.</p>

<h2 id="como-aplicar-o-single-responsibility-principle-em-python"><a name="2"></a>Como aplicar o single responsibility principle em Python?</h2>

<p>Vejamos o código extraído do <a href="https://www.amazon.com.br/Clean-Code-Python-maintainable-efficient/dp/1800560214">Clean Code in Python</a>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SystemMonitor</span><span class="p">:</span>
    <span class="c1"># Responsabilidade 1
</span>    <span class="k">def</span> <span class="nf">load_activity</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>

    <span class="c1"># Responsabilidade 2
</span>    <span class="k">def</span> <span class="nf">identify_events</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>

    <span class="c1"># Responsabilidade 3
</span>    <span class="k">def</span> <span class="nf">stream_events</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>
</code></pre></div></div>

<p>A mesma classe <code class="language-plaintext highlighter-rouge">SystemMonitor</code> é responsável por várias coisas e cada uma dessas coisas pode apresentar
motivos para mudar, considerando seus contextos e fluxo. Exemplo: imagine que precisamos fazer alguma
transformação adicional na hora de fazer stream de eventos; teríamos que adaptar a função <code class="language-plaintext highlighter-rouge">stream_events</code>,
e assim sucessivamente com cada coisa do “universo” de cada responsabilidade que a class contém.</p>

<p>O ideal seria desacoplar essas múltiplas responsabilidades em outras classes:</p>

<div align="center">
<img alt="single responsability" src="../../../assets/images/8/srp.webp" />
</div>

<p>O UML acima pode ser interpretado desse forma em Python:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Event</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">ActivityWatcher</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">SystemMonitor</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">Output</span><span class="p">:</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">AlertSystem</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">_activity_watcher</span> <span class="o">=</span> <span class="n">ActivityWatcher</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">_system_monitor</span> <span class="o">=</span> <span class="n">SystemMonitor</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">_output_system</span> <span class="o">=</span> <span class="n">Output</span><span class="p">()</span>
    <span class="p">...</span>
</code></pre></div></div>

<h2 id="como-aplicar-o-single-responsibility-principle-em-go"><a name="3"></a>Como aplicar o single responsibility principle em Go?</h2>

<p>Aqui temos um ponto importante: Go não tem classes, mas podemos pensar na aplicação do SRP em Go
em termos de objetos (structs, functions, interfaces ou packages). Utilizando um exemplo do <a href="https://www.amazon.com.br/Hands-Dependency-Injection-Corey-Scott/dp/1789132762">Hands-On Dependency Injection in Go</a>:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Calculator</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span>
<span class="p">}</span>

<span class="c">// Responsabilidade 1</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">Calculate</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
<span class="p">}</span>

<span class="c">// Responsabilidade 2</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">Output</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As funções acima não estão seguindo o SRP, temos mais de uma responsabilidade sendo implementada
nesse struct. Se quisermos adicionar uma forma de printar o output em csv:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Calculator</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span>
<span class="p">}</span>

<span class="c">// Responsabilidade 1</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">Calculate</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
<span class="p">}</span>

<span class="c">// Responsabilidade 2</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">Output</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>

<span class="c">// Adicionando mais responsabilidade</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="n">Calculator</span><span class="p">)</span> <span class="n">OutputCSV</span><span class="p">(</span><span class="n">writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>

<p>O exemplo abaixo demonstra como desacoplar as várias responsabilidades atreladas ao <code class="language-plaintext highlighter-rouge">Calculator</code>:</p>

<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">// Objeto para calcular</span>
<span class="k">type</span> <span class="n">Calculator</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span>
<span class="p">}</span>

<span class="c">// Calcular é uma responsabilidade</span>
<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">Calculate</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
<span class="p">}</span>

<span class="k">func</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">Calculator</span><span class="p">)</span> <span class="n">getData</span><span class="p">()</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span> <span class="p">{</span>
<span class="p">}</span>

<span class="c">// Comportamento</span>
<span class="k">type</span> <span class="n">Printer</span> <span class="k">interface</span> <span class="p">{</span>
    <span class="n">Output</span><span class="p">(</span><span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// Objeto para printar</span>
<span class="k">type</span> <span class="n">DefaultPrinter</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="n">Writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span>
<span class="p">}</span>

<span class="c">// Printar é outra responsabilidade, implementando o comportamento Output</span>
<span class="k">func</span> <span class="p">(</span><span class="n">d</span> <span class="o">*</span><span class="n">DefaultPrinter</span><span class="p">)</span> <span class="n">Output</span><span class="p">(</span><span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>

<span class="c">// Objeto para printar em CSV</span>
<span class="k">type</span> <span class="n">CSVPrinter</span> <span class="k">struct</span> <span class="p">{</span>
  <span class="n">Writer</span> <span class="n">io</span><span class="o">.</span><span class="n">Writer</span>
<span class="p">}</span>

<span class="c">// Outra responsabilidade, que implementa seu próprio comportamento Output</span>
<span class="k">func</span> <span class="p">(</span><span class="n">d</span> <span class="o">*</span><span class="n">CSVPrinter</span><span class="p">)</span> <span class="n">Output</span><span class="p">(</span><span class="n">data</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">float64</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<p>Flash da Jequiti para lembrar os princípios:</p>

<div align="center">
<img alt="solid" src="../../../assets/images/8/solid.webp" />
</div>

<hr />

<p>Fontes:</p>

<p>ANAYA, Mariano. <a href="https://www.amazon.com.br/Clean-Code-Python-maintainable-efficient/dp/1800560214">Clean Code in Python</a>.
Packt, 2021.</p>

<p>SCOTT, Corey. <a href="https://www.amazon.com.br/Hands-Dependency-Injection-Corey-Scott/dp/1789132762">Hands-On Dependency Injection in Go</a>.
Packt, 2018.</p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="solid," /><category term="single" /><category term="responsibility" /><category term="principle" /><summary type="html"><![CDATA[explicando o que é o single responsibility principle do SOLID, com exemplos em Python e em Go]]></summary></entry><entry><title type="html">O que é engenharia de dados?</title><link href="https://nfo94.github.io/2025/01/15/o-que-%C3%A9-engenharia-de-dados.html" rel="alternate" type="text/html" title="O que é engenharia de dados?" /><published>2025-01-15T00:00:00+00:00</published><updated>2025-01-15T00:00:00+00:00</updated><id>https://nfo94.github.io/2025/01/15/o-que-%C3%A9-engenharia-de-dados-</id><content type="html" xml:base="https://nfo94.github.io/2025/01/15/o-que-%C3%A9-engenharia-de-dados.html"><![CDATA[<p>O propósito desse texto é descrever brevemente o que é engenharia de dados e seu ciclo
de vida utilizando o livro <a href="https://www.amazon.com.br/Fundamentos-Engenharia-Dados-Construa-Sistemas/dp/8575228765/ref=sr_1_1?crid=2XWCTM1GCFZIV&amp;dib=eyJ2IjoiMSJ9.RUj0CiiEh8_elypAdWYI92YmVFpvFJPjoiNLwcPl07Q_YCQvHMZtW7OhPOjNDFfYCR-tvmub57o0OU-_sAI53NNNa650UwWf3zmABlpbiXJIFhGWYPC4LbWMIjXy8AN9W8RlLJcuNSb84OZeAfh-YOkl9GVaGYrd6IJr3_hx-esKdbr6T43S6V6Sq4_XfUvtPWXJS_0PQL4k95QTdtgprzQCYIrNri7Kw6YQn8e5JVRLteoLPsc5s37_BRX39_g6BZQSQxsI5MMHG7UcIcfrrRQ0okhiRtdGeQRE4UDmwqD5EB8Yr0av8hcevapvbTRwXFGFeZqQyEx89jiYo90pyFt3oRwJHMiAPZe1HlV65VIEToIAqiUsF8DS341G11lxqQIf2JGOd2tF187eFkJo7gCfR-qiigOQBpeGc_03a7zkHrfW19w3lH7jRijkUOh3.eNOhhfMg0umQ5cp57TuD3xZFDKg-pjGY6mnQUfOTVH8&amp;dib_tag=se&amp;keywords=fundamentos+de+engenharia+de+dados&amp;qid=1735996483&amp;sprefix=fundamentos+de+enge%2Caps%2C189&amp;sr=8-1&amp;ufe=app_do%3Aamzn1.fos.6d798eae-cadf-45de-946a-f477d47705b9">Fundamentos de Engenharia de Dados</a>
do Joe Reis e Matt Housley como base.</p>

<ul>
  <li><a href="#1">O que é engenharia de dados?</a></li>
  <li><a href="#2">O ciclo de vida de engenharia de dados</a></li>
</ul>

<h2 id="o-que-é-engenharia-de-dados"><a name="1"></a>O que é engenharia de dados?</h2>

<p>Engenharia de dados não é exatamente uma coisa nova e já existia de alguma forma em
empresas, mas tomou mais foco e cresceu mais ou menos no mesmo período em que big data e
ciências de dados começaram a aparecer nos holofotes da bolha tech.</p>

<p>De forma resumida, podemos dizer que pessoas engenheiras de dados configuram e operam
a infraestrutura de dados de um empresa, preparando esses dados para analistas de dados,
cientistas de dados, etc. Segundo Reis e Housley:</p>

<blockquote>
  <p><strong>Engenharia de dados é o desenvolvimento, implementação e manutenção de sistemas e
processos que recebem dados brutos e produzem informações consistentes e de alta
qualidade que dão suporte a casos de uso posteriores, como análise e aprendizado de
máquina</strong>. Engenharia de dados é a interseção de segurança, gerenciamento de dados,
DataOps, arquitetura de dados, orquestração e engenharia de software. Um engenheiro
de dados gerencia o ciclo de vida da engenharia de dados, começando com a obtenção de
dados de sistemas de origem e terminando com o fornecimento de dados para casos de
uso, como análise ou aprendizado de máquina</p>
</blockquote>

<p>Ou seja, engenharia de dados foca em receber ou extrair dados crus e trabalhar esses dados
para que possam ser repassados para vários casos de usos. Considerando toda a infrastrutura
que isso abarca, é muito comum que as pessoas profissionais da área tenham um background
em engenharia de software, já que ferramentas como Python, SQL, Java, Scala, bash, entre
outros, são bastante utilizadas aqui.</p>

<h2 id="o-ciclo-de-vida-de-engenharia-de-dados"><a name="2"></a>O ciclo de vida de engenharia de dados</h2>

<p>Há uma imagem no livro <a href="https://www.amazon.com.br/Fundamentos-Engenharia-Dados-Construa-Sistemas/dp/8575228765/ref=sr_1_1?crid=2XWCTM1GCFZIV&amp;dib=eyJ2IjoiMSJ9.RUj0CiiEh8_elypAdWYI92YmVFpvFJPjoiNLwcPl07Q_YCQvHMZtW7OhPOjNDFfYCR-tvmub57o0OU-_sAI53NNNa650UwWf3zmABlpbiXJIFhGWYPC4LbWMIjXy8AN9W8RlLJcuNSb84OZeAfh-YOkl9GVaGYrd6IJr3_hx-esKdbr6T43S6V6Sq4_XfUvtPWXJS_0PQL4k95QTdtgprzQCYIrNri7Kw6YQn8e5JVRLteoLPsc5s37_BRX39_g6BZQSQxsI5MMHG7UcIcfrrRQ0okhiRtdGeQRE4UDmwqD5EB8Yr0av8hcevapvbTRwXFGFeZqQyEx89jiYo90pyFt3oRwJHMiAPZe1HlV65VIEToIAqiUsF8DS341G11lxqQIf2JGOd2tF187eFkJo7gCfR-qiigOQBpeGc_03a7zkHrfW19w3lH7jRijkUOh3.eNOhhfMg0umQ5cp57TuD3xZFDKg-pjGY6mnQUfOTVH8&amp;dib_tag=se&amp;keywords=fundamentos+de+engenharia+de+dados&amp;qid=1735996483&amp;sprefix=fundamentos+de+enge%2Caps%2C189&amp;sr=8-1&amp;ufe=app_do%3Aamzn1.fos.6d798eae-cadf-45de-946a-f477d47705b9">Fundamentos de Engenharia de Dados</a>
que é excelente para visualizar o ciclo de vida de um pipeline de dados:</p>

<div align="center">
<img alt="data engineering lifecycle" src="../../../assets/images/7/data-engineering-lifecycle.webp" />
</div>

<p>Ou seja, uma pessoa engenheira de dados tem algumas responsabilidades técnicas:</p>

<ul>
  <li>Geração de dados</li>
  <li>Armazenamento de dados</li>
  <li>Ingestão de dados</li>
  <li>Transformação de dados</li>
  <li>Servir dados para diferentes casos de uso</li>
</ul>

<p>Os casos de uso, que podem ser vistos como <em>downstream</em> de dados servidos por um pipeline
desses, incluem análise de dados, machine learning, ciência de dados, reverse ETL
(engenharia reversa de ETL), etc.</p>

<hr />

<p>Fontes:</p>

<p>REIS, Joe; HOUSLEY, Matt. <a href="https://www.amazon.com.br/Fundamentos-Engenharia-Dados-Construa-Sistemas/dp/8575228765/ref=sr_1_1?crid=2XWCTM1GCFZIV&amp;dib=eyJ2IjoiMSJ9.RUj0CiiEh8_elypAdWYI92YmVFpvFJPjoiNLwcPl07Q_YCQvHMZtW7OhPOjNDFfYCR-tvmub57o0OU-_sAI53NNNa650UwWf3zmABlpbiXJIFhGWYPC4LbWMIjXy8AN9W8RlLJcuNSb84OZeAfh-YOkl9GVaGYrd6IJr3_hx-esKdbr6T43S6V6Sq4_XfUvtPWXJS_0PQL4k95QTdtgprzQCYIrNri7Kw6YQn8e5JVRLteoLPsc5s37_BRX39_g6BZQSQxsI5MMHG7UcIcfrrRQ0okhiRtdGeQRE4UDmwqD5EB8Yr0av8hcevapvbTRwXFGFeZqQyEx89jiYo90pyFt3oRwJHMiAPZe1HlV65VIEToIAqiUsF8DS341G11lxqQIf2JGOd2tF187eFkJo7gCfR-qiigOQBpeGc_03a7zkHrfW19w3lH7jRijkUOh3.eNOhhfMg0umQ5cp57TuD3xZFDKg-pjGY6mnQUfOTVH8&amp;dib_tag=se&amp;keywords=fundamentos+de+engenharia+de+dados&amp;qid=1735996483&amp;sprefix=fundamentos+de+enge%2Caps%2C189&amp;sr=8-1&amp;ufe=app_do%3Aamzn1.fos.6d798eae-cadf-45de-946a-f477d47705b9">Fundamentos de Engenharia de Dados</a>. O’Reilly, 2022.</p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="engenharia" /><category term="de" /><category term="dados," /><category term="etl," /><category term="banco" /><category term="de" /><category term="dados" /><summary type="html"><![CDATA[descrevendo e explicando o que é engenharia de dados e seu ciclo de vida]]></summary></entry><entry><title type="html">Resumindo características da linguagem Python</title><link href="https://nfo94.github.io/2025/01/08/resumindo-caracter%C3%ADsticas-da-linguagem-python.html" rel="alternate" type="text/html" title="Resumindo características da linguagem Python" /><published>2025-01-08T00:00:00+00:00</published><updated>2025-01-08T00:00:00+00:00</updated><id>https://nfo94.github.io/2025/01/08/resumindo-caracter%C3%ADsticas-da-linguagem-python</id><content type="html" xml:base="https://nfo94.github.io/2025/01/08/resumindo-caracter%C3%ADsticas-da-linguagem-python.html"><![CDATA[<p>Python é uma linguagem de <strong>propósito geral, multiparadigma, de alto nível, de tipagem
dinâmica, fortemente tipada, que roda em diferentes plataformas e é interpretada (com um
passo de compilação)</strong>. Vamos destrinchar esses conceitos utilizando principalmente o
livro “Python in a Nutshell”, documentações da linguagem e as aulas incríveis do <a href="https://www.youtube.com/@Dunossauro">Eduardo
Mendes</a>.</p>

<ul>
  <li><a href="#1">Propósito geral e alto nível</a></li>
  <li><a href="#2">Tipagem dinâmica e forte</a></li>
  <li><a href="#3">Linguagem intepretada com um passo de compilação</a></li>
  <li><a href="#4">Roda em diferentes plataformas</a></li>
</ul>

<h2 id="propósito-geral-e-alto-nível"><a name="1"></a>Propósito geral e alto nível</h2>

<p>Consideramos Python como de <strong>propósito geral</strong> pois suas características são úteis
para diversas áreas de software. Iremos encontrar Python em REST APIs, scripts, machine
learning, análises estatísticas, web scraping, etc. Python já era bastante utilizada
na área de inteligência artificial e, com o <em>boom</em> dos LLMs, me parece que muitas áreas
tornamram a linguagem como o padrão de uso. Se procurarmos por vagas de machine learning
engineer, data engineer e por aí vai é muito comum encontrar o Python como requisito.</p>

<p>A consideramos como de <strong>alto nível</strong> por possuir um <strong>alto nível de abstração</strong>, se
afastando bastante da linguagem de máquina que um computador de fato entende. Além disso,
a linguagem é bem “parecida” com uma leitura em inglês, o que é muito atrativo. Outros
exemplos de linguagens de alto nível são Java, JavaScript, entre outras.</p>

<h2 id="tipagem-dinâmica-e-forte"><a name="2"></a>Tipagem dinâmica e forte</h2>

<p>Acredito que esse tópico gere uma certa dúvida. Eu particularmente precisei revisitar
esses conceitos diversas vezes até entender. O Python tem <strong>tipagem dinâmica</strong>, ou seja,
não te obriga a declarar o tipo de uma variável, você pode declarar um <code class="language-plaintext highlighter-rouge">a = "texto"</code> e o
interpretador, por debaixo dos panos, vai inferir que a variável é do tipo <code class="language-plaintext highlighter-rouge">string</code>. Ao
mesmo tempo, é <strong>fortemente tipada</strong>, pois o interpretador mantém controle dos tipos de
variáveis que estão sendo declaradas no programa, coisa que não acontece numa linguagem
fracamente tipada como o JavaScript, por exemplo. No JavaScript você pode fazer <code class="language-plaintext highlighter-rouge">'x' + 3</code>
resultar em <code class="language-plaintext highlighter-rouge">'x3'</code> e não dará erro; se você tentar fazer isso em Python verá:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TypeError: can only concatenate str <span class="o">(</span>not <span class="s2">"int"</span><span class="o">)</span> to str
</code></pre></div></div>

<p>Sobre ser dinamicamente tipada e fortemente tipada ao mesmo tempo, vejamos esse excerto
do <a href="https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language">Wiki do Python</a>:</p>

<blockquote>
  <p>Python é fortemente tipado, pois o interpretador mantém o controle de todos os tipos
de variáveis. Ele também é muito dinâmico, pois raramente usa o que sabe para limitar o
uso de variáveis. Em Python, é responsabilidade do programa usar funções internas como
isinstance() e issubclass() para testar tipos de variáveis ​​e uso correto. Python tenta
ficar fora do seu caminho enquanto fornece tudo o que você precisa para implementar a
verificação de tipo forte.</p>
</blockquote>

<p>Falando em <em>“Python tenta ficar fora do seu caminho enquanto fornece tudo o que você
precisa para implementar a verificação de tipo forte”</em>, pegamos o gancho para falar de
“type hints” ou “<strong>type annotations</strong>”. <em>Type annotations</em> são uma feature mais recente
(<a href="https://peps.python.org/pep-0484/">PEP 484 de de 2014</a>) do Python que nos permite
“anotar” o tipo de dado que estamos lidando no código. Do livro “Python in a Nutshell”:</p>

<blockquote>
  <p>Anotar seu código Python com informações de tipo é uma etapa opcional que pode ser
muito útil durante o desenvolvimento e a manutenção de um projeto grande ou de uma
biblioteca. Verificadores de tipo estático e ferramentas lint ajudam a identificar e
localizar incompatibilidades de tipo de dados em argumentos de função e valores de retorno.
IDEs podem usar essas anotações de tipo (também chamadas de dicas de tipo) para melhorar
o preenchimento automático e fornecer documentação pop-up. Pacotes e frameworks de
terceiros podem usar anotações de tipo para personalizar o comportamento do tempo de
execução ou para gerar automaticamente código com base em anotações de tipo para métodos
e variáveis.</p>
</blockquote>

<p>É daí que temos libs como <a href="https://github.com/python/mypy"><code class="language-plaintext highlighter-rouge">mypy</code></a> e <a href="https://github.com/pydantic/pydantic"><code class="language-plaintext highlighter-rouge">Pydantic</code></a>
para checar e validar tipos.</p>

<h2 id="linguagem-intepretada-com-um-passo-de-compilação"><a name="3"></a>Linguagem intepretada com um passo de compilação</h2>

<p>O Python é considerado <strong>interpretado</strong> com um passo de <strong>compilação</strong>: uma linguagem
ser interpretada significa que ela não é executada diretamente pela máquina, e sim é
interpretada e executada por outro programa. Aqui temos um <em>catch</em> que confunde bastante,
pois na real o CPython, que é o interpretador referência da linguagem, é um compilador de
bytecode e também interpretador: ele compila o código Python e, com o resultado dessa
compilação (que chamamos de bytecode ou <em>intermediary language</em>), roda esse resultado
diretamente em uma máquina virtual. Recomendo fortemente a <a href="https://www.youtube.com/watch?v=pxfZTAJDipY&amp;t=946s">aula do Eduardo Mendes</a>
sobre isso:</p>

<div align="center">
<img alt="cpython" src="../../../assets/images/6/cpython.webp" />
</div>

<p>Aí você pode ser perguntar:</p>

<blockquote>
  <p><em>Mas qual a diferença entre esse processo e um processo de compilação de um linguagem
como Java?</em></p>
</blockquote>

<p>Para ficar mais claro, veja que em uma linguagem 100% compilada a linguagem intermediária
é transformada para linguagem de máquina, para então ser rodada pelo computador de fato.
Para ilustrar um pouco melhor esse processo acompanhe esse slide da <a href="https://www.youtube.com/watch?v=pxfZTAJDipY&amp;t=789s">aula do Eduardo Mendes</a>:</p>

<div align="center">
<img alt="compilação" src="../../../assets/images/6/compilação.webp" />
</div>

<h2 id="roda-em-diferentes-plataformas"><a name="4"></a>Roda em diferentes plataformas</h2>

<p>Se você viu essa afirmação em algum lugar, perceba que isso é dito pois você pode escrever
e rodar um programa Python em qualquer computador moderno que tenha Python instalado.
“Instalar” significa ter o interpretador Python para rodar a linguagem. Em computadores
com sistema operacional baseado em Unix, como Linux e MacOS, é comum que o interpretador
Python já esteja instalado em alguma versão. No caso de Windows, até onde sei, você
precisa ir lá no site no Python, baixar e instalar o interpretador.</p>

<hr />

<p>Fontes:</p>

<p><a href="https://www.amazon.com.br/Python-Nutshell-English-Alex-Martelli-ebook/dp/B0BRYRD295/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.1GrWfyxGQAtCbzVANdvWpIhsGUkbRmGr3ML2fa9FpnVxX7qlzYtkK_-90G8PkjJjgguYnjmO95dfRwRYpxq_KjO-ymBjxJUMcAg0yT84C9fRPz6a3nBhAM8lSKKrFvF3hGlrKUcoMemKQysYgZfgry8iAMCF6td3Hxgn2ewAhQvhBTq7b2NgOPNn467iWo-9eJLV3dAY2oXJNBL2Z2V7IeuYejkKm7JPGhoPmIqu3keAuUEQVk088S7ZYYoK5WLR9GjCa2Do0sSEha3oWfbMz-FHIk0a9t-LOEqeVc2r-Tg.w512AtUskmia2OZ6AWaNIM0RwlmCrPBH-66aAFwmhEI&amp;qid=1732842474&amp;sr=8-1">Python in a Nutshell</a></p>

<p><a href="https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language">Why is Python a dynamic language and also a strongly typed language</a></p>

<p><a href="https://stackoverflow.com/questions/3265357/compiled-vs-interpreted-languages">StackOverflow Compiled vs. Interpreted Languages</a></p>

<p><a href="https://www.youtube.com/watch?v=pxfZTAJDipY">Como o interpretador do Python funciona? Live de Python #218</a></p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="python" /><summary type="html"><![CDATA[resumo das características da linguagem Python]]></summary></entry><entry><title type="html">Leituras técnicas de 2024</title><link href="https://nfo94.github.io/2024/12/31/leituras-t%C3%A9cnicas-de-2024.html" rel="alternate" type="text/html" title="Leituras técnicas de 2024" /><published>2024-12-31T00:00:00+00:00</published><updated>2024-12-31T00:00:00+00:00</updated><id>https://nfo94.github.io/2024/12/31/leituras-t%C3%A9cnicas-de-2024</id><content type="html" xml:base="https://nfo94.github.io/2024/12/31/leituras-t%C3%A9cnicas-de-2024.html"><![CDATA[<p>Faz algum tempo que comecei a perceber minha falta de paciência para prestar atenção em
conteúdos escritos, coisa que não acontecia antes. Acredito que fiquei mal acostumada a
buscar informações em vídeo e, quanto mais avanço na área, mais percebo que conteúdos
escritos às vezes são a única fonte de informação para determinados assuntos. Com isso,
no início de 2024, me propus a ler mais livros, para:</p>

<ul>
  <li>Fortalecer o foco e forçar a atenção em conteúdos mais difíceis de se consumir;</li>
  <li>Exercitar o “não” a conteúdos de rede social/de conteúdo (exemplo: antes de ir dormir,
ler, ao invés de ficar olhando o celular);</li>
  <li>Exercitar meu vocabulário (inglês e português);</li>
  <li>Ter contato inicial com temas específicos;</li>
  <li>Exercitar a reflexão.</li>
</ul>

<p>Resolvi unir o últil ao agradável e separar alguns livros técnicos para ler durante o ano,
por completo. Essas foram as leituras que fiz em 2024:</p>

<ul>
  <li><a href="#1">Designing Data-Intensive Applications</a></li>
  <li><a href="#2">Artificial Intelligence Basics</a></li>
  <li><a href="#3">Database Internals</a></li>
  <li><a href="#4">Criando Microsserviços</a></li>
</ul>

<p>E por fim separei algumas <a href="#5">menções honrosas</a>.</p>

<h2 id="designing-data-intensive-applications"><a name="1"></a>Designing Data-Intensive Applications</h2>

<p>De longe o melhor que eu li no ano. É o tipo de livro para ser relido pelo menos umas 3
vezes, e isso é o que pretendo fazer. Foi graças a esse livro que consegui entender uma
apresentação sobre um tema super complexo envolvendo escalabilidade em escrita de dados,
de um time no trabalho. É também uma excelente forma de revisão sobre sistemas distribuídos,
assunto que geralmente é tratado na faculdade.</p>

<p>O autor, Martin Kleppmann, escreve muito bem e a leitura não é de um <em>feeling</em> pesado
acadêmico, é algo simples de ler com vários exemplos de tecnologias usadas hoje em dia.
Não é a toa que esse livro já vendeu muito e tem trocentos bons reviews em várias
plataformas. Recomendo a leitura.</p>

<p>Obs.: tem uma nova edição desse livro no forno prevista para dezembro de 2025 e espero
que essa edicão seja traduzida para o português.</p>

<ul>
  <li><a href="https://www.amazon.com.br/Designing-Data-Intensive-Applications-Reliable-Maintainable-ebook/dp/B06XPJML5D/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.uKKyaNHuzp5D7DchHIgwHtXJv8tk_RD31Eetcm-YM317qEFGsD6Tq8EXynYuUFgG2U60SDWNVKMMtCkNGeHhauCgDO8KiyDBJAzyg0MdQ6aGORrnUGA7gle55HimQdB3T8YzwQb40LbedZQP54uTEbspTsMH-UnTcrtVoQbhIdU5cvoyTQIrTj_zWpH4xHMdcxEbgbW1ubwle-L7DjEjcBOey9AOAMbyEvm3zcNgMl-fO3MpzZoiiTGurcOwM1KA0BuW4e3Ri9V1IfqQS9dLGi4jEevLKujETxx4WK0vTk9Vpz5zKvZjAyhDw_cOLdgOg2vAvOtaApmfh2CnoEDBFD_mv7zo8XnR9wzdBV7lX8MYBrDPnboDwCIYyaWtFHkR3eg0fjDAPQID-vLAwe9CsMm4ZFzEihannjz_9ujWM5cjzkpuGYBEYSLaLWQNOEPh.imRmUHBJGkV1Btbrug3EDo_o23CRxdYv9YwPmwwS--A&amp;qid=1735228860&amp;sr=8-1"><strong>Link para o livro Designing Data-Intensive Applications</strong></a></li>
</ul>

<div align="center">
<img width="55%" alt="designin data-intensive applications" src="../../../assets/images/5/ddia.webp" />
</div>

<h2 id="artificial-intelligence-basics"><a name="2"></a>Artificial Intelligence Basics</h2>

<p>Fui de uma leitura bastante técnica e primorosa para um livro OK. Esse livro é bom para
deixar a gente refletindo e ter algumas noções básicas sobre o assunto, mas não sei se é
uma leitura útil para todas as pessoas da área tech. Para alguém de fora da área pode ser
mais interessante. No meu caso foi últil para refletir sobre o assunto, apenas como
leitura superficial mesmo, mas achei o último capítulo meio abaixo do resto. No geral,
pessoalmente valeu a pena, por ser uma leitura leve e com alguns conceitos introdutórios.</p>

<p>Vale frisar que esse livro foi publicado em 2019, antes do hype de generative AI, então
o autor, Tom Taulli, não estava apenas surfando a onda.</p>

<p>Se você é da área tech e quer ler algo profundo sobre AI, vá ler <a href="https://www.amazon.com.br/Artificial-Intelligence-Modern-Approach-English-ebook/dp/B092QVWSNX/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.p6JTNZQOtrZx-r90u2ah_vAjmfHiZ7Ncd2HnQlawuao_QUC6esfn_bjTAxGihdxFrlwwSfT4w-arxRxtxEHbmyfnUybF39eu_zZ-qd1q5pWtHpPp-_4eqMOiY1bMVsebhKEyrR8zquobm6gq33-Kbt7CBbM-dFjAJ8OgTc3Ha3Gg7CkOOXBCkkP-4bkDMrLCSI-EbWfCN8NpGbRrpkgYfBA_Czygi8-IZOZxuipU-KBoR8zxeJ9muY8c4zsw13dYXaWIeiHByOk2FM9pm7x17f8d-os9uU1LI9nri549-bbfPICKVgTsF3yudjCyNO-GIglRnlrNkfkc4G1oRt-gxd1TGDdZdUvd5O9CXDlwwrbGavY-lFHoP_6IA5A2zZhGdhRrFPwbUHzL2TbessByuumh4MZzbP3-iOZV7Umly2yPfKFWJkYXqIlQunO4zGAJ.ev32P58-2YIzcDv8CDAMDh4-EXNW90ztOiMiXcoxkPo&amp;qid=1735229802&amp;sr=8-2">Norvig e Russell</a>. Se quer colocar a
mão na massa com algo atual, estou vendo bons reviews sobre <a href="https://www.amazon.com.br/Build-Large-Language-Model-Scratch/dp/1633437167/ref=tmm_pap_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.f_1HBi0zdrW6-jWiZT7RBHljTbR18kiiPVoB6pRvXlbJ8xNArtegOgTY80rMoraAm5jtsYcbvKBNWRzWkzDg4HZN5AgjTz5MIrIQWu_UOlnIKgXI4mBpsQ31wpgohh-ZD7i4jkqc6oXjhcjEmg8ImuRFFnutFXU6Bu0lpuXoE2ihGF642EQUx9czikkzViRAfrtWJY9QPCUMeXlzDJSVzkSZB5wLp7iXiFfUF5Q6GXuntzYElWgeQC295z71BUf_m6TOO2n3pUxfOfptJydpl-HTRzY5k0rQ38eyf5ot7F4ITaE6NSH7SxNAJ8qRWZkoE0CqrZc-axbbYZnPZX9ap_UE-twprAZqEmwJrjoz1ddKwz_nZNyOVej8s65TGEMWrgnmPzBX3aL_kwCai20vtr1eGJ_XGDz8BQZ5l39fdbrtzFoUqMCjeiQUZ6i0Mxwi._On-gcHhocJ7kyszKXq1VlWT9OpQcuVDKQ4eLikMJRQ&amp;qid=1735230107&amp;sr=8-1">Build a Large Language Model (from Scratch)</a> do Sebastian Raschka.</p>

<ul>
  <li><a href="https://www.amazon.com.br/Artificial-Intelligence-Basics-Non-Technical-Introduction-ebook/dp/B07VY31R29/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.jt4CqVTrLNenFCBEI6nCEdIJw-P_AqzN8WZDreOP2ipZYiDjG2ds9s_nPg-P47vstmoVP3NrMiG15aBX2P7GEXSjYjxNsi21buM50tGwWBulGMJQJWETWuO0YYMe9M2XzTMJECwvfLRCRRySi9M2yN5ZSjgjG7709n4Dmt7ovac8DN_BLgTAm1M-t9kl4VxJDQ0xwUWYpOAi5gynZhis2iSCqWWvzZ4v_0mBZgXmAhgBVFpRFOlK5gV-nT8d-pO3uzn3sF7hwCk_9J2edLhDDCdFwZ8rO8jmHV6BpWO_j-zGvEFkV_jo7Kmhc5ig4jbasXKQNjecYmcLJ5aIeBE650zbKgeClOf_5deanxNQ5q4OC9_vo1lY0CeMuUALGZ9BSEZIVAuk-ipHjXoklOl1ApVlc5C8ZaZpYCxbQ3EIEASqMPWsXfNW-O2f4DpxmIbk.1MlPVNtrWiX-rMsupMA5N6GxeCRNSOVR3GArVbhKX14&amp;qid=1735229354&amp;sr=8-1"><strong>Link para o livro Artificial Intelligence Basics</strong></a></li>
</ul>

<div align="center">
<img width="58%" alt="artificial intelligence basics" src="../../../assets/images/5/aib.webp" />
</div>

<h2 id="database-internals"><a name="3"></a>Database Internals</h2>

<p>É um livro bastante enxuto para os conceitos que trata. Em outras palavras, leitura
extremamente difícil para mim, pois me faltavam vários conhecimentos prévios para entender
o livro. Exemplo: funcionamento da estrutura de dados b-tree. O livro é pequeno e demorei
horrores para terminar, pois estava voltando alguns parágrafos, pesquisando artigos na
internet e olhando vídeos no YouTube toda hora para consolidar o entendimento. Felizmente
isso me fez encontrar canais bem legais no YouTube como o <a href="https://www.youtube.com/@SpanningTree">Spanning Tree</a>,
com uma <a href="https://www.youtube.com/watch?v=K1a2Bk8NrYQ">explicação visual bem legal sobre b-trees</a>.</p>

<p>Recomendo para pessoas curiosas, quem trabalha na área de dados, banco de dados, etc. Pode
ser uma leitura útil e interessante, mas vai depender bastante da pessoa. No meu caso posso
dizer que valeu a pena, mas definitivamente não foi uma leitura que posso considerar
“agradável”, já que fiquei empacando.</p>

<ul>
  <li><a href="https://www.amazon.com.br/Database-Internals-Distributed-Systems-English-ebook/dp/B07XW76VHZ/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.pVEOjduOXDM_zskjXBld1F3o9TiB-7TOz4x9sLerf5grnu7lgPObDlyGqkY8N34_afgJlFRYMApte6ej-isrEB6qHh_nAcW0AS6E1e6aUEgwxNkbHqkMIO0mzQhti4TKQdt--mennr4o1Q5Bncqdf0LSODOGAvG7GYyYk7RGZtVN0DZ5RY-IfAoAT92h4SoM6KAXO0i3mWYeOf7uueGZauFRD2WVCf4Su9Lc777IAsTvE1VUlltwu2YjC8Bkeosl_K4CmVbuMII7zIG5_FH11gODGowJaE_lUnK2IzWYp-6-j7wzLV_O6Y_aDNVgKBWe6eROq0HArVdSkRvz_eALQuaIyRxJ6oHN2h9q05m3yMY2HL-RqegcPsr-QqFg3L1nJMu_pzStmCOy9s1boGPsQlfTOUawwrVpvV_NVkaghjilev7H83KNMCpmVwldOwmX.oxIzW6k7ym1iBmbF_JqQxkdvavvTIVU5u83A2DOBRAI&amp;qid=1735230384&amp;sr=8-1"><strong>Link para o livro Database Internals</strong></a></li>
</ul>

<div align="center">
<img width="55%" alt="database internals" src="../../../assets/images/5/di.webp" />
</div>

<h2 id="criando-microsserviços"><a name="4"></a>Criando Microsserviços</h2>

<p>Livro de referência completa para microsserviços e creio que o livro por si só já tenha
esse <em>status</em>, a julgar pelos reviews e pelas vezes que já vi sendo citado. A leitura foi
bem fácil e fluida, não só pela escrita, mas pelo fato da maioria dos temas e tecnologias
já fazerem parte do meu dia a dia, ou pelo menos já ouvi falar e está próximo de mim. Li
a versão em português e notei alguns erros, além da sensação esquisita de ver alguns termos
traduzidos que eu só vejo em inglês no dia a dia, mas não foi nada que atrapalhasse a
leitura.</p>

<p>Recomendo a leitura.</p>

<ul>
  <li><a href="https://www.amazon.com.br/Criando-Microsservi%C3%A7os-Projetando-Componentes-Especializados/dp/6586057884/ref=tmm_pap_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.dvx4HFxiyI6I07qs7oxjtEYEFK633haephUjCZ4vxYi09x0Dzw5qihvccH3JoSCKpQpIknHQAz36glIWaeJtEoxcFKx6iXgLL0DDX-7a3BM-vz1pqNzK8yc5KmMzAZKHs7PB9QExtMxiWxnMNPZoOglcV4YCfNhsCeV5jM7C8nJxaeoRoIcLUSgdmO11kR4hwEiw1C_IBnbHlyMMEd-ckk8GloqRDzm2bz2ktxIJUquLNH73o6zuXzt4KkHCKip7YGgFk5VtiiwspfKa11HErOnW6yy5koQJMO03pa9Pzyzmy0qqmHehpfg7la-MI53t9pzoq5ht57MEK1yvAJAH_OGZUQB5G5f-eVyJIag9IVaxxA8tM9O_O6pWGZWbKKrX.93vvDhRHRpM26LH-BzkSsj78tQ0-P5pJxHzVSGOOzSA&amp;qid=1735739451&amp;sr=8-1"><strong>Link para o livro Construindo Microsserviços</strong></a></li>
</ul>

<div align="center">
<img width="55%" alt="building microservices" src="../../../assets/images/5/bm.webp" />
</div>

<h3 id="menções-honrosas"><a name="5"></a>Menções honrosas</h3>

<p>Precisei ler alguns capítulos de uns livros para a pós-gradução, então não li estes por
completo:</p>

<ul>
  <li><a href="https://www.amazon.com.br/Cassandra-Definitive-Guide-Revised-Distributed/dp/1492097144/ref=sr_1_2?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=1G9IQ2FQ24KAB&amp;dib=eyJ2IjoiMSJ9.jBo07BQNSuzzYY4HqTN1iz3IAj_vf-b0vv8ucp0WTy8k7JPxLg3KzDwZszfFjb5LYLDYr-i95mq3HXWTFgCffLfgcWZ2X3_yyolAZ5OFh9mkzOM71PqstyDjgiuBTJ6zi0tqF-nAJu6j-_pkUaDdI8n1J3ZMpOFHF5lWyiiCLXJYj78Cn3-XWsyV5_GJOf8Kw-ccxJay0BQz3vH5DDg2iCq-KH_WMbm4ABfJPbiNHB1QTrk_HbCgUlJCYVe5QwqxvZdmYR5brhI8MgxVE3VELwx9S6PVKaaPQKD6m2Qsw50nYyYnNRgBPC9WDGGaWcsQc_BUDd46z3t7PSV2zAQhvDopKrBlS4GFiLEeiYBpCuU-2elvKbPXnrWxTjAAJkar0uPmCeKQka6D9QN9lsU6FLoJ2CAgJoKJ-lZLBW7ctoPTZcIwJfSlS6ijrjQFsS5H.Y4hRmGEepsu669XnnZr9NLpoFO-As-JwCkNg3AejWP4&amp;dib_tag=se&amp;keywords=apache+cassandra&amp;qid=1735224364&amp;sprefix=apachecassandra+%2Caps%2C183&amp;sr=8-2&amp;ufe=app_do%3Aamzn1.fos.e05b01e0-91a7-477e-a514-15a32325a6d6"><strong>Cassandra The Definitive Guide</strong></a>: livro excelente e completo sobre o Apache
Cassandra. Achei bem complexo entender o Cassandra e esse livro ajudou muito;</li>
  <li><a href="https://www.amazon.com.br/MongoDB-Definitive-Powerful-Scalable-Storage-ebook/dp/B082J7DMBX/ref=sr_1_2?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=3U8GSO108UJ68&amp;dib=eyJ2IjoiMSJ9.WJpjFIYDai0U8v6hRylC75yuoja2kamkMexqW3-bieQGHGBuX5J7exrfFoKWvuZQ_SrLN8dJBOgsdamuUreWjb5ZTHoLM7nXLqWi-sf0z8ck_SVz5r1ccrHU3IJ6rrTW3JHBY-KpOmYPD0C9MAuyVsgbQVlaEfQsArvNSPb98gEYK_WWMfd1wNrTLImu8cKmyCIS2Wez0cI--4Gcda9q6uZcv8udy_W5jmSLFpBHy6Ib6OGrT-gtOgDzYq4XDhhMg7RfUcO1-dkdf5qVEbkygcxGgFY7AZVMZK4srDXVR4I9NC9BQ4rSJJO1Z9HzEXxt176qckpfQuz--eZjK28aYU41qmzKq7_YnJl5EjzficGyzTf8rtnfMTn0FayWcSqGNQQkIUNYv-n93XMtONNSUSg9AouHHWu60bKLFX909-XawEQmtVuFje63hn2O3KKt.ZBo-s-Tk00KMPHHkojkbAQm24h4XRVq_rt0xlD5NdoI&amp;dib_tag=se&amp;keywords=mongodb&amp;qid=1735224395&amp;sprefix=mongod%2Caps%2C174&amp;sr=8-2"><strong>MongoDB The Definitive Guide</strong></a>:
livro completinho sobre MongoDB, me ajudou não só com a parte teórica, mas também tirei
várias dúvidas quando estava fazendo o projeto prático.</li>
</ul>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="livros," /><category term="tech,designing" /><category term="data-intensive" /><category term="applications," /><category term="artificial" /><category term="intelligence" /><category term="basics," /><category term="database" /><category term="internals," /><category term="building" /><category term="microservices" /><summary type="html"><![CDATA[listando minhas leituras técnicas de 2024]]></summary></entry><entry><title type="html">Infraestrutura para análise de dados com Jupyter, Cassandra, Pyspark e Docker</title><link href="https://nfo94.github.io/2024/11/27/infraestrutura-para-analise-de-dados-com-jupyter-cassandra-pyspark-docker.html" rel="alternate" type="text/html" title="Infraestrutura para análise de dados com Jupyter, Cassandra, Pyspark e Docker" /><published>2024-11-27T00:00:00+00:00</published><updated>2024-11-27T00:00:00+00:00</updated><id>https://nfo94.github.io/2024/11/27/infraestrutura-para-analise-de-dados-com-jupyter-cassandra-pyspark-docker</id><content type="html" xml:base="https://nfo94.github.io/2024/11/27/infraestrutura-para-analise-de-dados-com-jupyter-cassandra-pyspark-docker.html"><![CDATA[<p>Hoje vou mostrar como configurar um projeto para análise de dados com o Cassandra e o
Jupyter Notebook com Pyspark, usando tudo no Docker. Vamos abordar:</p>

<ul>
  <li><a href="#1">Configurando o Apache Cassandra com Docker</a></li>
  <li><a href="#2">O que é o Spark?</a></li>
  <li><a href="#3">Configurando o Jupyter com Pyspark no Docker</a></li>
  <li><a href="#4">Iniciando um sessão Spark conectada no Cassandra</a></li>
</ul>

<p>Antes de começar, essa é a estrutura de pastas do projetinho:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cassandra-jupyter-spark-python
├── .gitignore
├── Makefile
├── README.md
├── data
│   └── csv-here.md
├── docker-compose.yml
├── jupyter
│   └── Untitled.ipynb
└── pyproject.toml
</code></pre></div></div>

<p>Você pode encontrar um projeto similiar a esse, completo, com análise de dados (porcamente
feita por mim) no <a href="https://github.com/nfo94/infraestrutura-cassandra-pd">GitHub</a>.</p>

<h2 id="configurando-o-apache-cassandra-com-docker"><a name="1"></a>Configurando o Apache Cassandra com Docker</h2>

<p>O Cassandra é um <strong>banco de dados NoSQL decentralizado, com escalabilidade elástica,
altamente disponível, tolerante a falhas e orientado a linhas particionadas</strong>; escrevi
um <a href="https://nfo94.github.io/2024/10/27/o-que-e-o-apache-cassandra-e-quando-usar.html">texto sobre o Cassandra aqui</a>
e você pode verificar a <a href="https://cassandra.apache.org/doc/latest/">documentação do Cassandra aqui</a>.</p>

<p>Para subir o Cassandra com Docker podemos fazer o seguinte:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">services</span><span class="pi">:</span>
  <span class="na">cassandra1</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">cassandra:4.0.14</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">cassandra1</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">cassandra_network</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">CASSANDRA_CLUSTER_NAME=cassandra_cluster</span>
      <span class="pi">-</span> <span class="s">CASSANDRA_SEEDS=cassandra1</span>
      <span class="pi">-</span> <span class="s">CASSANDRA_DC=datacenter1</span>
      <span class="pi">-</span> <span class="s">CASSANDRA_RACK=rack1</span>
      <span class="pi">-</span> <span class="s">CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./data:/data</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">9042:9042"</span>
</code></pre></div></div>

<p>No código acima estamos criando um node do Cassandra 4.0.14 (versão escolhida para evitar
problemas de compatibilidade nesse projeto) numa rede Docker chamada <code class="language-plaintext highlighter-rouge">cassandra_network</code>.
Explicando as variáveis de ambiente no <code class="language-plaintext highlighter-rouge">environment</code>:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">CASSANDRA_CLUSTER_NAME</code>: define o nome do cluster onde um ou mais nodes do Cassandra
irão rodar. Cluster se refere a mais de uma máquina, geralmente para se referir a um
sistema distribuído. No “docker-compose” do projeto chamamos de “cassandra_cluster”;</li>
  <li><code class="language-plaintext highlighter-rouge">CASSANDRA_SEEDS</code>: indica os serviços (ou IPs) usados pelo gossip do Cassandra, para
adicionar novos nodes ao cluster. O gossip é um protocolo utilizado para manter
informações sobre o status dos nodes no cluster, para dar suporte a descentralização e
tolerância a particionamento;</li>
  <li><code class="language-plaintext highlighter-rouge">CASSANDRA_DC</code>: define o data center do node, que é um agrupamento lógico de racks. Não
é necessário para rodar essa infraestrutura localmente em um notebook, como é o caso
atual, mas seria utilizado caso estivéssemos utilizando o Cassandra com o uso adequado
a que se propõe;</li>
  <li><code class="language-plaintext highlighter-rouge">CASSANDRA_RACK</code>: define o rack do node, que é um agrupamento lógico de nodes.
Novamente, não é necessário para a situação atual, mas seria utilizado em um caso real;</li>
  <li><code class="language-plaintext highlighter-rouge">CASSANDRA_ENDPOINT_SNITCH</code>: define a implementação de snitch que esse node irá utilizar.
O snitch provê informações sobre a topologia da rede onde o Cassandra está para
redirecionar requisições de forma mais eficiente. Nesse caso aqui configuramos como
“GossipingPropertyFileSnitch”, geralmente usado em produção, para considerar as
informações de rack e datacenter.</li>
</ul>

<p>O volume <code class="language-plaintext highlighter-rouge">./data:/data</code> serve para que você coloque, por exemplo, arquivos <code class="language-plaintext highlighter-rouge">.csv</code> parte
da sua análise de dados. No meu caso, <a href="https://github.com/nfo94/infraestrutura-cassandra-pd">criei um projeto para a pós-graduação</a>,
onde usei o comando <code class="language-plaintext highlighter-rouge">COPY</code> para repassar os dados tratados do <code class="language-plaintext highlighter-rouge">.csv</code> para o Cassandra.</p>

<p>Agora, criando um segundo node Cassandra:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">cassandra2</span><span class="pi">:</span>
  <span class="na">image</span><span class="pi">:</span> <span class="s">cassandra:4.0.14</span>
  <span class="na">container_name</span><span class="pi">:</span> <span class="s">cassandra2</span>
  <span class="na">networks</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">cassandra_network</span>
  <span class="na">environment</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">CASSANDRA_CLUSTER_NAME=cassandra_cluster</span>
    <span class="pi">-</span> <span class="s">CASSANDRA_SEEDS=cassandra1</span>
    <span class="pi">-</span> <span class="s">CASSANDRA_DC=datacenter1</span>
    <span class="pi">-</span> <span class="s">CASSANDRA_RACK=rack1</span>
    <span class="pi">-</span> <span class="s">CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch</span>
  <span class="na">volumes</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">./data:/data</span>
  <span class="na">ports</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s2">"</span><span class="s">9043:9042"</span>
  <span class="na">depends_on</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">cassandra1</span>
</code></pre></div></div>

<p>Você pode usar somente um node, já que está rodando em seu computador, mas vale lembrar
que um node só perde o propósito de uso do Cassandra. Esse banco é feito para ter diversos
nodes no cluster.</p>

<p>Veja que esse segundo node aponta os seeds para o outro node. Isso é para que o <code class="language-plaintext highlighter-rouge">cassandra2</code>
se conecte com o <code class="language-plaintext highlighter-rouge">cassandra1</code>, para descrobrir a topologia do cluster e se unir a esse
cluster.</p>

<h2 id="o-que-é-o-spark"><a name="2"></a>O que é o Spark?</h2>

<p>O <a href="https://spark.apache.org/">Apache Spark</a> é uma engine para engenharia e análise de
dados, ciência de dados e machine learning em larga escala, onde é possível rodar para
máquinas com um único nó ou cluster. Podemos usar Python, SQL, Scala, Java e R para
interagir com o Spark, e aqui nesse projeto usaremos Python, com Pyspark.</p>

<p>Usos do Spark, segundo sua documentação:</p>

<ul>
  <li>Batch/streaming: unifica o processamento dos dados em lotes e streaming em tempo real,
usando Python, SQL, Scala, Java ou R</li>
  <li>Análise de SQL: executa consultas ANSI SQL rápidas e distribuídas para painéis e
relatórios ad-hoc</li>
  <li>Ciência de dados em escala: executa Análise Exploratória de Dados (EDA) em dados em
escala de petabytes sem precisar recorrer à redução de amostragem</li>
  <li>Aprendizado de máquina: treine algoritmos de aprendizado de máquina em um laptop e use
o mesmo código para escalar para clusters tolerantes a falhas de milhares de máquinas.</li>
</ul>

<h2 id="configurando-o-jupyter-com-pyspark-no-docker"><a name="3"></a>Configurando o Jupyter com Pyspark no Docker</h2>

<p>O Jupyter é uma tecnologia para computação interativa onde usamos uma linguagem de
programação para, geralmente, fazer análises de dados e experimentos do tipo. Para rodá-lo
no Docker:</p>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1"># Docker Hub Image. Uses spark-3.5.0-bin-hadoop3</span>
  <span class="na">jupyter_pyspark</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">jupyter/pyspark-notebook:latest</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">juptyer_pyspark</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">JUPYTER_ENABLE_LAB</span><span class="pi">:</span> <span class="s2">"</span><span class="s">yes"</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">8888:8888"</span>
    <span class="na">networks</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">cassandra_network</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./jupyter:/home/jovyan</span>
    <span class="na">depends_on</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">cassandra1</span>

<span class="na">networks</span><span class="pi">:</span>
  <span class="na">cassandra_network</span><span class="pi">:</span>
    <span class="na">driver</span><span class="pi">:</span> <span class="s">bridge</span>
</code></pre></div></div>

<p>Essa imagem do Jupyter já vem com o Spark, mas vale apontar que aqui estamos usando a
imagem do <a href="https://hub.docker.com/r/jupyter/pyspark-notebook/">Docker Hub</a>, que não
recebe atualizações e está parada no Spark 3.5.0 e Hadoop 3, e não da <a href="https://quay.io/repository/jupyter/pyspark-notebook">Quay</a>,
que recebe atualizações. Tive muitos problemas tentando manter a compatibilidade entre
as ferramentas, e a imagem do Docker Hub funcionou para o propósito.</p>

<p>O volume, assim como nos cassandras, é para poder salvar os notebooks no host. O
container está na mesma rede que os outros e o <code class="language-plaintext highlighter-rouge">JUPYTER_ENABLE_LAB</code> é para que a gente
não precise fazer login ou usar token, bastará abrir o browser no <code class="language-plaintext highlighter-rouge">http://localhost:8888</code>:</p>

<div align="center">
<img alt="jupyter" src="../../../assets/images/4/jupyter.webp" />
</div>

<h2 id="iniciando-uma-sessão-spark-conectada-no-cassandra"><a name="4"></a>Iniciando uma sessão Spark conectada no Cassandra</h2>

<p>Com o <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> finalizado, podemos rodar os containers:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker compose up <span class="nt">--build</span>
</code></pre></div></div>

<p>No <code class="language-plaintext highlighter-rouge">http://localhost:8888</code>, abrindo um novo arquivo no Jupyter, vamos importar uma sessão
Spark da lib <code class="language-plaintext highlighter-rouge">pyspark</code>:</p>

<pre><code class="language-ipynb">from pyspark.sql import SparkSession
</code></pre>

<p>E configurar a sessão:</p>

<pre><code class="language-ipynb">spark = SparkSession.builder.appName("test").config("spark.jars.packages", "com.datastax.spark:spark-cassandra-connector_2.12:3.5.0").config("spark.cassandra.connection.host", "cassandra1").config("spark.cassandra.connection.port", "9042").getOrCreate()
</code></pre>

<p>Muita atenção aqui nessa parte. O código acima está:</p>

<ul>
  <li>Iniciando uma sessão Spark</li>
  <li>Criando um novo “app” (o projeto em si) chamado “test”</li>
  <li>Configurando o Spark com um pacote jar, utilizando um conector de Spark para Cassandra</li>
  <li>Conectando com o serviço Cassandra chamado <code class="language-plaintext highlighter-rouge">cassandra1</code></li>
  <li>Configurando a porta da conexão para o 9042, que é onde está nosso container</li>
  <li>Criando a conexão</li>
</ul>

<p>Note que estamos usando um conector específico:</p>

<pre><code class="language-txt">spark-cassandra-connector_2.12:3.5.0
</code></pre>

<p>Podemos olhar essas versões <a href="https://mvnrepository.com/artifact/com.datastax.spark/spark-cassandra-connector">no site do Maven</a>,
e aqui nesse ponto foi onde mais topei com erros, especialmente de compatibilidade.</p>

<p>Se tudo der certo no comando anterior, depois rode esse comando para ver a sessão
ativa:</p>

<pre><code class="language-ipynb">spark.active()
</code></pre>

<p>Você verá algo assim:</p>

<div align="center">
<img alt="jupyter-pyspark" src="../../../assets/images/4/jupyter-pyspark.webp" />
</div>

<hr />

<p>Fontes:</p>

<p><a href="https://hub.docker.com/_/cassandra/">Imagem Docker do Cassandra</a></p>

<p><a href="https://hub.docker.com/r/jupyter/pyspark-notebook/">Image Docker do Jupyter com Spark</a></p>

<p><a href="https://spark.apache.org/">Apache Spark</a></p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="apache" /><category term="cassandra," /><category term="nosql," /><category term="docker," /><category term="pyspark," /><category term="jupyter," /><category term="spark" /><summary type="html"><![CDATA[como rodar o apache cassandra e jupyter notebooks com spark localmente com Docker, conectando o jupyter no cassandra]]></summary></entry><entry><title type="html">O que é o Apache Cassandra e quando usar?</title><link href="https://nfo94.github.io/2024/10/27/o-que-e-o-apache-cassandra-e-quando-usar.html" rel="alternate" type="text/html" title="O que é o Apache Cassandra e quando usar?" /><published>2024-10-27T00:00:00+00:00</published><updated>2024-10-27T00:00:00+00:00</updated><id>https://nfo94.github.io/2024/10/27/o-que-e-o-apache-cassandra-e-quando-usar</id><content type="html" xml:base="https://nfo94.github.io/2024/10/27/o-que-e-o-apache-cassandra-e-quando-usar.html"><![CDATA[<p>Hoje falarei um pouco sobre o Apache Cassandra. Usei como base o livro <a href="https://learning.oreilly.com/library/view/cassandra-the-definitive/9781098115159/">Cassandra
The Definitive Guide</a>,
bastante utilizado para entender sobre a tecnologia, e um pouco do já clássico
<a href="https://learning.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/">Designing Data-Intensive Applications</a>. Abordarei os seguintes tópicos:</p>

<ul>
  <li><a href="#1">O que é o Apache Cassandra?</a></li>
  <li><a href="#2">“Row-oriented”: o que isso significa?</a></li>
  <li><a href="#3">Quando utilizar o Cassandra?</a></li>
</ul>

<h2 id="o-que-é-o-apache-cassandra"><a name="1"></a>O que é o Apache Cassandra?</h2>

<p>O Cassandra é um <strong>banco de dados NoSQL de código aberto, decentralizado, com
escalabilidade elástica, altamente disponível, tolerante a falhas e orientado
a linhas particionadas, onde os dados são armazenados em tabelas hash multidimensionais
esparsas</strong>. Vamos discutir esses pontos.</p>

<p>Bancos NoSQL (<em>not only SQL</em>) são bancos que não seguem os padrões de bancos
relacionais, resolvendo problemas um pouco diferentes (em breve farei um texto
sobre isso), sendo mais flexíveis (ou totalmente livres) no quesito de <em>schema</em>
(como os dados são organizados, restrições lógicas como nome de tabelas, campos
e seus tipos, etc), também chamados de <em>schemaless</em> ou de <strong><em>schema on read</em></strong>
(schema reforçado apenas na leitura, e não na escrita como os relacionais). No
caso do Cassandra podemos dizer que atualmente ele possui um <em>schema flexível</em>.</p>

<p>O Cassandra é capaz de rodar em várias máquinas como um sistema só, por isso é
considerado <strong>distribuído</strong> e foi feito pensando nisso. Faz pouco sentido rodar o
Cassandra em um único nó (<em>node</em>).</p>

<blockquote>
  <p>Grande parte de seu design e base de código são projetados especificamente não
apenas para funcionar em muitas máquinas diferentes, mas também para otimizar o
desempenho em vários racks de data center e até mesmo para um único cluster
Cassandra em execução em data centers geograficamente dispersos. (CARPENTER
and HEWITT, 2022)</p>
</blockquote>

<p>O Cassandra também é <strong>descentralizado</strong> porque cada node é idêntico, no sentido de
que nenhum node realiza tarefas especializadas como operações de organização; em
outras palavras, o Cassandra possui uma arquitetura <strong><em>peer-to-peer</em></strong>. Como nenhum
node é especializado podemos dizer que <em>não há um único ponto de falha</em> aqui
(<em>single point of failure</em>).</p>

<p>Ser <strong>elasticamente escalável</strong> significa que o sistema pode continuar servindo para
mais usuários sem degradar a performance, podendo escalar e desescalar perfeitamente,
sem problemas.</p>

<p>A <strong>alta disponibilidade</strong> do Cassandra é devido a sua alta capacidade de atender
requests. Isso está diretamente relacionado com teorema CAP: assumindo uma situação
de <em>partitioning</em>, o Cassandra prioriza <em>availability</em> em detrimento de
<em>consistency</em>. Entretanto, vale a pena esclarecer que a <strong>consistência no Cassandra
é ajustável (<em>tuneable consistency</em>, é uma configuração)</strong>. Em minhas leituras
entendi que atualmente o CAP theorem é como <em>knobs</em>, como se pudéssemos ajustar
um pouco mais uma ou outra configuração. Recomendo ler um pouco mais sobre o
teorema CAP no capítulo 9 do Designing Data Intensive Application.</p>

<div align="center">
<img alt="cap" src="../../../assets/images/3/cap.webp" />
</div>

<h2 id="row-oriented-o-que-isso-significa"><a name="2"></a>“Row-oriented”: o que isso significa?</h2>

<p>Na pesquisa para fazer esse artigo e entender melhor o assunto encontrei informações
discrepantes, o que me levou a crer que há muita confusão aqui e talvez seja bom
evitar algumas fontes da internet. Felizmente estamos seguindo um livro base.
Pela definição de Carpenter e Hewitt:</p>

<blockquote>
  <p>O modelo de dados do Cassandra pode ser descrito como um armazenamento de linha
particionado, no qual os dados são armazenados em tabelas hash multidimensionais
esparsas. <strong>“Esparso” significa que para qualquer linha dada você pode ter uma ou
mais colunas, mas cada linha não precisa ter todas as mesmas colunas que outras
linhas como ela (como em um modelo relacional)</strong>. <strong>“Particionado” significa que
cada linha tem uma chave de partição exclusiva</strong> usada para distribuir as linhas em
vários armazenamentos de dados. (CARPENTER and HEWITT, 2022)</p>
</blockquote>

<p>Ou seja, quando for ter uma “imagem mental” dos dados no Cassandra faz sentido
pensar numa linha de banco relacional, dadas as devidas diferenças: cada linha
pode ter uma ou mais colunas e não precisa ter as mesmas colunas que outra linha,
além de ter uma chave de partição única.</p>

<p>Sobre a confusão de termos que citei anteriormente, você pode ter visto o termo
<em>column oriented</em>, mas o livro base desse texto aborda isso:</p>

<blockquote>
  <p>O Cassandra tem sido frequentemente chamado de banco de dados orientado a colunas
ou colunar, mas isso não é tecnicamente correto. O erro é baseado na confusão
entre termos que soam semelhantes. Um banco de dados orientado a colunas é aquele
em que os dados são armazenados por colunas, ao contrário de bancos de dados
relacionais, que armazenam dados em linhas (daí o termo orientado a linhas).
Bancos de dados orientados a colunas, como Apache HBase ou Apache Kudu, são
projetados para casos de uso analítico. (CARPENTER and HEWITT, 2022)</p>
</blockquote>

<h2 id="quando-utilizar-o-cassandra"><a name="3"></a>Quando utilizar o Cassandra?</h2>

<p>O Cassandra pode ser um bom fit para o seu projeto caso você precise lidar com:</p>

<ul>
  <li><strong>Grandes deployments</strong>: você precisa de muitos e muitos nodes para a sua aplicação,
com a expectativa de escalar muito de forma fácil</li>
  <li><strong>Muita escrita, estatística e análise</strong>: sua aplicação precisa de muita estatística
e muita escrita concorrent, com poucas leituras. Exemplos: pesquisa documentos,
uso de redes sociais, recomendações/avaliações, etc</li>
  <li><strong>Distribuíção geográfica</strong>: o Cassandra tem suporte para distribuição geográfica de
dados <em>built in</em></li>
  <li><strong>Nuvem híbrida e deployment multicloud</strong>: você precisa fazer deploy não só em múltiplos
data centers, mas também em provedores de cloud diferentes. Exemplo: você precisa
da maior disponibilidade possível para um aplicativo <em>mission critical</em> e por
isso utiliza mais de um proveador (se houver problemas com um provedor ainda
haverá o outro)</li>
</ul>

<hr />

<p>Fontes:</p>

<p>CARPENTER, Jeff; HEWITT, Eben. <a href="https://www.amazon.com.br/Cassandra-Definitive-Guide-Revised-English-ebook/dp/B09R2BVFB1/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.6zE2HqOAmHI71tyWkGZRDbLPTVrs-GbLZBOVO4zVkXBUEH3ctz8FfXt05MjA4CO2S8fnSYljlMHa8nClsN4iL3ywFW5EwS_HmtLS10Wg8_sqrX3Wx80y6ObXr73DEps1DHnYOyG7i237Qi5p5jyMD0j_1GpC5Es-d8gdXkVzM0B_HtFHtodOr3S8abb0BZwS6SxF_01I5r9795odj2MzwNWxq70m9qHKp17jfQwuCpusLv36CH-BQKp4_VEiZnTq-69CeJRJ773JYazTAykwViGnLMr0XcDidwWQEtZNlGg.6drW06ZASw4T1RAl41weZ1UXAU2Fi2q-uIMgIlf6_-w&amp;qid=1729416247&amp;sr=8-1">Cassandra: The Difinitive Guide</a>. O’Reilly, 2022.</p>

<p>KLEPPMANN, Martin. <a href="https://www.amazon.com.br/Designing-Data-Intensive-Applications-Reliable-Maintainable-ebook/dp/B06XPJML5D/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.5pF53c-4K5lBHgnp-yQa_RJqJfJfPBVyDbdON_9Uqa6GrLYGUQ2pqldnzPh0j8kRTLevdzrF8EseH1lUO7IbFLNQwsJVPs9JQTpBzuD8D_Iv6wY54Mu9j3KGdUDt9z8rE2w3iqoqah8RAxd-S5FqB-fNN6RC1X005uYmHxBIgX56gpYuK28W08MAeoVkHt1YVKfJBhWxZnCTSEC2DfMVvRMpxnMjqVdU7TIGyzvhgx3zfHGygMbP_O0SR0jxDmR26VB7o5vOT7vPejc8xhzKJd_kcfUdT8LhuxCaRsH3zWg.LcAAww-jCWt1_AFannzv6PZ49ZiksTv1LGD_vywgoXQ&amp;qid=1729446561&amp;sr=8-1">Designing Data-Intensive Applications</a>. O’Reilly, 2017.</p>

<p><a href="https://www.ibm.com/topics/database-schema">What is a database schema? por IBM</a></p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="apache" /><category term="cassandra," /><category term="row-oriented," /><category term="nosql," /><category term="open" /><category term="source," /><category term="resumo" /><summary type="html"><![CDATA[resumo sobre o apache cassandra, o que é e quando usar]]></summary></entry><entry><title type="html">Resumo de conceitos de bancos de dados relacionais</title><link href="https://nfo94.github.io/2024/10/20/resumo-de-bancos-de-dados-relacionais.html" rel="alternate" type="text/html" title="Resumo de conceitos de bancos de dados relacionais" /><published>2024-10-20T00:00:00+00:00</published><updated>2024-10-20T00:00:00+00:00</updated><id>https://nfo94.github.io/2024/10/20/resumo-de-bancos-de-dados-relacionais</id><content type="html" xml:base="https://nfo94.github.io/2024/10/20/resumo-de-bancos-de-dados-relacionais.html"><![CDATA[<p>Nesse texto irei abordar de forma resumida alguns conceitos (não é uma lista
exaustiva!) que envolvem bancos de dados relacionais:</p>

<ul>
  <li><a href="#1">Transações (<em>transactions</em>)</a></li>
  <li><a href="#2">ACID</a></li>
  <li><a href="#3">Two-phase commit (2PC)</a></li>
  <li><a href="#4">Schema</a></li>
  <li><a href="#5">Sharding</a></li>
</ul>

<h2 id="transações-transactions"><a name="1"></a>Transações (<em>transactions</em>)?</h2>

<p>Banco de dados relacionais suportam <strong>transações (<em>transactions</em>)</strong>, que são
como uma <strong>unidade de operação completa</strong> num banco relacional, que executa
primeiro “virtualmente” e <strong>permite que a operação seja desfeita (rollback) se
qualquer modificação tenha dado errado</strong>. No caso de dar tudo certo com todos os
passos da transação, ela pode ser <strong>comitada (<em>commited</em>) com segurança no banco</strong>.
Em outras palavras, uma <strong>transação pode ser compreendida como uma transformação
de estado que possui as propriedades ACID</strong>.</p>

<h2 id="acid"><a name="2"></a>ACID</h2>

<div align="center">
<img alt="acid" src="../../../assets/images/2/acid.webp" />
</div>

<p>ACID é um acrônimo para atômico, consistente, isolado e durável. Você pode encontrar
a expressão <em>ACID compliant</em> para se referir a um banco que dê suporte a essas
propriedades.</p>

<ul>
  <li><strong>Atômico (atomicity)</strong>: significa “tudo ou nada” em uma transação. Se uma transação é executada,
todas as operações que ela contém precisam ser um sucesso. Ou todas as operações
são um sucesso ou a transação falha (pense em OR exclusivo aqui).</li>
  <li><strong>Consitente (consistency)</strong>: uma transação bem sucedida leva os dados de um estado consistente
para outro, sem a possibilidade de usuários verem dados diferentes que não
fazem sentido juntos.</li>
  <li><strong>Isolado (isolation)</strong>: as transações que forem executadas concorrentemente não afetarão umas
as outras. Ou seja, se uma transação tentar modificar os mesmos dados que outra,
ela terá que esperar.</li>
  <li><strong>Durável (durable)</strong>: uma transação bem sucedida não será perdida, por exemplo, caso ocorra
algum desastre com o data center que contém o banco.</li>
</ul>

<h2 id="two-phase-commit-2pc"><a name="3"></a>Two-phase commit (2PC)</h2>

<p>Lidar com transações é um pouco mais difícil quando temos grandes cargas, com
vários usuários realizando muitas operações no banco, e quando vamos escalar
horizontalmente (adicionando mais máquinas e agora lidando com um sistema
distribuído) para lidar com essa carga passamos a lidar também com transações
distribuídas (<em>distributed transactions</em>). Com isso, para manter o banco com
propriedades ACID, precisamos ter algum gerenciador de transações para conseguir
orquestrar essas transações em vários nodes diferentes.</p>

<p>É aqui que entra a ideia de <strong>two-phase commit, que é um algortimo pensado para
lidar com consenso entre nodes (máquinas) em um sistema distribuído</strong>. O 2PC
possui duas fases, duas interações entre hosts: <strong>fase de preparação</strong> e <strong>fase
de commit</strong>, as quais bloqueiam os recursos associados. Com esse <em>lock</em> (bloqueio)
de recursos já podemos imaginar que algumas operações podem levar muito tempo para
terminar.</p>

<p>Abaixo uma ilustração do livro Designing Data Intensive Application:</p>

<div align="center">
<img alt="two-phase-commit" src="../../../assets/images/2/two-phase-commit.webp" />
</div>

<p>O 2PC espera um node responder, mesmo que o node já tenha morrido e, para não ter
um loop rodando para sempre, esperando o node ficar vivo, podemos configurar um
<em>timeout</em>. Ainda assim é possivel que ocorra um loop infinito pois um node pode
responder OK para commitar a transação, esperar o gerenciador (<em>coordenador</em>) de
transações e, se o coordenador está down, o node vai esperar para sempre. Para
lidar com esse tipo de problema no mundo relacional temos a ideia de *compensation*,
onde a transação é imediatamente comitada, e no caso de um erro ser reportado, uma
nova operação é feita para retificar o estado.</p>

<p>Alguns problemas que o 2PC introduz:</p>

<ul>
  <li>Perda de disponibilidade (<em>availability</em>)</li>
  <li>Maior latência (tempo para chegar de um ponto a outro na rede) em falhas parciais</li>
</ul>

<p>Para manter o banco relacional <em>ACID compliant</em> é necessário levar em consideração
esses problemas que surgem no cenário de um sistema distribuído.</p>

<h2 id="schema"><a name="4"></a>Schema</h2>

<p>Você pode representar seus objetos de domínio em um modelo relacional, onde temos
entidades e relacionamentos. Geralmente nos referimos ao modelo relacional como
<strong>schema on write</strong>, em contraste com o schema on read de bancos NoSQL, que
são mais flexíveis. <em>Schema on write</em> é a característica de ter um schema mais
rígido que é reforçado na hora da escrita no banco:</p>

<blockquote>
  <p>As bases de dados relacionais assumem frequentemente que todos os dados na base
de dados estão em conformidade com um esquema: embora este esquema possa ser
alterado (através de migrações de esquemas; ou seja, instruções <code class="language-plaintext highlighter-rouge">ALTER</code>), existe
exatamente um esquema em vigor. Por outro lado, as bases de dados schema-on-read
(“sem esquema”) não impõem um esquema, então a base de dados pode conter uma
mistura de formatos de dados mais antigos e mais recentes escritos em diferentes
momentos(…) (KLEPPMANN, 2017)</p>
</blockquote>

<h2 id="sharding"><a name="5"></a>Sharding</h2>

<p><strong>Sharding é uma forma de escalar o banco de dados relacional dividindo os dados</strong>,
ao invés de tê-los em um único servidor, ou tê-los replicados em todos os servidores
do cluster. É como se dividíssemos porções dos dados horizontalmente, hospedados
separadamente em mais de um node.</p>

<p>É necessário pensar muito bem qual será a lógica para dividir os dados. De nada
adianta, por exemplo, dividir dados de forma que as partes mais acessadas (<em>hot
spots</em>) continuem juntas, já que não iremos “desafogar”, escalar, o banco de fato.</p>

<p>Existem algumas estratégias bem conhecidas de sharding:</p>

<ul>
  <li>Por feature (segmentação funcional)</li>
  <li>Por chave (<em>key-based</em>)</li>
</ul>

<p>Recomendo fortemente a leitura do livro Designing Data Intensive Applications para
navegar em assuntos complementares a esse texto:</p>

<div align="center">
<img alt="designing data intensive applications" src="../../../assets/images/2/designing-data-intensive-applications.webp" />
</div>
<hr />

<p>Fontes:</p>

<p>CARPENTER, Jeff; HEWITT, Eben. <a href="https://www.amazon.com.br/Cassandra-Definitive-Guide-Revised-English-ebook/dp/B09R2BVFB1/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.6zE2HqOAmHI71tyWkGZRDbLPTVrs-GbLZBOVO4zVkXBUEH3ctz8FfXt05MjA4CO2S8fnSYljlMHa8nClsN4iL3ywFW5EwS_HmtLS10Wg8_sqrX3Wx80y6ObXr73DEps1DHnYOyG7i237Qi5p5jyMD0j_1GpC5Es-d8gdXkVzM0B_HtFHtodOr3S8abb0BZwS6SxF_01I5r9795odj2MzwNWxq70m9qHKp17jfQwuCpusLv36CH-BQKp4_VEiZnTq-69CeJRJ773JYazTAykwViGnLMr0XcDidwWQEtZNlGg.6drW06ZASw4T1RAl41weZ1UXAU2Fi2q-uIMgIlf6_-w&amp;qid=1729416247&amp;sr=8-1">Cassandra: The Difinitive Guide</a>. O’Reilly, 2022.</p>

<p>KLEPPMANN, Martin. <a href="https://www.amazon.com.br/Designing-Data-Intensive-Applications-Reliable-Maintainable-ebook/dp/B06XPJML5D/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.5pF53c-4K5lBHgnp-yQa_RJqJfJfPBVyDbdON_9Uqa6GrLYGUQ2pqldnzPh0j8kRTLevdzrF8EseH1lUO7IbFLNQwsJVPs9JQTpBzuD8D_Iv6wY54Mu9j3KGdUDt9z8rE2w3iqoqah8RAxd-S5FqB-fNN6RC1X005uYmHxBIgX56gpYuK28W08MAeoVkHt1YVKfJBhWxZnCTSEC2DfMVvRMpxnMjqVdU7TIGyzvhgx3zfHGygMbP_O0SR0jxDmR26VB7o5vOT7vPejc8xhzKJd_kcfUdT8LhuxCaRsH3zWg.LcAAww-jCWt1_AFannzv6PZ49ZiksTv1LGD_vywgoXQ&amp;qid=1729446561&amp;sr=8-1">Designing Data-Intensive Applications</a>. O’Reilly, 2017.</p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="bancos" /><category term="de" /><category term="dados," /><category term="banco" /><category term="relacional," /><category term="rdbms," /><category term="transações," /><category term="ACID," /><category term="two-phase" /><category term="commit," /><category term="schema," /><category term="sharding," /><category term="transactions" /><summary type="html"><![CDATA[resumo sobre conceitos de bancos relacionais, como transações (transactions), ACID, two-phase commit, schema, sharding]]></summary></entry><entry><title type="html">Concorrência e paralelismo em Python</title><link href="https://nfo94.github.io/2024/07/14/concorr%C3%AAncia-e-paralelismo-em-python.html" rel="alternate" type="text/html" title="Concorrência e paralelismo em Python" /><published>2024-07-14T00:00:00+00:00</published><updated>2024-07-14T00:00:00+00:00</updated><id>https://nfo94.github.io/2024/07/14/concorr%C3%AAncia-e-paralelismo-em-python</id><content type="html" xml:base="https://nfo94.github.io/2024/07/14/concorr%C3%AAncia-e-paralelismo-em-python.html"><![CDATA[<p>O objetivo deste texto é dar um resumo direto ao ponto dos <strong>conceitos básicos necessários para entender sobre concorrência a paralelismo na linguagem Python</strong>. Recomendo ter uma base mínima sobre o assunto ou aliar esse texto com estudo em outras fontes. Todas as referências estão ao final do texto.</p>

<p>Abordarei os seguintes tópicos:</p>

<ul>
  <li><a href="#1">O que é um processo?</a></li>
  <li><a href="#2">O que são threads?</a></li>
  <li><a href="#3">O que significa I/O bound e CPU bound?</a></li>
  <li><a href="#4">O que é o GIL do Python?</a></li>
  <li><a href="#5">O que é concorrência?</a></li>
  <li><a href="#6">O que é paralelismo?</a></li>
  <li><a href="#7">A biblioteca asyncio</a></li>
  <li><a href="#8">A biblioteca threading</a></li>
  <li><a href="#9">A biblioteca multiprocessing</a></li>
</ul>

<h2 id="o-que-é-um-processo"><a name="1"></a>O que é um processo?</h2>

<p>Em computação um <strong>processo é uma instância de uma aplicação rodando</strong>. Se você abrir uma aplicação no seu computador, como o navegador, essa aplicação vai estar associada a algum processo. Um processo é composto por:</p>

<ul>
  <li>Contexto de hardware: armazena conteúdo de registradores gerais e específicos da CPU</li>
  <li>Contexto de software: especifica os recursos que podem ser alocados pelo processo</li>
  <li>Espaço de endereçamento: especifica a área da memória que o processo pertence</li>
</ul>

<p>A imagem a seguir foi retirada do <a href="https://www.amazon.com.br/Arquitetura-Sistemas-Operacionais-Incluindo-Exerc%C3%ADcios/dp/8521622104/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=150WW8OAI7BK3&amp;dib=eyJ2IjoiMSJ9.A1ZhX8ImePrgue4fqDmOFhTfVbkIf5kIlU2jq5kd4laG4KvRRBXQekMR1rhx34OdkcpofR8kV8Ln0SjtzbN9on9rfe1wq8VNaqPBEYyuFuE.byPfWCKB9260AyrDAXjLab022xEJbcexS5jc_qZgex0&amp;dib_tag=se&amp;keywords=Arquitetura+de+Sistemas+Operacionais%3A+Incluindo+Exerc%C3%ADcios+com+o+Simulador+SOSIM+e+Quest%C3%B5es+do+ENADE&amp;qid=1720896386&amp;sprefix=arquitetura+de+sistemas+operacionais+incluindo+exerc%C3%ADcios+com+o+simulador+sosim+e+quest%C3%B5es+do+enade%2Caps%2C137&amp;sr=8-1">livro do Francis Machado e do Luis Maia</a>:</p>

<div align="center">
<img alt="processo" src="../../../assets/images/1/processo.webp" />
</div>

<p>Essas informações são necessárias para a execução de um programa.</p>

<h2 id="o-que-são-threads"><a name="2"></a>O que são threads?</h2>

<p>Uma <strong>thread é uma sub-rotina de um programa, sendo a menor unidade de execução que um sistema operacional gerencia e componente de um processo</strong>.</p>

<p>As várias threads de um processo hipotético podem ser executadas concorrentemente (que entenderemos em breve), compartilhando recursos como memória. Diferentes processos não compartilham esses recursos.</p>

<p>A imagem abaixo foi retirada do <a href="https://en.wikipedia.org/wiki/File:Concepts-_Program_vs._Process_vs._Thread.jpg#filelinks">Wikipedia</a>:</p>

<div align="center">
<img alt="programa vs processo vs thread" src="../../../assets/images/1/programa-vs-processo-vs-thread.webp" />
</div>

<p>Interpretando a imagem acima, podemos extrair que um programa fica salvo em disco (memória secundária, não-volátil) e inclui várias instruções, podendo ser instanciado (iniciado) em um ou mais processos, e esses por sua vez podem ter várias threads associadas.</p>

<h2 id="o-que-significa-io-bound-e-cpu-bound"><a name="3"></a>O que significa I/O bound e CPU bound?</h2>

<p>Essas duas expressões aparecem bastante na discussão sobre concorrência e podem aparecer em português com E/S (entrada/saída) e UCP (unidade central de processamento).</p>

<p>Quando falamos sobre I/O bound e CPU bound estamos falando dos fatores limitantes que previnem uma operação de rodar mais rápido em nosso computador, e podemos encontrar esse dois tipos de operações na mesma codebase.</p>

<p><strong>Uma operação CPU bound faz uso intenso da CPU, e rodará mais rápido se a CPU for mais poderosa</strong>. Ou seja, se formos de 2GHz para 4GHz de velocidade de clock essa operação provavelmente rodará mais rápido. Estamos falando aqui de operações que realizam muitas computações, cálculos; a exemplo, como calcular Pi.</p>

<p><strong>Uma operação I/O bound depende da velocidade da rede e velocidade dos dispositivos de entrada e saída</strong>. Fazer um request a um servidor web ou ler um arquivo do disco são operações I/O bound.</p>

<p>Ambos os tipos de operações podem se beneficiar do uso de concorrência.</p>

<h2 id="o-que-é-o-gil-do-python"><a name="4"></a>O que é o GIL do Python?</h2>

<p>GIL significa <strong>global interpreter lock (bloqueio do interpretador global), cujo objetivo é prevenir um processo Python de executar mais de um bytecode de instrução Python ao mesmo tempo</strong>. Para rodar uma thread é necessário “adiquirir” o GIL e enquanto uma thread detém o GIL outra thread não pode adiquiri-lo ao mesmo tempo. Isso não significa que não podemos ter mais de uma thread nesse contexto.</p>

<p>Aqui estamos considerando a implementação de referência do Python. <strong>O CPython é a implementação padrão do Python</strong>, usada como referência de como a linguagem se comporta. Existem outras implementações, como Jython ou IronPython. O GIL está presente no CPython e só recentemente tivemos uma <a href="https://peps.python.org/pep-0703/">PEP (Python Enhancement Proposal - proposta de melhoria do Python) propondo tornar o GIL opcional</a>.</p>

<p>A ideia do GIL é prevenir <em>race conditions</em>, que podem surgir quando mais de uma thread precisa referenciar um objeto Python ao mesmo tempo. Se mais de uma thread modificar uma variável compartilhada essa variável pode ficar em um estado inesperado. Imagem retirada do <a href="https://www.amazon.com.br/Python-Concurrency-Asyncio-Matthew-Fowler/dp/1617298662/ref=sr_1_3?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=FRBELDMJHT23&amp;dib=eyJ2IjoiMSJ9.5wyYTHKbZ2idvH8GDqdbsq8qRPv7t5SNNgCQixjEVop7TeR9YRqA66AL9DV1wY3BDFdBJN0pwlU42loLLQGPfFRIKTBDWUW3NzW89oL-TWOnyuyCSLBpYg32aUEyvo5Et8n9sA-Feyh4aMTTeEGydk8r9QKSR-i9FHsBOteOdSn9pQuhlgSHG2YU0jZ4FiaBOXUznz3Ka7XEtQc_ctlNnBN0sDGXPuLqYVgpyhEEYAGP6aTFzdY-SsLaB3duqYq9r15Q6Ux3Zat5I4eqg68T6Gf_jVopvKUv8QJ_je91pOA.eYk31md2uMKA_h8es6XGgFyU1luNGSDMeCdmmaPw0Yc&amp;dib_tag=se&amp;keywords=asyncio&amp;qid=1720900096&amp;sprefix=asyncio%2Caps%2C170&amp;sr=8-3&amp;ufe=app_do%3Aamzn1.fos.a492fd4a-f54d-4e8d-8c31-35e0a04ce61e">livro do Matthew Fowler</a>:</p>

<div align="center">
<img alt="race condition" src="../../../assets/images/1/race-condition.webp" />
</div>

<p>Na imagem acima duas threads estão tentando incrementar uma reference count simultaneamente, e aí ao invés da contagem dar 2, já que as duas estão incrementando 1, o resultado final dá 1 (cada thread é uma coluna).</p>

<h2 id="o-que-é-concorrência"><a name="5"></a>O que é concorrência?</h2>

<p>Concorrência em computação acontece quando <strong>lida-se com mais de uma tarefas, sem necessariamente estar executando essas duas tarefas exatamente ao mesmo tempo</strong>. Uma frase conhecida do <a href="https://en.wikipedia.org/wiki/Rob_Pike">Rob Pyke</a> sobre o assunto:</p>

<blockquote>
  <p>Concorrência significa <strong>lidar</strong> com muitas coisas ao mesmo tempo. Paralelismo é <strong>fazer</strong> muitas coisas ao mesmo tempo.</p>
</blockquote>

<p>Pense nessa situação hipotética: se você for fazer dois bolos, pode começar pré-aquecendo o forno e, enquanto isso, prepara a massa do primeiro bolo. Assim que o forno estiver na temperatura correta você já pode colocar a massa do primeiro bolo no forno e, enquanto aguarda o bolo crescer no forno, já pode preparar a massa do segundo bolo. A ideia de concorrência é basicamente essa, você não precisa ficar ocioso, travado, parado, enquanto aguarda uma tarefa completar, você pode fazer um <em>switch</em> e trocar de tarefa.</p>

<p>Nesse contexto, temos dois tipos de multitasking:</p>

<ul>
  <li><strong>Cooperative multitasking</strong>: nesse modelo explicitamos no código os pontos onde se pode fazer o <em>switch</em> de tarefas. No Python isso é alcançado com o uso de um event loop, um design pattern comum, usando apenas uma thread e um core de CPU, usando, por exemplo, o <code class="language-plaintext highlighter-rouge">asyncio</code> com <code class="language-plaintext highlighter-rouge">async</code> e <code class="language-plaintext highlighter-rouge">await</code></li>
  <li><strong>Preemptive multitasking</strong>: nesse modelo deixamos o sistema operacional lidar com o <em>switch</em>. No Python isso é alcançado com mais de uma thread e um core de CPU usando, por exemplo, a lib <code class="language-plaintext highlighter-rouge">threading</code></li>
</ul>

<p>A imagem abaixo ajuda a sumarizar concorrência em Python:</p>

<div align="center">
<img alt="concorrência" src="../../../assets/images/1/concorrencia.webp" />
</div>

<h2 id="o-que-é-paralelismo"><a name="6"></a>O que é paralelismo?</h2>

<p><strong>Paralelismo significa que mais de uma task está sendo executada ao mesmo tempo</strong>. Em outras palavras, paralelismo implica concorrência (lidar com mais de uma task), mas concorrência não implica paralelismo (tasks não estão necessariamente sendo executadas em paralelo, ao mesmo tempo). Para que paralelismo seja possível precisamos de mais de um core de CPU.</p>

<p>No Python paralelismo é alcançado, por exemplo, com a lib <code class="language-plaintext highlighter-rouge">multiprocessing</code>, onde teremos mais de um processo Python, cada um com seu GIL. A imagem ajuda a ilustrar paralelismo em Python:</p>

<div align="center">
<img alt="paralelismo" src="../../../assets/images/1/paralelismo.webp" />
</div>

<h2 id="a-biblioteca-asyncio"><a name="7"></a>A biblioteca asyncio</h2>

<p>Existem formas diferentes de se atingir concorrência e paralelismo em Python e podemos utilizar algumas bibliotecas para otimizar nosso código, a depender do tipo de operação que estamos lidando, I/O bound ou CPU bound. O <a href="https://docs.python.org/pt-br/3/library/asyncio.html"><code class="language-plaintext highlighter-rouge">asyncio</code></a> é uma <strong>lib para atingir concorrência usando o <code class="language-plaintext highlighter-rouge">async</code> e <code class="language-plaintext highlighter-rouge">await</code></strong>. Pela documentação:</p>

<blockquote>
  <p>O asyncio é usado como uma base para várias estruturas assíncronas do Python que fornecem rede e servidores web de alto desempenho, bibliotecas de conexão de banco de dados, filas de tarefas distribuídas etc.</p>
</blockquote>

<p>Como você pode imaginar, essa lib é adequada para otimizar tarefas I/O bound, onde temos tempo de espera de network, escrita em disco, etc. Numa operação CPU bound não há espera, dependemos apenas da velocidade de cálculo da CPU.</p>

<h2 id="a-biblioteca-threading"><a name="8"></a>A biblioteca threading</h2>

<p><strong>A lib <a href="https://docs.python.org/pt-br/3/library/threading.html"><code class="language-plaintext highlighter-rouge">threading</code></a> do Python nos permite operar mais de uma thread</strong>, porém, continuamos a lidar com um core de CPU e um processo Python, e lembre-se de que esse é um caso de preemptive multitasking onde o sistema operacional faz a troca de tarefas por nós. A lib também é mais útil para otimizar operações I/O bound.</p>

<p>Sobre o <code class="language-plaintext highlighter-rouge">threading</code>, o site <a href="https://realpython.com/python-concurrency">Real Python</a> traz alguns pontos importantes:</p>

<blockquote>
  <p>Porque o sistema operacional está no controle de quando uma task será interrompida e outra task irá começar, qualquer dado que for compartilhado entre as threads precisa ser protegido, ou <em>thread-safe</em>. Infelizmente <code class="language-plaintext highlighter-rouge">requests.Session()</code> não é <em>thread-safe</em>. Existem várias estratégias para fazer o acesso de dados <em>thread-safe</em> a depender de que dado é e como você está usando. Uma delas é usar estruturas de dados <em>thread-safe</em> como <code class="language-plaintext highlighter-rouge">Queue</code> do módulo <code class="language-plaintext highlighter-rouge">queue</code> do Python.</p>
</blockquote>

<p>Encontramos a documentação do <a href="https://docs.python.org/pt-br/3/library/queue.html#module-queue"><code class="language-plaintext highlighter-rouge">queue</code> aqui</a>.</p>

<h2 id="a-biblioteca-multiprocessing"><a name="9"></a>A biblioteca multiprocessing</h2>

<p>Sobre a lib <a href="https://docs.python.org/pt-br/3/library/multiprocessing.html"><code class="language-plaintext highlighter-rouge">multiprocessing</code></a> na documentação do Python:</p>

<blockquote>
  <p><code class="language-plaintext highlighter-rouge">multiprocessing</code> é um pacote que suporta gerar processos usando uma API similar ao módulo <code class="language-plaintext highlighter-rouge">threading</code>. O pacote <code class="language-plaintext highlighter-rouge">multiprocessing</code> oferece concorrência tanto local quanto remota, efetivamente desviando o GIL usando sub-processos ao invés de threads. Por isso o <strong>módulo <code class="language-plaintext highlighter-rouge">multiprocessing</code> permite o programador aproveitar múltiplos processadores em uma máquina</strong>.</p>
</blockquote>

<p>Vale apontar que rodar mais de um processo em diferentes cores de CPU não significa desabilitar o GIL, e sim que cada processo terá o seu próprio GIL. Por aproveitar de mais de um core de CPU, compartilhando workloads pesados de CPU entre os múltiplos cores dispiníveis, a lib é mais adequada a CPU bound.</p>

<hr />

<p>Fontes:</p>

<p>FOWLER, Matthew. <a href="https://www.amazon.com.br/Python-Concurrency-asyncio-English-Matthew-ebook/dp/B09S4NBW2X/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;dib_tag=se&amp;dib=eyJ2IjoiMSJ9.hrCR3O_nnpP3z502Q_U-90OBMrmIMAXl3zIBDIRAa6ZtVFLXDmHRGneAJVIt0nU80CejmcvLhZvK60Jk1LpM3sO1Mqe9MtF1AXr4H3gRLKprHITsENvjoIvmTmfRkV0hF7peJqUAB8EJUejNW-0jVMq4kuzVS_6ku0Q-0Ge1M1V1O147m3K1c1gU8BQwioqpdimWwJBO7TUvxtDEIRjC9ASkmKNr46PqT5JL2jpcK-jbEw-_nYSxPk0lHmW_XBMngMORwj2znV96dfoUXACcfQJ04lRRbHDJmYhkyZNaN4k.IURAGkadqEEUNyjwE5NoLWNseUJm58Vopo-2CV2n5U4&amp;qid=1720896914&amp;sr=8-1">Python Concurrency with asyncio</a>. Manning Publications, 2022.</p>

<p>MACHADO, Francis Berenger; MAIA, Luiz Paulo. <a href="https://www.amazon.com.br/Arquitetura-Sistemas-Operacionais-Incluindo-Exerc%C3%ADcios/dp/8521622104/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=150WW8OAI7BK3&amp;dib=eyJ2IjoiMSJ9.A1ZhX8ImePrgue4fqDmOFhTfVbkIf5kIlU2jq5kd4laG4KvRRBXQekMR1rhx34OdkcpofR8kV8Ln0SjtzbN9on9rfe1wq8VNaqPBEYyuFuE.byPfWCKB9260AyrDAXjLab022xEJbcexS5jc_qZgex0&amp;dib_tag=se&amp;keywords=Arquitetura+de+Sistemas+Operacionais%3A+Incluindo+Exerc%C3%ADcios+com+o+Simulador+SOSIM+e+Quest%C3%B5es+do+ENADE&amp;qid=1720896386&amp;sprefix=arquitetura+de+sistemas+operacionais+incluindo+exerc%C3%ADcios+com+o+simulador+sosim+e+quest%C3%B5es+do+enade%2Caps%2C137&amp;sr=8-1">Arquitetura de Sistemas Operacionais: Incluindo Exercícios com o Simulador SOSIM e Questões do ENADE</a>. Rio de Janeiro: LTC, 2013.</p>

<p><a href="https://en.wikipedia.org/wiki/Thread_(computing)">Thread (computing) por Wikipedia</a></p>

<p><a href="https://realpython.com/python-concurrency">Speed Up Your Python Program With Concurrency por Real Python</a></p>]]></content><author><name>Natália Oliveira</name><email>nataliaferreiraoliveira1994@gmail.com</email></author><category term="python," /><category term="asyncio," /><category term="threading," /><category term="multiprocessing," /><category term="concorrência," /><category term="paralelismo" /><summary type="html"><![CDATA[resumo sobre concorrência e paralelismo em Python]]></summary></entry></feed>