<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Notas do Bidu]]></title><description><![CDATA[Notas do Bidu]]></description><link>https://notasdobidu.com/</link><image><url>https://notasdobidu.com/favicon.png</url><title>Notas do Bidu</title><link>https://notasdobidu.com/</link></image><generator>Ghost 3.2</generator><lastBuildDate>Fri, 28 Nov 2025 16:37:17 GMT</lastBuildDate><atom:link href="https://notasdobidu.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Pyscript & Python no Front - o passado & o futuro]]></title><description><![CDATA[<p>Recentemente o time da Anaconda anunciou o <a href="https://pyscript.net/">Pyscript</a> uma nova tentativa de integrar Python no desenvolvimento de Frontends web. Python é famosa por ser uma linguagem multipropósitos - em contraste com linguagens como R e Matlab, que são linguagens pensadas para usos mais fechados. No entanto, os 'multipropósitos' do Python</p>]]></description><link>https://notasdobidu.com/pyscript-python-no-frontend/</link><guid isPermaLink="false">6311345724f90c07f8bc2e4a</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Thu, 01 Sep 2022 22:44:55 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2022/09/2022-05-14_09-43.png" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2022/09/2022-05-14_09-43.png" alt="Pyscript & Python no Front - o passado & o futuro"><p>Recentemente o time da Anaconda anunciou o <a href="https://pyscript.net/">Pyscript</a> uma nova tentativa de integrar Python no desenvolvimento de Frontends web. Python é famosa por ser uma linguagem multipropósitos - em contraste com linguagens como R e Matlab, que são linguagens pensadas para usos mais fechados. No entanto, os 'multipropósitos' do Python são normalmente distantes do usuário final não-técnico. APIs, pipelines de Machine Learning, Sistemas de Suporte, Análises de Dados, Python faz tudo isso bem.</p><p>No entanto Python não possui uma presença forte no lado do cliente. Projetos como o <a href="https://kivy.org/#home">Kivy</a>, o <a href="https://beeware.org/">Beeware</a> e o <a href="https://brython.info/">Brython</a> tentam lutar essa batalha há alguns anos com níveis diferentes de sucesso. Escrevendo essa matéria, descobri inclusive que o <a href="https://beeware.org/news/buzz/now-hiring/">Beeware está contratando</a>!</p><p>O Pyscript é o novo projeto na área. Construído em cima do <a href="https://pyodide.org/en/stable/">Pyodide</a>, ele consegue fazer uma forma nova de integração com o browser. O projeto Beeware, por exemplo, tinha o projeto Batavia - que também mirava rodar Python no browser. O problema de rodar coisas no browser é que, historicamente, <strong>browsers só rodam JavaScript</strong>. Como contornar isso?</p><h3 id="o-monop-lio-do-js">O Monopólio do JS</h3><figure class="kg-card kg-image-card"><img src="https://buttondown.s3.amazonaws.com/images/c95ebfd8-9697-4704-af2e-80969d51cdd1.jpg" class="kg-image" alt="Pyscript & Python no Front - o passado & o futuro"></figure><p><em>Moeda comemorativa que ganhei em 2016, por colaborar com o projeto Batavia</em></p><p>Bem, linguagens de programação "grandes" como Python, JavaScript, C, PHP, Java, Pascal e etc possuem uma propriedade interessante conhecida como Turing-Equivalência. Informalmente isso significa que <strong>qualquer uma dessas linguagens pode ser usada para rodar código feito em qualquer outra</strong>. Ou seja, eu posso escrever um interpretador de Javascript em C, ou um compilador de C em PHP, ou um interpretador de Java em Python. Como consequência dessa propriedade, <strong>podemos escrever um interpretador de Python em JavaScript</strong>. Ora, se eu consigo escrever um interpretador Python em JavaScript e os navegadores sabem rodar JavaScript, eu consigo então rodar Python no navegador. Era esse o <a href="https://github.com/beeware/batavia">objetivo do projeto Batavia - escrever um interpretador Python em JavaScript.</a></p><p>Apesar dessa estratégia garantidamente funcionar, ela tem seus pontos negativos. Notadamente, no processamento normal do Python, o interpretador converte nossos códigos para um bytecode que é interpretado pela máquina virtual do Python que por sua vez é implementada em C. Com um projeto como o Batavia, a máquina virtual é feita em JavaScript. A execução dessa máquina virtual vai envolver passar o código agora pelo pipeline de processamento do JavaScript em si, que também vai ter a sua própria máquina virtual. Ou seja, <strong>o processamento vai ter aproximadamente o dobro de passos</strong>.</p><p>Quase dois anos atrás, em 30 de maio de 2020 o projeto Batavia foi pausado <a href="https://github.com/beeware/batavia/commit/ecbdc21dc7e002415e6c0ea8654d2b8a8c7a85fa">num anúncio que é basicamente uma previsão do futuro, que viria ser o Pyscript</a>:</p><blockquote>... [T]he approach that is being used by Batavia needs to be reconsidered.<br>In particular, the emergence of WASM as a viable target for web development<br>opens many options for Python on the web that weren't previously possible.</blockquote><p><em>Tradução minha:</em></p><blockquote>A abordagem que está sendo usada pelo Batavia precisa ser reconsiderada.<br>Em particular, <strong>o surgimento do WASM como algo viável</strong> em desenvolvimento<br>web <strong>abre muitas opções para Python na web</strong> que não eram previamente possíveis</blockquote><h3 id="wasm">WASM?</h3><p>Na mensagem de fechamento do Batavia, fica claro que o criador do projeto estava vislumbrando um futuro - o WASM, também conhecido como WebAssembly. Nossos computadores não entendem nossas linguagens de programação <em>de verdade</em>. Se você tentar conversar com a sua CPU em C, Python, JavaScript ou qualquer uma dessas linguagens, você vai ter como resposta o silêncio eterno de um punhado de silício.</p><p><strong>A única forma de conversar com uma CPU é através da sua própria linguagem de montagem</strong>, conhecida como "Assembly". Por exemplo na página 87 <a href="https://www.amd.com/system/files/TechDocs/24592.pdf">desse PDF</a> - "3.3.6 Arithmetic" - você pode ver as instruções matemáticas que minha CPU suporta. Note que ela não tem uma instrução para, por exemplo, elevar um número a uma potência arbitrária, como 7 elevado à 3. Se eu quiser fazer isso, vou precisar montar uma série de instruções para fazer isso.</p><p>Independente da linguagem de programação ser puramente interpretada, compilada ou uma combinação dos dois - Python e JS são normalmente chamadas de "interpretadas" mas, na verdade, elas <a href="https://craftinginterpreters.com/a-map-of-the-territory.html#compilers-and-interpreters">possuem compiladores dentro de seus interpretadores</a> - <strong>no fim do dia você <em>precisa</em> que seu código vire Assembly de alguma forma</strong>. Sem isso, você não faz nada.</p><p>Então, em 2017, surgiu o que é conhecido como <a href="https://webassembly.org/">WebAssembly, o WASM</a>. Basicamente, a ideia é definir uma <strong>série de instruções que uma máquina virtual embutida nos navegadores vai aceitar</strong>. Se todos os navegadores embutirem essa máquina virtual dentro de si, algo interessante pode acontecer! Ao invés de nós construirmos código Python que vai ser convertido no Assembly entendido por uma CPU Intel ou AMD, nós convertemos em Assembly que vai ser entendido por uma máquina virtual Web Assembly! O resultado - <strong>Python que roda no navegador. Ou Rust, ou Go, ou qualquer outra linguagem, na verdade. Basta que a gente comece ter como alvo do processo de compilação uma máquina virtual WASM!</strong></p><h3 id="entra-o-pyodide">Entra o Pyodide</h3><p>Para essa "mágica" acontecer nós precisamos fazer com que código na linguagem de entrada (Python, no caso) seja de alguma forma traduzido para WASM. O Pyodide faz exatamente isso.</p><p><a href="https://pyodide.org/en/stable/console.html">Nesse link</a> você vai ter um console Python completo. <strong>Rodando no seu navegador</strong>. Não tem um servidor em algum lugar servindo esse console. O que está acontecendo aí é que o seu navegador está recebendo instruções na máquina virtual web assembly que ele tem embutida dentro dele!</p><h3 id="pyscript-pyodide-html">Pyscript - Pyodide + HTML</h3><p>E finalmente temos a nova promessa de Python nos navegadores. Somando o poder do Pyodide com uma forma fácil de rodar código in-line, o pyscript tem potencial para tornar o uso de <strong>Python no front realmente viável</strong>.</p><p><strong>Observe como nós estamos lidando com o novo passo de um processo histórico</strong> - o pyscript é a realização do que o projeto Batavia já vislumbrava dois anos atrás, quando parou suas atividades. O próprio projeto Batavia já vinha de anos de experimentação com o tema. Eu, particularmente, conheci o projeto em 2016.</p><h3 id="o-futuro">O Futuro</h3><p>O Pyscript vem da Anaconda, uma empresa que possui gente muito boa e recursos para de fato fazer a diferença. A performance ainda é uma questão. Python através de WASM é mais lento que Python comum. Porém, Python no Frontend é uma área que interessa a muita gente. Por exemplo, <strong>o gigantesco mercado de Data Science com todo o investimento que tem recebido possui muito a ganhar com soluções Python <em>verdadeiramente</em> "full stack".</strong> A Anaconda é em si uma empresa que atua nesse mercado.</p><p>Além disso, a linguagem Python em si - <a href="https://buttondown.email/ndb/archive/ndb-6-musk-e-seu-megafone-python-311-e/">como discuti nas Notas</a> do Bidu - possui planos de melhoria que vão fatalmente avançar na performance do Pyodide também.</p><p>No fim das contas, além de ficar feliz em ver Python - uma linguagem que gosto bastante - ganhar um novo caminho no importantíssimo mundo do desenvolvimento frontend web, eu fico também feliz com a possibilidade de novas linguagens abrirem caminho nesse espaço. Independente das minhas opiniões sobre JavaScript, <strong>o monopólio tecnológico que ela tem sobre o frontend web tem se mostrado, na minha opinião, nocivo</strong>.</p><p>Os porquês disso são assuntos para um outro post, hoje vou me limitar a dizer que vejo valor no conflito de ideias de tecnologias diferentes no mesmo espaço. Que forma será que o ecossistema de computação numérica do Python teria hoje sem a competição que teve por vários anos com R? <strong>Será que uma competição saudável não vai nos permitir a focar melhor nossos esforços em ideias que entregam valor de maneira duradoura ao invés de criar frameworks inteiros para JS toda vez que ficamos tristes com algo?</strong></p><p>O futuro vai nos mostrar se pyscript se estabelecerá ou será mais um passo rumo ao objetivo, seja como for, eu acho uma baita ideia e que realmente tem potencial.</p><h3 id="saiba-mais">Saiba Mais</h3><p>O <a href="https://twitter.com/rochacbruno">@rochacbruno</a> gravou um vídeo explorando o pyscript e seus exemplos:</p><p><a href="https://www.youtube.com/watch?v=Mj47se4FOPk">https://www.youtube.com/watch?v=Mj47se4FOPk</a></p><p>Veja também a <a href="https://github.com/pyscript/pyscript/blob/main/GETTING-STARTED.md">documentação oficial</a></p><p>Como toda tecnologia nova, é legal ler e assistir sobre, mas o mais legal é colocar a mão na massa :D</p><p>Ah, aquela moeda bonita que ganhei por colaborar com o Batavia foi graças à uma Python Brasil! Na Python Brasil de 2016, Russel, o criador do projeto, esteve no Brasil e nós tivemos a oportunidade de colaborar com o projeto junto dele, ao vivo e presencialmente. Essas são as chamadas "Sprints" que acontecem nos eventos da comunidade. Você pode acompanhar as novidades sobre a Python Brasil 2022 no <a href="https://2022.pythonbrasil.org.br/">site oficial</a>. Será em Manaus, de 17 a 23 de Outubro</p>]]></content:encoded></item><item><title><![CDATA[Dias Que Não São]]></title><description><![CDATA[Nos nossos dias, temos muitas possibilidades. Podemos fazer muito mais do que qualquer geração jamais sonhou. Porém nosso cérebro vai arrumar tempo para descansar, quer a gente queira, quer não]]></description><link>https://notasdobidu.com/dias-que-nao-sao/</link><guid isPermaLink="false">623f22bc24f90c07f8bc2e31</guid><category><![CDATA[saúde mental]]></category><category><![CDATA[produtividade]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Sat, 26 Mar 2022 14:32:26 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2022/03/christopher-lemercier-12yvdCiLaVE-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2022/03/christopher-lemercier-12yvdCiLaVE-unsplash.jpg" alt="Dias Que Não São"><p>Um dia, essa semana, acordei me sentindo mal. Uma mistura estranha de enjôo e dor de cabeça. Refleti sobre o dia anterior, não havia consumido nada de estranho. Tentei trabalhar, não consegui. Declarei 'dia de saúde', como a gente chama na minha empresa quando não consegue trabalhar por estar mal.</p><p>Sentei na minha mesa e fiquei refletindo - o que fazer? Bem, tomei um remédio para ajudar os sintomas e comecei a pensar nos meus dias. Ando lotado de trabalho vindo de diversas fontes. Tanto do meu emprego full-time como de outros projetos paralelos que tenho, mentorias, aulas que dou, consultorias, aulas que faço, etc. Olhei para minha agenda, meu Todoist, minha mesa, minha gaveta - tudo estava bagunçado.</p><p>A sensação era de sufocamento. Onde eu olhava, não conseguia ver o que deveria fazer. A quantidade de informação era absurda e separar sinal de ruído era praticamente impossível. Então eu parei e comecei a organizar as coisas.</p><p>Minha principal ferramenta? Dizer "não" para coisas que não faziam mais sentido, responder aquele e-mail que me propunha pegar 4 tarefas dizendo que eu poderia - naquele prazo - pegar no máximo uma ou duas, jogar fora aqueles 3 cabos USB-C que já não funcionavam, mas estavam na primeira gaveta do meu armário, cancelar aquele MBA aleatório que eu tava fazendo e não estava conseguindo aproveitar, alinhar expectativas com projetos que assumi, limpar armários.</p><p>Enfim, encontrar espaço para respirar. Nos cronogramas, nos e-mails, nas gavetas, no dia-a-dia. Nos nossos dias e na nossa era, temos muitas possibilidades. Podemos fazer muito mais do que qualquer geração jamais sonhou. Quer aprender um pouco de Polonês? Bem, você pode instalar um app de idiomas, navegar pela Cracóvia no Street View, ler jornais poloneses on-line e até conversar com poloneses, tudo isso em pouco mais de uma ou duas horas na internet.</p><p>Informação, como diz o título de um livro de James Gleick, virou uma inundação (<a href="https://www.amazon.com.br/dp/B004DEPHUC/ref=dp-kindle-redirect?_encoding=UTF8&amp;btkr=1&amp;_encoding=UTF8&amp;tag=notasdobidu-20&amp;linkCode=ur2&amp;linkId=e001df079f127e226011c91404fb815f&amp;camp=1789&amp;creative=9325">The Information: A History, a Theory, a Flood</a>). Com tantas possibilidades, é fácil querermos fazer muito e nos esquecermos do que é mais importante, do que tem mais impacto, do que queremos fazer de fato. E nós, pessoas da computação, somos particularmente vulneráveis a isso, simplesmente pelo número gigantesco de possibilidades naturais da nossa área, nossa exposição gigante à tecnologia e os diversos incentivos do mercado para fazer mais coisas.</p><p>Minha dica? Evitem precisar parar de maneira meio forçada para pensar em como andam seus dias e o que vocês tem feito. No atrito diário, é fácil perder noção - eu mesmo costumava fazer revisões semanais todas às sextas e parei de fazer nas últimas muitas semanas, simplesmente porque deixei outras coisas ocuparem o lugar. Infelizmente, perdemos o fio da meada de vez em quando, acontece. Por mais vigilante que a gente fique, uma hora podemos nos ver numa bola de neve. O importante, para mim, é fazer as pazes com isso, não me sentir culpado pela eventual bagunça, limpar e pensar em como evitar que ela apareça de novo.</p><p>O nosso cérebro, afinal, vai arrumar tempo para descansar. Quer a gente queira, quer não. Quer a gente planeje por isso, quer não.</p>]]></content:encoded></item><item><title><![CDATA[SQL & Performance]]></title><description><![CDATA[O que é mais rápido? Somar valores em um banco de dados SQL usando SUM, do SQL ou utilizando um código customizado? Descubra nesse post!]]></description><link>https://notasdobidu.com/sql-e-performance/</link><guid isPermaLink="false">61f7069164c96207e68e3b38</guid><category><![CDATA[Iniciantes]]></category><category><![CDATA[Teóricos]]></category><category><![CDATA[SQL]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Mon, 31 Jan 2022 21:52:23 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2022/01/sonja-langford-eIkbSc3SDtI-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2022/01/sonja-langford-eIkbSc3SDtI-unsplash.jpg" alt="SQL & Performance"><p>A linguagem SQL possui algumas funções úteis para fazer análises estatísticas. Normalmente você encontrará funções como <code>sum</code>, <code>average</code>, <code>max</code> e <code>min</code> que retornam a soma, média, valor máximo e mínimo de uma determinada coluna, respectivamente. Essas funções são chamadas de "agregações", pois elas retornam um único dado com base em uma série de dados, ou seja, elas <em>agregam </em>esses dados.</p><p>É difícil falar de SQL em geral pois cada distribuidor faz o seu próprio "jeitinho" de SQL, formalmente conhecidos como dialetos. O SQL usado pelo Google BigQuery, por exemplo, possui um <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate_analytic_functions">ecossistema riquíssimo de funções estatísticas prontas</a>. O ponto desse post, porém, é mais amplo:</p><blockquote>É mais eficiente em termos de tempo de execução utilizar dessas funções prontas do SQL ou fazer as análises em seja lá qual linguagem de programação a gente tá usando?</blockquote><h2 id="um-exemplo-em-python">Um Exemplo em Python</h2><blockquote>O código abaixo foi recortado para exibir apenas as partes mais importantes.</blockquote><p>Considere duas funções diferentes para somar o total de valores de uma coluna chamada "Milliseconds". A primeira, faz uma query para listar todos os resultados da tabela, passa por todos os resultados um a um e soma o valor da coluna numa variável:</p><figure class="kg-card kg-code-card"><pre><code class="language-python">def sum_manual():
    query = select(track)
    result = engine.execute(query)

    sum_ = 0
    for row in result:
        sum_ += row.Milliseconds
    return sum_</code></pre><figcaption>Somando a coluna milliseconds manualmente</figcaption></figure><p>A segunda função, por outro lado, envia para o servidor SQL uma query pedindo pelo resultado de <code>sum</code>. Ou seja, quem vai fazer o trabalho é o servidor SQL e não nosso código:</p><pre><code class="language-python">def sum_sql():
    query = select(func.sum(track.columns["Milliseconds"]))
    result = engine.execute(query)
    return result.scalar()
</code></pre><p>Com a função mágica <code>%timeit</code> do Jupyter e do ipython, podemos comparar os resultados:</p><figure class="kg-card kg-code-card"><pre><code class="language-jupyter">%timeit sum_manual()
2.07 s ± 13.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit sum_sql()
39.1 ms ± 418 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)</code></pre><figcaption>Comparando as performances</figcaption></figure><p>Ou seja, somar manualmente levou, em média, 2.07s. Somar através do SQL, 39.1ms. <strong>A função que utiliza de SQL foi quase 53 vezes mais rápida do que a manual</strong>.</p><p>Em geral, esse é o comportamento que veremos - utilizar do servidor de SQL para fazer essas operações é mais rápido. A análise aqui foi bastante limitada - o servidor SQL era simplesmente um SQLite que estava rodando na minha máquina local - e ainda assim conseguimos ver diferenças.</p><p>Você talvez já tenha ouvido falar sobre coisas como "análise de complexidade de algoritmos", "notação grande-O (big-O)", "análise assintótica" e outras coisas do tipo. É possível utilizar de ferramentas assim para fazer uma análise mais detalhada dessas duas funções. Mais tarde, nessa mesma semana, publico uma análise do tipo. <a href="https://buttondown.email/ndb">Se inscreva na newsletter do blog</a> para ficar sabendo das novidades :D</p>]]></content:encoded></item><item><title><![CDATA[Carta aos Futuros Calouros]]></title><description><![CDATA[Um curso de graduação em computação – assim como toda graduação – é um possível primeiro passo em uma carreira. Não é a sua carreira toda]]></description><link>https://notasdobidu.com/carta-aos-futuros-calouros/</link><guid isPermaLink="false">60a8f08264c96207e68e3a56</guid><category><![CDATA[graduação]]></category><category><![CDATA[formação em comp]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Sat, 22 May 2021 12:03:20 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2021/05/dom-fou-YRMWVcdyhmI-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2021/05/dom-fou-YRMWVcdyhmI-unsplash.jpg" alt="Carta aos Futuros Calouros"><p>O texto abaixo foi escrito no <a href="https://docs.google.com/forms/d/e/1FAIpQLSf4Oc-3MfWKvccfgisLGyvzBbcwRGzAc2wcjDEQwkKT2-ZnTw/viewform?fbzx=-5793851995183347556">formulário do SBC</a> sobre "Por que você escolheu um curso de Computação", da <a href="https://sbc.org.br/educacao/diretoria-de-educacao">Comissão de Educação</a>. A ideia era dar uma mensagem de motivação para futuros alunos em um curso superior de Computação</p><hr><p>Eu acho importante alinharmos as expectativas. Um curso de graduação em computação assim como toda graduação é um possível primeiro passo em uma carreira. Não é a sua carreira toda e nem é o único primeiro passo possível.</p><blockquote>Um curso de graduação (...) não é sua carreira toda</blockquote><p>Dito isso, eu ouço muitas críticas de colegas com coisas do tipo "nossa, a faculdade não me ensinou nada que a empresa X me cobra no trabalho". Bem, eu não acho que isso seja um problema tão grave quanto parece.</p><p>Veja, uma graduação não deveria ficar correndo atrás do que há de mais chamativo ou mais na moda na indústria. Como alguém que trabalha na indústria desde antes de entrar na graduação eu te falo - essas coisas vão e vem. Mas o que você vai aprender numa graduação sólida em computação vai te permitir absorver mais rápido seja lá qual for a novidade que a empresa X, Y ou Z tem usado.</p><p>Tome desenvolvimento <em>mobile</em>, por exemplo, as técnicas usadas para programar Android em 2014 são consideradas antigas hoje. Porém, de Java ao Kotlin, de Objective-C ao Swift - no caso de iOS - os fundamentos de orientação à objetos e demais paradigmas, algoritmos, bancos de dados, engenharia e arquitetura de software continuam bastante válidos. Se nosso foco fosse em seja lá o que há de mais chamativo em um determinado momento, não montaríamos essa base.</p><blockquote>Conhecimentos teóricos podem ser mais chatos, mas eles costumam ser mais duradouros do que correr atrás de tecnologias mais aplicadas</blockquote><p>Existe muito a ser falado sobre onde mora o equilíbrio entre conhecimentos teóricos mais 'puros' e conhecimentos práticos mais aplicados e onde um bacharelado se encaixa nisso. Esse debate, por definição, não tem fim. Cada um de nós tem a sua visão e tá tudo bem.</p><blockquote>Temos sorte de gostarmos da nossa área – podemos aplicar muito do quê aprendemos usando um computador doméstico</blockquote><p>No fim do dia, saiba que a gente tem muita sorte de gostarmos e estarmos na nossa área. Nós podemos ter aulas teóricas em um momento e então irmos - até mesmo sozinhos - para uma prática bem avançada. Nossos amigos da engenharia civil e química, por exemplo, nem sempre tem a mesma sorte - não é todo mundo que tem um canteiro de obras ou uma planta química no quintal. Aproveite a oportunidade e bem-vindo(a)</p>]]></content:encoded></item><item><title><![CDATA[O que é uma API? E uma Interface?]]></title><description><![CDATA[APIs - antes de serem HTTP, REST e afins são interfaces. Nesse texto, retomo a noção de interface para elaborar o papel importante que APIs possuem - mesmo além da web]]></description><link>https://notasdobidu.com/apis-sao-interfaces/</link><guid isPermaLink="false">5f0f9c29c2fc0a153543fd34</guid><category><![CDATA[API]]></category><category><![CDATA[Iniciantes]]></category><category><![CDATA[Teóricos]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Tue, 29 Dec 2020 21:35:30 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2020/12/immo-wegmann--kMLhgAoo7k-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2020/12/immo-wegmann--kMLhgAoo7k-unsplash.jpg" alt="O que é uma API? E uma Interface?"><p>Um termo bastante falado em computação é API. Normalmente, quando ele aparece, logo se fala de coisas como REST, HTTP, <em>frameworks</em> e etc. Pouco depois, a conversa cai no <em>framework</em> favorito da pessoa que está escrevendo ― Flask? Django REST Framework? Phoenix? Rails?? ― existe uma infinidade deles! Além disso, existe também uma infinidade de conceitos relacionados à arquitetura de API usada ― REST? SOAP? ― ao protocolo de comunicação usado ― HTTP? ― enfim, é uma conversa longa e cheia de caminhos possíveis.</p><p>Cada um desses conceitos merece atenção. Hoje, eu vou falar só do primeiro deles, a tal API. API é uma sigla ― Interface de Programação de Aplicações. Vou dar um "zoom" maior ainda e me focar em apenas uma palavra da sigla: <strong>interface</strong>.</p><!--kg-card-begin: html--><aside class="toc"></aside><!--kg-card-end: html--><h2 id="interfeice-vs-interf-ce">Inter<em>feice </em>vs Inter<em>fáce</em></h2><p>A palavra interface pode ser pronunciada de duas formas diferentes. Em Inglês, "interfeice" ou de forma mais aportuguesada, "interfáce". O acento não existe, é apenas para marcar que a segunda pronúncia faz referência à face, rosto, frente.</p><p>Quando falamos sobre interfaces, falamos de uma interação entre duas entidades, entre duas coisas diferentes, entre duas <em>faces</em> diferentes. Note o prefixo "inter", como em "internacional" ou "interestadual". Entre nações, entre estados e entre faces. Por fim, quando falamos em APIs, falamos em interfaces entre sistemas computacionais.</p><h2 id="interfaces-f-sicas-e-computacionais">Interfaces Físicas e Computacionais</h2><p>Em nosso dia-a-dia, interagimos com diversas interfaces físicas. O controle-remoto de uma televisão, os botões de uma cafeteira, o interruptor de um ventilador. Todos são exemplos de entidades que fazem a ponte entre o usuário e um outro recurso ― são interfaces.</p><p>Em nossos computadores, também temos diversas interfaces ativas à todo momento. O fato delas serem computacionais, porém, não significam que elas são APIs.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://notasdobidu.com/content/images/2020/12/image-5.png" class="kg-image" alt="O que é uma API? E uma Interface?"><figcaption>A calculadora do seu computador possui uma interface, porém ela não é programável</figcaption></figure><p>Uma API é uma interface computacional muito especial. Relembrando, a sigla significa "Interface de Programação de Aplicações". A característica fundamental de uma API é que ela é uma <em>interface programável</em>. Nós podemos, através de APIs, conectar diferentes pedaços de software uns aos outros, criando novas combinações e novas possibilidades.</p><p>Você pode alegar, corretamente, que você <em>consegue</em> escrever um código que aperta os botões da calculadora! Isso seria uma API certo? Não exatamente. Observe, a calculadora do meu sistema operacional não oferece nenhuma facilidade para que outro software utilize dela. Ela não foi feita para isso.</p><blockquote>APIs permitem que softwares conectem-se entre si e utilizem as capacidades uns dos outros</blockquote><h2 id="exemplos">Exemplos</h2><p>Quando você utiliza uma biblioteca ou até mesmo uma função, ela expõe para você uma interface. A função <code>sorted</code> do Python, por exemplo, ela possui uma habilidade ― ordenar sequências ― que você pode querer usar em seu código. Os argumentos da função são o "rosto público" desse recurso.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://notasdobidu.com/content/images/2020/12/image-4.png" class="kg-image" alt="O que é uma API? E uma Interface?"><figcaption>A "assinatura" de uma função constitui uma forma simplificada de API</figcaption></figure><p>‌Bibliotecas complexas como o NumPy expõem uma série de recursos na forma de funções, classes e módulos. Mais uma vez, os nomes, atributos e argumentos dessas entidades são a "face pública" de um recurso computacional que você pode usar em seu código.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://notasdobidu.com/content/images/2020/12/image-3.png" class="kg-image" alt="O que é uma API? E uma Interface?"><figcaption>Bibliotecas complexas como o Numpy expõem APIs</figcaption></figure><h2 id="externo-interno">Externo &amp; Interno</h2><p>Até aqui, desenvolvi a ideia da interface como sendo o "rosto público" de alguma entidade. Existe uma consequência importante dessa definição:</p><blockquote>uma interface oculta as complexidades desnecessárias do recurso enquanto exibe uma face pronta para o usuário, que não precisa se preocupar com os detalhes.</blockquote><p>Tome a função <code>sorted</code> que dei como exemplo ali em cima. <a href="https://github.com/python/cpython/blob/226a012d1cd61f42ecd3056c554922f359a1a35d/Python/bltinmodule.c#L2218">Por baixo dos panos, ela é uma função em C embutida na linguagem Python</a>, que se preocupa com diversos detalhes que não são necessários ao usuário da função. Um interface — e por consequência, uma API — bem feitas exibem o que é necessário, enquanto ocultam o que é irrelevante. Decidir onde traçar a linha entre o fundamental e o supérfluo é um problema na hora de arquitetar APIs (e muita gente tem opiniões muito fortes sobre isso!).</p><h2 id="documenta-o">Documentação</h2><p>Não é acidental que os dois exemplos que dei, eu mostrei print de uma documentação. Se uma API é uma interface pública e você não <em>publica</em> ela de forma alguma, quão útil ela de fato é? Ora, uma face pública que ninguém sabe como funciona, não é exatamente útil!</p><p>Documentação de código e de APIs é outro ponto que merece uma série de artigos só para si. Porém, quero deixar um recado importante para quem está começando nesse mundo</p><blockquote>Uma API é tão útil por terceiros quanto melhor for a sua documentação. Uma face pública escondida, não é tão pública assim e não cumpre exatamente com seu papel.</blockquote><h2 id="http-rest-a-web">HTTP, REST &amp; a Web</h2><p>Como vocês podem notar nos exemplos anteriores, não precisamos falar de Internet ao discutirmos APIs. No entanto, a Internet é um meio extremamente importante de <em>conexão entre recursos computacionais diferentes</em>. Portanto, um número gigantesco de APIs ― e de artigos sobre APIs ― é focado na web.</p><p>Eu quis escrever esse texto sem tocar nesses assuntos pois eles são densos e eu senti falta de um texto que lida com APIs sem pular para a Internet. No futuro, devo autorar mais materiais sobre essa parte.</p><p>Por hora ― e para satisfazer a curiosidades das eventuais pessoas decepcionadas por eu não ter tocado nisso ainda ― vou dar um breve resumo.</p><p>O protocolo HTTP define uma linguagem para que computadores se conversem. Nós podemos utilizar dessa linguagem pronta na hora de pensarmos numa API. Por exemplo, o HTTP vai nos dar formas estruturadas de comunicar erros — alguém pediu por algo que não existe? Retorne o famoso HTTP-404 ao invés de criar a sua solução customizada de erro!</p><p>O HTTP também nos dá formas robustas de responder perguntas do tipo "eu preciso servir esse texto. Ele possui traduções completas em 3 idiomas diferentes e traduções parciais em outros 5. Qual tradução do texto eu ofereço ao usuário?". De novo, ao invés de criarmos uma solução complexa, podemos utilizar das facilidades testadas ao longo do tempo que o HTTP nos oferece para isso.</p><p>REST, por outro lado, tem mais relação com estruturação, com a arquitetura da aplicação. Existe muito abuso de notação quando lidamos com REST mas, para um breve resumo, o REST vai nos facilitar pensar sobre as entidades que nossa aplicação contém e como arquitetar suas partes.</p><h3 id="um-exemplo-web">Um exemplo web</h3><p>Um exemplo simples de API web é o MathJS. Ela permite que a gente tenha uma calculadora verdadeiramente programável e pela internet. Essa URL, por exemplo:</p><p><code><a href="https://api.mathjs.org/v4/?expr=21*2">https://api.mathjs.org/v4/?expr=21*2</a></code></p><p>Irá retornar <code>42</code>, o resultado da expressão <code>21*2</code>. Observe como esse "site" aceita explicitamente um cálculo matemático através de um texto e retorna também um texto simples como resposta. Podemos, por exemplo, facilmente acessar esse recurso através de um terminal, com um comando como <code>curl "<a href="https://api.mathjs.org/v4/?expr=21*2">https://api.mathjs.org/v4/?expr=21*2</a>"</code></p><figure class="kg-card kg-image-card"><img src="https://notasdobidu.com/content/images/2020/12/image-6.png" class="kg-image" alt="O que é uma API? E uma Interface?"></figure><p>Como você pode ver, tanto pelo navegador, quanto pelo terminal, você consegue o resultado. O MathJS expõe uma API através do protocolo HTTP, uma língua que o seu navegador e o <code>curl</code> também falam.</p><h3 id="uma-reflex-o-sobre-conectividade-na-web">Uma Reflexão sobre Conectividade na Web</h3><p>‌Por fim, eu recomendo fortemente esse vídeo maravilhoso — e relativamente curto — sobre a história recente da interconexão de serviços na Internet.</p><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe width="200" height="113" src="https://www.youtube.com/embed/BxV14h0kFs0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><figcaption>Uma reflexão sobre APIs web e sua evolução nos últimos anos</figcaption></figure><h2 id="resumo">Resumo</h2><p>APIs são um assunto importantíssimo e grande. Como todo assunto que cumpre esses dois quesitos, existem muitos recortes que a gente pode fazer ao falar deles. Nesse texto eu quis focar na seguinte ideia:</p><blockquote>APIs não são nada mais do que interfaces especiais e, como tal, devem ser vistas como a face externa de um recurso computacional.</blockquote><blockquote>APIs servem para interconectar recursos computacionais, permitindo que o seu código utilize recursos de outros serviços.</blockquote><p><em>Agradeço aos meus colegas de Computação-UNICAMP ― Gabriel Lima, Ian Loron, Dede, Júlio e Murilo ― pela revisão e feedbacks</em></p>]]></content:encoded></item><item><title><![CDATA[List & Dict Comprehensions]]></title><description><![CDATA[Conhecendo melhor a sintaxe do Python para criar estruturas de forma mais prática]]></description><link>https://notasdobidu.com/comprehensions/</link><guid isPermaLink="false">5f0f75c5c2fc0a153543fcdb</guid><category><![CDATA[Python]]></category><category><![CDATA[Python-Iniciante]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Mon, 10 Aug 2020 22:56:00 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2020/08/comp2.png" medium="image"/><content:encoded><![CDATA[<img src="https://notasdobidu.com/content/images/2020/08/comp2.png" alt="List & Dict Comprehensions"><p>Listas e dicionários são duas estruturas de dados bastante usadas no dia-a-dia. Em resumo, listas servem para guardar sequências ordenadas de informações. Dicionários, por outro lado, permitem atrelar uma chave à um valor.</p><figure class="kg-card kg-code-card"><pre><code class="language-python">autores = ["Ramalho", "Bostrom", "Larson", "Pola", "Banks"]

dados = {
	"nome": "Bidu",
    "país": "Brasil"
}</code></pre><figcaption>Exemplo de uma lista e um dicionário</figcaption></figure><!--kg-card-begin: html--><aside class="toc"></aside><!--kg-card-end: html--><h2 id="uma-nota-sobre-nomenclatura">Uma Nota Sobre Nomenclatura</h2><p><strong><em>Compreensão de Listas</em></strong> — é um termo que tem se tornado mais comum em Português do Brasil! Ainda me soa estranho, mas provavelmente isso vem da minha falta de hábito com o termo. É bom ter uma expressão "nossa" para coisas técnicas. Obrigado ao grande <a href="https://twitter.com/villares">@villares</a> pelo toque!</p><p><em><strong>Sequência Ordenada </strong></em>— significa que a lista "lembra" a ordem em que os itens foram inseridos nela e não que esses itens serão <em>magicamente</em> ordenados como por exemplo em ordem alfabética ou algo do tipo. Em Inglês existem dois termos diferentes para isso: "<em>ordered"</em> para coisas como uma lista comum e "<em>sorted" </em>para uma lista que foi ordenada por algum critério como alfabético, crescente, etc</p><h2 id="criando-listas-com-comprehensions">Criando Listas com <em>Comprehensions</em></h2><p>Suponha que você queira gerar 1000 números inteiros de 0 a 100 e então você quer separar todos os números que estão acima da média:</p><pre><code class="language-python">from random import randint

# Cria 1000 números de 0 a 100
n = []
for _ in range(1000):
	n.append(randint(0, 100))
    
    
média = sum(n) / 1000

# Filtra os números
selecionados = []
for i in n:
	if i &gt;= média:
		selecionados.append(i)</code></pre><p>Esse exemplo mostra dois casos úteis para usarmos <em>list comprehensions:</em></p><ol><li>Criar uma lista com base na repetição de uma chamada de função</li><li>Criar uma lista com base em outra lista</li></ol><h3 id="criando-listas-por-repeti-o-de-chamadas">Criando Listas por Repetição de Chamadas</h3><p>A lista <code>n</code> contém o resultado de 1000 chamadas para a função <code>randint(0, 100)</code>. Nesse caso, aquele <em>loop for</em> pode ser reescrito assim:</p><pre><code class="language-python">n = [randint(0, 100) for _ in range(1000)]</code></pre><p>Note que a chamada da função foi para o começo, a estrutura do <em>loop</em> foi para depois da chamada da função e o <code>append</code> desapareceu. Essa é a estrutura geral de uma <em>list comprehension</em>:</p><pre><code class="language-python">lista = [elemento_para_adicionar for variável in iterador]</code></pre><p>Você pode usar a variável de iteração no cálculo do elemento que vai ser adicionado também. No meu exemplo eu usei <em>underline </em>porquê eu não precisava de fato do valor <code>[0...1000)</code>, eu só queria repetir algo mil vezes. Em Python, quando <em>precisamos</em> colocar uma variável em algum lugar mas a gente não <em>se importa</em> com o valor dela de fato, usamos <code>_</code> como nome.</p><h3 id="criando-listas-com-base-em-outra">Criando Listas com Base em Outra</h3><p>Agora nós já temos nossa lista de mil números aleatórios! A segunda parte do nosso código tinha essa cara:</p><pre><code class="language-python">média = sum(n) / 1000

# Filtra os números
selecionados = []
for i in n:
	if i &gt;= média:
		selecionados.append(i)</code></pre><p>A criação de uma lista com base em uma outra, checando se os itens satisfazem uma condição é um <em>filtro. </em>Podemos implementar essa estrutura também com uma <em>list comprehension</em>:</p><pre><code class="language-python">média = sum(n) / 1000

# Filtra os números
selecionados = [i for i in n if i &gt;= média]</code></pre><p>Observe como a estrutura foi modificada de forma muito parecida com a anterior ― a coisa que queremos colocar na lista foi pro começo, logo em seguida nós "embutimos" o <em>loop</em>. A diferença agora é que <em>depois</em> do loop colocamos uma condicional. Essa estrutura pode ser lida como</p><blockquote>"Adicione <code>i</code> em <code>selecionados</code> onde <code>i</code> são os elementos de <code>n</code> que possuem valor maior ou igual à <code>média</code>"</blockquote><h3 id="cuidado-com-abusos-de-nota-o-">Cuidado com Abusos de Notação!</h3><p><em>Comprehensions</em>  são estruturas bem legais e interessantes em Python. Porém, elas podem ser abusadas. A função principal de uma <em>comprehension</em> é <strong>criar uma estrutura</strong> com base em outra. Ou seja, você usa uma <em>comprehension</em> quando se interessa pelo <strong>resultado</strong> dela.</p><p>Um abuso possível é usar de <em>comprehensions</em> como substitutas genéricas de <em>loop for. </em>Por exemplo, podemos imprimir todos os números de 0 à 10 assim:</p><pre><code class="language-python">[print(i) for i in range(11)]</code></pre><p>A execução desse código será:</p><pre><code>0
1
2
3
4
5
6
7
8
9
10
Out[1]: [None, None, None, None, None, None, None, None, None, None, None]
</code></pre><p>Usar de <em>comprehensions</em> quando na verdade você se importa apenas com um <em>efeito colateral</em> da função invocada e não com a estrutura gerada, pode comprometer a legibilidade do seu código, além de te dar uma estrutura vazia.</p><blockquote>É tentador pensar que essa criação de lista também vai ter um impacto na performance. Isso eu deixo como Tarefa aos Leitores (TM). Dica: <a href="https://jakevdp.github.io/PythonDataScienceHandbook/01.07-timing-and-profiling.html">Profiling and Timing</a>. Fiquem à vontade para discutir isso comigo no <a href="https://twitter.com/fevir0">twitter</a> também</blockquote><p>Outro ponto de cuidado é o aninhamento extremo de coisas em uma <em>comprehension</em>. É possível fazer muita coisa com "one-liner", os código de uma linha só, e tem gente que adora coisas do tipo. Eu particularmente acho <em>legal</em> o poder que Python e outras linguagens tem de fazer isso, mas para códigos em produção que serão mantidos futuramente, eu evito. A foto de capa desse artigo é um <strong>péssimo</strong> exemplo de <em>comprehension.</em></p><p>A legibilidade do código é uma propriedade extremamente importante em equipes de software. Tomem cuidado com isso e não tenha medo de usar de <em>code reviews</em> para discutir com seus colegas e validar que sua solução está legível! Legibilidade é um conceito subjetivo e divergências podem acontecer.</p><hr><h2 id="criando-dicion-rios-com-comprehensions">Criando Dicionários com Comprehensions</h2><p>Assim como listas, dicionários também podem ser criados com <em>comprehensions. </em>Suponha que eu queira construir um dicionário onde a chave é um número e o valor é esse número ao quadrado. Podemos fazer com um <em>loop for</em> normal:</p><pre><code class="language-python">quadrados = {}

for i in range(100):
	quadrados[i] = i ** 2</code></pre><p>Esse código irá nos dar o dicionário:</p><pre><code class="language-python">{0: 0,
 1: 1,
 2: 4,
 3: 9,
 4: 16,
 5: 25,
 6: 36,
 7: 49,
 8: 64,
 9: 81,
 10: 100,
(...)</code></pre><p>Observe que dicionários, diferente de listas, são inicializados com <code>{ }</code> ao invés de <code>[ ]</code>. Isso será refletido na <em>dict comprehension</em> também:</p><pre><code class="language-python">quadrados = {i: i**2 for i in range(100)}</code></pre><p>Note como essa estrutura é muito similar à de uma <em>list comprehension, </em>com a diferença que agora temos um par <code>chave: valor</code>. Podemos ler esse código como</p><blockquote>"Adicione <code>i</code> como chave, <code>i ao quadrado</code> como valor, para cada <code>i</code> de 0 até 99"</blockquote><h3 id="filtrando-dicion-rios">Filtrando Dicionários</h3><p>Temos nosso dicionário de números e seus valores ao quadrado! Vamos fazer duas separações ― separar todas as chaves pares e separar todos os valores que são maiores que 100. Como dicionários, ao contrário de listas, possuem duas "entidades" para cada entrada, podemos filtrar por cada uma delas.</p><p>Para filtrar as chaves pares, podemos fazer algo do tipo:</p><pre><code class="language-python">chaves_pares = {}

for chave in quadrados:
	if chave % 2 == 0:
    	chaves_pares[chave] = quadrados[chave]</code></pre><p>Esse código vai nos dar:</p><pre><code class="language-python">{0: 0,
 2: 4,
 4: 16,
 6: 36,
 8: 64,
 10: 100,
 12: 144,
 14: 196,
 16: 256,
(...)</code></pre><blockquote>"Bidu, mas e o método <code>items</code> em dicionários?" Vamo um passo de cada vez :D</blockquote><p>Esse loop for pode ser reescrito de maneira similar com a filtragem de listas:</p><pre><code class="language-python">chaves_pares = {chave: quadrados[chave] for chave in quadrados if chave % 2 == 0}</code></pre><p>De novo, temos uma estrutura que evolui da criação normal usando <em>comprehensions</em>, acrescentando uma condicional ao final. Podemos ler como </p><blockquote>"Adicione <code>chave</code> com o mesmo valor que ela possui em <code>quadrados</code>, para cada <code>chave</code> em <code>quadrados</code>, se o resto da divisão da chave por 2 for 0"</blockquote><h3 id="filtrando-valores">Filtrando Valores</h3><p>O segundo problema que propus foi filtrar todos os <em>valores</em> maiores do que 100. Uma iteração comum em dicionários, <code>for x in dicionário</code>, faz um loop através <strong>apenas das chaves</strong>. Porém, podemos utilizar da seguinte sintaxe: <code>for chave, valor in dicionário.items()</code>. Ela nos permite iterar pelas chaves e valores de uma só vez:</p><pre><code class="language-python">data = {"nome": "Bidu", "país": "Brasil"}

for chave, valor in data.items():
	print(f"O valor de {chave} é {valor}")   </code></pre><p>Esse código imprime</p><pre><code class="language-python">O valor de nome é Bidu
O valor de país é Brasil</code></pre><p>Nosso filtro pode ser implementado assim:</p><pre><code class="language-python">valores_grandes = {}

for chave, valor in quadrados.items():
	if valor &gt; 100:
		valores_grandes[chave] = valor</code></pre><p>Esse código irá nos retornar:</p><pre><code>{11: 121,
 12: 144,
 13: 169,
 14: 196,
 15: 225,
 16: 256,
 17: 289,
 18: 324,
 (...)</code></pre><p>E ele também pode virar uma <em>comprehension!</em></p><pre><code class="language-python">valores_grandes = {c: v for c, v in quadrados.items() if v &gt; 100}</code></pre><p>Essa comprehension pode ser lida como</p><blockquote>"Adicione <code>chave</code> com o mesmo <code>valor</code> que ela possui em <code>quadrados</code>, para cada <code>chave</code> e <code>valor</code> em <code>quadrados</code>, se <code>valor</code> for maior do que 100</blockquote><hr><h2 id="resumo">Resumo</h2><p>Nesse post eu discuti sobre como <em>comprehensions</em> são uma sintaxe útil do Python para quando queremos <strong>criar </strong>estruturas com base em outras ― seja filtrando ou transformando os valores originais ― ou com base em repetições de uma certa computação.</p><p>Fica também o alerta quanto ao <em>abuso</em> dessas estruturas, <em>comprehensions </em>não são um "<em>loop</em> <em>for</em> chique", elas servem apenas para substituir um tipo específico de <em>loop </em>― quando queremos criar uma estrutura nova.</p><p>Não são apenas listas e dicionários que suportam <em>comprehensions</em>, elas também são compatíveis com outras estruturas como <em>sets</em> e tuplas!</p>]]></content:encoded></item><item><title><![CDATA[Autoformatação de Código ― Quando e Como]]></title><description><![CDATA[Uma descrição da minha jornada desde não gostar de formatadores automáticos até usá-los em tudo]]></description><link>https://notasdobidu.com/autoformat-black/</link><guid isPermaLink="false">5f0f594e377cfc3b482bf1c4</guid><category><![CDATA[Python]]></category><category><![CDATA[Black]]></category><dc:creator><![CDATA[Felipe Bidu]]></dc:creator><pubDate>Wed, 15 Jul 2020 20:59:31 GMT</pubDate><media:content url="https://notasdobidu.com/content/images/2020/07/header.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="introdu-o">Introdução</h2><img src="https://notasdobidu.com/content/images/2020/07/header.jpg" alt="Autoformatação de Código ― Quando e Como"><p>Fazer um código legível e bonito é algo importante no nosso dia-a-dia, especialmente quando colaboramos com demais colegas. Um código que é mal formatado e mal estruturado é cansativo de ler e difícil de compreender.</p><p>A formatação de um código é só um pedaço da história, mas um pedaço muito importante. Ela não é a única responsável pela legibilidade do código ― <strong>um projeto mal estruturado, feito de classes e funções com responsabilidades mal definidas pode até ser bem formatado, mas será difícil de compreender. </strong></p><hr><p>No começo de minha carreira, eu não gostava muito da ideia de formatação automática de código. Por um lado, eu a<strong>cho que eu era um pouco orgulhoso em relação à isso e não estava afim de perder "controle" do meu código</strong>. Por outro lado, mais de 10 anos atrás, essas ferramentas não eram exatamente boas, pelo menos não as que eu conhecia.</p><p>Quanto ao primeiro argumento, hoje eu vejo essa resistência à perda do "controle" como algo meio bobo. <strong>A formatação do código por mais importante que seja, não é exatamente o foco do trabalho de um desenvolvedor ou sua finalidade</strong>. O centro do nosso trabalho é a abstração de problemas do mundo real para dentro de um algoritmo e a solução desse problema através de ferramentas computacionais, levando em consideração as restrições de projeto que temos.</p><p>Além disso, se nosso código deve seguir um livro de estilo padronizado ― como é cada vez mais comum atualmente ― qual é o mérito em gastar tempo e esforço para cumprir um padrão definido? Humanos são bons em criar, em fazer coisas novas. É aí que mora nosso diferencial, <strong>o que for automatizável, podemos deixar que o computador faça por nós e nos deixe mais livres</strong>.</p><p>Já em relação ao segundo argumento, hoje nós <strong>temos diversas ferramentas de formatação automática que são cada vez mais robustas.</strong> O foco do restante desse artigo é o <a href="https://github.com/psf/black">Black</a>, um formatador automático para Python.</p><h2 id="black">Black</h2><p>A instalação do Black pode ser feita usando <code>pip install black</code> . Se seu ambiente estiver bem configurado, você conseguirá digitar <code>black --help</code> em seu terminal e ver algumas de suas opções de uso. Caso você queira, pode explorar o funcionamento dele no <a href="https://black.now.sh">Black Playground</a>.</p><p>O Black <strong>permite diversas formas de execução</strong>. Podemos, por exemplo, invocá-lo direto da linha de comando com uma string de código:</p><pre><code class="language-bash">black -c "x=2  * 3+4"</code></pre><p>E ele te retornará a expressão propriamente formatada, <code>x = 2 * 3 + 4</code> com os espaços corretos.</p><h2 id="explorando-erros-com-pylint">Explorando Erros com Pylint</h2><p>Considere agora esse código, bem mal formatado mas ainda assim é válido:</p><pre><code class="language-python">
def fatorial(n):

    result=1

    for i in(range(1, n+1)):
        result*=i
    return result

print(  fatorial(   3))
print(fatorial(2     ))
print(fatorial(10     ))</code></pre><p>Uma forma de avaliarmos a situação desse código é usando o <code>pylint</code>. Esse arquivo está salvo em minha máquina como "black_sample01.py". Rodando <code>pylint black_sample01.py</code> , nos dá a seguinte resposta:</p><pre><code>
************* Module black_sample01
black_sample01.py:2:10: C0326: Exactly one space required around assignment

    result=1

          ^ (bad-whitespace)

black_sample01.py:7:0: C0325: Unnecessary parens after 'in' keyword (superfluous-parens)
black_sample01.py:8:14: C0326: Exactly one space required around assignment

        result*=i
              ^^ (bad-whitespace)

black_sample01.py:11:5: C0326: No space allowed after bracket
print(  fatorial(   3))

     ^ (bad-whitespace)

black_sample01.py:11:16: C0326: No space allowed after bracket
print(  fatorial(   3))

                ^ (bad-whitespace)

black_sample01.py:12:21: C0326: No space allowed before bracket
print(fatorial(2     ))

                     ^ (bad-whitespace)

black_sample01.py:13:0: C0304: Final newline missing (missing-final-newline)
black_sample01.py:13:22: C0326: No space allowed before bracket
print(fatorial(10     ))

                      ^ (bad-whitespace)

black_sample01.py:1:0: C0114: Missing module docstring (missing-module-docstring)
black_sample01.py:1:0: C0103: Argument name "n" doesn't conform to snake_case naming style (invalid-name)
black_sample01.py:1:0: C0116: Missing function or method docstring (missing-function-docstring)

--------------------------------------------------------------------
Your code has been rated at -3.75/10
</code></pre><p>Existem erros de parênteses desnecessários, erros de espaço em branco e várias linhas desnecessárias também. Podemos agora explorar o <code>black</code>.</p><h2 id="verificando-poss-veis-mudan-as">Verificando Possíveis Mudanças</h2><p>Chamando o black com a flag <code>--check</code> , ele apenas nos conta se o arquivo seria reformatado ou não. <strong>Isso é útil para usar em servidores de CI e evitar que arquivos mal formatados subam para a base:</strong></p><pre><code class="language-bash">$ black --check black_sample01.py

would reformat black_sample01.py
Oh no! 💥 💔 💥
1 file would be reformatted.
</code></pre><p>(<em>Mais sobre CI e ferramentas assim em breve!</em>) </p><p>Nós podemos usar a flag <code>--diff</code> para ver as mudanças que seriam feitas</p><pre><code class="language-bash">$ black --diff black_sample01.py

--- black_sample01.py	2020-05-20 13:52:23.495800 +0000
+++ black_sample01.py	2020-05-20 13:55:56.786380 +0000
@@ -2, 19 +2, 16 @@
 Módulo que oferece um fatorial iterativo
 """

 def fatorial(n):

*    result=1
*    result = 1

-
-
-

*    for i in(range(1, n+1)):
*        result*=i
*    for i in range(1, n + 1):
*        result *= i

     return result

+print(fatorial(3))
+print(fatorial(2))
+print(fatorial(10))

-print(  fatorial(   3))
-print(fatorial(2     ))
-print(fatorial(10     ))
reformatted black_sample01.py
All done! ✨ 🍰 ✨
1 file reformatted.</code></pre><p>Honestamente, é meio raro eu usar essas duas flags no meu dia-a-dia. Uma situação em que eu costumo usar a <code>--diff</code> é <strong>quando eu estou trabalhando em uma base de código pela primeira vez e estou pensando se vou ou não sugerir uma mudança de estilo</strong>. Rodar o <code>--diff</code> me permite estimar o quão trabalhoso seria reformatar a base toda. Já a flag <code>--check</code> eu uso em servidores de CI (Integração Contínua) mesmo.</p><h2 id="reformatando-com-black-">Reformatando com Black!</h2><p>E finalmente a reformatação é bem direta. Basta invocar o <code>black</code> sem flags e com o arquivo:</p><pre><code class="language-bash">$ black black_sample01.py

reformatted black_sample01.py
All done! ✨ 🍰 ✨
1 file reformatted.</code></pre><p>O arquivo em si será modificado:</p><pre><code class="language-python">"""
Módulo que oferece um fatorial iterativo
"""

def fatorial(n):
    result = 1

    for i in range(1, n + 1):
        result *= i
    return result

print(fatorial(3))
print(fatorial(2))
print(fatorial(10))
</code></pre><hr><h2 id="usando-black-no-dia-a-dia">Usando Black no Dia-a-Dia</h2><!--kg-card-begin: markdown--><p>Okay, formatamos <em>um</em> arquivo! Mas como garantir isso ao longo do processo?<br>
Eu gosto de usar três abordagens diferentes:</p>
<ul>
<li>Direto no meu editor de texto</li>
<li>Como um hook <em>pre-commit</em> no git</li>
<li>No servidor de CI</li>
</ul>
<p>A parte do hook e do CI merecem um artigo só pra elas. Quanto ao editor, seja lá qual for, ele <a href="https://github.com/psf/black/blob/master/docs/editor_integration.md">provavelmente já tem uma integração com o Black</a>.</p>
<p>Ultimamente, tenho usado o <a href="https://code.visualstudio.com/">VSCode</a> como editor principal. A configuração no VSCode pode ser global ou específica de projeto. Uma vez habilitado, você pode autoformatar seu código apertando <code>CTRL + Shift + I</code></p>
<!--kg-card-end: markdown--><h3 id="configura-o-global">Configuração Global</h3><p>No caso da configuração global, abra as configurações em <code>File &gt; Preferences &gt; Settings</code> ou digite <code>CTRL + ,</code> . Na barra de busca, digite "python formatting provider". Você deverá ver essa opção:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://notasdobidu.com/content/images/2020/07/vscode-black.png" class="kg-image" alt="Autoformatação de Código ― Quando e Como"></figure><p>Selecione "black" na lista e pronto!</p><h3 id="configura-o-local">Configuração Local</h3><p>A configuração local de projetos é feita através do arquivo <code>.vscode/settings.json</code>. Basta adicionar nele a chave <code>"python.formatting.provider": "black"</code> para habilitar o black no seu projeto atual.</p><h2 id="autoformatar-ao-salvar-ou-n-o">Autoformatar ao Salvar ou Não?</h2><p>Tudo isso que a gente fez habilitou a invocação <code>manual</code> do Black ― você precisa apertar <code>CTRL + Shift + I</code> para formatar o código. O VSCode e muitos outros editores dão uma outra opção ― autoformatar ao salvar.</p><p>Particularmente, eu deixo essa opção desativada nas configurações globais. <strong>Muitas vezes eu trabalho em código que envolve outros colegas, em projetos que não usam black ou que simplesmente possuem um padrão de formatação diferente. Autoformatar nesses casos é ruim.</strong> Quando trabalho em projetos novos, deixo habilitado!</p><p>Projetos com código "feio" ou seguindo um padrão de formatação diferente, podem ser problemáticos. <strong>Mas mais problemático ainda é quebrar a consistência interna do projeto</strong>. Usar <code>CamelCase</code> para dar nomes em variáveis não é comum em Python e o <code>PyLint</code> vai reclamar disso. Porém, se você está trabalhando em um projeto que usa CamelCase para tudo, <strong>mantenha a consistência e ― talvez ― proponha a mudança de padrão em um segundo momento</strong>. Mas isso é assunto pra outro post!</p>]]></content:encoded></item></channel></rss>