<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Programacao | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/programacao/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/programacao/index.xml" rel="self" type="application/rss+xml"/><item><title>VS Code é o novo Cartão Perfurado</title><link>https://akitaonrails.github.io/2026/04/11/vs-code-e-o-novo-cartao-perfurado/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/11/vs-code-e-o-novo-cartao-perfurado/</guid><pubDate>Sat, 11 Apr 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Toda vez que alguém pergunta se os júniors vão deixar de aprender a programar porque LLMs escrevem código, eu tenho a mesma reação: vocês estão fazendo a pergunta errada.&lt;/p&gt;
&lt;p&gt;Vocês estão confundindo &lt;strong&gt;input de código&lt;/strong&gt; com &lt;strong&gt;engenharia de software&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Não é a mesma coisa. Nunca foi.&lt;/p&gt;
&lt;p&gt;Teve uma época em que programar significava saber converter números pra binário de cor e enfiar instrução direto em endereço de memória, bit por bit, na mão. Teve uma época em que programar significava saber organizar baralho de cartão perfurado, saber que ordem do deck estava certa, saber onde um furo errado destruiu a execução, e saber debugar visualmente sem a fantasia moderna de backspace infinito. Teve uma época em que programar de verdade significava saber 6502, Z80 e Assembly porque os computadores tinham tão pouco recurso que cada byte importava mesmo, não como figura de linguagem.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Toda vez que alguém pergunta se os júniors vão deixar de aprender a programar porque LLMs escrevem código, eu tenho a mesma reação: vocês estão fazendo a pergunta errada.</p>
<p>Vocês estão confundindo <strong>input de código</strong> com <strong>engenharia de software</strong>.</p>
<p>Não é a mesma coisa. Nunca foi.</p>
<p>Teve uma época em que programar significava saber converter números pra binário de cor e enfiar instrução direto em endereço de memória, bit por bit, na mão. Teve uma época em que programar significava saber organizar baralho de cartão perfurado, saber que ordem do deck estava certa, saber onde um furo errado destruiu a execução, e saber debugar visualmente sem a fantasia moderna de backspace infinito. Teve uma época em que programar de verdade significava saber 6502, Z80 e Assembly porque os computadores tinham tão pouco recurso que cada byte importava mesmo, não como figura de linguagem.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/altair-8800-computer.jpg" alt="Altair 8800, símbolo da era em que programar ainda passava por painéis físicos e entrada manual de instruções"  loading="lazy" /></p>
<p><em>Painel frontal e switches: antes de editor, antes de IDE, antes de terminal confortável.</em></p>
<p>E olha, tem fase da computação que foi ainda pior que cartão perfurado. Esse vídeo abaixo mostra alguém programando num LGP-21, um dos computadores pessoais mais antigos do mundo (o segundo mais velho, depois do Bendix G15 dos anos 50). Começa a partir do minuto 5:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/TJjRCCetyo4?start=300"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Imagina o que isso era: você digitava o programa em binário direto numa máquina de escrever, olhando pro acumulador, instrução por instrução, depois virava uma alavanca fisicamente pra executar, e o resultado era datilografado de volta em papel. A métrica não era framerate. Era caractere por minuto. Uma operação que hoje você faz num piscar de olho dentro de qualquer aplicativo, ali demorava horas de trabalho humano, digitando bit a bit, conferindo, testando, conferindo de novo.</p>
<p>É a mesma coisa que tá acontecendo com digitar código em editor de texto hoje versus agente de IA rodando no seu lugar. O jeito manual continua funcionando, do mesmo jeito que o painel do Altair continuou funcionando por anos depois que compilador ficou comum. Mas a ferramenta de escolha virou outra, e a diferença de velocidade e esforço é exatamente a mesma ordem de magnitude que separava o LGP-21 do editor de texto moderno. A nossa geração tá vendo essa transição acontecer em câmera lenta, e muita gente não quer ver.</p>
<p>Depois vieram compiladores melhores. Veio C. Vieram máquinas mais gordas, consoles 32/64 bits, PCs mais decentes, e Assembly deixou de ser o centro de tudo pra virar ferramenta de baixo nível, otimização localizada, rotina crítica, inicialização, driver, essas coisas. Ninguém sério olhou pra essa transição e falou: &ldquo;pronto, agora acabou a programação porque o compilador escreve as instruções de máquina pra você.&rdquo;</p>
<p>No século 21 veio a Web e empurrou uma geração inteira pra HTML, CSS e um monte de burocracia de markup que agrega pouco valor intelectual e exige muito trabalho braçal pra ficar minimamente certo. Eu continuo achando que a indústria estendeu demais a vida útil desse modelo. Por anos demais, programador virou operador de formulário glorificado, montador de CRUD, alinhador de <code>div</code>, sacerdote de framework de front-end que faz a mesma coisa com sintaxe diferente.</p>
<p>E aí a bolha dos anos 2010 piorou tudo.</p>
<p>Eu já escrevi sobre isso em <a href="/2026/02/08/rant-ia-acabou-com-programadores/">RANT: IA acabou com os programadores?</a> e também no <a href="/2026/03/05/37-dias-de-imers%C3%A3o-em-vibe-coding-conclus%C3%A3o-quanto-a-modelos-de-neg%C3%B3cio/">37 dias de Imersão em Vibe Coding</a>. A bolha das startups, o dinheiro barato e a fome de contratação produziram uma legião de programadores muito ruins, saídos de bootcamps de dois meses e cursinhos prometendo salário de Google sem base, sem formação e sem profundidade. O mercado passou uma década fingindo que isso era normal. Não era. Era a mesma história de sempre: muito volume, pouco valor agregado, muita gente confundindo empregabilidade inflada com competência real.</p>
<p>E quando os layoffs começaram em 2022, isso não caiu do céu. Eu passei anos avisando que a bolha ia estourar. Tá tudo registrado na playlist <a href="https://www.youtube.com/watch?v=wpPv1dJWjDs&amp;list=PLdsnXVqbHDUehzKjiRruy--gncHz9Injy&amp;pp=sAgC"target="_blank" rel="noopener">EU AVISEI</a>. A mensagem sempre foi a mesma: quando o dinheiro barato acabasse, a régua subiria de novo, e só teria chance quem tivesse feito o esforço de aprender Ciência da Computação de verdade. O novo ciclo econômico seria menos sobre volume de contratação e mais sobre eficiência. Foi exatamente o que aconteceu.</p>
<h2>O que mudou de verdade<span class="hx:absolute hx:-mt-20" id="o-que-mudou-de-verdade"></span>
    <a href="#o-que-mudou-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>LLMs ficaram populares no fim de 2022. Isso é fato. Mas popular não é a mesma coisa que útil pra projeto sério.</p>
<p>Entre 2023 e 2024, eu já usava IA pra escrever código. Funcionava? Funcionava. Mas ainda era cheio de chatice: alucinação demais, loop agente demais, contexto se perdendo fácil demais, ferramenta quebrando demais, custo alto demais pra pouca confiabilidade. Era útil pro programador experiente que sabia segurar o bicho na coleira. Ainda não era ferramenta madura pra trabalho pesado do dia a dia.</p>
<p>Pra mim, a virada veio no fim de 2025. Foi quando a combinação de melhores modelos, prompt caching, tool calling decente, otimizações de inferência, janelas de contexto mais úteis na prática, e principalmente interfaces de agentes de verdade fizeram a coisa parar de parecer demo de conferência e começar a parecer ferramenta de trabalho.</p>
<p>Foi aí que Claude Code, Codex, OpenCode e similares deixaram de ser &ldquo;autocomplete turbinado&rdquo; e viraram outra categoria de interface.</p>
<p>Pra mim, Claude Code já virou o novo terminal. O editor ficou em segundo plano.</p>
<p>Eu falei disso também em <a href="/2026/03/31/migrando-meu-home-server-com-claude-code/">Migrando meu Home Server com Claude Code</a>. Eu simplesmente não tenho mais paciência pra gastar atenção com trabalho braçal de shell Linux quando o problema é mundano: instalar servidor, subir e organizar serviços Docker, endurecer firewall, revisar regra de segurança, ajustar parâmetro de kernel, auditar <code>dmesg</code>, caçar log de systemd, esse tipo de coisa. Eu mando o Claude fazer o grosso, eu reviso direção e risco. E, ironicamente, meus Linux nunca pareceram tão estáveis, rápidos e robustos.</p>
<p>Hoje, pra quem trabalha o dia inteiro construindo software, voltar pro combo cru de editor de texto mais terminal e fazer tudo manualmente começa a parecer regressão. Não porque digitar ficou impossível. Claro que não. Eu digitei código por décadas. O problema é outro: virou desperdício de atenção.</p>
<p>Se eu posso descrever uma intenção, pedir pra um agente vasculhar o código, editar vinte arquivos, rodar teste, compilar, corrigir, e me devolver uma proposta de mudança em minutos, por que exatamente eu vou sentir nostalgia de ficar digitando boilerplate na unha dentro do VS Code?</p>
<p>Não vou.</p>
<p>E aqui entra uma distinção que muita gente ainda não entendeu. Não é pra usar agente de código como se fosse extensão burra de editor, no estilo &ldquo;gera esse arquivinho aqui&rdquo; e você fica microgerenciando cada linha no canto da tela. Isso é usar Ferrari pra ir comprar pão na esquina. O ganho grande não vem de tratar Claude Code, Codex ou similares como autocomplete glorificado dentro do VS Code. O ganho vem quando você larga a mentalidade de operador de editor e passa a tratar o agente como pair programmer de verdade.</p>
<p>Em vez de agir como digitador profissional, você sobe um nível. Age mais como tech lead, product owner, QA, gerente do fluxo. Define a intenção, explica contexto, cobra critério, pede plano, manda rodar teste, pede refatoração, pede comparação de alternativas, pede revisão da própria mudança. Deixa o trabalho braçal do código com o agente e usa sua cabeça pra julgar direção, prioridade, risco e qualidade.</p>
<p>Mas tem um equilíbrio aí que eu já comentei em outros posts de Agile Vibe Coding. Não é pra largar o volante e deixar a LLM dar <code>git push</code> cega em tudo. E também não é pra cair no extremo oposto e virar fiscal de vírgula, nitpickando cada detalhe pequeno até o agente virar mais uma burocracia e matar o ganho de velocidade. Os dois extremos são ruins. Num extremo você terceiriza responsabilidade. No outro você estrangula produtividade.</p>
<p>O ponto certo do pêndulo é outro: usar práticas de XP e engenharia de verdade pra sustentar a velocidade. Refactoring contínuo. Testes. CI. Revisão. Feedback rápido. Código pequeno. Mudança incremental. Foi exatamente isso que eu vim documentando em posts como <a href="/2026/02/20/do-zero-a-pos-producao-em-1-semana-como-usar-ia-em-projetos-de-verdade-bastidores-do-the-m-akita-chronicles/">Do Zero à Pós-Produção em 1 Semana - Como usar IA em Projetos de Verdade</a> e <a href="/2026/03/01/software-nunca-esta-pronto-4-projetos-a-vida-pos-deploy-e-por-que-one-shot-prompt-e-mito/">Software Nunca Está &lsquo;Pronto&rsquo;</a>. O multiplicador de 10x não vem da mágica do modelo. Vem do modelo somado a processo decente.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/cursor-homepage-crop.png" alt="Interface moderna de agente de código, representando a transição do editor tradicional para uma interface orientada a intenção e execução assistida"  loading="lazy" /></p>
<p><em>A interface mudou. O que continua igual é a necessidade de julgamento.</em></p>
<h2>VS Code é o novo cartão perfurado<span class="hx:absolute hx:-mt-20" id="vs-code-é-o-novo-cartão-perfurado"></span>
    <a href="#vs-code-%c3%a9-o-novo-cart%c3%a3o-perfurado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>É isso que o título quer dizer.</p>
<p>VS Code não &ldquo;ficou ruim&rdquo;. Não é isso. Cartão perfurado também não era &ldquo;ruim&rdquo; no contexto histórico dele. Foi uma evolução brutal em relação a digitar bit na mão ou religar fio. O ponto é que ele era o mecanismo da era dele pra informar instruções à máquina.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/punched-card-program-deck.jpg" alt="Deck de cartões perfurados, quando a profissão exigia mais disciplina na preparação do input do que conforto na interface"  loading="lazy" /></p>
<p><em>VS Code não é o inimigo. Ele só está virando o mecanismo de input da era anterior.</em></p>
<p>Hoje, editor de texto está virando isso de novo: um mecanismo de input que ainda funciona, ainda vai existir por muito tempo, mas que já não é mais o centro da atividade.</p>
<p>Se você nunca viu essa história das eras mais antigas da computação, eu já expliquei isso em <a href="/2020/10/23/akitando-86-o-computador-de-turing-e-von-neumann-por-que-calculadoras-nao-sao-computadores/">Akitando #86 - O Computador de Turing e Von Neumann</a>:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/G4MvFT8TGII"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>E se quiser relembrar por que 6502, Z80 e as máquinas antigas forçavam outro tipo de disciplina, revisita o <a href="/2020/06/04/akitando-80-o-guia-hardcore-de-introducao-a-computacao/">Guia +Hardcore de Introdução à Computação</a> e o episódio <a href="/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/">Aprendendo sobre Computadores com Super Mario (do jeito Hardcore++)</a>. Aquilo não era nostalgia de velho. Era pra mostrar que, em cada era, a interface muda, mas a máquina continua exigindo precisão.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/akitando-80-6502.jpg" alt="Thumbnail do Akitando #80, parte da série feita para ensinar fundamentos de computação usando a era 6502 e microcomputadores como ponto de partida"  loading="lazy" /></p>
<p><em>Foi pra isso que boa parte do Akitando existiu: ensinar o que continua valendo quando a ferramenta da moda muda.</em></p>
<p>Aliás, vale lembrar uma coisa que muita gente esquece: os 146 vídeos do <a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener">Akitando</a>, mais de 96 horas de conteúdo, foram feitos justamente pra ensinar esse tipo de fundamento pra estudante de Ciência da Computação, júnior e pra quem queria deixar de ser apertador de framework. Eu gravei aquilo porque já via a indústria empurrando gente demais pra tarefa braçal e entendimento de menos. Ironicamente, agora que os agentes chegaram, esse acervo ficou mais relevante do que nunca.</p>
<p>Hoje a interface mudou de novo.</p>
<p>Antes você precisava saber como digitar a instrução.
Depois você precisava saber como ordenar o deck.
Depois você precisava saber como convencer o compilador.
Depois você precisava saber como costurar framework, HTML, CSS, YAML, CI, container, cloud, ORM, fila, observabilidade e mais cinquenta camadas de parafernália.</p>
<p>Agora você precisa saber como <strong>orquestrar um agente</strong>.</p>
<p>E isso, de novo, não elimina fundamento. Só muda o ponto onde o trabalho braçal termina e o trabalho intelectual começa.</p>
<h2>&ldquo;Então não precisa mais aprender Ciência da Computação?&rdquo;<span class="hx:absolute hx:-mt-20" id="então-não-precisa-mais-aprender-ciência-da-computação"></span>
    <a href="#ent%c3%a3o-n%c3%a3o-precisa-mais-aprender-ci%c3%aancia-da-computa%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Pelo contrário.</p>
<p>Agora precisa mais.</p>
<p>O sujeito sem base olha pro agente fazendo um <code>SELECT * FROM table</code>, vê o negócio funcionando localmente com 300 linhas na base fake, e acha que tá tudo certo. Em produção a query puxa um milhão de linhas, explode memória, degrada latência, derruba fila, congestiona conexão, e o cidadão não faz a menor ideia de por que &ldquo;na minha máquina funciona&rdquo;.</p>
<p>Esse é o problema real.</p>
<p>O agente não sabe o contexto do seu sistema do jeito que um engenheiro experiente sabe. Ele não sabe quais tabelas vão crescer dez vezes no próximo trimestre. Ele não sabe qual endpoint precisa responder em 80 ms e qual pode levar 2 segundos. Ele não sabe qual fluxo precisa de transação, qual precisa de idempotência, qual precisa de lock pessimista, qual precisa de compensação assíncrona, qual precisa de auditoria, qual não pode jamais vazar dado sensível.</p>
<p>Ele pode até acertar a sintaxe.</p>
<p>Só que sintaxe nunca foi a parte mais difícil.</p>
<p>Eu já falei isso no <a href="/2026/02/24/rant-o-akita-abriu-as-pernas-pra-ia/">RANT: o Akita abriu as pernas pra IA??</a>: o que IA faz muito bem é remover as tarefas mundanas. E graças a deus. Eu não entrei em computação pra virar operador de IDE. Eu não sinto nenhum apego romântico por ficar formatando HTML, brigando com CSS, montando CRUD de sempre, colando framework novo em stack velha, ou escrevendo pela centésima vez o mesmo monte de código de infraestrutura que qualquer máquina decente já deveria conseguir produzir.</p>
<p>Mas o que sobra depois que essa camada mundana some?</p>
<p>Sobra justamente a parte que separa amador de programador de verdade:</p>
<ul>
<li>modelagem de domínio</li>
<li>arquitetura</li>
<li>trade-off</li>
<li>performance</li>
<li>escalabilidade</li>
<li>segurança</li>
<li>observabilidade</li>
<li>manutenção</li>
<li>legibilidade</li>
<li>custo operacional</li>
<li>decisão de produto</li>
</ul>
<p>Tudo isso continua existindo. Tudo isso continua sendo difícil. Tudo isso continua dependendo de julgamento.</p>
<h2>O erro da turma que acha que programar era digitar<span class="hx:absolute hx:-mt-20" id="o-erro-da-turma-que-acha-que-programar-era-digitar"></span>
    <a href="#o-erro-da-turma-que-acha-que-programar-era-digitar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem gente realmente achando que, se a máquina escreve o código, então acabou a necessidade de saber software.</p>
<p>Isso é a mesma burrice de achar que compilador matou a necessidade de entender computador.</p>
<p>Não matou.</p>
<p>Só matou a necessidade de ficar escrevendo Assembly pra tudo.</p>
<p>E ainda bem.</p>
<p>Da mesma forma, agente de código não mata a necessidade de entender software. Mata a necessidade de você ser datilógrafo de sintaxe.</p>
<p>E ainda bem.</p>
<p>Aliás, tem uma ironia bonita aqui: durante anos a indústria vendeu a fantasia de que programar era &ldquo;aprender framework&rdquo;. Depois vendeu a fantasia de que programar era &ldquo;aprender React&rdquo;. Depois vendeu a fantasia de que programar era &ldquo;aprender a stack do momento&rdquo;. Agora vai vender a fantasia de que programar é &ldquo;aprender prompt&rdquo;.</p>
<p>Também não é.</p>
<p>Prompt é interface.
Framework é interface.
IDE é interface.
Cartão perfurado era interface.</p>
<p>Programação continua sendo o ato de instruir uma máquina a computar algo útil dentro de restrições reais.</p>
<p>Quem entende isso sobrevive a qualquer mudança de ferramenta.
Quem não entende vira operador da ferramenta da moda e, quando a moda muda, dança junto.</p>
<h2>O que eu acho que vai acontecer com os júniors<span class="hx:absolute hx:-mt-20" id="o-que-eu-acho-que-vai-acontecer-com-os-júniors"></span>
    <a href="#o-que-eu-acho-que-vai-acontecer-com-os-j%c3%baniors" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Então vamos responder a pergunta original direito.</p>
<p>Os júniors não vão deixar de aprender.</p>
<p>Mas vão ter que aprender <strong>outra coisa</strong>.</p>
<p>Se o júnior de 2015 conseguia passar anos escondendo ignorância atrás de tarefa braçal de baixo valor, mexendo em view, ajustando CSS, montando endpoint bobo, copiando snippet de Stack Overflow e fazendo parecer que estava &ldquo;produzindo&rdquo;, esse esconderijo está acabando.</p>
<p>O júnior da era dos agentes vai subir de nível mais rápido ou vai ser exposto mais rápido. Não tem muito meio-termo.</p>
<p>Se ele usar agente e realmente estudar fundamento, ele vai conseguir testar hipótese mais rápido, ler mais código, comparar mais soluções, iterar mais, errar mais cedo e corrigir mais cedo. Vai aprender mais em menos tempo.</p>
<p>Mas se ele usar agente sem fundamento, ele vai só terceirizar a própria ignorância. Vai virar revisor incapaz de revisar. Vai aceitar patch que não entende. Vai aprovar decisão que não sabe medir. Vai confundir &ldquo;passou no teste local&rdquo; com &ldquo;está pronto pra produção&rdquo;.</p>
<p>Esse profissional é perigoso.</p>
<p>Muito mais perigoso do que o júnior antigo que ao menos era limitado pela própria lentidão.</p>
<h2>O pós-bolha<span class="hx:absolute hx:-mt-20" id="o-pós-bolha"></span>
    <a href="#o-p%c3%b3s-bolha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A boa notícia é que isso vem logo depois do colapso da fase mais idiota da bolha de contratação.</p>
<p>Já passou da hora de o mercado parar de premiar trabalho intensivo e burro como se fosse competência. Já passou da hora de parar de tratar burocracia de stack como profundidade técnica. Já passou da hora de parar de confundir volume de commit com valor de engenharia.</p>
<p>Se a nova era elimina uma parte grande desse teatro, ótimo.</p>
<p>Num cenário pós-bolha, pós-bootcamp milagroso, pós-CSS como carreira, pós-CRUD como profissão, fundamento volta a ser o que sempre deveria ter sido: o ativo principal.</p>
<p>Quem entende sistema operacional, banco de dados, rede, estrutura de dados, compiladores, arquitetura de computador, profiling, debugging, concorrência, consistência, segurança e custo, vai usar agentes como exoesqueleto.</p>
<p>Quem não entende nada disso vai usar agente como muleta.</p>
<p>Exoesqueleto amplia força.
Muleta só tenta esconder fraqueza.</p>
<h2>&ldquo;Mas isso não é sustentável&rdquo;<span class="hx:absolute hx:-mt-20" id="mas-isso-não-é-sustentável"></span>
    <a href="#mas-isso-n%c3%a3o-%c3%a9-sustent%c3%a1vel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sempre aparece alguém com a mesma desculpa: &ldquo;ah, mas eu não acho que isso seja sustentável, os data centers não vão aguentar, os preços estão subsidiados demais, não tem como isso continuar assim.&rdquo;</p>
<p>E olha, essa pessoa não está completamente errada.</p>
<p>Só que isso não muda em nada o que eu tenho pra fazer amanhã de manhã.</p>
<p>Esse tipo de preocupação pode até render papo de bar ou thread no X, mas não me ajuda a decidir nada útil. Eu, você, nenhum de nós vai sentar com a diretoria da Anthropic ou da OpenAI pra redesenhar capex de data center, renegociar contrato de energia, decidir margem de subsídio ou planejar a próxima geração de GPU. Não tem nenhuma ação concreta que saia disso pra nós além de ficar repetindo que &ldquo;um dia vai dar problema&rdquo;.</p>
<p>É a mesma mentalidade de quem olhava pra internet nos anos 90 e falava: &ldquo;vamos não usar muito isso, é lento demais, o limite é ridículo, o preço por kilobyte é absurdo, melhor esperar arrumarem.&rdquo; Ou de quem, no começo dos anos 2000, olhava pra dados móveis e dizia: &ldquo;2G é lento demais, é limitado demais, melhor não depender disso.&rdquo; Por que exatamente você ia querer ser essa pessoa?</p>
<p>Ainda bem que OpenAI, Anthropic e o resto estão se estapeando e subsidiando pesado essa corrida. Eu estou aproveitando sem o menor pudor. Já torrei meu Claude Max 20x inteiro, já bati no limite de extra usage, já torrei meu plano do Codex, e subi pra Pro pra continuar usando neste fim de semana. Quem paga mensalidade e usa pouco está, na prática, me subsidiando pra eu usar tudo o que consigo. Eu não tenho a menor intenção de desacelerar. Por que você teria?</p>
<p>Se amanhã os preços mudarem, a infraestrutura apertar ou o jogo virar, eu reavalio amanhã. É assim que tecnologia sempre funcionou. Enquanto a janela está aberta, o racional não é frear por antecipação. O racional é aprender o máximo, extrair o máximo, ganhar vantagem enquanto o resto está ocupado explicando por que ainda não começou.</p>
<h2>A decisão continua sendo humana<span class="hx:absolute hx:-mt-20" id="a-decisão-continua-sendo-humana"></span>
    <a href="#a-decis%c3%a3o-continua-sendo-humana" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No fim do dia, nada do que importa mudou.</p>
<p>Alguém continua precisando olhar pro resultado e decidir:</p>
<ul>
<li>isso pode ir pra produção?</li>
<li>isso aguenta carga?</li>
<li>isso está legível?</li>
<li>isso está seguro?</li>
<li>isso está fácil de manter?</li>
<li>isso conversa com o resto do sistema?</li>
<li>isso resolve o problema certo?</li>
</ul>
<p>Se a resposta for não, alguém continua precisando saber <strong>por que</strong> é não.</p>
<p>E mais importante: alguém continua precisando saber <strong>como corrigir</strong>.</p>
<p>É por isso que, na era dos agentes, conhecimento de base não ficou menos importante. Ficou mais caro errar sem ele.</p>
<p>VS Code é o novo cartão perfurado.</p>
<p>Não porque ficou inútil.</p>
<p>Mas porque finalmente estamos entrando numa era em que o ato de digitar código manualmente deixa de ser o centro da profissão.</p>
<p>E, honestamente? Já foi tarde.</p>
<blockquote>
  <p><strong>IA reflete quem você é.</strong></p>
<p>Se você é bom, ela acelera código bom.</p>
<p>Se você é ruim, ela acelera dívida técnica numa velocidade industrial.</p>
<p>IA não vai pegar programador ruim e transformar em programador bom. Nunca transformou, não transforma e não vai transformar.</p>

</blockquote>
<p>Por isso fundamento importa mais agora do que antes.</p>
<p>O agente pode escrever. Quem continua precisando saber se aquilo presta é você.</p>
]]></content:encoded><category>agentes-de-codigo</category><category>programacao</category></item><item><title>[Akitando] #136 - Python? Java? Rust? Qual a Diferença? | Discutindo Linguagens</title><link>https://akitaonrails.github.io/2023/01/18/akitando-136-python-java-rust-qual-a-diferenca-discutindo-linguagens/</link><guid isPermaLink="true">https://akitaonrails.github.io/2023/01/18/akitando-136-python-java-rust-qual-a-diferenca-discutindo-linguagens/</guid><pubDate>Wed, 18 Jan 2023 08:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/MI9cdxETA4c"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Finalmente vou falar sobre linguagens que você goste ou use, mas vou fazer isso do meu jeito: escovando bits e explicando como muita coisa funciona por baixo de Python, Javascript e outras linguagens que talvez você não sabia antes de concluir na segunda metade onde discuto onde cada linguagem pode ser melhor aproveitada e porque.&lt;/p&gt;
&lt;h2&gt;Capítulos&lt;span class="hx:absolute hx:-mt-20" id="capítulos"&gt;&lt;/span&gt;
&lt;a href="#cap%c3%adtulos" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;00:00 - Intro&lt;/li&gt;
&lt;li&gt;01:36 - Cap 1 - Perl e Regex | Anos 90&lt;/li&gt;
&lt;li&gt;06:18 - Cap 2 - Estilo C e ICU | strftime&lt;/li&gt;
&lt;li&gt;10:25 - Cap 3 - Tudo de Python é em C! | Linguagem &amp;ldquo;Grude&amp;rdquo;&lt;/li&gt;
&lt;li&gt;17:54 - Cap 4 - Tudo de Node.js é em C! | LibUV&lt;/li&gt;
&lt;li&gt;22:31 - Cap 5 - Compilado vs Interpretado | ABI de C&lt;/li&gt;
&lt;li&gt;28:21 - Cap 6 - Interoperabilidade: Marshalling/Unmarshalling | FFI&lt;/li&gt;
&lt;li&gt;36:21 - Cap 7 - Onde cada Linguagem é mais Forte? | Rust&lt;/li&gt;
&lt;li&gt;38:09 - Cap 8 - Sistemas Distribuídos | Apache Java&lt;/li&gt;
&lt;li&gt;42:41 - Cap 9 - Produtividade &amp;gt; Performance? | Apps Comerciais&lt;/li&gt;
&lt;li&gt;48:31 - Bloopers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Links&lt;span class="hx:absolute hx:-mt-20" id="links"&gt;&lt;/span&gt;
&lt;a href="#links" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/python/cpython/search?p=2&amp;amp;q=ifdef&amp;#43;MS_WINDOWS"target="_blank" rel="noopener"&gt;https://github.com/python/cpython/search?p=2&amp;q=ifdef+MS_WINDOWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/python/cpython/blob/a87c46eab3c306b1c5b8a072b7b30ac2c50651c0/Modules/_ssl.c"target="_blank" rel="noopener"&gt;https://github.com/python/cpython/blob/a87c46eab3c306b1c5b8a072b7b30ac2c50651c0/Modules/_ssl.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pandas-dev/pandas/blob/main/requirements-dev.txt"target="_blank" rel="noopener"&gt;https://github.com/pandas-dev/pandas/blob/main/requirements-dev.txt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/numpy/numpy/wiki/Building-with-MSVC"target="_blank" rel="noopener"&gt;https://github.com/numpy/numpy/wiki/Building-with-MSVC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/scipy/scipy"target="_blank" rel="noopener"&gt;https://github.com/scipy/scipy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyter/notebook"target="_blank" rel="noopener"&gt;https://github.com/jupyter/notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/openjdk/jdk/search?l=c%2B%2B&amp;amp;p=99"target="_blank" rel="noopener"&gt;https://github.com/openjdk/jdk/search?l=c%2B%2B&amp;p=99&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/libuv/libuv"target="_blank" rel="noopener"&gt;https://github.com/libuv/libuv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tensorflow/tensorflow"target="_blank" rel="noopener"&gt;https://github.com/tensorflow/tensorflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tensorflow/tfjs"target="_blank" rel="noopener"&gt;https://github.com/tensorflow/tfjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pytorch/pytorch"target="_blank" rel="noopener"&gt;https://github.com/pytorch/pytorch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nodejs/node/search?q=libuv"target="_blank" rel="noopener"&gt;https://github.com/nodejs/node/search?q=libuv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/async-await-retry"target="_blank" rel="noopener"&gt;https://www.npmjs.com/package/async-await-retry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/11996988/how-good-is-oniguruma-compared-to-other-cross-platform-regexp-libraries"target="_blank" rel="noopener"&gt;https://stackoverflow.com/questions/11996988/how-good-is-oniguruma-compared-to-other-cross-platform-regexp-libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/jni"target="_blank" rel="noopener"&gt;https://www.baeldung.com/jni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.elastic.co/blog/found-zookeeper-king-of-coordination"target="_blank" rel="noopener"&gt;https://www.elastic.co/blog/found-zookeeper-king-of-coordination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener"&gt;https://github.com/akitaonrails/ObjC_Rubyfication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zaiste.net/posts/shell-commands-rust/#"target="_blank" rel="noopener"&gt;https://zaiste.net/posts/shell-commands-rust/#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SCRIPT&lt;span class="hx:absolute hx:-mt-20" id="script"&gt;&lt;/span&gt;
&lt;a href="#script" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Olá pessoal, Fabio Akita&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/MI9cdxETA4c"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Finalmente vou falar sobre linguagens que você goste ou use, mas vou fazer isso do meu jeito: escovando bits e explicando como muita coisa funciona por baixo de Python, Javascript e outras linguagens que talvez você não sabia antes de concluir na segunda metade onde discuto onde cada linguagem pode ser melhor aproveitada e porque.</p>
<h2>Capítulos<span class="hx:absolute hx:-mt-20" id="capítulos"></span>
    <a href="#cap%c3%adtulos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00 - Intro</li>
<li>01:36 - Cap 1 - Perl e Regex | Anos 90</li>
<li>06:18 - Cap 2 - Estilo C e ICU | strftime</li>
<li>10:25 - Cap 3 - Tudo de Python é em C! | Linguagem &ldquo;Grude&rdquo;</li>
<li>17:54 - Cap 4 - Tudo de Node.js é em C! | LibUV</li>
<li>22:31 - Cap 5 - Compilado vs Interpretado | ABI de C</li>
<li>28:21 - Cap 6 - Interoperabilidade: Marshalling/Unmarshalling | FFI</li>
<li>36:21 - Cap 7 - Onde cada Linguagem é mais Forte? | Rust</li>
<li>38:09 - Cap 8 - Sistemas Distribuídos | Apache Java</li>
<li>42:41 - Cap 9 - Produtividade &gt; Performance? | Apps Comerciais</li>
<li>48:31 - Bloopers</li>
</ul>
<h2>Links<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="https://github.com/python/cpython/search?p=2&amp;q=ifdef&#43;MS_WINDOWS"target="_blank" rel="noopener">https://github.com/python/cpython/search?p=2&q=ifdef+MS_WINDOWS</a></li>
<li><a href="https://github.com/python/cpython/blob/a87c46eab3c306b1c5b8a072b7b30ac2c50651c0/Modules/_ssl.c"target="_blank" rel="noopener">https://github.com/python/cpython/blob/a87c46eab3c306b1c5b8a072b7b30ac2c50651c0/Modules/_ssl.c</a></li>
<li><a href="https://github.com/pandas-dev/pandas/blob/main/requirements-dev.txt"target="_blank" rel="noopener">https://github.com/pandas-dev/pandas/blob/main/requirements-dev.txt</a></li>
<li><a href="https://github.com/numpy/numpy/wiki/Building-with-MSVC"target="_blank" rel="noopener">https://github.com/numpy/numpy/wiki/Building-with-MSVC</a></li>
<li><a href="https://github.com/scipy/scipy"target="_blank" rel="noopener">https://github.com/scipy/scipy</a></li>
<li><a href="https://github.com/jupyter/notebook"target="_blank" rel="noopener">https://github.com/jupyter/notebook</a></li>
<li><a href="https://github.com/openjdk/jdk/search?l=c%2B%2B&amp;p=99"target="_blank" rel="noopener">https://github.com/openjdk/jdk/search?l=c%2B%2B&p=99</a></li>
<li><a href="https://github.com/libuv/libuv"target="_blank" rel="noopener">https://github.com/libuv/libuv</a></li>
<li><a href="https://github.com/tensorflow/tensorflow"target="_blank" rel="noopener">https://github.com/tensorflow/tensorflow</a></li>
<li><a href="https://github.com/tensorflow/tfjs"target="_blank" rel="noopener">https://github.com/tensorflow/tfjs</a></li>
<li><a href="https://github.com/pytorch/pytorch"target="_blank" rel="noopener">https://github.com/pytorch/pytorch</a></li>
<li><a href="https://github.com/nodejs/node/search?q=libuv"target="_blank" rel="noopener">https://github.com/nodejs/node/search?q=libuv</a></li>
<li><a href="https://www.npmjs.com/package/async-await-retry"target="_blank" rel="noopener">https://www.npmjs.com/package/async-await-retry</a></li>
<li><a href="https://stackoverflow.com/questions/11996988/how-good-is-oniguruma-compared-to-other-cross-platform-regexp-libraries"target="_blank" rel="noopener">https://stackoverflow.com/questions/11996988/how-good-is-oniguruma-compared-to-other-cross-platform-regexp-libraries</a></li>
<li><a href="https://www.baeldung.com/jni"target="_blank" rel="noopener">https://www.baeldung.com/jni</a></li>
<li><a href="https://www.elastic.co/blog/found-zookeeper-king-of-coordination"target="_blank" rel="noopener">https://www.elastic.co/blog/found-zookeeper-king-of-coordination</a></li>
<li><a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener">https://github.com/akitaonrails/ObjC_Rubyfication</a></li>
<li><a href="https://zaiste.net/posts/shell-commands-rust/#"target="_blank" rel="noopener">https://zaiste.net/posts/shell-commands-rust/#</a></li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Hoje é dia de fazer um episódio que vinha postergando faz anos: falar sobre as principais linguagens de programação em uso no momento. Quem acompanha o canal sabe que evito ao máximo mostrar código dessa ou daquela linguagem, de vez em quando mostro uns trechos de javascript porque sei que a maioria sabe um pouco pelo menos, e em muitos casos uso pseudo-código que não existe quando o foco é o conceito.</p>
<p>Eu tenho algumas linguagens favoritas, obviamente Ruby, um pouco de Elixir, Crystal, todas linguagens meio parecidas em sintaxe, embora  diferentes por baixo, e mesmo assim  acho que nunca mostrei código delas em nenhum video. Mas hoje quero compartilhar algumas curiosidades técnicas e opiniões pessoais que muitos assistindo provavelmente nunca pararam pra pensar. A intenção não é fazer prós e contras, falar bem ou mau de qualquer linguagem. A idéia é fazer você enxergar sua linguagem favorita com outros olhos.</p>
<p>(&hellip;)</p>
<p>Já vou avisar: meu objetivo não é dizer que linguagem X é melhor que linguagem Y nem nada disso. Então os macacos de auditório de torcida organizada podem se retirar. Programação não é pra isso e código não liga pra sua &ldquo;lealdade&rdquo; a essa ou aquela tecnologia. Na verdade tecnologia e inovação recompensam a deslealdade. Quem conhece mais tecnologias diferentes sempre vai ser melhor e na verdade esse video é pra mostrar isso. Iniciantes vão ter seus níveis de ansiedade indo pras alturas porque vou mostrar um monte de coisas que nunca viram. Não se aflijam, anotem os termos que não conhecem, estudem, depois voltem pra assistir de novo.</p>
<p>A primeira coisa que quero levantar é o seguinte: Python. Nos últimos anos aumentou rápido de popularidade, principalmente por causa de projetos como Jupyter Notebooks, Pandas, Tensorflow, PyTorch e outros projetos relacionados a data science e machine learning. Se você se interessa por essas duas áreas, acho que é seguro dizer que maioria dos cursos e artigos a respeito vai usar uma ferramenta feita em Python. Por isso parece que Python é a linguagem que se deve aprender, certo?</p>
<p>Não está errado e não me entenda mau: apesar de não ser minha linguagem favorita, não tenho nenhum problema com Python. O que quero demonstrar hoje é mais dar uma perspectiva pé no chão. Primeiro de tudo, na minha opinião, Python estava no lugar certo na hora certa. Nos anos 90 a linguagem de script mais popular no nascente mundo de Linux foi Perl.</p>
<p>Acho que muitos iniciantes aqui nunca ouviram falar, mas muitos scripts de configuração e administração de sistemas Linux eram escritos em Perl. E quando a web começou a surgir, as primeiras aplicações interativas web, o que conhecemos hoje como programação back-end, era ou em C ou em Perl, porque essa linguagem era mais flexível pra lidar com strings, com um HTML, por causa da sua principal funcionalidade: Regular Expressions ou Regex.</p>
<p>Mais especificamente PCRE ou Perl Compatible Regular Expressions. Quem programa em Objective-C ou Swift pra iOS e Mac e já tentou usar regex, deve ter notado como é um pouco diferente do regex compatível com Perl. Isso porque a Apple, a Microsoft usam regex com sintaxe baseado em ICU que é International Components for Unicode. Eles são parecidos mas tem pequenas diferenças que podem confundir quem não sabe que existem dois padrões diferentes de regex.</p>
<p>Enfim, por causa de regular expressions, Perl sempre foi muito usado pra processar textos, logs, até coisas como sequências de DNA em pesquisa de genoma e coisas assim, já que envolve muito pattern matching de sequências. Porém, na virada do século, o pessoal de Perl quis dar passos maiores que as pernas. Eu lembro que queriam desenvolver um novo Perl, o Perl 6, como uma virtual machine que suportasse múltiplas sintaxes de linguagem por cima, o projeto Parrot.</p>
<p>Esse ciclo de desenvolvimento levou anos e nunca chegou no fim. O Perl 5, que foi a última grande versão de Perl ficou estagnado e sem novidades por muito tempo. Enquanto isso outras linguagens evoluíram mais rápido e de forma mais pragmática, e uma delas foi o Python. Não sei se foi a RedHat quem adotou primeiro, mas o fato é que com a incerteza no futuro do Perl, acredito que muitos começaram a migrar pra Python.</p>
<p>Python também tinha uma sintaxe e ergonomia muito mais modernas. Perl não era originalmente orientado a objetos, embora tivesse como gambiarrar classes com <code>bless</code>. Era uma linguagem dinâmica de tipagem fraca, então bugs por causa de coerção de valores e tipos errados não era incomum. Mas Perl influenciou todas as linguagens de script que vieram depois, incluindo Python, Ruby e o mais óbvio, PHP. De onde vocês acham que variáveis com cifrão vieram? De Perl.</p>
<p>O principal legado de Perl, na minha opinião, foi popularizar a viabilidade de linguagens dinâmicas pra aplicações web e popularizar o uso de regular expressions pra pattern matching de textos. Várias linguagens até hoje usam a sintaxe específica de Perl, como em Ruby, Node.js, acho que Go também porque usa a biblioteca &ldquo;re2&rdquo; que é compatível com PCRE.</p>
<p>Na realidade, nem todas são 100% compatível com Perl. Por exemplo, em Python, se usar a biblioteca &ldquo;re&rdquo;, o método <code>match</code> tem comportamento como se toda regex começasse com crase, que em Perl significa dizer pra começar o matching do começo do string. Ele também não tem o operador global &ldquo;/g&rdquo;, pra isso se usa o método &ldquo;re.sub()&rdquo;.  São pequenas diferenças, mas pode confundir quem conhecia regex de Perl, por exemplo, se costuma usar Vim como editor, que suporta regex Perl.</p>
<p>De qualquer forma, linguagens que quase totalmente suportam a sintaxe de regex de Perl são Python, Javascript, PHP, Ruby. Como falei antes, a biblioteca &ldquo;re&rdquo; de Python é só uma casca pra biblioteca Oniguruma, que em japonês significa carro do demônio, sei lá porque. A gem Oniguruma de Ruby é a mesma coisa. A classe RegExp de Javascript também. Oniguruma é uma das melhores e mais rápidas bibliotecas de regex que existem. Mas não é a única. Linguagens como C#, C++, Go usam outra biblioteca, a &ldquo;RE2&rdquo;. Não confundir com Resident Evil 2.</p>
<p>Acho que nem a Oniguruma e nem a RE2 forçam a sintaxe de Perl. Eles oferecem o motor, mas os detalhes da sintaxe, cada linguagem pode configurar como quiser. Por exemplo, C# tem a opção de usar &ldquo;verbatim string literal&rdquo; que é escrever a regex com arroba na frente, assim não precisa escapar caracteres especiais dentro do regex com barra ao contrário.</p>
<p>Algumas linguagens não usam o estilo Perl e sim a sintaxe ICU, de International Components for Unicode. Exemplos disso são a classe <code>java.util.regex</code> de Java, a classe <code>icu::RegexPattern</code> de C++, a classe <code>NSRegularExpression</code> de Swift da Apple, as funções &ldquo;preg_*&rdquo; de PHP. Eu pessoalmente gosto mais da sintaxe Perl. Quando precisava usar ICU pra programar mobile de iOS em Swift ou Objective-C, lembro que vira e mexe tropeçava na sintaxe.</p>
<p>11 anos atrás fiz um pequeno experimento em Objective-C pra importar o Oniguruma e adicionar sintaxe de regex de Perl pra programar iOS. É uma das poucas coisas que ainda sobrou no meu GitHub. Maioria dos meus códigos sempre foi pra projetos de cliente por isso tenho bem pouca coisa aberta. Essa foi uma delas. 11 anos atrás foi 2011, pouco mais de 2 anos depois que a App Store abriu oficialmente.</p>
<p>Além do regex não ser compatível com Perl, formatação de data e hora também não era compatível com a biblioteca Time de Linux. Sabe a função strftime? Onde podemos pedir pra formar data e hora usando uma string de template como &ldquo;%d/%m/%Y %H:%M:%S&rdquo;?</p>
<p>Em Objective-C e depois Swift, usando a classe <code>DateFormatter</code> com o método <code>dateFormat</code>, o mesmo template fica assim: &ldquo;dd/MM/yyyy HH:mm:ss&rdquo;. É bem diferente e isso me incomodava porque Ruby usa o mesmo padrão de C mas de novo, Objetive-C e Swift usam o padrão ICU.</p>
<p>Diferente de Regex onde a sintaxe Perl ainda é forte em muitas linguagens em vez do formato ICU, no caso de formatação de data e hora, o formato ICU é mais forte do que strftime de C. C++, Python, Ruby, Elixir ainda usam o formato de C, mas Swift, Java, C#, até PHP e JavaScript usam o formato ICU. Tecnicamente, por serem padrões internacionais de Unicode, o formato ICU é quem deveria ser considerado o &ldquo;correto&rdquo;, mas por direito, formatos derivados do mundo Unix e Linux continuam sendo usados.</p>
<p>E de novo, naquele projetinho de biblioteca que fiz pra Objective-C, além de importar Oniguruma, também implementei uma versão de formatador de data e hora usando a função &ldquo;strftime&rdquo; da biblioteca &ldquo;time&rdquo; de C. Assim eu poderia usar os formatos de Linux e contrariar o formato ICU. E por que? Só pra mostrar que era possível.</p>
<p>E eu contei essas duas histórias pra ilustrar um ponto. Não sei se vocês entendem que muita coisa de Javascript ou Python não são escritos em Javascript ou Python e sim em C. A classe RegExp de Javascript ou &ldquo;re&rdquo; de Python são meras casquinhas mas por baixo chamam bibliotecas escritas em C.</p>
<p>Eu digo isso porque muitas linguagens são escritas nelas mesmas. O compilador de Rust é escrito em Rust. O compilador de Go é escrito em Go. Muito do OpenJDK de Java é escrito em Java. Linguagens compiladas costumam muitas vezes ser escritos nelas mesmas. Isso não torna automaticamente uma linguagem melhor ou pior. Apenas facilita pros desenvolvedores das linguagens não ter que ficar mudando de linguagem o tempo todo. Por exemplo, escrever o compilador em C mas as bibliotecas em Rust. Lembrei disso quando conversei com os criadores e mantenedores de Ruby e eles comentando que escrevem mais C que Ruby.</p>
<p>Isso é mais uma curiosidade, não comecem a brigar em Reddit dizendo que sua linguagem é melhor porque é bootstrapped, ou seja, escrita nela mesma. Mais importante é o seguinte: linguagens interpretadas de script como Python, Ruby, Javascript ou PHP herdam muitas características da plataforma onde nasceram: do C. Diferente de Java ou Go que é na maior parte escrita nelas mesmas, linguagens de scripts costumam parecer mais &ldquo;cascas&rdquo; pras funcionalidades de C.</p>
<p>Veja a função de formatação de data e hora &ldquo;strftime&rdquo; de Ruby ou &ldquo;datetime.strftime&rdquo; de Python. Por que acha que tem esses nomes? Porque herdaram da função strftime da biblioteca time, cujo cabeçalho se chama &ldquo;time.h&rdquo;. Se num Linux, abrir um terminal e digitar &ldquo;man strftime&rdquo; vai dar os detalhes da função original de C. Essa função fica disponível numa biblioteca compartilhada chamada &ldquo;libc&rdquo; ou &ldquo;glibc&rdquo;, que praticamente todo programa que roda em Linux carrega e usa.</p>
<p>Vamos ver mais exemplos? Em Python, claro, muitos dos métodos do módulo &ldquo;os&rdquo; são derivados da libc. Temos &ldquo;os.mkdir()&rdquo; pra criar diretórios, não por acaso, é o mesmo nome do comando que você usa em qualquer terminal de linha de comando pra criar diretórios, porque ambos usam a mesma função da libC. Ou &ldquo;os.getenv()&rdquo; que é o mesmo nome da função da libC pra pegar variáveis de ambiente. Tem funções do módulo &ldquo;ctypes&rdquo; que, como o nome diz são &ldquo;tipos de C&rdquo;, como &ldquo;ctypes.memcmp()&rdquo; que compara dois blocos de memória e retorna um inteiro. Em particular vários métodos do módulo &ldquo;math&rdquo; herdam funções do cabeçalho &ldquo;math.h&rdquo; da libC como &ldquo;math.sin()&rdquo; pra calcular seno ou &ldquo;math.pow()&rdquo; pra calcular a potência de um número.</p>
<p>A mesma coisa vale pra Javascript, Ruby, PHP. E eu quero pegar esse gancho pra voltar pros projetos mais populares de Python. Vamos pegar o Pandas que é uma ferramenta muito poderosa, flexível e razoavelmente amigável de usar pra fazer análise e manipulação de dados. Povo de data science acho que começa aprendendo Pandas. Se abrirmos a página do projeto no GitHub, podemos ver que a maior parte é escrita em Python mesmo.</p>
<p>Mas essa não é a história toda. Como todo bom projeto moderno de Python, tem um arquivo de &ldquo;requirements&rdquo; que lista as dependências que o projeto precisa carregar pra funcionar, vamos dar uma fuçada. Tem uma quantidade enorme de bibliotecas, mas 2 das principais incluem o numpy e scipy. Vamos começar pelo numpy que é importantíssimo porque fornece coisas como array multidimensional, funções de álgebra linear, transformada de Fourier e mais.</p>
<p>Vamos abrir o projeto no GitHub e olha só: um terço é código C. Um dos pontos fortes do numpy é justamente facilitar integrar com bibliotecas em C e Fortran. É por isso que pra gerar o pacote pra Mac, por exemplo, o script que tá na wiki manda instalar o pacote de Fortran. Ou na página de wiki pra Windows, precisa do MSVC que é o pacote de compiladores de C e C++ do Visual Studio da Microsoft. Sim, pra gerar o pacote de um projeto de Python, precisa de compiladores de C, C++ e Fortran. Sabiam disso?</p>
<p>O numpy é requisito pra usar o scipy que é um conjunto de módulos científicos pra estatística, otimização, integração, álgebra linear, processamento de sinais e imagens e muito mais. Ele usa os arrays multidimensionais de numpy por exemplo. E no que SciPy é feito? Quase um quinto do código é Fortran e quase outro quinto é C e C++. Ou seja, pelo menos dois quintos do projeto todo também não é em Python e também precisa de compiladores de Fortran, C e C++.</p>
<p>Todo projeto de data science feito em Python precisa usar numpy e scipy, que são os grandes diferenciais, e eles são feitos em boa parte em Fortran, C e C++ e não em Python. E isso não é pra minimizar, denegrir, ou falar mal de Python, mas sim pra quem não sabia entender que só porque a cara da frente é numa linguagem, não significa que por baixo do capô também é.</p>
<p>E o Tensorflow que todo mundo fica hypado pra machine learning? Vamos ver a página no GitHub? Olha só, bem mais da metade do código é em C++, só um quinto dele é Python. O grosso, o motor mesmo, é todo em C++. E o PyTorch que é redes neurais acelerado por GPU? Metade desse código é em C++. E isso porque eu não estou olhando as dependências no arquivo de requirements.</p>
<p>Uma parte significativa que não tá contando aqui é a biblioteca de CUDA da NVIDIA e os shaders pra aceleração em GPU, que podem ser escritos em várias linguagens, incluindo Python mas compilam pra HLSL ou GLSL que é o OpenGL Shader Language. Eu falo sobre linguagens de shaders e GPU no video da longa história de CPUs e GPUs, depois dêem uma olhada.</p>
<p>Pra usar esses projetos, sabendo um pouco de Python é suficiente, mas se alguém queria realmente entender como redes neurais,  aceleração via GPU pra esse tipo de computação realmente funciona, obrigatoriamente não é Python e sim C++ e linguagens de shaders pra GPU. Eu estou sendo pedante nisso porque da forma como muita gente faz propaganda, parece que é tudo feito em Python e basta saber Python pra resolver tudo nessa área, o que não é verdade.</p>
<p>E de novo, meu objetivo não é pegar no pé do Python. Como contei no começo, ele estava no lugar certo na hora certa quanto Perl 5 foi desaparecendo. Linguagens de script como Perl ou Python, que foram feitos pra funcionar muito perto do sistema operacional, são ótimos pra funcionar como cascas pras bibliotecas de alta performance feitos em C ou C++.</p>
<p>Era esse tipo de coisa que se fazia com  Perl, que era menos ruim do que escrever scripts de SH ou Bash, e depois passamos a usar Python que, com sua sintaxe bem simples e espartana, caiu como uma luva pra administradores de sistemas que precisavam fazer coisas rápidas.</p>
<p>Com o tempo passou a ser adotado em distros com programas como o Conda que é escrito em Python e serve pra instalar e gerenciar pacotes. Não confundir com Anaconda que é outro projeto pra computação científica. Daí o pessoal de pesquisa do Google passa anos desenvolvendo um Tensorflow da vida em C++. Nesse estágio ele é difícil de usar, precisa saber C++. Em cima dele fizeram scripts em Python e um ferramental com mais usabilidade e mais simples de usar pra maioria das pessoas. Essa é vantagem do Python.</p>
<p>Diferente do Tensorflow de Python, o tfjs ou Tensorflow.js é na maior parte escrito realmente em TypeScript e Javacript. Assim como em Python as partes que exigem performance e falar diretamente com o hardware como GPUs, são feitos em C++, mas na versão de Javascript ele pode rodar no navegador e utiliza o suporte a WebGL e Web Assembly. A versão de Javascript não faz tudo que a de Python mas é suficiente. Tem o Tensorflow Lite pra rodar em smartphones também. Enfim, o principal é entender que quando precisamos de performance normalmente precisamos mais do que Python.</p>
<p>E pra não pegar só no pé do Python, Javascript é similar. Tudo que é impressionante e roda rápido no navegador não é mérito do Javascript e sim do navegador que oferece APIs como WebGL pra dar acesso à aceleração via GPU. E todo navegador é feito em C++. Entendam, toda linguagem interpretada depende muito do sistema operacional e outras bibliotecas instaladas.</p>
<p>Voltando ao ponto onde linguagens como Python, Javascript ou PHP dependem de bibliotecas como a LibC, - tanto que os nomes das funções são as mesmas das versões em C -, e se a LibC costuma vir em toda distro Linux mas não em Windows ou Mac, como que faz pra rodar Python em Windows? Vamos pro GitHub do CPython e vou te mostrar o que tem embaixo do tapete. Se procurarmos dentro desse repositório por &ldquo;ifdef MS_WINDOWS&rdquo; temos 8 páginas de resultados e olhem esses trechos.</p>
<p>Se nunca programou em C e não sabe o que é pré-processamento, deixa eu pegar um arquivo aleatório desse resultado. Vamos abrir o arquivo &ldquo;_ssl.c&rdquo;. Olha aqui na linha 628 tem um &ldquo;ifdef MS_WINDOWS&rdquo;. Se não existisse pré-processamento seria como se tivéssemos duas versões desse arquivo. Um chamado &ldquo;_ssl.c&rdquo; que teria esse trecho assim e outro arquivo chamado &ldquo;_ssl.c-ms_windows&rdquo; cujo trecho seria escrito dessa outra forma aqui. Conseguem ver a diferença?</p>
<p>O compilador, se estiver em Windows, vai compilar o código com esse &ldquo;if&rdquo; a mais chamando essa função &ldquo;SetFromWindowErr&rdquo; que só precisa no Windows. Em Linux ou Mac esse código não existe. E isso acontece em dezenas de arquivos, 8 páginas de resultados no GitHub. Ocódigo do CPython pra Windows é diferente da versão de Linux.</p>
<p>Por isso o CPython de Windows não é igual ao CPython de Linux que não é igual ao CPython de Mac. Isso vale pra tudo PHP de Windows, Javascript de Windows. Então vamos falar de Node.js. O Node é basicamente um projeto de C++. Um quinto desse projeto é só C++ mas precisamos falar de uma das dependências, o libuv. O coração da principal funcionalidade do Node, que é o famoso eventloop, o reactor, é implementado quase 100% em C. Vamos abrir a página dele no GitHub. Olha só aqui embaixo, 97% de C, mas o resto é só coisas administrativa, por isso é 100%.</p>
<p>E o que é a libuv. Novamente, sendo uma biblioteca de C, num terminal de Linux podemos usar o comando &ldquo;man&rdquo; que, se alguém tinha dúvida, significa &ldquo;manual&rdquo; e não &ldquo;homem&rdquo;. Normalmente bibliotecas de C instalam sua documentação nesse formato. E como diz aqui, esse projeto foi feito pelos desenvolvedores do Node.js pra ser uma biblioteca com capacidade pra rodar em diversas plataformas como Windows, Mac, BSD e é quem abstrai as funcionalidades de I/O assíncrono que o Node precisa pro seu reactor.</p>
<p>Cada sistema operacional implementa I/O assíncrono diferente. Linux costuma ter suporte a epoll, UNIX BSD tem Kqueue, Windows tem IOCP que é I/O Completion Ports, que muitos argumentam que é superior a epoll ou kqueue. Ou seja, a principal funcionalidade do Node só é possível porque quem de fato fornece o músculo é o sistema operacional. O libuv é mais uma casca em C++ pra abstrair essas diferentes formas de fazer I/O assíncrono e tornar possível o Node rodar em qualquer sistema operacional.</p>
<p>E o Deno, o competidor que muitos consideram melhor que o Node? Eu nem quero tentar entrar nessa discussão de quem é melhor. Mas se abrirmos a página GitHub do Deno, vemos que mais da metade, mais de 60% é escrito em Rust. Ahhh será que é por isso que ele é melhor que o Node então? Na verdade não. Se procurarmos por libuv nesse repositório, vemos que o Rust importa as mesmas funções do libuv do Node, então em termos do eventloop, ambos fazem a mesma coisa. Claro que podem parametrizar pra se comportar diferente, mas a fundação é a mesma e, de novo, é C++.</p>
<p>Eu poderia passar o dia todo dando exemplos em Ruby, em PHP, e até mesmo em Java. Mas ué, tudo que é de Java não era escrito todo em Java? Na realidade não. Como último exemplo, vamos abrir a página do OpenJDK e olha aqui embaixo, 13% do Java é escrito em C++. Mas o que? Vamos ver, olha só, muita coisa do HotSpot que é o motor do JIT ou Just in Time Compiler da JVM é escrito em C++.  Nem mesmo o Java, que nasceu nos anos 90 com a frase de &ldquo;Write Once, Run Anywhere&rdquo; é puramente feito em Java. E se isso não ficou claro, olha a página de resultados de arquivos C++: tem pelo menos 100 páginas de resultados, uma parte considerável da JVM não é feito em Java.</p>
<p>E isso não é perseguição. Ruby, PHP, DotNet, Go, Rust, Swift, e todo o resto tem partes consideráveis que depende de C e C++, coisas como a LibC, coisas de criptografia como OpenSSL ou alternativas como libsodium. Imagina se toda linguagem tivesse que fazer criptografia do zero? O mundo já tem bugs de segurança demais. É melhor todo mundo reusar o que já existe de melhor e mais maduro.</p>
<p>E isso só falando em Linguagens. Quem fez Ciências da Computação decentemente não perde muito tempo com discussões de melhor linguagem. Mas pessoal de desenvolvimento web, por alguma razão vira e mexe entra nesse tipo de argumento. Então só pra complementar, além de linguagens, no mundo web temos diversos outros serviços e componentes que precisamos usar no nosso dia a dia.</p>
<p>Por exemplo, no que é escrito o banco de dados Postgres? É mais de 85% de C. E o MySQL, mais especificamente o MariaDB? Metade é C++ e quase 40% é C. Bom, mas isso deve ser porque são velhos né, um banco de dados mais novo como MongoDB deve ser em outra coisa mais moderna? Não, 72% é C++.</p>
<p>E o Redis que usamos pra cache ou filas o tempo todo? É quase 80% de C. Mas não significa que tudo é em C ou C++. Vejamos o banco de dados distribuído Cassandra, esse é quase 100% feito em Java e não é o único. O Apache Kafka que é o sistema de filas que falei no episódio passado, é quase 75% em Java e 22% em Scala, que é outra linguagem que roda na JVM então 97% é Java. E falando em sistemas de fila, outro com excelente reputação e maturidade e que, se não me engano, era uma das estrelas por trás de serviços como Whatsapp, é o RabbitMQ que é escrito em Erlang, a plataforma por trás da moderna linguagem Elixir.</p>
<p>E aqui vem outra coisa que eu queria explicar. Tanto Java quanto Erlang são muito bons pra construir sistemas distribuídos, de forma mais produtiva do que fazer em C ou C++. Go também serviria, mas ele ainda é muito novo comparado com os outros, talvez o próximo grande banco de dados seja em Go, não sei. Ele ainda não se provou nesse espaço. Então deixa eu dar minha perspectiva sobre onde cada linguagem tem mais força.</p>
<p>Todo sistema operacional hoje é feito numa mistura de C e C++. E quando eu falo sistema operacional ou OS quero dizer coisas como a kernel e drivers de dispositivos, os componente que rodam no Ring Zero de maior privilégio. Todo o resto, nossos programas e scripts rodam no Ring 3, que tem menos privilégios, o que chamamos de userland. Todo programa em userland precisa usar o kernel do OS como intermediador pra falar com dispositivos como SSD, placa de rede, placa de video, teclado, mouse e tudo mais. O único que tem permissão pra falar com o hardware diretamente costuma ser o kernel e seus drivers, que rodam no mesmo espaço de memória.</p>
<p>Isso não vai mudar por muito tempo. A kernel XNU da plataforma Darwin do Mac, a kernel NT do Windows, a kernel do BSD UNIX, que eu não lembro se tinha codinome. Dispositivos Android usam a kernel do Linux. Dispositivos iOS como iPhone usam uma kernel derivada do MacOS. Existem outras de nicho, mas essas são as principais e vão continuar sendo por muito tempo. E todas elas tem uma coisa em comum: são escritos em C e C++. E porque isso importa já que no final, depois de compilar, vira tudo um binário?</p>
<p>Porque essas kernels expõe suas funcionalidades como funções de C, que podemos interfacear com os diversos arquivos de cabeçalho com extensão &ldquo;.h&rdquo;. Pra realmente entender isso, precisa entender um pouquinho de como compilação de C funciona. Eu expliquei parte disso em episódios como do Hello World, a diferença de arquivos texto e binário e o episódio de linguagem interpretada versus compilada. Depois assistam pra entender.</p>
<p>A explicação que vou fazer agora acho é um pouco errado, mas é pra simplificar o modelo na cabeça. Se alguém tiver uma explicação de forma mais simples, mandem nos comentários abaixo. Mas pense num driver, como driver da NVIDIA pra placa de video, ou driver pra placa de rede e coisas assim com uma DLL de Windows ou uma biblioteca .SO de Linux. A kernel depois que boota começa a carregar esses drivers. Pense um &ldquo;import&rdquo; em Python ou Javascript.</p>
<p>As estruturas de dados e funções que esses drivers implementam vão existir no mesmo espaço de memória que as outras estruturas da própria kernel. É como se a kernel já viesse embutida com esses drivers. Uma vez carregado, o driver enxerga tudo que a kernel enxerga e vice versa. Lembra ponteiros? A kernel pode manipular diretamente uma struct de uma placa de rede, por exemplo.</p>
<p>Isso é necessário porque no nível da kernel gostaríamos de ter a maior performance possível, o menor número de abstrações. A kernel ideal não desperdiça recursos fazendo indireções e abstrações. Por causa disso você nunca vai conseguir fazer um driver em Javascript, Python, Java ou Erlang.</p>
<p>O interpretador de Javascript, como o Google V8 ou o Spidermonkey da Mozilla, assim como a JVM de Java ou a BEAM de Erlang, poderíamos classificar mais ou menos como máquinas virtuais. A intenção delas é abstrair o sistema operacional por baixo, a kernel. Assim um programador de Python pode escrever praticamente o mesmo código pra rodar em Mac ou Windows ou Linux e o interpretador do Python vai se virar pra fazer funcionar embaixo. A JVM é a que mais esconde o OS por baixo, Python ou Javascript escondem menos e às vezes precisa fazer um &ldquo;if windows faça X else if Linux faça Y&rdquo; mas é raro precisar.</p>
<p>Pra ser capaz de criar um driver de dispositivo que consiga interagir direto com a kernel, em particular carregar no mesmo espaço de memória, precisa ser uma linguagem compilada que gera binários com a mesma ABI de C, ou seja cujo binário seja compatível com binários gerados pelo compilador de C em termos de tipos de dados básicos terem o mesmo tamanho, mesmo alinhamento, mesmo layout de structs e unions e chamadas de funções sigam as mesmas convenções, tipo uma compatibilidade de API no nível binário.</p>
<p>Outra coisa que talvez você não saiba de linguagens compiladas como C, C++, Rust, Nim, D ou Go e linguagens tecnicamente interpretadas como Python, Ruby, Javascript, PHP, e até Java, C# ou Erlang e Elixir. Eu digo &ldquo;tecnicamente interpretadas&rdquo; porque Java não gera binário nativo. Sim, Java ou Javascript tem coisas como JIT na JVM ou V8, que no final pode gerar binário de alguns trechos, mas originalmente não são binários nativos. Só em tempo de execução.</p>
<p>O problema de não ter binário nativo de antemão é que não sabemos o endereço de funções e estruturas de dados. Por isso não temos como fazer um código de C que aponta diretamente pra essas estruturas usando coisas como ponteiros. Mesmo assim é possível integrar binário feito em Rust ou C com programas em Java ou Javascript. Por exemplo, um JavaScript consegue importar bibliotecas como OpenSSL, só que um String de Javascript não é um tipo de dados igual a um String de C. Um String de Python não é igual a um String de C#, então como faz pra uma linguagem falar com outra?</p>
<p>A única forma do binário gerado por uma linguagem conseguir usar um tipo de dados diretamente via ponteiro de outra linguagem, só é possível se são binariamente iguais, tenham a mesma ABI. Quando não tem, precisa existir um processo de conversão. Você já deve ter ouvido falar dos termos serializar e desserializar ou marshalling e unmarshalling. A grosso modo, no mundo de web seria mais ou menos como converter uma estrutura XML num JSON ou vice versa.</p>
<p>O que acontece quando se chama uma API que só devolve XML mas precisa passar pra uma classe ou outra biblioteca que só entende JSON? Precisa converter, só que conversão tem o seguinte defeito. Veja este exemplo de XML que a API hipotética devolveria, ela tem  845 bytes.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;product&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;name&gt;</span>Playstation 5<span class="nt">&lt;/name&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;sku&gt;</span>PS5<span class="nt">&lt;/sku&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;manufacturer&gt;</span>Sony<span class="nt">&lt;/manufacturer&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;category&gt;</span>Video Games<span class="nt">&lt;/category&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;description&gt;</span>
</span></span><span class="line"><span class="cl">    The Playstation 5 is the next-generation gaming console from Sony, featuring lightning-fast loading, stunning graphics, and immersive gameplay.
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/description&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;specifications&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;CPU&#34;</span><span class="nt">&gt;</span>AMD Zen 2<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;GPU&#34;</span><span class="nt">&gt;</span>AMD RDNA 2<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;Memory&#34;</span><span class="nt">&gt;</span>16 GB GDDR6<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;Storage&#34;</span><span class="nt">&gt;</span>1 TB NVMe SSD<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;Dimensions&#34;</span><span class="nt">&gt;</span>39 x 10 x 26 cm<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;specification</span> <span class="na">name=</span><span class="s">&#34;Weight&#34;</span><span class="nt">&gt;</span>4.5 kg<span class="nt">&lt;/specification&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/specifications&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;pricing&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;price</span> <span class="na">currency=</span><span class="s">&#34;USD&#34;</span><span class="nt">&gt;</span>499.99<span class="nt">&lt;/price&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/pricing&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;inventory&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;quantity&gt;</span>50<span class="nt">&lt;/quantity&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/inventory&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/product&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Digamos que fizemos um código pra converter de XML pra JSON ou seja, faz marshall entre os dois formatos, e eis o JSON equivalente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;product&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Playstation 5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;sku&#34;</span><span class="p">:</span> <span class="s2">&#34;PS5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;manufacturer&#34;</span><span class="p">:</span> <span class="s2">&#34;Sony&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;category&#34;</span><span class="p">:</span> <span class="s2">&#34;Video Games&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;The Playstation 5 is the next-generation gaming console from Sony, featuring lightning-fast loading, stunning graphics, and immersive gameplay.&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;specifications&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;specification&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;CPU&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;AMD Zen 2&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;GPU&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;AMD RDNA 2&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Memory&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;16 GB GDDR6&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Storage&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;1 TB NVMe SSD&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Dimensions&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;39 x 10 x 26 cm&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Weight&#34;</span><span class="p">,</span> <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="s2">&#34;4.5 kg&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;pricing&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;price&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;currency&#34;</span><span class="p">:</span> <span class="s2">&#34;USD&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="mf">499.99</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;inventoryQuantity&#34;</span><span class="p">:</span> <span class="mi">50</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse JSON é um pouco menor, com 808 bytes. O importante é o seguinte: nesse instante a função que converte tem em memória as duas versões, ocupando o total de 845 + 808 que dá mais de 1600 bytes. Agora pense no nível de uma struct de C versus um objeto JSON de Javascript. Não tem como criar um ponteiro pra um objeto JSON a partir de um código C e tentar usar como se fosse uma struct. Se fossem compatíveis, não precisaria duplicar memória, mas como não são compatíveis, precisamos fazer marshalling, duplicando a memória usada.</p>
<p>Eu acho que muito iniciante não pensa assim, mas comece a enxergar onde memória é duplicada. Por exemplo, quando você abre seu navegador e pede uma página web pra amazon.com por exemplo, sabemos que o servidor web da Amazon vai processar o que precisar pra no final gerar um string gigante que é o conteúdo HTML pra te responder. Esse HTML está ocupando memória no servidor. Quando ele envia pra você, e chega no seu navegador, o navegador tem uma cópia dessa string. Tanto o servidor web quanto seu navegador tem uma cópia do mesmo HTML, duplicando memória nos dois lugares. Isso é inevitável.</p>
<p>O mesmo vale pra um script feito em Javascript ou Python. Lembra da tal função strftime pra formar data e hora que falei lá no começo do episódio? Por baixo é uma função em C. No Python criamos a String &ldquo;%d/%m/%Y&rdquo; pra formatar a data e chamamos &ldquo;datetime.strftime&rdquo;. Por baixo essa função vai chamar a função da LibC que também chama &ldquo;strftime&rdquo;, pra isso precisa criar uma String de C, mas a String de Python não é compatível com String de C, então precisa converter e isso vai duplicar esse String.</p>
<p>Esse é um dos custos escondidos que tem em várias linguagens quando integram com bibliotecas locais feitas em C por exemplo, ou quando fazemos chamadas remotas pra APIs de microserviços ou servidores de banco de dados. Várias estruturas de dados como Strings estão o tempo todo sendo duplicados pra converter num formato que o outro lado entende. O exemplo que dei de XML e JSON são pequenos, nem 1 kilobyte, mas no mundo real, quem já trabalhou em projetos de verdade sabe que estamos transitando documentos muito maiores que isso, de centenas de usuários o tempo todo. É uma das razões de tanta diferença no uso de recursos entre diferentes linguagens ou diferentes bibliotecas.</p>
<p>Quando Java tinha a noção de escrever tudo em Java, ou seja, tudo rodando dentro do mesmo processo da mesma JVM, onde todas as bibliotecas também seriam em Java, não era só pra ser bonito. Uma das vantagens é que se tudo fosse feito em Java, internamente não precisa ter marshalling e unmarshalling, poderia lidar diretamente com referências pras estruturas de dados. Sendo que se integrar como uma biblioteca feita em C usando o recurso de JNI ou Java Native Interface,  precisa existir uma tradução entre o layout do espaço de memória de Java pro espaço do C. O mesmo vale pra outras linguagens que não trabalham com os mesmos tipos de C.</p>
<p>Se ficou abstrato até aqui, deixa eu mostrar um exemplo super besta em Python. Considere o seguinte trecho de código em Python:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># Import the extension module</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">c_extension</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Call the py_c_function function with a Python string argument</span>
</span></span><span class="line"><span class="cl"><span class="n">c_extension</span><span class="o">.</span><span class="n">py_c_function</span><span class="p">(</span><span class="s2">&#34;Hello, C function!&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Aqui eu estou importando um módulo qualquer feito em C e em seguida chamo uma função declarada nesse módulo passando um String qualquer. Vamos ver como teríamos que fazer essa função em C.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;Python.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Declare a C function that expects a char* as a parameter
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">c_function</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Do something with the C string here
</span></span></span><span class="line"><span class="cl">  <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;C function received string: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Define a Python wrapper function for the C function
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">PyObject</span><span class="o">*</span> <span class="nf">py_c_function</span><span class="p">(</span><span class="n">PyObject</span><span class="o">*</span> <span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span><span class="o">*</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// Extract the Python string argument from the Python tuple
</span></span></span><span class="line"><span class="cl">  <span class="n">PyObject</span><span class="o">*</span> <span class="n">py_s</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="s">&#34;O&#34;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">py_s</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// Convert the Python string to a C string
</span></span></span><span class="line"><span class="cl">  <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">s</span> <span class="o">=</span> <span class="nf">PyBytes_AsString</span><span class="p">(</span><span class="n">py_s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">s</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// Call the C function with the C string
</span></span></span><span class="line"><span class="cl">  <span class="nf">c_function</span><span class="p">(</span><span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// Return None to indicate that the function succeeded
</span></span></span><span class="line"><span class="cl">  <span class="n">Py_RETURN_NONE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Primeiro declaro a tal função <code>c_function</code> que recebe uma string e imprime na tela. Um string em C é só um array de caracteres que termina com caracter nulo. Já uma string em Python é um objeto, uma estrutura de dados bem diferente. Por isso embaixo declaramos uma segunda função chamada <code>py_c_function</code> que recebe um objeto Python cujo tipo é um ponteiro pra <code>PyObject</code> chamado <code>args</code>. O primeiro parâmetro é o <code>self</code> que todo método de Python declara explicitamente, o equivalente <code>this</code> em Javascript, por exemplo.</p>
<p>O importante nessa função é essa <code>PyBytes_AsString</code> que vai devolver o ponteiro pro array de chars que está nessa variável <code>py_s</code>. Agora, praquele código em Python conseguir chamar esse código em C, precisamos de outro código que vai intermediar isso, escrito em Cython com extensão &ldquo;.pyx&rdquo; mais ou menos assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># c_extension.pyx</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Declare a C function that expects a char* as a parameter</span>
</span></span><span class="line"><span class="cl"><span class="n">cdef</span> <span class="n">void</span> <span class="n">c_function</span><span class="p">(</span><span class="n">const</span> <span class="n">char</span><span class="o">*</span> <span class="n">s</span><span class="p">)</span> <span class="n">nogil</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Do something with the C string here</span>
</span></span><span class="line"><span class="cl">    <span class="n">printf</span><span class="p">(</span><span class="s2">&#34;C function received string: </span><span class="si">%s</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Define a Python wrapper function for the C function</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">py_c_function</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Convert the Python string to a C string</span>
</span></span><span class="line"><span class="cl">    <span class="n">cdef</span> <span class="n">const</span> <span class="n">char</span><span class="o">*</span> <span class="n">cs</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Call the C function with the C string</span>
</span></span><span class="line"><span class="cl">    <span class="n">c_function</span><span class="p">(</span><span class="n">cs</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse é o código que faz o tal marshalling, ou conversão, do objeto de String do Python pra um array de char, é isso que faz o método &ldquo;encode&rdquo; da String, duplica a string. Isso é importante porque o objeto de String de Python está sob controle do garbage collector de Python. Digamos que ele decida que ninguém tá usando mais essa String e limpa da memória. Mas no lado do C, que o garbage collector não enxerga, a String ainda era necessária, daí iria crashear o programa. Mas passando uma cópia separada, agora cada um tem seu próprio string e um não pisa no pé do outro, mas o custo disso foi duplicar essa string.</p>
<p>É assim que linguagens como Python, Javascript, Ruby ou PHP fazem pra falar com funções de bibliotecas em C: via marshalling e unmarshalling de estruturas de dados, onde cada lado gerencia a memória do seu jeito. No lado do Python o garbage collector dele se vira com os objetos que ele criou. E do lado do C vai usar, por exemplo, malloc e free, pra lidar com seu espaço de memória. Por isso que precisa duplicar memória na comunicação entre eles e por isso é mais pesado.</p>
<p>E qual a diferença com uma linguagem que compila binário nativo compatível com C como Rust? Vamos fazer a mesma coisa usando Rust agora. Eis um exemplo de um código Rust que chama uma função de alguma biblioteca C qualquer que recebe uma String como parâmetro, e sendo em C, sabemos que String de C é sempre um ponteiro pra um array de chars terminado em nulo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">ffi</span>::<span class="n">CString</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">os</span>::<span class="n">raw</span>::<span class="n">c_char</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// Declare the C function using the extern keyword
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span><span class="w"> </span><span class="s">&#34;C&#34;</span><span class="w"> </span><span class="k">fn</span> <span class="nf">c_function</span><span class="p">(</span><span class="n">s</span>: <span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="n">c_char</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Do something with the C string here
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="fm">println!</span><span class="p">(</span><span class="s">&#34;C function received string: </span><span class="si">{}</span><span class="s">&#34;</span><span class="p">,</span><span class="w"> </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">CStr</span>::<span class="n">from_ptr</span><span class="p">(</span><span class="n">s</span><span class="p">).</span><span class="n">to_str</span><span class="p">().</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Create a Rust string
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&#34;Hello, C function!&#34;</span><span class="p">.</span><span class="n">to_owned</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Convert the Rust string to a CString
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">c_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">CString</span>::<span class="n">new</span><span class="p">(</span><span class="n">s</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Call the C function with the CString
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">unsafe</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">c_function</span><span class="p">(</span><span class="n">c_string</span><span class="p">.</span><span class="n">as_ptr</span><span class="p">())</span><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse &ldquo;extern C&rdquo; é pra declarar a assinatura da função C externa que vamos chamar, cujo nome é <code>c_function</code> de novo e o parâmetro é o ponteiro pro array de char. Na função <code>main</code> começamos criando um String de Rust. Só que, assim como no caso do Python, um String de Rust é um objeto, uma estrutura de dados diferente de array de char, por isso criamos uma <code>CString</code> que existe no módulo &ldquo;std::ffi&rdquo; pra converter o String de Rust num String de C. Finalmente, dentro de um bloco inseguro, <code>unsafe</code> chamamos a função de C passando esse novo String de C como ponteiro.</p>
<p>Assim como em Python, tivemos que duplicar a memória pra converter os strings. Mas em Rust podemos pular a parte de criar a string de Rust e direto já trabalhar com String de C. Pra demonstrar isso deixa eu começar fazendo uma nova função em Rust besta que recebe um String e converte tudo pra maiúsculo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">rust_function</span><span class="p">(</span><span class="n">s</span>: <span class="kp">&amp;</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">String</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Do something with the Rust string here
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">s</span><span class="p">.</span><span class="n">to_uppercase</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Simples, recebe uma referência pra um String e retorna outro String. Agora vamos ver a mesma função mas usando direto String de C em vez do String de Rust:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">ffi</span>::<span class="n">CString</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">rust_function</span><span class="p">(</span><span class="n">s</span>: <span class="nc">CString</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">CString</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Convert the CString to a slice of c_char
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s_slice</span>: <span class="kp">&amp;</span><span class="p">[</span><span class="n">c_char</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">as_ref</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Iterate over the slice and uppercase the characters
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">s_uppercase</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">c_char</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s_slice</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">iter</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|&amp;</span><span class="n">c</span><span class="o">|</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">to_ascii_uppercase</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// Create a new CString from the uppercase characters
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">CString</span>::<span class="n">new</span><span class="p">(</span><span class="n">s_uppercase</span><span class="p">).</span><span class="n">unwrap</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Eu não sou super fluente em Rust então não sei se tem jeito melhor de fazer isso, mas veja a diferença. Agora o parâmetro é direto um string de C e devolve um string de C também. Um objeto de String de Rust tem métodos conveniente como &ldquo;to_uppercase&rdquo; pra transformar tudo em maiúsculo. Mas pra trabalhar em cima de um String de C, precisamos manualmente iterar caracter a caracter do array e transformar em maiúsculo com o método &ldquo;to_ascii_uppercase&rdquo;.</p>
<p>Pra fazer código Rust compatível com estrutura de C sem ficar convertendo em objetos nativos de Rust, que são mais convenientes mas duplica memória, precisamos praticamente escrever C usando sintaxe de Rust. Não vai ser o código mais bonito do mundo, mas em casos mais complexos que esse certamente vai ser melhor do que escrever C na mão, porque podemos contar com os recursos mais avançados de gerenciamento de memória e segurança que o compilador do Rust nos fornece. Mas se alguém tinha dúvidas de como trabalhar com Rust e C, por exemplo, na kernel do Linux, esse é um exemplo besta que ilustra como é mais ou menos.</p>
<p>Agora é minha opinião, mas dado o que expliquei até agora, o que eu penso de linguagens é o seguinte: se quiser fazer programação de sistemas, ou seja, coisas de baixo nível como drivers de dispositivo ou mesmo componentes de infraestrutura como a stack TCP, o certo é usar C, C++ e agora Rust ou até linguagens meio desconhecidas mas  de mais alto nível e compiladas como Nim ou a linguagem D, que como o nome diz, foi pensado pra ser sucessor de C mas nunca conseguiu  popularidade, talvez porque Rust e Go surgiram no meio do caminho e meio que roubaram os holofotes.</p>
<p>Numa camada acima vem construção de ferramentas de administração e infraestrutura. Antes muitos faziam bibliotecas em C como um oniguruma pra regex, e pra facilitar o uso, criavam clientes com linguagens dinâmicas de script como Python ou Perl da vida. Mas Rust e Go tornaram menos dolorido escrever esse tipo de software. A sintaxe é mais moderna e limpa do que C ou C++ então não é incomum que não precise mais fazer scripts de Python por cima pra facilitar o uso. Exemplo disso é um Docker, feito em Go. Antigamente alguém poderia criar um libdocker em C e um script chamado Docker em Python que integra com essa lib pra ser a ferramenta de linha de comando. Agora podemos usar só Go ou só Rust.</p>
<p>Go e Rust geram binários quase tão eficientes quanto C ou C++ e no caso de Rust até mais eficientes e mais seguros em muitos casos. Nos últimos anos o mundo Linux ganhou várias ferramentas como o terminal Alacritty feito em Rust que eu gosto bastante, e tem esta página com várias ferramentas alternativas escritas em Rust que eu uso no dia a dia como o &ldquo;exa&rdquo; que substitui o &ldquo;ls&rdquo;, o &ldquo;procs&rdquo; que substitui o &ldquo;ps&rdquo;, &ldquo;fd&rdquo; que substitui o &ldquo;find&rdquo; e muito mais, depois dêem uma olhada.</p>
<p>Depois entramos na categoria que não expliquei muito que são sistemas distribuídos.  São softwares como bancos de dados ou sistemas de armazemento de volumes grandes de dados. Aqui eu vejo muitas soluções que saíram do ecossistema Apache, como Apache Hadoop, Apache Solr, Apache Spark, Apache Kafka, Apache Cassandra e muito mais, todos feitos em Java. Precisava ser em Java? Não, por exemplo, existem alternativas como a DataStax que é Cassandra escrito em C++.</p>
<p>Mas o que surgiu desse esforço massivo da Apache foi um ecossistema de bibliotecas e ferramentas que facilitam o desenvolvimento de sistemas distribuídos, como o famoso ZooKeeper que é o componente responsável pelo consenso entre diversos nodes de um sistema distribuído. Se isso soou grego, pensa assim. A grande vantagem de um banco de dados Cassandra é conseguir aumentar a capacidade adicionando novos servidores no cluster. O sistema se coordena pra receber esse node e passa a distribuir o armazenamento e processamento pra ele. Se um node falha, o sistema de consenso lida com isso também, via eleições por exemplo. São soluções pra quem precisa lidar com petabytes de dados, não é pra tech startup pequena sair usando.</p>
<p>A grande vantagem do Java é ser mais produtivo e menos doloroso do que C++. Uma coisa é fazer algo relativamente &ldquo;pequeno&rdquo; em quantidade de linhas de código como uma ferramenta de linha de comando ou driver, outra coisa é criar um software massivo com milhões de linhas de código pra lidar com processos complexos como coordenação de dados massivos em nós de um sistema distribuído. Java foi a escolha certa na época, talvez a única escolha. Pouca gente conhecia Erlang e a sintaxe também nunca foi muito familiar pra quem se acostumou a herança de sintaxe do C. Hoje em dia um novo Cassandra poderia ser feito ou em Elixir ou em Go, mas sendo sistemas super complexos e já maduros, não existe motivo pra reescrever tudo nessas linguagens.</p>
<p>Erlang foi uma oportunidade perdida e Elixir apareceu uns 5 ou 10 anos mais tarde do que deveria. Se tivesse aparecido no começo dos anos 2000, certamente seria uma das linguagens mais usadas hoje. O ZooKeeper que eu falei, boa parte de suas funcionalidades existem por padrão no Erlang, que também usa uma máquina virtual e foi feito pra criar serviços distribuídos no mercado de telecomunicações nos anos 80. Ele estava muito à frente do seu tempo, muito antes de começarmos a nos preocupar com escalabilidade horizontal em tamanho de internet no fim dos anos 90.</p>
<p>Só que naquela época as opções era fazer tudo em C++, que é eficiente mas é masoquismo, ou C# mas aí  estava fechado no ecossistema de Windows da Microsoft, ou Java, que era multiplataforma e bem mais amigável do que C++. Por eliminação, escolhemos Java. Só que a JVM não foi criado pra sistemas distribuídos como Erlang, então empresas como Apache precisaram criar essa infraestrutura, componentes como o ZooKeeper, Storm, Flink.</p>
<p>Eu posso estar superestimando, mas acredito que se fosse fazer tudo que tem no portfolio da Apache em Elixir, seria mais produtivo e menos difícil hoje. Mas nunca vamos saber, porque a essa altura do campeonato, não vale a pena tentar reescrever um ecossistema inteiro. A Apache já resolveu esses problemas com Java e equiparou as funcionalidades como Erlang. Pra entender qual é essa grande vantagem do Erlang, assista essa minha palestra onde explico como isso funciona dentro da VM do Erlang.</p>
<p>Do ponto de vista de sistemas distribuídos, outra alternativa moderna é Go. Só que Go tem bem menos ferramentas do que Java ou Erlang, que tiveram muito mais tempo pra amadurecer. Assim como Java, primeiro precisaria criar a mesma infraestrutura. Algoritmos de consenso, sistema de arquivos distribuídos, sistema de processamento de batch, streams distribuídos, armazenamento em cluster e assim por diante, antes de conseguir fazer os equivalente Spark, Kafka ou Cassandra. De novo, é tudo especulação da minha parte, porque a realidade é que se eu precisar de sistemas distribuídos, vou olhar o ecossistema Java da Apache.</p>
<p>O que nos leva a criação de aplicações comerciais, como eu chamaria. Coisas que a maioria aqui assistindo provavelmente vai lidar mais. Aplicações web. Seja feito em Ruby on Rails, ou Django com Python, ou Laravel com PHP, ou Spring Boot com Kotlin, ou Express com TypeScript e assim por diante. Aqui vem uma divisor: os softwares que falei até aqui como uma kernel de OS, driver de dispositivo, ferramentas de linha de comando de Linux, ou até um Kafka ou Cassandra tem uma coisa em comum: o ideal é que eles mudem pouco, que a maior parte das melhorias sejam em pequenas otimizações de performance, segurança, estabilidade. Eu não quero meu banco de dados mudando tanto que a cada nova versão dá crash.</p>
<p>Já aplicações web, que lidam com consumidor final, seja um chat, ecommerce, rede social, ferramentas de produtividade como um Figma ou Canva, ele competem pela atenção e o dinheiro das pessoas. Pra competir, uma precisa adicionar rápido funcionalidades que superam do concorrente. Mesmo que apareça um bug novo que alguns vão reclamar, o importante é que dê pra subir correções rápido. Pra isso queremos linguagens que facilitem produtividade mais do que performance. Sim, daria pra fazer sistemas mais eficientes escrevendo 100% em Rust, ou Go, ou mesmo Java e Elixir, mas até certo ponto é mais fácil treinar pessoas em Python ou Javascript e elas se tornam mais rapidamente produtivas nessas plataformas.</p>
<p>Esse é o motivo de porque não jogamos fora Python ou Javascript: porque taxa homem é mais caro do que custo de CPU por hora. Essas linguagens são mais limitadas como mostrei antes: não servem pra desenvolvimento de coisas com drivers ou protocolos de consenso nem processamento de imagem ou video, mas são ótimos pra fazer código cola mais fácil de usar, importando binários feitos em linguagens mais eficientes como C ou Rust. Portanto podemos usar um Python da vida pra 80% das funcionalidades mais &ldquo;mundanas&rdquo; e usamos C, Go ou Rust pra fazer as partes mais difíceis e integramos com uma extensão usando FFI.</p>
<p>Daí temos o mundo mobile, Android e iOS. Pra aplicativos simples, pense num iFood, AirBnb, até um Facebook ou Instagram, podemos apelar pra frameworks mais pesados mas, de novo, mais produtivos como React Native ou Flutter, que evita que a maioria dos desenvolvedores precisem saber como o baixo nível funciona e produzam mais rápido. A maioria dos smartphones hoje já tem mais de 2 gigabytes de RAM, e dá desperdiçar um pouco.</p>
<p>Claro, se todo mundo usa React Native, todo mundo vai estar limitado nas mesmas coisas que ele suporta. Pra se diferenciar, fazemos a mesma coisa que falei no mundo Web: criamos componentes mais eficientes, de mais baixo nível em Swift pra iOS ou Kotlin pra Android e  integramos nesses frameworks. Quem souber o baixo nível sempre vai ser um profissional mais valioso. É obrigatório? Não. Mas você quer evoluir na carreira e ganhar mais no futuro? Então sim, precisa saber. Sabe tudo que vim mostrando de exemplo na primeira metade do episódio? Sim, aquilo tem que parecer arroz com feijão pra você se considerar um especialista no assunto.</p>
<p>Daí chegamos nas categorias mais hypadas e consideradas mais modernas como data science, machine learning e inteligência artificial. E aqui o mais importante é tirar o máximo proveito do hardware, em particular de conjuntos de instruções como AVX, SSE ou CUDA em GPUs NVIDIA ou OpenCL em GPUs AMD. Pra isso precisamos voltar pro nível de C++. Como expliquei antes, tudo de data science em cima de Python começa em bibliotecas como numpy e scipy, que são feitos em C e Fortran. Machine learning como um Tensorflow começa em coisas como CUDA e C++. Mesmo em javascript, depende de acesso à GPU via WebGL dos navegadores. Não é a linguagem a parte mais importante e sim acesso a esses componentes de computação paralela de vetores e matrizes de dados.</p>
<p>Eu disse no episódio anterior comentando sobre o ChatGPT que no mundo de deep learning, criar modelos como de geração de imagens do Dall-e 2 ou geração de textos como GPT3, custam astronomicamente caro e nenhum de nós vai ser capaz de criar nada perto disso. Só quem tiver acesso a conseguir trabalhar nos centros de pesquisa de uma OpenAI ou Microsoft da vida que vai ter essa oportunidade. Mas pra coisas úteis do dia a dia não precisamos de um GPT. Machine learning com tensorflow e modelos ordens de grandeza mais simples já são úteis pra escopos específicos. Detecção de movimento é um exemplo, pra aplicações de realidade aumentada.</p>
<p>Muitos não pensam nisso, mas algoritmos mais &ldquo;simples&rdquo; como de relevância que é basicamente classificação estatística já é extremamente útil pra coisas como ecommerce conseguirem mostrar &ldquo;produtos recomendados pra você&rdquo;. Ou sistemas como Elastic terem pesquisa fuzzy com relevância, como um mini Google, onde o usuário não precisa escrever os termos exatos, mas mesmo assim ele consegue devolver resultados relevantes. Tudo isso já existe e já usamos em diversos sistemas, de ecommerces a redes sociais. A maioria dos desenvolvedores nem sabe o que é um Elastic ou Solr e acha que vai entender como funciona um ChatGPT. Tá longe, bem longe.</p>
<p>Enfim, eu sei que o episódio de hoje talvez tenha sido denso, mas eram alguns pensamentos aleatórios que tinha na minha cabeça fazia tempo que queria dar dump. Se você é iniciante, não espere compreender tudo que eu disse de uma só vez, pesquise os termos que não conhecia, volte de novo. Quem já tem experiência já sabia tudo que eu falei, talvez dê alguns insights pra complementar. O objetivo não era dizer que essa ou aquela linguagem é a melhor ou a pior.</p>
<p>Cada uma estava no lugar certo na hora certa, não necessariamente foram escolhidas por serem as melhores. E mesmo surgindo coisas novas consideradas melhores, não saímos reescrevendo. Maturidade é sempre mais importante que novidade. Se ficaram com dúvidas mande nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e não deixem de compartilhar o video com seus amigos. A gente se vê, até mais!</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #94 - O que vem DEPOIS do Hello World | Consertando meu C</title><link>https://akitaonrails.github.io/2021/03/22/akitando-94-o-que-vem-depois-do-hello-world-consertando-meu-c/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/03/22/akitando-94-o-que-vem-depois-do-hello-world-consertando-meu-c/</guid><pubDate>Mon, 22 Mar 2021 15:12:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/YyWMN_0g3BQ"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Algoritmos e Estruturas de Dados é parte do conhecimento fundamental que todo programador precisa saber ou nunca vai avançar de verdade na profissão. Vamos ver a ponta do iceberg pra vocês terem uma idéia do que isso significa. E vou aproveitar pra consertar alguns erros que cometi no episódio anterior.&lt;/p&gt;
&lt;p&gt;Conteúdo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:00 - Intro&lt;/li&gt;
&lt;li&gt;01:47 - Consertando meus erros de C&lt;/li&gt;
&lt;li&gt;04:13 - Segmentos da Memória Virtual&lt;/li&gt;
&lt;li&gt;11:53 - Arrays de Javascript são &amp;ldquo;Arrays&amp;rdquo;?&lt;/li&gt;
&lt;li&gt;15:56 - Lista Ligada em C&lt;/li&gt;
&lt;li&gt;21:37 - Hashtable em C&lt;/li&gt;
&lt;li&gt;39:11 - Algoritmos de Ordenação&lt;/li&gt;
&lt;li&gt;42:11 - Complexidade e Big O&lt;/li&gt;
&lt;li&gt;43:30 - Vendedor Viajante e Fatorial&lt;/li&gt;
&lt;li&gt;47:29 - Mergesort vs Quicksort&lt;/li&gt;
&lt;li&gt;52:18 - Melhor e pior caso, Bubble vs Quick&lt;/li&gt;
&lt;li&gt;55:45 - Livros sobre Algoritmos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Links:&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/YyWMN_0g3BQ"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Algoritmos e Estruturas de Dados é parte do conhecimento fundamental que todo programador precisa saber ou nunca vai avançar de verdade na profissão. Vamos ver a ponta do iceberg pra vocês terem uma idéia do que isso significa. E vou aproveitar pra consertar alguns erros que cometi no episódio anterior.</p>
<p>Conteúdo:</p>
<ul>
<li>00:00 - Intro</li>
<li>01:47 - Consertando meus erros de C</li>
<li>04:13 - Segmentos da Memória Virtual</li>
<li>11:53 - Arrays de Javascript são &ldquo;Arrays&rdquo;?</li>
<li>15:56 - Lista Ligada em C</li>
<li>21:37 - Hashtable em C</li>
<li>39:11 - Algoritmos de Ordenação</li>
<li>42:11 - Complexidade e Big O</li>
<li>43:30 - Vendedor Viajante e Fatorial</li>
<li>47:29 - Mergesort vs Quicksort</li>
<li>52:18 - Melhor e pior caso, Bubble vs Quick</li>
<li>55:45 - Livros sobre Algoritmos</li>
</ul>
<p>Links:</p>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>No último episódio eu fiz diversos tipos de Hello World em C pra explicar o básico de programação mais de baixo nível, e foi super trabalhoso porque eu não queria quebrar o  conteúdo em vários episódios.</p>
<p>Eu não programo em C faz muitos anos então muita coisa enferrujou mesmo. Eu nunca fui um bom programador de C e agora então, só o básico. Eu editei aquele script algumas vezes e mudei os exemplos enquanto fui revisando, e tirei muita coisa de cabeça. Nisso acabei deixando passar vários erros que me deixaram bem frustrado porque eu só vi depois. O bom foi que vários de vocês viram e relataram nos comentários. Eu coloquei algumas na erratas daquele vídeo e vou usar o video de hoje pra complementar o que eu acho que faltou falar.</p>
<p>A ideia destes vídeos não é ser um curso de C, nem de longe. É a mesma coisa na faculdade, C ou Pascal era usado só pra não termos que usar alguma pseudo-linguagem pra ensinar os conceitos. Tem várias nomenclaturas e conceitos que aos olhos de quem programa C no dia a dia ficou feio. Muita coisa eu simplifiquei pra explicação ficar mais fácil. Pra aprender C de verdade tem que ver livros com The C Programming Language do Kernighan e Ritchie, os criadores da linguagem e estudar muito código fonte.</p>
<p>Se você é programador de C, perdeu uma oportunidade. Podia ter feito um video chamado “Vamos consertar o C cagado do Akita”. É um bom tema. Tem muito pouco video sobre C hoje em dia. De qualquer forma, já que ninguém fez, vou fazer eu mesmo. A primeira metade de hoje vai ser uma errata aproveitando pra adicionar mais conteúdo ao que eu já tinha explicado e a segunda metade vai molhar um pouco os dedos em mais coisas de estruturas de dados e algoritmos que não coube no episódio passado. Então vamos lá.</p>
<p>(&hellip;)</p>
<p>Vamos começar com alguns erros pequenos. Tem um que se eu não prestar atenção cometo toda hora sem perceber, até eu acho irritante. Provavelmente porque por muitos anos programei em 32-bits, eu confundo quando converto bits em bytes. Mas é simples, só dividir por 8. Endereços de 32-bits são armazenados em 4 bytes. Mas endereços de 64-bits são 8 bytes. Só que minha memória muscular me ferra.</p>
<p>Aos 6 minutos e 6 segundos do video eu falo que se você alocar um inteiro de 64-bits mas não for usar valores maiores que 255, vai estar desperdiçando 7 bytes desses 8. E isso tá correto. Mas durante a edição a memória muscular ficou me falando “32 bits é quatro bytes”, o que tá errado, e achei que eu tinha gravado falando errado. Daí escrevi uma correção na tela de que iria desperdiçar 3 bytes. Ou seja, eu falei certo na gravação e corrigi errado na edição. A mesma coisa aconteceu aos 45 minutos e 20 segundos que eu falo que é 4 bytes, mas são 8.</p>
<p>Outra coisa que vira e mexe me confundo se falar muito rápido foi como aos 40 minutos e 54 segundos eu falo que 255 BYTES é um quarto de 1 megabyte. Tá errado, lógico, é um quarto de KILObyte. 255 vezes quatro são 1024 bytes, ou um kilobyte. Daí aos 6 minutos e 50 segundos eu falei errado o range de inteiros de 8-bits com sinal, o correto é de menos 128 a positivo cento e vinte e sete. Em hexa é mais difícil de errar porque vai de hexa FF até 7F.</p>
<p>Mais pro fim, depois dos 57 minutos quando faço a <code>struct</code> Person e começo a fazer createPerson escrevi errado <code>nome</code> em vez de <code>name</code> e ficou meio estranho. Foi um typo feinho mas como não chega a estragar o exemplo em si resolvi não regravar só por causa disso. Pior foi quando dei copy e paste do código de inicialização da struct pra dentro da função createPerson e esqueci os valores hardcoded em vez de usar os argumentos. O código ficou desse jeito aqui, mas o correto deveria ter editado pra ficar assim. Por isso a gente tem que tomar cuidado ao ficar dando copy e paste de código.</p>
<p>Além desses erros menores, o erro que me deixou mais irritado foi perto dos 39 minutos quando eu quis explicar sobre stack e passagem de parâmetros por valor. O exemplo original era com inteiros e nesse caso ela teria sido copiada 3 vezes passando da <code>main</code> pra <code>f1</code> e depois pra <code>f2</code>, mas eu substituí pela string “hello world” e na hora nem pensei muito porque eu tava com pressa, só segui o mesmo exemplo como se o string estivesse sendo duplicado na stack. Obviamente que não tá. E pra explicar, preciso complicar a parte que eu não queria. Quando falei de memória virtual pode parecer que ela é dividida só entre stack e heap, mas na verdade tem mais que isso.</p>
<p>Se eu quiser complicar e mostrar mais, vai ficar deste outro jeito. Seguindo pra baixo do heap a gente tem o segmento BSS que é o block starting symbol, ou que alguns chamam de better save space. Toda variável global estática que só foi declarada mas você não atribui nenhum valor fica nesse espaço, automaticamente inicializado como zero ou nulo. É diferente de quando você usa um <code>malloc</code> ou <code>calloc</code> que vai pegar algum trecho de memória disponível da heap.</p>
<p>Embaixo do BSS tem mais dois segmentos que interessa pra gente hoje, a ROData e a Text. Esse segmento Text, ao contrário do que você pode entender pelo nome, é o espaço de endereços do seu programa executável propriamente dito, é um segmento de código, das instruções em linguagem de máquina. Agora o segmento ROData é mais interessante pra gente.</p>
<p>Quando eu fiz <code>char hello[] = &quot;Hello World&quot;</code> eu tinha dito que isso seria alocado na stack, o string inteiro. Tá errado. Que burro, dá zero pra ele. E até podia ser assim mesmo numa outra linguagem, mas no caso de C, o hello vai ser uma referência pra um endereço que fica nesse espaço chamado <code>ROData</code>. Quando o compilador GCC passa pelo meu código fonte, ele vê dados como esse <code>hello</code> que é fixo e constante e grava dentro desse segmento no binário final. RO é de Read Only, então ROData é um segmento de dados somente de leitura.</p>
<p>Isso não altera a explicação de passagem por valor. Toda vez que eu passo a variável <code>hello</code> como argumento das funções <code>f1</code> e <code>f2</code>, cada uma vai empilhar uma nova cópia no stack, mas não do string inteiro, e sim dos 8 bytes de endereço que apontam pro array &ldquo;Hello World&rdquo; que é fixo, constante e tá dentro do segmento <code>ROData</code>.</p>
<p>Pense nesse segmento com uma versão estática do Heap, que é dinâmico. O ROData é pra valores que você tem hardcoded no seu código fonte. Como strings. Mas strings dinâmicas, por exemplo, de valores que vieram num JSON que você puxou via API, de linhas do banco de dados que você puxou da rede, tudo isso vai ser alocado no Heap e, mesma coisa, os ponteiros pra eles vão sendo empilhados na stack durante a execução do programa.</p>
<p>Quando eu falei do formato ELF binário, que é o linguição de bits num formato específico pro Linux executar, a primeira instrução começa no endereço hexa 1000. Mas no mesmo binário ELF existem outros segmentos que você pode inclusive ver usando o comando no shell <code>objdump -h</code> e o executável que acabou de compilar. Então, se passarmos esse objdump no nosso hello vão aparecer todos os segmentos. Você vê que o décimo primeiro é o segmento <code>init</code> no endereço hexa 1000 que eu falei antes e na décima quinta posição tem o endereço hexa 2000 que é o segmento ROData.</p>
<p>No video anterior, ignorem quando eu falo que o string inteiro é alocado no Stack. Ele tá no ROData e na stack as variáveis <code>hello</code> são referências com o endereço pra esse string. É algo assim. As referências ocupam espaço, pouco espaço se comparado a um arrayzão, mas ocupam. E quando são passadas por valor, de função pra função, vão sendo duplicadas na stack. Três vezes no nosso hello world, cada uma com 8 bytes. Mas não é pra você se preocupar com uso de espaço na stack, isso raramente é um problema. Como eu já tinha dito só quando seu programa é pesado em coisas como recursão.</p>
<p>Outra coisa que eu Não falei no episódio anterior quando expliquei ponteiros é que depois de chamar <code>malloc</code> pra alocar espaço no heap, quando você termina o que tinha pra fazer, a boa prática é chamar a função <code>free</code>, que avisa o gerenciador de memória que aquele segmento não tá mais em uso e ele pode usar pra outra coisa. Eu não fiz <code>free</code> pra explicação não ficar extensa mas também porque o programa executa e sai muito rápido. E quando um programa termina, o sistema operacional se encarrega de tornar toda memória que você tava usando disponível de novo pra outra coisa, independente se você deu free antes ou não.</p>
<p>Programinhas que executam rápido como um hello world não precisam se preocupar. O problema são programas que ficam abertos muito tempo, digamos um navegador, ou um servidor web. Tirando em exercícios como o hello world, em código de verdade, você DEVE se preocupar com a memória sendo usada porque elas vão ficar em uso por tempo indeterminado. Podem ser horas ou dias e se você ficar dando <code>malloc</code> e nunca der <code>free</code> a memória disponível no heap vai acabar ou chegar perto de acabar, e quando isso acontece mecanismos como o OOM do sistema operacional pode forçar a parada do seu aplicativo. OOM é o sistema que monitora a memória usada por aplicativos, que significa Out of Memory Killer.</p>
<p>Justamente porque gerenciamento de memória é complicado de explicar, eu já tinha feito dois vídeos que recomendo que vocês assistam. Uma das vantagens de linguagens de mais alto nível com Java, C#, Go e todas as interpretadas como Javascript, Ruby, Python, é que elas tem algum garbage collector, cuja responsabilidade é gerenciar o heap no lugar do programador. Porém, a comodidade vem com um custo: todo garbage collector sempre vai usar mais memória do que se você gerenciar manualmente e causar picos de pausa pra limpeza durante o processamento, o que pode ser um problema pra você. Por outro lado tem menos riscos de vazar memória por causa de código mal feito.</p>
<p>As duas linguagens modernas que tem um bom balanço entre comodidade e não desperdiçar muita memória são o Swift e o Rust. Recomendo estudar o ARC do Swift que é uma ajuda do compilador pra gerenciar memória via contador de referências e o sistema de Borrow do Rust que é o mais diferente de todos.</p>
<p>Voltando aos meus erros, outra coisa que eu falei errado no video anterior foi quando disse que o Stack, ou Pilha, tem dois tipos, LIFO e FIFO e logo na sequência falei que tem Queues ou filas. Eu bobeei aqui, uma cadeia onde a gente vai empilhando elementos no topo e desempilhando do topo é last in first out, LIFO que é uma Pilha. Uma cadeia onde a gente vai empilhando elementos no fim mas vai tirando do começo, ou seja, vai tirando por ordem de chegada, é first in first out, FIFO também conhecido como Fila. Então toda pilha é LIFO e toda fila é FIFO.</p>
<p>Pilhas são usadas na execução de quase todo programa. Filas você vê todo dia no supermercado ou banco, ou se é desenvolvedor web. Todo servidor web tem uma fila, as requisições http vão chegando e sendo enfileiradas e vão sendo servidas na ordem de chegada. Todo job em background usa uma fila. Tudo que você precisa segurar porque não dá pra processar tudo de uma vez usa uma fila. Em sistemas distribuídos é particularmente importante pra coordenar e controlar a carga. Não adianta sua linguagem ser rápida em conseguir iniciar um monte de jobs assíncronos e sobrecarregar a máquina. Você precisa controlar quanto processamento paralelo quer ter num determinado momento, e filas é a estrutura básica por baixo desses tipos de mecanismos de controle.</p>
<p>E antes que alguém comente, eu disse que “quase” toda execução de programas coloca frames no stack mas existem linguagens chamadas stackless, que significa “sem stack”, embora isso não seja totalmente verdade. Inclusive existe uma versão de Python stackless. Não é que elas não usam nada do stack, mas elas criam um stack próprio no heap também. É um assunto longo por si só então só quis mencionar pra quem tiver curiosidade, mas pode ser interessante em casos de muita recursão ou concorrência onde você separa a stack de cada thread pra evitar coisas como condições de corrida.</p>
<p>Continuando, ficou outra dúvida nos comentários sobre arrays, porque eu disse que array é uma sequência contínua de elementos de mesmo tamanho, ou mesmo tipo. Tipo, em C, meio que define o tamanho do elemento. Se for um uint8_t é um inteiro sem sinal de 8-bits, portanto o tamanho é de 1 byte. Uma struct como a Person que eu mostrei, tem 3 campos, uma string de 10 chars, depois 2 ints de 8-bits, portanto 12 bytes no mínimo. O tamanho e formato do binário é definido pelo compilador e não vai ser necessariamente na ordem que eu mostro no exemplo.</p>
<p>Mas num Javascript eu posso fazer arrays conterem strings, números, outros arrays e o que eu quiser. Então ele é um array ou não é um array? Sendo honesto nunca parei pra ver o código em C++ que implementa Arrays de Javascript mas se ele for parecido com a forma que outras linguagens como Java ou C# da vida fazem ele provavelmente é um array de ponteiros mesmo.</p>
<p>Se o espaço do Array acaba e você tenta inserir um novo elemento, ele vai alocar um novo array um pouco maior e copiar todos os elementos da antiga pra nova, e no final liberar o espaço do array original. E todos os elementos dentro vão ser ponteiros, endereços pra objetos que pode ser objeto de string, objeto de número, objeto de array. Esses objetos estão alocados em algum lugar no heap, mas nesse array não vai ter o objeto em si, só o endereço que aponta pra esses objetos. E todos os endereços vão ocupar o mesmo tamanho de 8-bytes, portanto são todos elementos de mesmo tamanho, exatamente o requerimento pra um array.</p>
<p>Se uma linguagem suporta coisas como Generics, daí você consegue limitar um array de objetos pra ter elementos só de um determinado tipo, como Strings, e nunca aceitar um objeto de número por exemplo. Por baixo dos panos, no binário, não faz diferença porque tudo vai ser um ponteiro. Mas importa pra linguagem. Tipos em C eu acho mais importante pra determinar o layout binário das coisas. Tipos em linguagens de alto nível como Java é pra determinar a semântica do seu código.</p>
<p>Se você nunca estudou estruturas de dados sempre vai coçar a cabeça de porque um Java da vida tem classes como ArrayList, LinkedList, Vector, ArrayDequeue, HashSet, e tantas outras que herdam das interfaces de Iterable, Collection, Set e List. Sem conhecimento prévio, à primeira vista, tudo parece só um array.  É impossível eu explicar tudo, mas quero tentar explicar dois tipos diferentes de coleções hoje, que são dois dos mais usados pra vocês entenderem porque tem diferença.</p>
<p>Recapitulando, a grande vantagem de um array é rapidamente encontrar os valores de qualquer posição, com a premissa que você sabe que posição quer acessar. Só pegar o endereço do primeiro elemento e multiplicar pela posição e pelo tamanho do elemento, e por isso é importante todo elemento ser do mesmo tamanho. A desvantagem é se esse array precisa crescer o tempo todo e você não sabe o tamanho final. Daí toda vez que chega no final, precisa criar um outro array maior pra poder continuar, copiar todos os elementos do anterior e liberar essa memória, e ficar fazendo isso até conseguir preencher com todos os dados que precisa.</p>
<p>Vamos fazer de conta que na sua linguagem favorita ele instancia um array de 10 elementos por padrão. Daí você conecta num banco de dados, faz uma pesquisa e começa a vir linhas de dados. Você vai colocando na posição 0 do array, a próxima linha na posição 1, depois na posição 2 e vai indo. Aí preenche as 10 posições mas ainda tem mais linhas vindo do banco de dados. Por baixo dos panos, vai alocar outro array, agora com 20 posições, copiar as 10 da anterior, liberar o espaço dessas 10 antigas e agora você continua preenchendo, posição 10, posição 11 e vai indo.</p>
<p>Digamos que no final vieram 100 linhas da tabela do banco de dados. Pra comportar isso na memória, seu array precisou ser expandido 10 vezes. Ou seja, teve 10 operações de alocar um novo array e copiar o anterior nele. E na última etapa, quando você tinha um array de 90 elementos e acabou espaço, ele precisou alocar um de 100 elementos. Ou seja, num determinado momento você ocupou o dobro de memória, além de ter que fazer operações de alocação e cópia de todos os elementos até 9 vezes. É um desperdício de processamento e de memória.</p>
<p>Imagina se fosse uma tabela com cem mil linhas. Ou no outro extremo, imagine se você precisasse de 100 arrays que só vão ter 2 elementos cada. Nas no nosso faz de conta, cada array começa com 10 posições pré-alocadas. Agora você tem 800 posições que vão ficar desocupadas, mas ainda assim ocupando espaço na memória. Então a linguagem não pode nem pré-alocar um array grande demais pra pra não ter que processar muitas operações de alocar novo array e copiar tudo e nem pode pré-alocar muito pequeno pra economizar memória. É um dilema, por isso sempre que possível você deve iniciar arrays dizendo pra ele quanto de espaço pretende usar.</p>
<p>Se você está no caso de listas que vão expandir e você não sabe quanto, pode escolher não usar arrays. Vamos começar usando o struct que aprendemos e criar uma chamada <code>Node</code> que traduz pra um nó, em português. Dentro vamos criar dois elementos, um valor inteiro pra guardar qualquer número, e eu vou usar número só porque Strings em C puro é mais chatinho e ia complicar o exemplo, mas eu recomendo de lição de casa vocês tentarem fazer o valor do nó ser um String. O próximo elemento é mais importante, vou chamar ele de <code>previous</code> pra apontar pro nó que foi criado antes desse. Esse é o truque da lista ligada, é uma lista que liga elementos um atrás do outro ou um na frente do outro, como você preferir.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;

struct Node {
	int value;
	struct Node *previous;
};

struct Node* createNode(int value, struct Node *previous) {
	struct Node *node = (struct Node*) malloc(sizeof(struct Node));
	node-&gt;value = value;
	if (previous) {
		node-&gt;previous = previous;
	}
	return node;
}

void main() {
	struct Node *first = createNode(2020, NULL);
	struct Node *second = createNode(2021, first);
	struct Node *third = createNode(2022, second);


	struct Node *iterator = third;
	while(iterator) {
		printf(&#34;%d, &#34;, iterator-&gt;value);
		iterator = iterator-&gt;previous;
	}
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Pra facilitar, vamos criar uma função que aloca e inicializa um nó, semelhante ao que fizemos no video anterior com a struct Person. Como argumentos ele vai receber um valor inteiro qualquer e o nó que foi criado antes pra ele apontar pra ele. Dentro vamos usar <code>malloc</code> pra alocar essa nova struct, depois preenchemos o campo <code>value</code> com o que veio como primeiro argumento e checamos se o segundo argumento veio nulo. No caso, o primeiro Node criado não aponta pra ninguém, então deixa ele nulo, senão preenche o campo <code>previous</code> pra apontar pro nó que passamos.</p>
<p>Agora no <code>main</code> vamos criar 3 nodes bestas, um com valor de 2020 e mandando NULL que é nulo, porque é o primeiro nó. O segundo nó vai ter 2021 e passamos a referência pro <code>first</code> que criamos antes. Mesma coisa pro terceiro nó que passamos o valor 2022 e a referência do segundo nó. Agora que a coisa fica interessante.</p>
<p>Vou criar um quarto ponteiro, chamado <code>iterator</code> que vai apontar pro mesmo endereço da variável <code>third</code>, a última. Assim começamos um loop que vai parar quando a variável <code>iterator</code> for nulo. Nulo em C e várias linguagens interpreta pra <code>false</code> e quando der isso o loop <code>while</code> vai sair. A cada rodada do loop vamos imprimir o valor inteiro do nó na tela separado por vírgula usando nossa conhecida função <code>printf</code>. Pra quem não sabia ele formata os valores que passamos pra ele. Então &ldquo;%d&rdquo; é de decimal, daí ele formata números. No vídeo anterior eu usei &ldquo;%x&rdquo; que formata números como hexadecimais e &ldquo;%s&rdquo; é pra interpretar como um string mesmo.</p>
<p>E finalmente, depois de usar o valor do node, fazemos a variável iterator apontar pro endereço que tá no campo <code>previous</code>. Como o iterator começou sendo a variável third, e como o previous dela aponta pro endereço que tava na variável second, é isso que ele vai se tornar. Daí o loop volta pro começo, checa que a variável iterator ainda não é nulo e imprime o valor que tá na struct apontada por second. Finalmente fazemos o iterator ser o endereço que tá no campo previous desse second, que vai ser o first, e repetimos o loop.</p>
<p>Como o iterator agora aponta pra mesma struct que a variável first, ela continua não sendo nula. Imprime o valor de first, e o iterator vai ser o que estiver no campo previous dela. Como ela foi a primeira a ser criada e passamos NULL no segundo argumento quando criamos, ela não aponta pra mais ninguém. Agora o iterator vai ser NULL e isso vai parar o loop do <code>while</code>, e também vai terminar a função main porque não tem mais nada pra fazer, então o programa acaba e sai.</p>
<p>Um Node ligado a outro Node forma uma lista de Nodes ligados. Por isso falamos em Lista ligada que é outra estrutura de dados importante na computação. Ela tem várias vantagens em cima de um array. Pra começar, é fácil adicionar novos nodes. Só alocar uma struct no Heap e fazer o campo de ponteiro dela apontar pro último nó que foi criado. Assim não precisamos pré-alocar espaço que não vamos precisar. Mais do que isso. Já pensaram como faz pra inserir um elemento novo no meio de um array?</p>
<p>Como o array é sequencial e fixo, você é obrigado a fazer alguma coisa como copiar todos os elementos do meio pro final pra outro lugar, inserir o valor novo no meio, e copiar todos os elementos que guardamos de volta. Vai desperdiçar espaço e processamento. No caso de uma lista ligada basta alocar uma nova struct e mudar os ponteiros dos nodes ao redor da posição onde queremos inserir. Fazemos o elemento seguinte apontar pra ele e a nova struct apontar pro elemento anterior e pronto, inserimos no meio. O custo de inserir um novo elemento no meio é praticamente igual a inserir no fim, e independe do tamanho da lista.</p>
<p>Mas então, porque não usamos listas ligadas pra tudo? Porque ela tem uma grande desvantagem. Repetindo, num array, pra eu pegar o valor do centésimo elemento, basta pegar o endereço do primeiro e multiplicar o tamanho de cada elemento vezes 100 e imediatamente chegamos. Mas numa lista ligada, preciso pegar a primeira struct, e ir seguindo os ponteiros pro próximo elemento 100 vezes. Então quanto maior for a lista ligada, mais lento vai ser achar elementos nela, porque cada struct fica em algum lugar aleatório no heap e não tem como achar só com aritmética de ponteiro.</p>
<p>Arrays e Listas Ligadas, à primeira vista, especialmente se tiver poucos elementos, funcionam praticamente igual. Você nunca vai notar a diferença de operações ou performance porque mexer em listas de 10 elementos, cem elementos, mesmo mil elementos, é muito rápido na sua máquina. Mas quando você conecta num banco de dados, ou precisa processar centenas de arquivos grandes, e precisa alocar listas pra manipular todos esses dados, usar arrays ou listas vai fazer uma grande diferença de performance. E sem saber como elas funcionam, você jamais vai entender o que tá dando errado.</p>
<p>E tem outras estruturas importantes. A próxima que eu quero explicar pra você é um Map, ou HashMap ou Hashtable ou dicionário. Tem vários nomes por diversas particularidades de implementação. Na maioria das linguagens você provavelmente chama só de Hash. É quando você cria uma lista, mas em vez de navegar nela direto por posição, navega usando uma chave.</p>
<p>Em Javascript é o que você chamaria de objeto JSON. Por exemplo, podemos criar uma variável person com os campos name, age e city, preencher com Fabio, 43, Sao Paulo e podemos acessar os valores com a sintaxe de colchetes que nem um array mas passando o nome do campo, como &ldquo;age&rdquo; e ele devolve 43. Se você não sabia disso, apesar da sintaxe parecer um array, isso não é um array e por baixo funciona bem diferente.</p>
<p>Existem diversas formas de implementar Hashtables. Quero mostrar uma forma rudimentar em C. Antes vamos ver como se usa. Na função <code>main</code> eu quero alocar primeiro uma struct chamada Hash que vamos criar depois. Daí vamos criar uma função chamada <code>insertNode</code> que recebe o ponteiro pra esse hash e vamos inserir alguns dados. Primeiro um valor &ldquo;world&rdquo; com uma chave &ldquo;hello&rdquo;. Se fosse javascript seria hash abre colchetes, daí &ldquo;hello&rdquo; igual &ldquo;world&rdquo;. Apesar da sintaxe não ser bonitinha com colchetes, pense no funcionamento como sendo a mesma coisa do equivalente em Javascript.</p>
<p>Vamos fazer mais um <code>insertNode</code> pro mesmo hash, mas com chave &ldquo;Fabio&rdquo; e valor &ldquo;Akita&rdquo;. Agora vamos imprimir na tela esses valores procurando pela chave. Se fosse javascript seria o equivalente a um console ponto log entre parênteses hash colchetes com a chave &ldquo;hello&rdquo;. Mas a gente vai fazer uma função chamada <code>search</code> que recebe como parâmetro o ponteiro do mesmo hash e a chave &ldquo;hello&rdquo;. Daí passamos o valor que ele vai retornar pro <code>printf</code> imprimir na tela.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;

#define HASH_SIZE 100

struct Node {
	char *key;
	char *value;
	struct Node* next;
};

struct Hash {
	struct Node *list[HASH_SIZE];
};

unsigned int hashCode(char *key) {
	unsigned long hash = 5381;
	unsigned int c;
	while(c = *key&#43;&#43;) {
		hash = ((hash &lt;&lt; 5) &#43; hash) &#43; c; // hash * 33 &#43; c
	}
	return hash % HASH_SIZE;
};

struct Node* createNode(char *key, char *value) {
	struct Node *node = (struct Node*) malloc(sizeof(struct Node));
	node-&gt;key = key;
	node-&gt;value = value;
	return node;
};

void insertNode(struct Hash *hash, char *key, char *value) {
	unsigned int index = hashCode(key);
	struct Node *node = hash-&gt;list[index];
	if(node == NULL) {
		hash-&gt;list[index] = createNode(key, value);
	} else {
		while(node) {
			if (node-&gt;next == NULL) {
				node-&gt;next = createNode(key, value);
				break;
			}
			node = node-&gt;next;
		}
	}
};

char* search(struct Hash *hash, char *key) {
	unsigned int index = hashCode(key);
	struct Node *node = hash-&gt;list[index];
	while(node) {
		if (strcmp(node-&gt;key, key) == 0) {
			return node-&gt;value;
		}
		node = node-&gt;next;
	}
	return &#34;&#34;;
}

void main() {
	struct Hash *hash = (struct Hash*) malloc(sizeof(struct Hash));
	insertNode(hash, &#34;hello&#34;, &#34;world&#34;);
	insertNode(hash, &#34;Fabio&#34;, &#34;Akita&#34;);

	printf(&#34;%s\n&#34;, search(hash, &#34;hello&#34;));
	printf(&#34;%s\n&#34;, search(hash, &#34;Fabio&#34;));
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora sabemos que precisamos implementar uma struct chamada Hash e pelo menos duas funções, a <code>insertNode</code> e a <code>search</code> que é procurar em inglês. Vamos começar pela struct Hash que vai conter uma variável chamada <code>list</code> que é um array de ponteiro pra struct chamado <code>Node</code>. O hashtable vai ser implementado com um array de tamanho fixo. Na prática nem precisava ser uma struct Hash, eu podia só ter criado direto um array, mas só pra ficar mais fancy.</p>
<p>Só pra ficar menos feio vamos definir essa constante 100 com o nome de HASH_SIZE lá em cima usando o pré-processamento #define, que eu expliquei no episódio anterior. É uma forma de não largar números mágicos por aí. Quando passarmos pelo compilador, imagine que vamos dar copy e paste do número 100 no lugar desse nome HASH_SIZE.</p>
<p>Agora temos que implementar a struct principal, que é a <code>Node</code> que vai conter os campos principais de chave e valor que são as strings <code>key</code> e <code>value</code>. Depois, como na lista ligada, um ponteiro pra <code>next</code> que vai ser o próximo Node na cadeia. De propósito antes eu mostrei uma lista ligada que vai apontando pro Node anterior. Aqui vai ser uma lista ligada na direção oposta, apontando pro próximo Node mais novo, só pra mostrar que tanto faz a direção. Dependendo do exemplo que você achar por aí vai ter jeitos diferentes de implementar.</p>
<p>Agora vamos implementar a função mais importante de um hashtable que é a função que converte a chave num identificador numérico. No nosso caso a chave vai ser só strings. Esse número identificador é o que chamamos de hash e eu expliquei mais sobre hashing nos episódios de criptografia, então dêem uma olhada depois. Grosseiramente é como se fosse um gerador de números aleatórios ou random, onde o seed ou semente é o valor da tal chave.</p>
<p>Gostaríamos que essa função de hash devolvesse números o mais aleatório possíveis, ou seja, cuja distribuição estatística seja próxima de uma curva normal ou gaussiana. Se não entendeu isso, coloque na lista estudar estatística básica. A razão disso é simples. A struct Hash que criamos vai conter um ponteiro pra um array de tamanho fixo. Num hashtable podemos inserir mais elementos do que o tamanho do array. A mágica pra isso começa em transformar a chave que é um string num número entre 0 e 99. Uma função de hash pega, por exemplo, a string &ldquo;hello&rdquo; e converte num número, por exemplo esse numerozão aqui do lado.</p>
<p>Pra isso vamos fazer uma função chamada <code>hashCode</code> que recebe essa chave. Se você é de Java já viu esse nome. Dentro começamos declarando um número mágico, no caso cinco mil trezentos e oitenta e um. Poderia ser qualquer número. Depois declaramos uma variável chamada <code>c</code> que a cada rodada do loop vai pegando uma letra da chave. Esse loop vai repetindo até acabar as letras da chave e o <code>c</code> ficar nulo e parar o loop.</p>
<p>O cálculo dentro do loop não é importante pra hoje, tem várias outras formas. Em particular neste exemplo começa com o valor inicial da variável hash que é o cinco mil e tantos acima. Daí multiplicamos por 33 que é o mesmo que fazer bitwise shift pra esquerda de 5 bits, somamos ao hash original junto com o endereço da primeira letra. E vamos fazendo isso letra a letra até o loop parar. No final vamos ter um numerozão que identifica essa chave. Esse número pode ser bem maior do que o tamanho do array e a gente gostaria que fossem posições válidas dentro do nosso array.</p>
<p>Sempre que você tem um range ou sequência limitada, no nosso caso que vai de 0 a 99, mas temos um número maior que isso, pra caber, usamos a operação de módulo. E aqui é mais um exemplo de porque matemática importa. Vamos precisar de módulo. Na prática um módulo faz um wrap. Qualquer número módulo 100, vai devolver um número menor que 100. Daí podemos usar isso como um índice ou hash. Toda chave sempre vai chegar no mesmo hash, mas a partir do hash não temos como voltar ao valor original da chave.</p>
<p>O cálculo do exemplo chamado de djb2. Não é o único e nem é o melhor, mas é fácil pra explicar pra hoje em uma linha só. Lembram quando eu disse que vídeos como esse e qualquer outro tutorial e curso priorizam a facilidade da explicação? Entenda que existem outros algoritmos mais sofisticados do que multiplicar por 33 e ir acumulando. Especialmente algoritmos estatisticamente melhor distribuídos. Mas por agora, o importante é entender que esta é uma das maneiras de converter um string num número e com o módulo, garantidamente devolver uma posição dentro do Array.</p>
<p>Antes de continuar, vamos criar uma função que instancia e popula uma struct Node. Podemos chamar de <code>createNode</code> que recebe como argumentos os strings de chave e valor, <code>key</code> e <code>value</code>. Dentro fazemos <code>malloc</code> pra reservar espaço pra essa struct. Em seguida populamos os campos <code>key</code> e <code>value</code> da struct com os valores que recebemos de argumento. Bem simples. Vamos manter o campo <code>next</code> da struct como nulo.</p>
<p>Como aprendemos no episódio anterior, ao usar a notação de setinha que é um traço e sinal de maior, ele acessa o valor do ponteiro de item que é a struct de Item que tá em algum lugar no Heap. Essa sintaxe de setinha é equivalente a fazer asterisco variável entre parênteses e usar a notação de ponto. Mas setinha fica mais bonito.</p>
<p>Finalmente chegamos ao filé mignon da explicação implementando a função <code>insertNode</code> que vai de fato armazenar o par de chave e valor dentro do nosso array fixo. Começamos com função <code>hashCode</code>, passando a <code>key</code> que veio como argumento e achando a posição numérica dentro do array, que vai ser essa variável <code>index</code>. Continuamos declarando uma variável node que vai apontar pro primeiro Node na posição index do arrayzão.</p>
<p>A lógica vai assim: se no array da estrutura de hash, na posição que chamamos de <code>index</code>, não existir nada, se for nulo, então criamos um novo Node com a função <code>createNode</code>, passando key e valor e armazenamos o endereço desse Node na posição <code>index</code> do Array chamado <code>list</code> dentro da estrutura que chamamos de hash.</p>
<p>Caso contrário, se na posição <code>index</code> já existir um Node, temos duas opções. Se no campo <code>next</code> desse Node não existir nada, for nulo, chamamos <code>createNode</code> pra criar um Node e associamos seu endereço no campo <code>next</code>. Agora temos uma lista ligada de dois elementos. Podemos quebrar o loop e sair fora. Se a lista tiver mais de um elemento já, esse <code>next</code> já vai estar apontando pra outro Node. Então fazemos a variável <code>node</code> apontar pra esse <code>next</code> e repetimos o loop, até achar o último Node cujo <code>next</code> é nulo e nele associamos nosso novo Node.</p>
<p>Essa nossa variável <code>list</code> na struct Hash não é um array simples como mostramos até agora. É um array onde cada posição vai apontar pra uma lista ligada, ou seja, é tipo uma matriz. O conceito é assim: cada lista ligada pode ter quantos elementos quisermos. Daí nesse array fixo vamos conseguir colocar mais elementos do que o tamanho total de posições só do array. Estamos combinando o melhor do array com o melhor da lista ligada numa estrutura só.</p>
<p>Outro conceito importante é que o número que o <code>hashCode</code> devolve identifica uma ou mais chaves. Já disse que ela não é única pra cada chave. Especialmente porque fazemos o módulo do hash pra ter a posição do array. Se múltiplas chaves podem chegar no mesmo número significa que mais cedo ou mais tarde vamos ter uma colisão, ou conflito. Esse é o termo mesmo. Quando acontecer uma colisão, dois Nodes vão competir pela mesma posição no array.</p>
<p>Vamos dar um exemplo, faz de conta que queremos inserir um valor &ldquo;bla&rdquo; com uma chave &ldquo;abc&rdquo;. E faz de conta que queremos inserir outro valor &ldquo;foo&rdquo; com uma chave sendo &ldquo;xyz&rdquo; e agora o principal, faz de conta que o cálculo da nossa função <code>hashCode</code> devolva o número 42 pra ambos os strings. Vamos simular um caso de colisão.</p>
<p>Da primeira vez, vamos pra posição 42 do array <code>list</code> e apontamos pra uma struct Node com a chave sendo &lsquo;abc&rsquo; e valor sendo &lsquo;bla&rsquo;. Na segunda tentativa o hash da chave &lsquo;xyz&rsquo; devolve o mesmo índice 42, mas na posição 42 do array já tem o Node com chave &ldquo;abc&rdquo;, então criamos um novo Node e fazemos o primeiro apontar pra ele. Agora temos os dois armazenados na posição 42 do array, entenderam?</p>
<p>Pra ficar claro, digamos que queremos incluir um terceiro par de valores cuja chave é “foo” e o valor é “bar” e de novo, faz de conta que o hashCode pra essa chave “foo” seja 42 também. Agora já existe uma lista ligada nessa posição do array. Começamos do primeiro Node com chave “abc”. O <code>next</code> dela aponta pra outro Node, com a chave “xyz” e agora o <code>next</code> é nulo, portanto é o fim da lista. Basta fazer esse <code>next</code> apontar pro novo Node com chave “foo” e pronto, adicionamos mais um elemento no hashtable. É isso que acontece num caso de várias chaves colidirem e competirem pela mesma posição no array.</p>
<p>De volta ao exemplo, na função <code>main</code> usamos a função <code>insertNode</code> duas vezes, na primeira pra inserir o par com chave <code>hello</code> e valor <code>world</code> e na segunda vez pra inserir o par com chave <code>Fabio</code> e valor <code>Akita</code>. A chave <code>hello</code> passando pela nossa função hashCode devolve o número 41 e passando a chave <code>Fabio</code> devolve o índice 90. Ou seja, a posição 41 do array <code>list</code> vai apontar pra uma instância da estrutura Node com o valor &ldquo;world&rdquo; e na posição 90 do array <code>list</code> vai existir outra instância de Node com o valor <code>Akita</code>.</p>
<p>Só pro nosso exemplo ficar mais interessante faz de conta que antes de inserir a chave <code>hello</code> já tinha um Node com chave <code>ano</code> e valor <code>2021</code> e faz de conta que se passarmos a string <code>ano</code> pra função hashCode vai dar o número 41. Daí a gente tenta inserir a chave <code>hello</code> e valor <code>world</code> e passando <code>hello</code> em <code>hashCode</code> sabemos que volta 41 também. Criamos um novo Node com a chave “hello” e colocamos seu endereço no ponteiro <code>next</code> do Node chave <code>ano</code>.</p>
<p>Esse é o mecanismo. O pior caso é quando a função de hashCode dá colisões demais e a maioria dos elementos que tentamos inserir acaba na mesma posição do array, e aí fica desbalanceado, por isso escolher a melhor fórmula vai fazer diferença e por isso eu falei em uma função que tivesse uma distribuição gaussiana, onde na média, cada posição do array vai ter mais ou menos o mesmo número de elementos.</p>
<p>Finalmente, uma vez inserido, e se a gente quiser achar o valor que corresponde à chave <code>hello</code>? Vamos criar a função <code>search</code> que devolve um ponteiro pra uma String, que vai ser esse valor. E como parâmetro vamos receber a referência pra struct Hash que contém o array <code>list</code> e como segundo parâmetro um ponteiro pra string que contém a chave que estamos procurando, no caso &ldquo;hello&rdquo;.</p>
<p>De novo, começamos calculando o tal hash da chave &ldquo;hello&rdquo; que já sabemos que vai ser 41. Daí pegamos o primeiro Node da lista ligada que tá na posição 41 do nosso array <code>list</code>. Agora começamos um loop. Enquanto a variável <code>node</code> não for nulo, entra no corpo do Loop. Dentro comparamos o valor da chave nesse Node com a chave que recebemos no parâmetro da função usando essa função do C chamada <code>strcmp</code> ou string compare, que vai devolver <code>zero</code> se as duas strings que passamos tiverem o mesmo valor.</p>
<p>No nosso exemplo vai dar false porque o primeiro Node contém um Item cuja chave é <code>ano</code>. Sendo assim, pulamos esse <code>if</code> e fazemos a variável <code>node</code> apontar pro <code>next</code> do atual. Repete o loop, a variável <code>node</code> ainda não é vazio. No <code>if</code> comparamos de novo o string do campo <code>key</code> com a variável <code>key</code> do parâmetro. E como esse segundo Node contém a chave <code>hello</code>, o <code>strcmp</code> vai dar verdadeiro e podemos retornar o campo <code>value</code> do Node, que vai ser <code>world</code>.</p>
<p>Pronto, em conceito é mais ou menos assim que funciona um hashtable pra inserir e procurar um Node. E é assim que conseguimos inserir centenas ou milhares de itens num array que é limitado em cem posições. Toda vez que tiver uma colisão de chave, anexamos o Node no final da lista ligada nessa posição do array. E quando for procurar a chave, calculamos o hash que dá a posição no array e vamos seguindo a lista ligada que está lá até encontrar o Node com a chave que procuramos.</p>
<p>A essa altura você deve estar pensando, &ldquo;por que todo esse trabalho&rdquo;? A vantagem é que se nosso array estivesse todo cheio, e quisermos achar onde tá o Node com a chave “hello”, rapidamente sabemos que tá na posição 41 do array, porque o cálculo do hash independe de quantos elementos existem. Mesmo se a hashtable tiver 200 Nodes já, chegamos na posição 41 com um simples cálculo. Daí só precisamos fazer mais 2 comparações de chaves na lista ligada pra ir de next em next até chegar no Node com chave “hello” e vamos achar o valor “world”.</p>
<p>Se usássemos só um array pra inserir 200 elementos, mas o array começa com 10 elementos pré-alocados, ia precisar expandir e copiar todos os elementos do array 20 vezes. Mas pra achar um valor numa posição específica é rápido. Por outro lado, se usássemos uma lista ligada pra inserir os 200 elementos, a inserção seria super rápida e econômica. Mas pra procurar teríamos, no pior caso, que vascular 200 elementos. Mas juntando o array com a lista ligada, diminuímos consideravelmente tanto o tempo de inserção quanto o tempo de procura.</p>
<p>Mas da forma como implementamos, não só agora eu posso usar uma string como chave em vez de um número, como estamos segmentando, ou seja, dividindo a lista ligada dentro de um array fixo. E isso nos dá o meio do caminho do melhor dos dois mundos entre um array e uma lista ligada. Não vamos desperdiçar memória e processamento tendo que duplicar o array toda vez que chega no fim. E ao mesmo tempo podemos procurar itens razoavelmente rápido porque em vez de vasculhar uma lista ligada inteira, vamos vasculhar só um trecho dela.</p>
<p>Então, toda vez que você fizer um hash em Javascript ou outras linguagens que suportam essa sintaxe de colchetes, por baixo dos panos é algo parecido com isso que tá acontecendo. Nessa nossa implementação rudimentar, esse <code>search</code> passando o <code>hash</code> e argumento <code>hello</code> seria o equivalente no Javascript a escrever <code>hash</code> colchetes e <code>hello</code> dentro.</p>
<p>Falando em Javascript, muitos que estão iniciando os estudos agora talvez já tenham visto exercícios implementando coisas como listas ligadas ou hashtables em Python, Javascript ou outra linguagem de alto nível. E de fato, eu poderia implementar exatamente esse hashtable que fiz em C só que em vez de usar structs eu poderia usar classes. Daí você poderia ter a péssima idéia de usar esse hashtable que escreveu em vez de usar a que já vem por padrão na linguagem.</p>
<p>Isso é uma má idéia porque nenhuma versão de hashtable que você escrever em Python puro vai ser mais rápido do que a que já vem nela. A explicação é simples. Vamos ver como o Python implementa o hashtable, que ele chama de <code>dict</code>. O Python mais usado é o CPython, e esse nome é porque o Python é escrito em C. E se a gente for no GitHub e vasculhar o código fonte do CPython vamos achar o arquivo <code>dictobject.c</code> que, chan chan chan chan, é escrito em C. Esse em particular tem mais de 5 mil linhas de C. Por isso eu repito, o exemplo que eu dei antes é uma simplificação rudimentar pra ser didático de explicar. Pra ver o de verdade, você precisa ver esse do Python.</p>
<p>A mesma coisa vale pra todas as estruturas de dados a algoritmos básicos de ordenação, procura e coisas mais avançadas como criptografia que o Python te dá. Arrays, listas ligadas, sets que são conjuntos e muito mais. E a mesma coisa acontece em todas as outras linguagens de alto nível como Ruby, como Javascript. Eu disse no episódio anterior que elas são ótimas linguagens pra colar estruturas feitas em C ou C++ com uma sintaxe de mais alto nível e mais fácil de usar. É isso que eu quero dizer.</p>
<p>Se você estudou ou for estudar a matéria de estruturas de dados e algoritmos, vai aprender a operar essas estruturas. Até agora eu só mostrei a coisa mais trivial que é inicializar e popular as estruturas. Mas e se quisermos procurar elementos num array gigante? Ou se quisermos ordenar em ordem alfabética? Daí você começa a aprender sobre algoritmos. Sem ter estudado nada, pense, como você ordenaria um array?</p>
<p>Ordenação é um dos tópicos da matéria e normalmente o primeiro algoritmo que você aprende é o famigerado bubblesort. Pra acelerar o código é este aqui do lado. Mas só ver o código talvez não ajude muito. Se você procurar no Google por sorting algorithms animation vai achar vários sites que mostram uma versão animada de como cada uma funciona. Vamos ver um bubble sort em ação. Conseguem ver como ele vai comparando pares de números e fazendo os números maiores irem pra direita? Compara um par, se o da esquerda for maior que o da direita, faz um swap e troca eles de lugar e vai fazendo isso até o fim da lista, e repete, até tudo estar ordenado.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;

void main() {
	int total = 15;
	int array[] = { 40, 55, 11, 32, 67, 5, 74, 89, 38, 66, 27, 36, 79, 99, 2 };

	int i, j, swap;

	for(i = 0; i &lt; total - 1; i&#43;&#43;) {
		for(j = 0; j &lt; total - i - 1; j&#43;&#43;) {
			if(array[j] &gt; array[j&#43;1]) {
				swap = array[j];
				array[j] = array[j&#43;1];
				array[j&#43;1] = swap;
			}
		}
	}
	printf(&#34;Ordenado: &#34;);
	for(i = 0; i &lt; total - 1; i&#43;&#43;) {
		printf(&#34;%d, &#34;, array[i]);
	}
	printf(&#34;%d\n&#34;, array[i]);
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No exemplo em C é assim. Começamos declarando uma variável total como sendo um número hardcoded 15 e em seguida criamos um array de 15 números fora de ordem qualquer. Daí precisamos de 3 variáveis inteiros pra ajudar, um chamado <code>i</code>, outro <code>j</code> e um chamado <code>swap</code>. Começamos um loop fazendo o <code>i</code> ir de 0 até o total menos um que é 14. Lembrando que arrays em C começam de 0 e vai até o total menos 1. Então um array de 15 elementos vai ter posições de 0 até 14.</p>
<p>Dentro tem outro loop, fazendo <code>j</code> ir de 0 também até o total menos <code>i</code>. Isso porque dentro comparamos o elemento na posição <code>j</code> com o seguinte que é <code>j</code> mais um, então não pode ir até o último senão vamos tentar pegar um décimo sexto elemento que não existe e vai dar pau. Daí comparamos entre o elemento na posição <code>j</code> com o de <code>j</code> mais um e se o de <code>j</code> for maior, fazemos o swap. Swap nesse caso é guardar o elemento de j mais um, copiar o elemento de j pra j mais um, e na posição j gravar o que tava na variável swap. Em outras linguagens tem como fazer swaps assim com uma operação só, mas por baixo dos panos sempre vai ter uma variável intermediária.</p>
<p>Se achou complicado depois tente você mesmo executar esse código em C com diferentes arrays, usando <code>printf</code> em cada etapa pra ver o que tem nas variáveis <code>i</code> ou <code>j</code> e o que tem no array nesses posições pra entender o que tá acontecendo. Mas o importante é entender o seguinte. Temos um loop dentro de outro loop percorrendo todos os elementos do array. Na primeira passada tem 14 comparações. Na próxima passada, o <code>i</code> vai ser 1 então total menos 1 menos 1 são 13 comparações. Na passada seguinte o <code>i</code> vai ser 2 então total menos 2 menos 1 são 12 comparações e vamos assim até o <code>i</code> ser igual a <code>14</code> e acabar.</p>
<p>Ou seja, vamos ter 14 mais 13 mais 12 mais 11 e assim por diante, que vai dar 105 comparações. Se colocarmos um contador no começo do código e ir incrementando dentro do segundo loop, no final podemos imprimir e ver que vai dar 105. Pra somar todos os número de 0 até N precisamos da matemática de análise combinatória. A fórmula é n vezes n menos 1 dividido por dois. Então 15 vezes 14 dividido por 2 é exatamente 105. Sendo essa fórmula da ordem de grandeza de N vezes N ou seja N ao quadrado, também dizemos que esse algoritmo tem complexidade quadrática.</p>
<p>Complexidade de tempo de um algoritmo é uma das coisas que você mais vai ver quando se compara algoritmos que fazem a mesma coisa. Por exemplo, no caso de ordenação de arrays, temos esse simples que é o Bubblesort e na média tem complexidade quadrático que escrevemos na notação big-O como sendo O n ao quadrado. Outros algoritmos melhores como o Mergesort ou Quicksort, na média tem complexidade O n vezes log de n ou logarítmico. E aqui eu vou falar de complexidade sem ser formal, então se você é matemático perdoe minha nomenclatura mais solta.</p>
<p>Complexidade é outro aspecto da matéria que vocês precisam entender. E pra resumir bem curto existem gráficos como este que compara os principais tipos. Se não me engano o pior tipo seria fatorial, que nem aparece aqui. No caso do nosso exemplo de 15 elementos, se nosso algoritmo fosse extremamente mal feito onde a ordem de grandeza fosse o fatorial de 15, o número de operações seria de 15 vezes 14 vezes 13 vezes 12 etc e isso dá mais de 1.3 trilhão de operações. Comparado com as 105 do bubblesort, que já é ruim, seria totalmente inviável.</p>
<p>Um exemplo de um algoritmo fatorial? É o próprio código da forma recursiva ingênua que calcula o resultado de um fatorial, que você encontra de exemplo em tudo que é lugar. Outro problema famoso que você aprende na faculdade é o do vendedor viajante, “the travelling salesman” resolvido usando força bruta. Tem até de fato um algoritmo de ordenação que de propósito foi feito pra demonstrar um caso fatorial, que é o snailsort, que pra cada elemento ele faz uma permutação de todos os outros elementos. Tudo que envolve permutações que são combinações de todos os elementos com todos os elementos, têm chances de ser fatorial.</p>
<p>Aliás, o algoritmo do vendedor viajante é o problema do sistema de logística de qualquer Amazon da vida. O caminho mais curto pra passar entre diversos endereços ou cidades diferentes. O jeito mais ingênuo de fazer isso, via força bruta, tem complexidade fatorial, ou seja, é absurdamente caro de processar porque a força bruta seria fazer a permutação de todas as possibilidades de rotas entre todos os pontos de destino e no final comparar pra achar a mais curta. E um algoritmo um pouco melhor vai cair de complexidade fatorial pra exponencial, que continua sendo lento.</p>
<p>Esse em particular é da categoria de problemas considerados NP Hard. Problemas ao redor de NP ou “tempo não polinomial” é uma coisa que eu mesmo tenho intuição mas não tenho bagagem matemática pra discutir formalmente. Só entenda que existem diversos problemas matemáticos que não tem uma fórmula simples. Pior, custam complexidade fatorial pra resolver.</p>
<p>Existem problemas P, NP, NP Complete, NP Hard. Problemas P podem ser resolvidos tem tempo polinomial, problemas NP são não-determinísticos cujos resultados podem ser verificados em tempo polinomial. Não se preocupe muito com isso no começo, basta saber que isso existe.</p>
<p>Mas voltando ao que nos interessa, acessar uma posição num array é complexidade constante, ou seja, não importa se o array tem 10 elementos ou 10 mil elementos, sabendo a posição, recuperar um valor custa sempre o mesmo tempo. Agora, procurar um elemento numa posição de uma lista ligada é complexidade linear, depende do tamanho da lista. Como não dá pra fazer aritmética de endereço, porque os elementos não são sequenciais um atrás do outro, a gente precisa ir de Node em Node seguindo o endereço pro próximo. Então pra achar o décimo Node de uma Lista Ligada onde só temos o endereço do primeiro Node, precisamos fazer a operação de seguir pro próximo ponteiro 9 vezes.</p>
<p>Pra achar o vigésimo elemento precisamos seguir ponteiros 19 vezes no pior caso, e assim por diante, ou seja, o tempo que vai custar depende da quantidade de elementos, por isso a ordem de grandeza é chamado de linear, que no gráfico de comparação é a linha que cresce igual nos eixos x e eixo y. Imagina carregar um arquivo com palavras, quebrar num array, e procurar uma palavra. Sem saber coisas como busca binária ou qualquer tipo de indexação via hashing ou algo assim, você vai primeiro fazer um loop e vasculhar elemento a elemento até achar o que procura. Isso é mais ou menos linear, lógico depende do que mais você processa, mas estou falando de ordem de grandeza do caso simples.</p>
<p>Agora, na categoria de logarítmico, estão coisas como busca binária, que eu não expliquei e não pretendo detalhar hoje pra não alongar. Mas pensa assim. Em vez de procurar um a um linearmente, você pode usar a estratégia de segmentar a procura quebrando sua lista primeiro ao meio, e recursivamente ir procurando em listas da metade do tamanho e cada pedaço. É meio que a estratégia de dividir pra conquistar. Imagina uma função chamada <code>pesquisa</code>. E dentro dela você quebra a lista em duas e passa cada metade pra mesma função <code>pesquisa</code>, e vai fazendo isso recursivamente. É a base da idéia de busca binária.</p>
<p>Então numa lista de 100 elementos, você quebra em 2. Agora tem a lista de 50. Quebra de novo em 2. Vai ter 25. Quebra de novo. 12. De novo. 6. De novo 3. De novo 1. Se o que procura estiver na primeira metade, talvez você ache em 6 operações em vez de 50. Essa mesma idéia tá por trás de algoritmos como mergesort ou quicksort que são mais rápidos que bubblesort que é complexidade quadrática. Se voltarmos na nossa animação de algoritmos de ordenação, vou mostrar tanto o merge quanto o quick um embaixo do outro.</p>
<p>Viram como eles segmentam a lista? Logaritmo é a operação inversa da exponencial, se uma complexidade exponencial seria 15 ao quadrado que seria ordem de 225 operações, a logaritmica seria o log de 15 na base 2, que daria menos de 4 operações. Complexidade exponencial fica mais caro mais rápido que linear. São opostos no nosso gráfico e você gostaria de escrever código mais próximo da logarítmica do que da exponencial. Mas não é sempre que você tem a sorte de achar algoritmos logaritmicos, mais comum eu acho que é achar loglineares que é linear vezes logaritmico ou O n vezes log n.</p>
<p>Algoritmos loglineares são por exemplo os mergesort e quicksort que mostrei, que embora sejam bem melhores que quadrático ou exponencial, ainda ficam caros mais rápido que puramente linear. Pra memorizar, veja que a notação O n vezes log n é como se fosse a complexidade linear que é O n vezes a complexidade logaritmica que é O log n.</p>
<p>Essa notação de O alguma coisa ou Big O provavelmente porque usamos uma letra <code>O</code> maiúscula é pra você ter noção da ordem de grandeza do tempo de processamento e/ou do uso de recursos de um algoritmo. Algoritmos podem ser qualquer código que você faz. Tudo que recebe algum dado de input e faz algum processamento pra resultar em alguma coisa. A notação é pra dar uma ideia da complexidade, no pior caso. Por exemplo, o quicksort na média é loglinear que é O n vezes log de n, mas no seu pior caso pode virar quadrático.</p>
<p>Por exemplo, pra acessar o valor de um array, eu repeti dezenas de vezes que é só pegar o endereço do primeiro elemento e somar pelo número da posição vezes o tamanho de bits de cada elemento. Num array de inteiros 64-bits de 100 posições, pra pegar o valor na nonagésima posição basta pegar o endereço da posição 0 e somar por oitenta e nove vezes 8 bytes que é o comprimento de inteiros de 64-bits. Pra qualquer outra posição é o mesmo cálculo.</p>
<p>Independente se o array tiver 10 elementos, 100 elementos ou 100 milhões de elementos, pra pegar o valor em qualquer posição o tempo gasto vai ser exatamente o mesmo, porque esse cálculo de endereço inicial mais a soma da multiplicação entre o número da posição e o tamanho de cada elemento independe do tamanho total do array. É o que em notação de Big O a gente chamaria de O 1, ou seja, tempo constante. Esse é o ideal, e todo algoritmo que chega perto disso pode ser considerado muito bom. Você vê no gráfico que à medida que o tempo corre pra direita no eixo x, a complexidade permanece constante no eixo vertical y, constante.</p>
<p>A Lista Ligada que implementamos tem complexidade O 1, constante, pra operações de inserir novos Nodes ou apagar existentes, porque independe do tamanho total da lista. Mesma coisa pro Array enquanto ele tem espaço sobrando no fim. Mas procurar elementos na Lista Ligada é da ordem de grandeza de O n, linear. No melhor caso, o elemento que queremos é o primeiro, daí só com uma comparação e achamos, no pior caso é o último elemento da lista, daí precisa navegar Node a Node até o fim.</p>
<p>Por isso existe a opção de Lista Duplamente Ligada, onde cada Node aponta pro próximo elemento e pro anterior ao mesmo tempo, assim dá pra começar uma procura do começo da lista ou do fim da lista. Mesmo assim, a complexidade, a ordem de grandeza, continua sendo linear, dependente da quantidade de elementos na lista, sendo o pior caso se o elemento que procuramos estiver no meio da lista, porque se começar a procurar do começo ou do fim, o meio é o ponto mais longe agora.</p>
<p>No hashtable que implementamos a complexidade depende do algoritmo de hashing. Se o hashing for bom, ou seja, resulta em números com pouca colisão, o tempo de inserção no melhor caso seria O 1 constante, porque por baixo é literalmente inserir num array. O pior caso é se o hashing der sempre o mesmo número pra toda chave. Por exemplo, digamos que queremos inserir 3 palavras quaisquer e o hashing de todas dá o número 10, agora todos vão estar na posição 10 do array. E a gente implementou cada elemento pra ser uma lista ligada. O tempo de inserção vira linear, porque tem que chegar até o fim da lista pra adicionar o Node novo.</p>
<p>Mas a pesquisa, que num array seria tempo constante, no hashtable vai ser linear, igual da lista ligada, O n, linear. Outra coisa importante, só porque dois algoritmos tem complexidade Big O iguais, digamos, O n, linear, não quer dizer que elas têm exatamente a mesma performance. Só significa que vão ficando mais lentas linearmente em proporção à quantidade de elementos pra processar. Ambos array e lista ligada tem complexidade O 1 constante pra inserir novos elementos, mas inserir num array é mais rápido porque já tem o espaço reservado pro elemento ao contrário da lista ligada que precisa chamar <code>malloc</code> pra reservar um espaço no heap pra cada elemento. Mas proporcionalmente o tempo de cada um é constante, independente de quantos elementos cada um tenha, entenderam?</p>
<p>O importante é lembrar que tudo que você codifica é um algoritmo (ou mais corretamente, pode ser uma heurística, mas vamos deixar isso pra outro dia). Todo algoritmo tem uma complexidade. Ela tem melhor caso, pior caso e tempo médio. No melhor caso, todas são parecidas. Se você testar um bubblesort, quicksort ou mergesort ou outros como insertion sort ou timsort, num array com 10 elementos, meio que não faz diferença nenhuma.</p>
<p>Você só vai sentir diferença quando começar a passar mil elementos, cem mil, 1 milhão, daí a diferença de tempo começa a ser mensurável e significativa. Isso é pra lembrar que só porque o código rodou na sua máquina, testando com pouca coisa, nem sempre vai funcionar pra todos os casos. Mas sem entender sobre complexidade, só vai entender como seu código é ruim quando estiver rodando em produção com dados reais, e vai ficar coçando a cabeça sem entender porque e vai ficar botando a culpa na linguagem ou no framework.</p>
<p>Seu código roda em tempos diferentes dependendo dos dados que você passar. Por exemplo, o melhor caso de um bubblesort é tentar ordenar uma lista que já tá ordenada. Ele não vai fazer swap de nenhum elemento e ao terminar de comparar com o último elemento, termina. Então vai rodar como se fosse O n, linear. Mas ironicamente, num quicksort, o pior caso é justamente passar uma lista que já tá ordenada, porque ele vai tentar ordenar e rodar em tempo quadrático em vez de loglinear. Ou seja, só porque no tempo médio o quicksort é bom, não quer dizer que é sempre bom.</p>
<p>Por isso mesmo, em linguagens como Java, Javascript, Python e outros, quando você dá <code>sort</code> não necessariamente vai ser um quicksort por baixo. No caso de Python se usa o algoritmo Timsort que é meio inspirado no mergesort com insertion sort que eu não expliquei. É mais estável e com pior caso melhor do que o quicksort. Vale a pena pesquisar. Mas o recado é que nem sempre o algoritmo mais rápido vai ser o melhor sempre, porque se o pior caso derrubar seu sistema, é melhor um algoritmo um pouco mais devagar mas que lide melhor com o pior caso.</p>
<p>Finalmente, antes que alguém jogue nos comentários que eu não mencionei, notação Big O é pode ficar controverso porque povo diz &ldquo;ah, algoritmo X é quadrático então é ruim, algoritmo Y é linear então é bom&rdquo; mas não entende que não é pra comparar só pelo Big O, especialmente sem levar em conta coisas como melhor ou pior caso, e sem levar em conta coisas como Big Omega e Big Theta. Na prática, Big O é uma notação de complexidade do limite superior, não necessariamente do pior caso. Big Omega é notação pro limite inferior, não necessariamente do melhor caso. E Big Theta é notação pro tempo entre Big O e Big Omega.</p>
<p>Se pareceu complicado é porque é um pouco mesmo, na prática Big Omega e Big Theta é mais interessante pro povo acadêmico, mais matemático da ciência da computação. Big O serve pra dar uma noção da ordem de grandeza do tempo de execução de um código ou algoritmo qualquer. Um programador não se preocupa muito com a notação formal matemática, basta entender que existe, e que algoritmos diferentes tem complexidades diferentes. Todo código é diferente, só porque códigos diferentes chegam no mesmo resultado não significa que são equivalentes. Certamente suas complexidades são diferentes. E certamente sua primeira tentativa vai ter complexidade quadrática, então toma cuidado.</p>
<p>Por agora vou encerrar essa introdução à algoritmos e estruturas de dados. E esses dois episódios foram de fato só o topo do iceberg. Mas pros próximos episódios eu precisava que pelo menos todo mundo estivesse na mesma página da existência desses conceitos e uma pequena noção do básico pra eu poder falar de outras coisas. Lembrem-se, o que eu mostrei nesses dois episódios não é um tutorial, nem um curso, pra isso tem material bem melhor. A ideia foi só mostrar que essas coisas existem pra vocês estudarem em mais detalhes.</p>
<p>Eu mesmo não sou acadêmico então me falta a matemática formal. Mas as noções principais incluem que todo algoritmo tem características diferentes. Tem o caso médio, tem os extremos, tem casos excepcionais e cada caso vai rodar com qualidades diferentes de performance e uso de recursos e por isso a gente fala que pra escolher um algoritmo, uma biblioteca, ou mesmo um framework ou arquitetura depende do problema que queremos resolver, como vai ser usado, porque aí uma solução que é boa pra um projeto pode não ser tão bom pra outro. Como já disse no episódio do livro The Mythical Man Month, não existe bala de prata e boa parte do trabalho de um programador é saber como escolher entre diferentes opções.</p>
<p>Quando eu tava na faculdade estudei essa matéria usando o livro de algoritmos do Nicolau Wirth, criador de linguagens como Modula e Pascal, então eu aprendi usando Pascal. Ela é bem simples de ler de cabo a rabo mas eu acho que pra hoje em dia tá defasado. De longe a melhor coleção é o The Art of Computer Programming, escrito por um dos maiores mitos da ciência da computação, Donald Knuth. Ele começou a escrever em 1968 um conjunto que era pra ser de 7 livros. Pausou no fim da década de 70 porque acho que tava trabalhando em outro projeto que tornou ele famoso, o sistema TeX que você deve conhecer como Latex se já escreveu algum artigo científico pra faculdade.</p>
<p>Ainda faltam 3 volumes e os 4 que já existem são bem difíceis de ler e entender sem ter uma base matemática forte. Eu mesmo não tenho paciência e só li trechos específicos. Talvez uma hora faça um episódio de alguns assuntos dele que me interessam. No geral, eu não recomendo esses livros. Pra começar são bem caros. A coleção dos 4 livros na Amazon custa 200 dólares, que convertendo hoje vai pra mais de mil reais. Qualquer livro que você achar que seja de estruturas de dados e algoritmos é suficiente. Veja a bibliografia de qualquer universidade pra ter referências.</p>
<p>Um que não é tão barato, melhor do que eu usei na faculdade, mas tá longe de ser o monstro que é o do Knuth, procure pelo Introduction to Algorithms do Cormen, Leiserson, Rivest e Stein. Diferente do que eu fiz neste vídeo, o livro do Cormen vai começar ensinando o Insertion Sort, no capítulo seguinte vai falar sobre notação assintótica que foi o que eu pulei quando falei sobre notação Big O e na sequência vai explicar o que é a estratégia de dividir pra conquistar e depois um pouco sobre análise probabilística.</p>
<p>Isso é só a introdução. Depois disso ele vai falar de algoritmos de ordenação como Heap Sort e Quicksort, depois estruturas de dados, grafos e só no final vai falar sobre NP Completeness. Eu também não li esse livro de cabo a rabo, mas se você puder, vai cobrir bastante coisa importante. Mesmo não estando no mesmo nível do Knuth, continua sendo um pouco mais pesado na parte matemática mas também com assuntos mais modernos como multithreading.</p>
<p>Mas como eu disse, não importa muito qual livro, contanto que estude pelo menos um que cubra esses tópicos principais de algoritmos, complexidade, estruturas de dados e entenda o que são algoritmos de tempo polinomial versus de tempo não polinomial. Isso é o que em vários vídeos eu venho falando que é parte da base fundamental da programação. Enquanto você não souber esse básico vai ter dificuldade de pular pra tópicos mais avançados e sempre vai ter dúvida se o que tá codando é o melhor jeito pro problema que tem que resolver, ou porque escolher biblioteca X em vez da Y ou porque certa boa prática funciona em alguns casos mas não em outros.</p>
<p>O estudo da ciência da computação é bem divertido quando você começa a sentir que tá dominando a ferramenta e não a ferramenta te dominando, e conquistar esse nível de controle vai exigir centenas de horas de esforço, estudo e exercícios. E esse estudo precisa dessa base. Espero que estes vídeos tenham dado um pouco de luz e vocês se motivem a procurar o resto sozinhos. Se ficaram com dúvidas mande nos comentários, quem já estudou tudo isso ajudem os colegas também, se curtiram o video deixem um joinha, assinem o canal, não deixem de clicar no sininho pra não perder os próximos episódios e continuem compartilhando com seus amigos pra ajudar o canal. A gente se vê, até mais.</p>
]]></content:encoded><category>algoritmos-e-estruturas-de-dados</category><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #93 - Hello World Como Você Nunca Viu! | Entendendo C</title><link>https://akitaonrails.github.io/2021/03/06/akitando-93-hello-world-como-voce-nunca-viu-entendendo-c/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/03/06/akitando-93-hello-world-como-voce-nunca-viu-entendendo-c/</guid><pubDate>Sat, 06 Mar 2021 10:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/Gp2m8ZuXoPg"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Se você nunca viu C ou como um programa funciona de verdade no baixo nível, hoje é sua chance de ver todo o básico de uma só vez!&lt;/p&gt;
&lt;p&gt;Vou desde tipos primitivos, strings, arrays, stacks, heap, alocação de memória, structs, até minimamente entender o que está por baixo do que você chama de linguagem &amp;ldquo;orientada a objetos&amp;rdquo;.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/Gp2m8ZuXoPg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Se você nunca viu C ou como um programa funciona de verdade no baixo nível, hoje é sua chance de ver todo o básico de uma só vez!</p>
<p>Vou desde tipos primitivos, strings, arrays, stacks, heap, alocação de memória, structs, até minimamente entender o que está por baixo do que você chama de linguagem &ldquo;orientada a objetos&rdquo;.</p>
<p>ERRATAS</p>
<ul>
<li>em 00:06:50 falei errado o range de INT, o certo é de -128 a 127</li>
<li>em 00:06:06 eu falei certo e deixei a correção escrita errada. 64 bits, se você não precisar, desperdiça 7 bytes</li>
<li>em 00:40:54 eu falei que 255 bytes é 1/4 de 1 megabyte, mas é de 1 KILObyte.</li>
<li>em 00:45:41 eu coloquei <code>hello</code> no sizeof e ele pegou o sizeof do endereço e não do array.</li>
<li>em 00:38:40 eu não sei como deixei passar, mas quando falo de passar o string pras funções <code>f1</code>, <code>f2</code> não está duplicando toda a string e sim a referência pra ela. Se fossem valores primitivos como <code>int</code> sim, mas array só o endereço duplica mesmo.</li>
<li>em 00:57:55 quando dei copy e paste pro createPerson, eu esqueci de usar os argumentos pra fazer <code>person.age = age</code> por exemplo e ficou hardcoded. Viram?? Por isso copy e paste é perigoso, especialmente meia noite depois de estar cansado de passar 3 dias editando kkkkk</li>
</ul>
<p>LINKS:</p>
<ul>
<li>Integer (Wikipedia) (<a href="https://en.wikipedia.org/wiki/Integer_%28computer_science%29"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Integer_(computer_science)</a>)</li>
<li>Two’s Complement (Wikipedia) (<a href="https://en.wikipedia.org/wiki/Two%27s_complement"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Two%27s_complement</a>)</li>
<li>How numbers are encoded in JavaScript (<a href="https://2ality.com/2012/04/number-encoding.html#:~:text=JavaScript%20numbers%20are%20all%20floating,binary%20format%2C%20in%2064%20bits"target="_blank" rel="noopener">https://2ality.com/2012/04/number-encoding.html#:~:text=JavaScript%20numbers%20are%20all%20floating,binary%20format%2C%20in%2064%20bits</a>.)</li>
<li>FLOATING POINT VISUALLY EXPLAINED (<a href="https://fabiensanglard.net/floating_point_visually_explained/"target="_blank" rel="noopener">https://fabiensanglard.net/floating_point_visually_explained/</a>)</li>
<li>What Every Computer Scientist Should Know About Floating-Point Arithmetic (What Every Computer Scientist Should Know About Floating-Point Arithmetic (oracle.com))</li>
<li>IEEE-754 Floating Point Converter (IEEE-754 Floating Point Converter (h-schmidt.net))</li>
<li>Number.MAX_SAFE_INTEGER (Number.MAX_SAFE_INTEGER - JavaScript | MDN (mozilla.org))</li>
<li>Signed Binary/Decimal Conversion Using the Two&rsquo;s Complement Representation (Signed Binary/Decimal Conversion (ubc.ca))</li>
<li>C - Pointer arithmetic (C - Pointer arithmetic - Tutorialspoint)</li>
<li>Why Discord is switching from Go to Rust (<a href="https://blog.discord.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f"target="_blank" rel="noopener">https://blog.discord.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Seguindo meus episódios com o tema de fita de bits que venho explicando desde os episódios de introdução à computação até a história de Turing e Von Neumann, no penúltimo episódio eu expliquei sobre a diferença entre arquivos binários executáveis como os de formato ELF e arquivos texto e como tudo são fitas de bits ou o que eu chamei de linguição de bits. E hoje quero tentar explicar como podemos representar dados e manipular bits nessa linguiçona pra vocês conseguirem enxergar um pouco melhor como linguagens de programação lidam com dados.</p>
<p>Se você foi direto aprender uma linguagem de alto nível como Python ou Javascript, sem ter aprendido linguagens de baixo nível, vai eternamente ter dúvidas de &ldquo;o que&rdquo; exatamente a linguagem tá fazendo. Por que certos comportamentos estranhos acontecem do nada. Eu aprendi programação no começo dos anos 90 com linguagens de alto nível também, no caso foi Basic e depois dBase. Eu só fui entender como as coisas funcionavam quando comecei a estudar Ciências da Computação. Muita gente resolveu pular essa etapa e por isso vai ficar travado muito em breve. No video de hoje eu quero tentar abrir as portas pra coisas que você raramente vai encontrar num curso qualquer por aí.</p>
<p>Infelizmente é impossível eu resumir anos de ciências da computação num video só, então você vai precisar complementar o que eu disser hoje com a ajuda do seu professor da faculdade, ou pelo menos alguém mais experiente que você. Aliás, sei que tem vários professores que assistem os vídeos, então este é um episódio onde seus alunos vão precisar de ajuda.</p>
<p>Eu fiquei me indagando se devia quebrar este episódio em dois ou três mas resolvi entuchar tudo em um só mesmo pra tirar isso do caminho, então já aviso que vai ser super denso e bem difícil mesmo se você for iniciante. É normal não entender tudo só assistindo uma vez. Mesmo se você já sabe C, talvez goste de rever alguns conceitos de novo e até ajudar o povo nos comentários. Com tudo isso dito, respirem fundo, peguem papel e caneta pra anotações e vamos lá!</p>
<p>(&hellip;)</p>
<p>O objetivo hoje é destrinchar o linguição de bits de Turing e mapear o que acontece numa linguagem de programação de verdade. Vamos seguir o buraco de coelho e tentar enxergar a mulher de vermelho na Matrix. E a primeira coisa pra relembrar: na fita de bits, a máquina de Turing, ou o tal programa tem tanto binários que representam instruções pra sua CPU como também valores e dados, tudo junto um atrás do outro. Por exemplo, num hello world da vida, vai existir o valor &ldquo;hello world&rdquo; como uma cadeia de caracteres, o que chamamos de um String, e junto vai ter instruções pra mostrar esse String na tela de alguma forma.</p>
<p>String, em inglês é tipo um barbante, uma corda ou um fio. A forma mais simples de String é uma cadeia de bytes terminada com nulo de C. Se a gente encodar o &ldquo;hello world&rdquo; usando ASCII ou UTF-8, cada letra será representada por um código de 8-bits que é 1 byte. Então serão 11 bytes de tamanho mais o nulo no final. Mas se for em japonês &ldquo;haroo waarudo&rdquo;, isso é uma String de 7 símbolos, cada símbolo no alfabeto katakana vai ocupar 3-bytes, então serão 21 bytes de tamanho. Como expliquei no episódio anterior, quantos bytes cada símbolo ocupa depende da tabela de conversão entre glifos e caracteres. Esse é o encoding.</p>
<p>Uma String com caracteres ocidentais de 8-bits é particularmente interessante porque é igual a um Array de bytes. Array em inglês é tipo uma série ou conjunto de coisas. Uma lista sequencial, com cada elemento do array um atrás do outro na memória, sem buracos no meio. Essa distinção é importante e já vou voltar a falar de arrays daqui a pouco, mas antes precisamos falar de números.</p>
<p>Em algumas linguagens você vai ver duas palavras distintas, um byte e um char. Se o char for ASCII de 8-bits, então um char é a mesma coisa que um byte na prática, como é em C. Mas em C# ou Java cada char representa um caractere UTF-16 que tem 16-bits ou 2 bytes, portanto é um double byte. Não se pode achar que um char é sempre um pra um com um byte, só quando falamos de C. Como hoje só vou falar de C, então considere um char sendo 1 byte.</p>
<p>Cada linguagem suporta um certo número do que chamamos de tipos primitivos. Char é um exemplo de primitivo, que é um pequeno pacote de bits, sem metadados. Outro exemplo são números. No mundo real estamos acostumados a pensar em números como os inteiros indo de menos infinito até mais infinito, mas em computadores os números são limitados por seus tipos e temos diversos tipos de inteiros.</p>
<p>Na maioria das linguagens de programação a gente costuma lidar com Inteiros de 8, 16, 32 ou 64-bits, respectivamente Int8, Int16, Int32 ou Int64. Na linguagem Rust, por exemplo, é exatamente assim que é dividido e eles são chamados de i8, i16, i32 e i64. E o Rust ainda tem o i128 também. Um int8 é basicamente um byte ou um char de C.</p>
<p>No caso de C# o Int16 é chamado de Short, o Int32 é o Inteiro propriamente dito e Int64 é chamado de long. No caso do C é mais complicado porque se eu não estou muito errado o int dependia da arquitetura do CPU, então um int num computador de 16-bits era o Int16, mas num computador de 32-bits, se você recompilasse o mesmo programa, o int passava a ser 32-bits.</p>
<p>À primeira vista parece uma boa idéia, porque assim toda vez que as CPUs evoluem, bastaria recompilar o programa e ele automaticamente teria acesso a mais memória. Mas na prática isso pode levar a diversos tipos de bugs inesperados. Então quem decide o tamanho dos inteiros de C é o compilador. Mas nas linguagens mais modernas como C# ou Rust a declaração fica mais explícito qual tipo de inteiro você tá usando.</p>
<p>A razão de ter diferentes tipos de inteiros é a eficiência. Se você sabe que no seu programinha não vai precisar de números maiores que duzentos e cinquenta cinco, basta alocar um int8, ou 1 byte, e vai ser suficiente. Se você alocar um int64 sem precisar, vai desperdiçar 7 bytes que não vão servir pra nada. Se for uma variável só, não faz diferença, mas se for um array com milhares ou milhões de elementos, você vai rapidamente desperdiçar megabytes ou até gigabytes à toa.</p>
<p>Números inteiros ainda tem outra característica importante. Eles podem ser signed ou unsigned, ou seja, ter sinal ou não ter sinal. Se declarar um inteiro unsigned, sem sinal, ele pode ser usado pra números de 0 até hexa FF que é duzentos e cinquenta e cinco. Mas se for signed pode ir de negativo 127 até positivo 128. Quase a metade. Nesse caso o primeiro bit, que é chamado de bit mais significativo, e costuma ficar à esquerda dependendo do endianness do processador, é onde vai ficar o sinal. Se o primeiro bit for 0 então é um número positivo. Se for 1, então é negativo.</p>
<p>Daria pra fazer um video inteiro só falando de inteiros negativos e porque eles são interessantes, e isso é uma das coisas que recomendo pesquisarem a respeito depois. Mas vamos dizer o seguinte. Pra subtrair dois números com sinal, como 15 e 5, o computador primeiro vai enxergar eles em binário. Em 8-bits, no caso de 15 seria o binário 0000 1111. No caso de 5 seria 0000 0101. Você já aprendeu que subtrair um número é o mesmo que somar com seu negativo. Então poderíamos usar a máquina de somar que já mostrei como funciona no episódio de introdução mais hardcore a computadores. Reveja se não lembra mais.</p>
<p>Computadores usam o que se chama de método de complemento, que é a ideia de fazer uma subtração virar uma soma e usar o mesmo circuito de soma. Pra fazer isso ele transforma o segundo número no seu complemento de dois, ou two’s complement. Esse é um tema que você pode perguntar pro seu professor se ele não explicou. Pra achar esse complemento é simples, basta flipar todos os bits e somar 1, então o número 5 que é 0000 0101 vai virar 1111 1010 + 1 que é 1111 1011. O porquê de ter esse 1 extra no final é um dos motivos pra você estudar a teoria completa de two’s complement depois. Por agora vamos somar o 15 com esse 5 negativo.</p>
<p>Da direita pra esquerda, vamos lá, 1 mais 1 dá 2 que é 1 e 0 então fica zero e sobe um. Agora 1 mais 1 mais 1 é 3 que é 1 e 1, então fica 1 e sobe 1 de novo. 1 + 1 é 1 e 0 então fica zero e sobe um. De novo 1 mais 1 mais 1 é 3 então fica 1 e sobe 1. Agora tá fácil, 1 mais 1 fica zero e sobe 1. De novo, 1 mais 1 fica zero e sobe 1. Fica zero e sobe um. Fica zero e sobe um.</p>
<p>O último um que subiu a gente descarta. E o que fica no final é 0000 ou seja, como o primeiro bit é zero, o número é positivo e depois 1010 que é 8 mais 2 que dá 10. Exatamente 15 menos 5, como você já sabia. E com isso demonstramos que é possível subtrair números inteiros com sinal usando o método de complementos e reusando o mesmo circuito da máquina de somar binário.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>11111 111
 0000 1111
&#43;1111 1011
 ---------
         0
        1
       0
      1
     0
    0
   0
  0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>As CPUs são feitas de tal maneira pra tirar vantagem de ser base 2 em vez de base 10 pra conseguir calcular de forma mais eficiente do que fazemos com número decimais. Multiplicar e dividir é mais complicado e se tiverem interesse estudem o algoritmo de multiplicação de Booth. Mas tudo isso foi só pra dizer que existe diferença entre inteiros com sinal e sem sinal.</p>
<p>Já expliquei que dentro da CPU existem diversos registradores, que é como se fossem variáveis globais fixas no hardware. No 6502 do Nintendinho tinha o registrador A, X, Y e outros, todos de 8-bits. E quando falamos de um Intel ou AMD moderno, eles têm registradores e instruções de 64-bits. Mas e quando precisamos fazer contas com números extraordinariamente grandes, acima dos exabytes que 64-bits comportam? Isso não é incomum, principalmente num mundo de Big Data e data science. Pra isso existem tipos compostos como o BigInteger, que tecnicamente não tem limites.</p>
<p>Se você tentar colocar um número de 128-bits num registrador de 64-bits vai dar overflow, ou seja, transbordar. Daí esse número seria truncado e metade seria perdido. Em vez disso, alocamos memória na RAM pra guardar esse número e, a grosso modo, fazemos a soma com a primeira metade, depois com a segunda metade e concatenamos o resultado. E sim, você pode fazer a soma de um número grande como duas somas de números menores, basta carregar o carry bit pra segunda soma.</p>
<p>Então precisaria de pelo menos 2 instruções de adição numa máquina de 64-bits pra somar dois BigInteger de 128-bits, mas é possível. Só vai custar pelo menos 2 vezes mais caro do que somar números menores de 64-bits. Tudo em computação tem um custo, não é automático nem tudo igual.</p>
<p>Isso dito, falei um monte de nomes que podem parecer complicados mas só precisa lembrar que são convenções de como representar números inteiros decimais em formato binário, com limites que vão de 8 até 64-bits dependendo da arquitetura nativa da CPU, ou mais se usarmos abstrações como BigInteger. E com esses números podemos fazer praticamente tudo que precisamos. Aliás, pense que a geração de microcomputadores de 8 e 16 bits foi quase inteira baseada só em números inteiros. Todo joguinho de nintendinho até mega drive é feito usando números inteiros.</p>
<p>A tela de um jogo tem 320 colunas por 240 linhas de resolução, que é um número inteiro. Um sprite de nintendinho tem 8 por 8 pixels ou 8 por 16 pixels. Pra mover um sprite de lugar basta ir somando de um em um pixel. Os sprites podem escolher entre paletas de 4 cores dentre 54 disponíveis. Pontuação de jogos, quantidade de vidas, número de fases, são todos números inteiros.</p>
<p>E fora dos games, em aplicativos de produtividade, seja planilhas, processadores de texto, tudo é baseado em números inteiros. Quantidade de letras ou palavras num texto é um número inteiro. Mesmo se você mexer com coisas como preços, que têm frações da moeda em centavos, basta multiplicar por 100 e fazer contas com inteiros e só no final dividir por 100 e truncar depois de 2 casas decimais. Então preços de produtos, salários, impostos, tudo pode ser calculado facilmente e mais importante, rápido, porque o hardware tem circuitos pra somar números inteiros.</p>
<p>Foi principalmente com o advento de coisas como computação gráfica, animação em 3D, que números fracionados começaram a fazer diferença no mundo comercial. Claro, na computação científica já precisavam fazer cálculos fracionados com muita precisão. Em previsões de meteorologia ou laboratórios. Mas isso era em nichos mais isolados e restritos com acesso a hardware especializado. Desde o começo do século XX já haviam formas de calcular números fracionados. O Z1 de Konrad Zuse, que mencionei na história de Turing e Von Neumann, já tinha esses conceitos. Inclusive seu Z4 foi o primeiro computador comercial nos anos 1940 a ter suporte a números fracionados.</p>
<p>Mainframes como o UNIVAC ou os da IBM dos anos 60 tinham suporte a calcular números fracionados também. Mas foi só quando começamos a adotar arquitetura de 32-bits no começo dos anos 80 que os diversos padrões começaram a convergir pro que viria a se tornar o padrão IEEE 754. E só a partir do meio dos anos 80 que começamos a adotar em microcomputadores domésticos.</p>
<p>Nos CPUs de 8-bits como o 8086 a Intel começou a desenvolver o que se chamaria de co-processadores matemáticos, como o 8087. Até a era do 386 a gente tinha opção de adicionar um segundo chip, como o 80387 que custava caro pra caramba e poucos programas usavam. Não lembro se foi já a partir dos 486 ou só nos Pentiums que paramos de precisar de co-processadores porque as instruções passaram a vir na própria CPU.</p>
<p>Precisamos entender pra que serviam esses co-processadores. Eu disse que até agora estávamos indo bem com números inteiros. Os CPUs dos anos 80 eram bons em processar números inteiros. Mas eventualmente a gente precisa lidar com números fracionados, com decimais. Em particular, números irracionais, ou seja, números que não podem ser representados por uma fração de números inteiros. Raíz quadrada de 2, o número Pi e muito mais. O Pi é o inteiro 3, depois tem uma vírgula e começa uma cadeia infinita de números um, quatro, um, cinco, nove, dois, seis, cinco, três e assim vai sem padrão nenhum até o infinito.</p>
<p>Se um número com decimais pode ser representado por uma fração, podemos usar números inteiros. Por exemplo, o número 0 vírgula 33333333 ad infinitum, é o inteiro um dividido pelo inteiro três. Assim muitos números com casas decimais infinitas podem ser representadas claramente com números inteiros finitos. Mas o mesmo não acontece com números irracionais como Pi. E computadores não tem memória infinita, então não temos como representar perfeito. Daí precisamos de uma aproximação. E a palavra importante aqui é “aproximação”, o que significa que ele não vai ser armazenado na memória como você acha que deveria e sim algo perto disso.</p>
<p>Essa aproximação é a especificação IEEE 754 que define o que chamamos de ponto flutuante. Esse tema é super chatinho e levaria um curso inteiro pra explicar e mesmo assim você vai ter dificuldade de entender, então vou simplificar grosseiramente hoje. Agora pouco eu expliquei como podemos ter inteiros com sinal e sem sinal. E quando tem sinal reservamos o primeiro bit mais significativo pra ser o sinal. Se for zero é positivo e se for 1 é negativo. Mas podemos reservar mais bits pra outras coisas também. Bits são o que a gente quiser que elas sejam.</p>
<p>Em países como Brasil as casas decimais são separadas por vírgula, mas nos Estados Unidos e em outros lugares se usa ponto em vez de vírgula. Por isso falamos em ponto flutuante e não vírgula flutuante. Você já deve ter ouvido falar do tipo <code>float</code>. O ponto separa a parte inteira do número da parte decimal e num computador fazemos esse ponto flutuar pra aumentar ou diminuir a precisão. Mas isso não é a história toda.</p>
<p>O IEEE 754 define vários tipos de float. O mais conhecido hoje é o binary64 que é um número de 64-bits ou 4 bytes. O primeiro bit é igual de um inteiro com sinal, ele define o sinal. Depois vêm 11 bits que representam o número do expoente e os demais 52 bits representam a mantissa. E o que é isso? É notação científica, mas na base 2. Na base 10 pra representar um número como 15000 poderia ser 1.5 x 10^4 ou 1.5e4, e esse “e” é de “expoente”. 1.5 é a mantissa e 4 é o expoente na base 10.</p>
<p>Um float é a mesma coisa, só que seria o primeiro bit de sinal pra positivo ou negativo, daí 2 elevado ao expoente armazenado nos próximos 11 bits, multiplicado pelo número representado nos 52-bits seguintes, que é a mantissa. O número inteiro máximo que pode ser representado nesse formato é 2 elevado a 53 que dá o número 9 quadrilhões e alguma coisa, que em particular, se você é de Javascript, é o que você já conhece como MAX_SAFE_INTEGER que, em binário, é representado assim aqui do lado: zero pro sinal pra ser positivo, o expoente só com o último bit flipado e a mantissa inteira de uns.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>0
00000000001
1111111111111111111111111111111111111111111111111111</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Da mesma forma, o que no Javascript você chama de MIN_SAFE_INTEGER que é o menor número que se pode representar assim, é só flipar ou inverter todos os bits do expoente e o primeiro bit significativo do sinal que temos o 9 quadrilhões e tanto negativo.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>1
11111111110
0000000000000000000000000000000000000000000000</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O grande lance é que não conseguimos representar em notação científica de base 2 exatamente o número que normalmente queremos de decimal, sempre vai ter um erro de conversão. Por exemplo, podemos ir no site do link abaixo, que eu vou deixar nas descrições, que mostra essa conversão pra gente. Se tentarmos converter 0.1 na realidade vai dar zero ponto um zero zero sete vezes um quatro nove etc que é esse binário aqui do lado. É uma aproximação na base 2. Ou seja, depois do 1 vai ter uma pequena sujeira por isso tecnicamente é diferente de 0.1 exato, embora bem próximo se arredondar.</p>
<p>Mesma coisa se tentarmos converter 0.2 em binário, vai virar zero ponto dois, zero zero sete vezes de novo, dois nove oito etc. E esse numero float em binário é esse outro numerozão aqui do lado. E pra finalizar, 0.1 mais 0.2 deveria ser 0.3 se fosse base 10, mas 0.3 em binário vai ser esse numerozão aqui do lado. Com o erro de conversão na verdade vai ser zero ponto três zero zero seis vezes um um nove dois etc. Sempre vai sobrar uma sujeirinha em vez de ser zero zero zero só zero.</p>
<p>Se somarmos o 0.1 e 0.2 na instrução de soma binária do CPU, com os erros de precisão da conversão em binário, o resultado vai dar zero ponto três zero zero sete vezes, depois quatro quatro sete etc. Mas a conversão do 0.3 pra float dá zero ponto três zero zero só seis vezes em vez de sete e depois um um e não quatro quatro. É por isso que no Javascript e em diversas outras linguagens como Python, se você fizer 0.1 + 0.2 e tentar comparar com 0.3 vai dar false. Porque de fato quando converter de decimal pra float na base 2 ele vai ganhar essas sujeirinhas de erro de precisão na conversão e quando se faz conta com essas precisões ligeiramente erradas, a precisão do resultado também vai ser ligeiramente errado.</p>
<p><code>0.100000001490116119384765625 + 0.20000000298023223876953125 00111101110011001100110011001101 + 00111110010011001100110011001101 0.3 = 0.300000011920928955078125 = 00111110100110011001100110011010 0.1 + 0.2 = 0.300000004470348358154296875</code></p>
<p>Quem já tentou fazer muitas contas com float já se deparou com isso. E pra ser justo não é só em Javascript. Se você fizer a comparação de 0.1 mais 0.2 com 0.3 vai encontrar que é falso em Ruby, em Rust, em Python. Se não me engano, C# é uma linguagem que se dá ao trabalho de ajustar esse erro de precisão e devolve verdadeiro, mas no resto, que só faz a conversão direta pra binary64 do IEEE 754, vai ter esse problema nada intuitivo se você só pensar na base 10 e não na base 2. Você faz 0.1 mais 0.2 e no final não é exatamente 0.3. E isso é pior no Javascript por outra razão.</p>
<p>Em Javascript o único tipo numérico que existe é o float binary64. Não existem inteiros primitivos como mostrei antes. Então, em vez do inteiro máximo de dois elevado a 64, o máximo vai ser dois elevado a 53 como declarado no tal MAX_SAFE_INTEGER. Que é um número grande, mas não é o máximo que sua arquitetura suporta. E se você fizer conta com dinheiro, tipo desconto em produtos, ou calcular saldo baseado num extrato de conta, não faça contas com float, porque esse erro de precisão uma hora vai dar ruim. Pequenas sujeiras de precisão, em volume grande de contas, uma hora vai afetar bastante. No mínimo multiplique o valor por 100 pra trabalhar com centavos ou trunque depois de duas casas pra não ter essa sujeira final.</p>
<p>Melhor ainda, justamente por conta de bugs de precisão como esse, existe outro tipo de dado. Semelhante ao BigInteger que falei antes, a maioria das linguagens tem um tipo chamado BigDecimal. Assim como o BigInteger, pra fazer contas aritméticas, vai ser mais lento, porque vai precisar quebrar o numero em segmentos, fazer aritmética das partes e depois dar um jeito de concatenar o resultado, porque o numerozão não cabe nos registradores de 64-bits. No caso do BigDecimal, mesma coisa, ele vai permitir mais precisão e cuidar pra evitar essa sujeira de conversão.</p>
<p>A linguagem Javascript não tem um BigDecimal nativo, então você precisa baixar uma biblioteca que ofereça isso. Na verdade esse é um dos pontos onde Javascript é corretamente criticado. Todo número nele, seja um inteiro ou seja um float, em binário, é representado como um float binary64, o que eu pessoalmente acho tosco. Existe uma classe Number e ela deveria converter nos tipos corretos internamente, até pra pesar menos toda vez que precisa fazer cálculos. Dependendo de que versão da história você ver, esse é um dos efeitos colaterais da linguagem ter sido criada tão às pressas. E depois que já foi adotado assim, você tem dificuldade de voltar atrás agora. Pesquise sobre isso depois.</p>
<p>Enfim, o float que a maioria das linguagens usa é o tal binary64, de 64-bits que eu expliquei. Mas antigamente o que era chamado de float em C era a versão binary32. E a versão 64-bits era chamada de double. Então se algum dia você ver double, é o float de 64-bits. De qualquer forma, o importante era explicar que existia essa forma de se representar números e existem outras, como pra representar números complexos, mas não é importante pra hoje. Lógico, que fique de lição de casa pra vocês depois.</p>
<p>Agora vamos voltar ao tal do Array. Array é um conjunto que contém elementos do mesmo tipo, sequencialmente, um atrás do outro na fita de bits, como por exemplo array de números int8 ou float. Quando associamos uma variável a um array na realidade estamos apontando pro endereço do primeiro elemento desse array. E toda vez que tentamos acessar uma posição específica dentro desse array, basta pegar o endereço inicial e somar pelo tamanho do tipo do elemento que ele contém.</p>
<p>O importante de Arrays e Strings é entender que a sequência de bytes ou chars é necessariamente um atrás do outro, sem intervalos no meio. Se a gente aloca um array de 100 elementos int8, que é de 1 byte de tamanho, o array vai usar cento e um bytes de memória contígua. Esse um a mais é o byte nulo no final da sequência que indica o término dela, no caso de Strings. A beleza é que pra acessar qualquer elemento dessa sequência, sabendo a posição, basta pegar o endereço do primeiro elemento, o comprimento de cada elemento, no caso 1 byte, e multiplicar pela posição pra ter o endereço do que estamos procurando.</p>
<p>No exemplo do &ldquo;hello world&rdquo;, é um array de chars de 12 bytes contando o nulo no final. Se eu quiser puxar a 7a letra, basta pegar o endereço do primeiro elemento que é o &ldquo;h&rdquo; do hello, e somar por 7 bytes, já que cada char tem 1 byte de comprimento, e nesse 7o endereço vai estar a letra &ldquo;w&rdquo;, de &ldquo;world&rdquo;, como esperado.</p>
<p>Agora, isso só funciona porque cada elemento tem exatamente o mesmo comprimento, a mesma quantidade de bits. O requerimento de todo array é que todos os elementos dentro devem ser do mesmo tipo. Se quisermos armazenar números long, que tem 4 bytes, então todos os outros elementos precisam ser long. Daí um array de 100 elementos long vai ter 400 bytes de tamanho. E um outro problema disso é que um array tem tamanho fixo. Uma vez alocado, não tem como ser expandido.</p>
<p>Daí você pode ficar confuso, porque num Javascript e outras linguagens, se o array inicial tem 100 elementos e eu quiser adicionar mais, basta acessar direto a posição 101 e escrever lá. Por exemplo, vamos abrir o console de Javascript em qualquer navegador e declarar um array chamado <code>lista</code> com umas cinco letras, como nosso &ldquo;hello&rdquo;. Se eu tentar acessar a posição 4, vamos pegar a última letra &ldquo;o&rdquo;, e é 4 porque todo array que se preza começa da posição 0. Se eu tentar pegar a posição 5, vai vir undefined porque passei do fim do array. Mas eu posso tranquilamente gravar uma nova letra como &ldquo;exclamação&rdquo; nessa posição e boom, o array automaticamente “expande” pra comportar a nova letra, mas como isso é possível se eu falei que arrays tem tamanho fixo?</p>
<p>Na maioria das linguagens mais alto nível que C, tem estratégias, do grego estrategia. Se eu não disser o tamanho exato que quero, ela vai pré-alocar um espaço maior do que preciso. Dessa forma, se precisar de mais elementos depois do fim, tem espaço livre sobrando. E é uma estratégia quando você sabe que tem mais RAM do que precisa. Mas, se eu realmente chegar ao fim do espaço que a linguagem alocou pro meu array, o que ela vai fazer é alocar um novo array maior, copiar elemento a elemento pro novo array e descartar o antigo.</p>
<p>De novo, você não tá sabendo, mas tá acontecendo um custo extra de processamento por baixo dos panos. No dia a dia você nem percebe porque normalmente mexe em poucos arrays, mas em operações que tenham milhares ou milhões, aí você vai querer tomar mais cuidado com operações que fiquem mudando o tamanho dos arrays. Mesmo que a operação na linguagem seja só uma linha, por baixo dos panos ela vai fazer diversas outras, como duplicar seu array, que você nem fica sabendo e aí não entende porque a performance ficou tão ruim sem motivo aparente.</p>
<p>Mais ou menos a mesma coisa acontece com Strings. No C, sem bibliotecas extras, um String é literalmente declarado só como um array de chars. Em linguagens mais modernas o String é um tipo separado do Array, mas internamente a maioria usa Arrays, só que o tipo extra dá um suporte maior a coisas como conversão de encoding e tudo mais. Na prática, tanto arrays quanto strings, uma vez declarados e preenchidos, são fixos. E aumentar o tamanho deles pode envolver criar um novo array e copiar o conteúdo do antigo em cima do novo. Por isso um Java tem classes extras como StringBuffer pra lidar com strings que você vai precisar crescer depois.</p>
<p>Agora, tudo isso que eu vim falando até agora, array, string, ints ou floats, todos ocupam algum lugar numa memória, seja RAM, ROM, SSDs ou qualquer outra coisa. É tudo uma fita de bits, onde cada posição tem um endereço. Zero, um, dois, e assim vai. Cada valor em uso pode ser encontrado nessa fita com um endereço, é uma localização. O conceito importante aqui é entender que tudo tem um endereço nessa fita, que pode ser qualquer tipo de memória. Pode parecer complicado só porque endereços em máquinas de 64-bits podem ir até numerozões do tamanho de exabytes. E pra piorar escrevemos esses endereços como hexadecimais. Mas endereços são só isso: números.</p>
<p>Eu sei que tô andando bem rápido e já soltei bastante coisa até agora, mas se segurem que agora que a coisa vai ficar interessante. Recomendo que depois assistam tudo de novo com calma se isso é novo pra vocês, mas agora é uma boa hora pra eu descer mais ainda na escovação de bits. Uma coisa que não é claro pra iniciantes é onde ficam todas essas variáveis ao longo da execução de um programa. Então vamos partir de um exemplo bem besta em C. E não se preocupem se você nunca usou C, mesmo assim você deve ser capaz de acompanhar.</p>
<p>Em outros episódios eu já mostrei como isso funciona. A gente abre um editor de textos, escreve o codigozinho em C e usa o compilador <code>cc</code> que é o GCC pra ler esse código e dar output ou saída num binário executável em formato ELF, que o Linux consegue entender e executar. Se não sabe o que é isso, pelo menos assista o episódio da diferença de arquivos binário e texto, onde eu mostro como isso funciona.</p>
<p>O binário ELF tem um endereço específico onde fica a primeira instrução que vai começar a executar. No caso é o hexa 0x1000. Esse endereço é gravado no registrador chamado PC, que é o program counter ou contador de programa. É a partir disso que o CPU vai executando a instrução que tá apontado nesse contador. Uma vez executado o contador incrementa o endereço e aponta pra próxima instrução na fita de bits.</p>
<p>Bem a grosso modo, só pra ficar mais fácil de explicar, é como se esses endereços fossem os números da linha do código C no nosso editor de textos. Claro que não é, porque o que tá no binário não é o código que digitamos e sim o que o compilador traduziu pra linguagem de máquina, o linguição de bits. Mas pra facilitar a explicação, pense que no tal endereço 0x1000 ele pula ou dá JUMP pro endereço da função <code>main</code> do C e vai executando uma linha de cada vez dessa função. Sempre que eu me referir a endereço de programa como sendo o número da linha, é só uma metáfora pro endereço hexadecimal da instrução equivalente na memória de verdade.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;

void f2(char hello[]) {
    printf(&#34;from f2: %d\n&#34;, &amp;hello);
    printf(&#34;%s\n&#34;, hello);
}

void f1(char hello[]) {
    printf(&#34;from f1: %d\n&#34;, &amp;hello);
    f2(hello);
}

void main() {

    char hello[] = &#34;Hello World&#34;;
    printf(&#34;from main: %d\n&#34;, &amp;hello);
    f1(hello);

    return;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A função <code>main</code> é o ponto de partida de qualquer programa em C. Neste exemplo vai alocar uma String &ldquo;hello world&rdquo;. Daí pegamos a referência dessa variável com esse &amp; comercial na frente. Isso pega o endereço onde a string tá armazenada pra podermos imprimir na tela. Daí passamos a variável pra outra função que vamos chamar de <code>f1</code> e colocar no começo do arquivo. Aqui parece qualquer outra linguagem que você já usou, chamando uma função e passando um argumento entre parênteses. E precisamos declarar a função <code>f1</code> antes da <code>main</code> porque em C, pra usar uma função embaixo, ela precisa estar definida antes. Em outras linguagens isso não é verdade, depende do compilador. Mas no caso de C é assim.</p>
<p>Daí nessa função <code>f1</code> vamos receber como argumento um array de chars de novo e dentro vamos imprimir o endereço onde a variável desse argumento foi armazenado, e depois repassar essa variável pra outra função <code>f2</code>. De novo, definimos acima a função <code>f2</code> que, mesma coisa, vai receber um argumento de array de chars, imprimir o endereço da variável e por último imprimir o valor da variável que é o &ldquo;hello world&rdquo;. É um exemplo super besta, só fomos passando o mesmo valor algumas funções pra frente. Vamos sair do editor e usar <code>gcc</code> ou <code>cc</code> pra compilar esse código no tal executável ELF, e podemos rodar.</p>
<p>Agora a gente vê primeiro o endereço da primeira vez que declaramos a variável <code>hello</code> na função main. Vou repetir caso tenha ficado confuso. Se eu der <code>printf</code> direto na variável <code>hello</code> iria imprimir o valor “Hello World”. Mas como colocamos esse &amp; comercial na frente da variável, na realidade ele vai acessar o endereço onde o Hello World está gravado na memória. Tudo tem um endereço e em C, diferente de outras linguagens, temos acesso direto a esse endereço com essa notação.</p>
<p>Eu já falei do endereço de cada instrução do executável e na mesma memória estão valores que vamos criando, como essa String. Então executar um programa é executar a instrução que tá em algum endereço. E os valores que cada instrução vai usar, por sua vez, também estão em algum endereço na memória. E com esse &amp; comercial na frente da variável podemos fuçar o endereço. Pense no Hello World como o conteúdo de um arquivo texto e esse endereço como sendo uma URL de uma página web tipo <a href="http://hello.com"target="_blank" rel="noopener">http://hello.com</a>.</p>
<p>O segundo numerozão que aparece é o endereço do argumento de dentro da função <code>f1</code>, quando passamos o <code>hello</code> pra ela. Veja que o endereço é diferente, apesar do valor ser o mesmo. Ou seja, ao passar a variável pra função ela foi duplicada. E a terceira linha é a mesma coisa, outro endereço diferente que foi impresso de dentro da função <code>f2</code>. Porque quando a <code>f1</code> passou sua variável pra <code>f2</code> como argumento, essa variável foi duplicada de novo.</p>
<p>No final criamos 3 cópias desse String na memória ao longo do caminho, cada uma com endereços diferentes. Você pode ver que toda vez que damos <code>printf</code> passando a referência da variável ela imprime um número diferente. Toda vez que se passa uma variável de tipo primitivo como argumento de uma função, ela é duplicada. E isso não é só em C, mas na maioria das linguagens. Isso tem um nome, se chama “passagem por valor”, que é diferente de “passagem por referência”, que eu vou mostrar já já. A vantagem é que se a gente modificar o valor do argumento dentro da função, por exemplo a <code>f1</code>, o valor original antes de ser duplicada, por exemplo, na função <code>main</code>, não vai mudar depois que a <code>f1</code> der return.</p>
<p>Outro detalhe, o endereço é impresso negativo na tela porque o binário desse endereço começa com 1 e a função <code>printf</code> interpreta como sendo um integer com sinal, que como eu expliquei agora pouco, se começa com 1 ele acha que é um número negativo. Mas também por começar com 1 sabemos que se trata de um endereço na metade mais alta dos endereços da memória. Considere que o endereço mais baixo é o binário zero zero zero etc sessenta e quatro vezes e vai incrementando de um a um até o endereço um um um um sessenta e quatro vezes que é o endereço mais alto.</p>
<p>O espaço de memória que um programa enxerga é segmentado segundo alguma convenção. Pra facilitar a vida, num Windows da vida, ele começa a alocar memória pra drivers e coisas do sistema no final da metade alta, ou seja, começa no endereço binário um um um etc ou hex FFFF etc e vai diminuindo. Já programas de usuário, tipo seu navegador, o Spotify e tals, começa no início da metade baixa, mais próxima dos endereços que começam com zero.</p>
<p>Um adendo. Um computador antigo de 32-bits suportava um máximo de RAM de dois elevado a 32 que é pouco mais de 4 gigabytes. Quando passamos a adotar arquiteturas 64-bits, não dobramos de memória, mas sim elevamos ao quadrado. Por isso o máximo teórico é mais de 16 exabytes. Porém, nenhum chip comercial que a Intel ou AMD fabricam de fato suportam mapear esse tanto de memória ainda. Internamente as instruções lidam com valores de 64-bits mas nenhum hardware que você conseguir comprar, nem os AMD EPIC Threadripper da vida suporta tudo isso. Eles costumam ser capados em 42 ou 48 bits de endereços em vez de 64, ou seja, pouco mais de 280 terabytes. Que é coisa pra caramba, claro, mas só pra você saber que ainda não chegamos no máximo dos 64-bits em hardware comercial.</p>
<p>De qualquer forma, isso é a memória real. Mas como expliquei nos episódio de gerenciamento de memória, um processo rodando enxerga memória virtual, que é o sistema operacional mentindo pros nossos programas como se eles tivessem acesso a toda a memória teórica de 64-bits. É o que chamamos de memória virtual. Dentro desse espaço virtual, os endereços que começam do zero e vão subindo é o que chamamos de memória dinâmica, ou &ldquo;heap&rdquo; que é pra onde vai a maioria dos dados que seu programa carrega. Quando você carrega um arquivo em memória, ou quando se conecta num servidor de API e puxa JSON, ou quando pede dados no banco de dados, tudo vai pro heap. Heap em inglês é um montão, um amontoado.</p>
<p>Repetindo, lá no topo, nos endereços que começam com bit 1, é onde fica o segmento de memória reservada pra kernel, que é uma área exclusiva pra endereços de coisas do sistema operacional, mas o próximo segmento é o que chamamos de pilha ou &ldquo;stack&rdquo;. Se eu não tô muito enganado, todo processo começa com pelo menos 8 megabytes de memória alta reservada pra stack e ela pode expandir decrementando endereços pra baixo. Pode consumir até uns 2 gigabytes.</p>
<p>A heap é a mesma coisa mas do outro lado, começa na memória baixa já com pelo menos 1 megabyte reservado e se precisar de mais vai incrementando endereços pra cima. Lembre-se que o stack de um nintendinho de 8-bits tinha meros 255 bytes, que é do endereço hexa $0100 até $01FF.</p>
<p>Eu explico pra que serve essa stack no episódio da introdução mais hardcore a computadores mas vamos resumir usando o exemplo do hello world que fiz agora. Eu tenho 3 funções, a main, a f1 e a f2. Cada uma delas aloca espaço pra duplicatas da string hello world, daí imprimem o endereço onde a variável foi alocada e no final sai fora e retorna pra função que chamou ela. Aliás, em C, se uma função tem como tipo de retorno um <code>void</code> que é tipo <code>nada</code> em C, então nem precisa dar return, porque não estamos retornando nenhum valor. Vamos na ordem.</p>
<p>Ao executar o binário ele pede pra kernel do sistema operacional alocar espaço pro novo processo e inicializar seja lá o que ele precisa. A kernel vai usar o gerenciador de memória e alocar o mínimo necessário pro programa rodar e depois vai dando memória real pra ele à medida que for pedindo.</p>
<p>Depois ele pula pra primeira função que é a <code>main</code>. Agora cria a variável <code>hello</code> que é um array de chars com 12 bytes de tamanho. Isso é alocado na Stack. Agora eu chamo a função do C chamado <code>printf</code>. Não vou explicar como o <code>printf</code> funciona, mas vamos aproveitar pra explicar a mecânica dessa tal stack ou pilha. Toda chamada de função começa guardando o endereço atual de execução, o que está no tal contador de programas. No nosso pseudo-exemplo de endereços seria o número da linha do nosso código onde chama a função.</p>
<p>No momento que a função <code>main</code> chama a função <code>printf</code> ele faz tipo um bookmark do contador de programa e coloca no stack. Daí podemos substituir o endereço no contador de programa pelo endereço da função que tá chamando, no caso o endereço pra <code>printf</code>. Agora, dentro da <code>printf</code> vai alocar outras variáveis, faz de conta, umas variáveis x ou y quaisquer, que vão sendo colocadas na stack.</p>
<p>Finalmente imprime na tela o que precisava e no final dá <code>return</code>. Esse return começa a desempilhar o que alocou na stack até achar o último endereço que a <code>main</code> gravou, o tal bookmark do contador de programas, e dá jump, ou seja, pula pra ela. E pular significa colocar de volta esse endereço mais um no contador de programa, daí ele pode continuar da próxima linha depois de chamar a função. É mais ou menos isso que faz um <code>return</code>. O que tinha sido colocado na stack pelo <code>printf</code> foi liberado e voltamos a executar na próxima linha.</p>
<p>De volta ao <code>main</code> a próxima linha chama a nossa função <code>f1</code>. Mesma coisa, vamos empilhar o endereço dessa posição na stack. Como eu disse antes, ao passar a variável <code>hello</code> como argumento, estamos duplicando a variável, então vai empilhar essa duplicata na stack também. Dentro de <code>f1</code> vai chamar <code>printf</code> de novo pra imprimir o endereço dessa duplicata, por isso temos valores diferentes de endereços.</p>
<p>Já sabemos como isso funciona, então vamos pular os detalhes de <code>printf</code> pra não ficar repetitivo. Pode assumir que empilhamos e desempilhamos <code>printf</code>. Em seguida o <code>f1</code> vai chamar a <code>f2</code>, e novamente o endereço dessa linha vai ser empilhado na stack, a variável hello vai ser duplicada e empilhada na stack também, e de novo vamos chamar <code>printf</code>. por fim vai ter um return.</p>
<p>Esse <code>return</code> vai desempilhando até ver o endereço de volta à função <code>f1</code> e dar jump pra ela. Agora no <code>f1</code> não tem mais nada a não ser outro <code>return</code>, então continua desempilhando até o último endereço gravado da função <code>main</code> e dá jump de volta pra ela. E finalmente na <code>main</code> também temos um return. Agora é o último de todos, então ele sai do programa inteiro, daí o sistema operacional vai fazer a limpeza da memória desse processo e tudo termina com sucesso.</p>
<p>A razão dessa explicação longa foi pra mostrar no nível mais básico o que significa chamar funções e como variáveis são gerenciadas na stack. Toda vez que você chama funções e passa argumentos pra ela, esse registro de execução vai sendo empilhado na stack, que é uma pilha. Pilha é uma estrutura de dados super importante e uma das mais fundamentais junto com Queues, que é inglês pra filas. Elas são parecidas, mas não vou falar de queues hoje. E pilhas existem dois tipos, FIFO e LIFO.</p>
<p>A pilha que estamos usando aqui é do tipo LIFO, ou seja, Last in, first out. Então o último elemento que empilhamos é o primeiro que vai ser desempilhado. Esse é mais um tema que você precisa estudar em detalhes, como é implementada e como funciona em todos os casos. É uma das lições da matéria de Estrutura de Dados e Algoritmos que qualquer faculdade ensina e mesmo se você for autodidata deveria estudar.</p>
<p>De qualquer forma, você vai se lembrar que eu falei que essa stack costuma começar com um tamanho de 8 megas e pode expandir até uns 2 gigas. Isso é bastante pra programas de qualquer tamanho. Repetindo, um jogo de Nintendinho inteiro, seja Super Mario, Zelda ou Final Fantasy conseguia se virar com uma stack de meros 255 bytes, isso é um quarto de um mísero megabyte. Estourar esse stack é sinal de má programação e acredite, não é difícil estourar a stack. E quando ela estoura, seu programa crasheia.</p>
<p>O jeito mais fácil de estourar é via recursão. Recursão é uma função ficar chamando ela mesma sem parar. Vamos dar um exemplo, podemos fazer uma função chamada <code>f3</code> como essa aqui do lado, e ela ficar chamando ela mesma. Além disso, nessa função <code>f3</code> vou ficar passando o argumento hello toda vez. Cada chamada a <code>f3</code> vai duplicar a string de hello world na stack. Daí vamos imprimir o endereço que cada uma delas tá ocupando na stack.</p>
<p>Se compilar e executar notem como os endereços seguem uma sequência decrescente um atrás do outro. Não são números aleatórios. Como eu disse, a stack começa nos endereços mais altos, depois do espaço da kernel na memória. À medida que vamos empilhando novas chamadas de f3 e duplicando a variável hello como argumento, os endereços vão diminuindo. Ela vai do fim em direção ao meio da memória.</p>
<p>E no final, boom, o programa crasheia porque acabou a stack. A função <code>f3</code> fica chamando ela mesma infinitamente até bater no limite que o sistema operacional permite. No caso do linux dá um segmentation fault. Esse erro é bem genérico mas significa que você tentou acessar memória que não existe, ou que não te pertence, ou qualquer tipo de acesso a memória que o sistema não sabe como lidar. No nosso caso, por ter acabado a memória da stack. Se pegarmos o primeiro endereço impresso na tela e o último e subtrair um pelo outro, podemos saber quanto de memória da stack foi ocupada antes do crash.</p>
<p>Como expliquei antes, esse primeiro número é negativo porque em binário começa com o primeiro bit mais significativo sendo 1, que o <code>printf</code> entendeu como integer com sinal negativo. Mas se convertermos de volta pra hexa temos esse linguição aqui, hexa F nove sete D dois zero A oito. Mesma coisa fazemos com o último endereço que foi impresso na tela e vamos ter hexa quatro um zero nove três sete zero oito. Fazendo um menos o outro temos esse numerozão, que se formos dividindo por mil e vinte e quatro, vai dar exatamente 2 gigabytes. Então podemos estabelecer que nosso stack durou até bater 2 gigabytes.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>-109240152 = 0xF97D20A8 = 11111001 01111101 00100000 10101000
1091122952 = 0x41093708 = 01000001 00001001 00110111 00001000</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Recursão é extremamente importante na programação e você precisa garantir que uma hora essa recursão vai parar antes da stack encher. Existe um caso especial de recursão que não enche a stack agressivamente desse jeito e ela simplesmente vai fazer jump de volta pra algumas instruções pra trás sem ficar enchendo a stack a cada chamada recursiva. Isso se chama Tail Recursion e vou deixar de lição de casa pra vocês estudarem caso nunca tenham ouvido falar disso. A maioria das boas linguagens suporta tail recursion e isso diminui bastante os casos de estourar a stack.</p>
<p>Mas além da recursão temos outro problema nesse exemplo besta. Toda vez que chamamos a função <code>f3</code> recursiva, passamos a string de hello world e ela é passada por valor, ou seja, é duplicada. Cada chamada recursiva que fazemos, no mínimo, tá empilhando o endereço pra onde o return vai dar jump de volta, que é um endereço de 64-bits ou 4 bytes, “mais” a duplicata de hello world que custa 12 bytes. Só isso são no mínimo 16 bytes a cada chamada.</p>
<p>Ou seja, dos 2 gigabytes de stack, talvez uns 3 quartos tão ocupados só com duplicatas de hello world, que é um grande desperdício. Uma string idealmente deveria ser imutável. Quando precisamos modificar a String ou concatenar mais texto nela, aí sim precisaríamos fazer uma duplicata. Mas se a variável vai permanecer sempre a mesma como uma constante, não precisaríamos ficar duplicando toda vez que passamos pra outra função. Imagina se em vez de hello world essa string fosse um texto enorme, uma ou mais páginas da Wikipedia, ocupando 1 mega, ou talvez 1 giga. Em duas chamadas de função duplicando a variável passando por valor ia acabar a stack. Então o que fazemos?</p>
<p>Vamos nos lembrar que eu falei que a stack é só um dos segmentos da memória total. A memória virtual total de 64-bits caberia até 16 exabytes de dados. Meros 1 giga não é nada. Eu poderia duplicar um texto de 1 gigabyte trilhões de vezes até acabar a memória toda. Mas no nosso caso o segmento da stack acaba em 2 gigabytes. Então como fazemos?</p>
<p>Agora vem a parte mais complicada. Vou tentar explicar pra vocês o temido Pointer ou apontador. Parece difícil mas o básico é bem simples, na real. Em vez de alocar espaço na stack pra guardar meus strings ou mesmo qualquer outro array gigante, vamos alocar ela no heap. Já expliquei antes que o Heap é o segmento da memória total que começa nos endereços mais baixos perto de zero e cujos endereços vão incrementando.</p>
<p>Repetindo, enquanto os endereços da stack começam do endereço mais alto e vão decrementando em direção ao começo, os da heap começam no endereço mais baixo e vão incrementando em direção ao fim. O sistema operacional vai garantir que um não cruze os limites do outro no meio. Tecnicamente os endereços da heap podem ir incrementando até o limite de não ultrapassar os endereços do stack, entenderam?</p>
<p>Quando você instancia um objeto numa linguagem como Python, Javascript, Ruby, Java, C#, o bloco de memória que contém todos os dados do objeto ficam no heap. E na stack fica só endereço, ou a referência que aponta pra esse objeto, que numa arquitetura de 64-bits vai ter sempre o tamanho fixo de 4 bytes, independente de quanta memória foi alocada pro objeto no heap. O truque é simples, vamos voltar ao hello world e em vez de alocar na stack, vamos mover pro heap.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

void main() {

    char hello[] = &#34;Hello World&#34;;
    printf(&#34;from main: %d\n&#34;, &amp;hello);

    char *hello2 = malloc(sizeof(hello));
    strcpy(hello2, hello);
    printf(&#34;hello2: %x\n&#34;, hello2);

    char *hello3 = hello2 &#43; 6;
    printf(&#34;from hello2: %s\n&#34;, hello2);
    printf(&#34;from hello3: %s\n&#34;, hello3);

    return;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em C precisamos incluir o cabeçalho <code>stdlib.h</code> que nos dá acesso à famosa função <code>malloc</code> que significa “memory allocation”. O argumento que passamos é quantos bytes queremos que ela reserve no heap. No caso, podemos usar outra função chamada <code>sizeof</code> que, como o nome diz, mede o tamanho de alguma coisa. E como parâmetro pra essa função passamos a variável hello que alocamos na stack, que é 12 bytes.</p>
<p>Poderíamos passar direto o número 12, também. Mas o que o <code>malloc</code> vai fazer é procurar um segmento contínuo de 12 bytes no heap e passar pra gente o endereço que ele reservou no heap. E essa nova variável <code>hello2</code> vai guardar esse endereço, que é um número de 4 bytes. Então esse <code>hello2</code> é um ponteiro porque seu endereço aponta aonde vai estar o string na Heap. É só isso.</p>
<p>Aqui a coisa pode ficar mais cabeluda ainda, então prestem atenção. Com esse endereço em mãos podemos usar outra função do C, o <code>strcpy</code> ou string copy, passando como argumentos esse endereço e a variável hello antiga pra copiar o hello world pra esse novo espaço na heap. Essa é a única duplicata que vamos ter a partir de agora. A parte importante é entender que na variável <code>hello2</code> nós não temos a string hello world e sim o endereço pro primeiro byte na heap onde vamos encontrar essa cópia do hello world.</p>
<p>Sendo o hello2 um ponteiro com um endereço e sabendo que cada char da string tem exatamente um byte e sabendo que ela acaba quando encontramos o caracter NULO, se fizermos outro ponteiro chamado <code>hello3</code> que é <code>hello2</code> mais 6, agora vamos ter só a palavra <code>World</code> se dermos <code>printf</code> nela. Vamos compilar e rodar pra ver. Olha como imprime na tela o Hello world do ponteiro hello2 e só world do ponteiro hello3. Mas a gente não criou ou duplicou uma nova string, estamos apontando pro mesmo espaço na memória só que 6 bytes mais pra frente.</p>
<p>Essa sintaxe ou notação de asterisco é pra indicar à linguagem que essa variável é um ponteiro e queremos acessar o valor gravado no heap, nesse exato endereço. Se não colocarmos o asterisco, vemos direto só o endereço. Se colocarmos o asterismo ele trás o valor pra onde esse endereço tá apontando. Tanto as variáveis <code>hello2</code> quanto <code>hello3</code> parecem representar um string diferente mas na verdade são só endereços ou, mais corretamente, referências, ao mesmo string, só apontando pra posições diferentes no mesmo string. Pra acessar o string em si, usamos asterisco hello2 e asterisco hello3.</p>
<p>Seja um string ou seja um array, já que string é um caso especial de array, a variável <code>hello</code> não contém &ldquo;O&rdquo; array e sim o endereço pro primeiro elemento do array. Se eu quiser pegar um elemento no meio do array, primeiro pego o endereço e somo a quantidade de bytes que leva ao elemento que eu quero. Se for um array de chars, que é uma string, onde cada char tem 1 byte; pra pegar a 6a letra, basta somar 6 bytes ao primeiro endereço.</p>
<p>Quando fazemos aquela notação que tem em toda linguagem, com brackets ou colchetes, com um número no meio, a linguagem tá traduzindo por baixo em uma soma de endereço, como eu mostro aqui no código. É o endereço inicial, mais o tamanho de cada elemento multiplicado pela posição. Vejam que estou repetindo essa operação pra tentar deixar bem claro esse funcionamento.</p>
<p>Tem uma última estrutura de dados que eu quero explicar pra vocês hoje. Como eu repeti de propósito várias vezes até agora, arrays são listas que tem sempre os mesmos tipos de elementos, ou mais corretamente, que tem elementos de mesmo tamanho. Se for um string, é um array onde cada elemento tem 1 byte, se for um array de inteiros de 64-bits, todo elemento tem exatamente 4 bytes. E eu vim repetindo a mesma coisa sobre elementos iguais por causa do seguinte: e se eu quiser uma sequência onde cada elemento tem tamanhos diferentes?</p>
<p>Pra isso, em linguagens de alto nível tipo Python existe a tupla ou tuple, ou no caso de C existe Struct. Em conceito não são a mesma coisa, mas pra hoje pense que é. Vou explicar porque. Diferente de um array onde cada elemento em sequência tem o mesmo tamanho, num struct ou tupla podemos declarar tipos diferentes que vão ser concatenados um atrás do outro no linguição de bits.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;inttypes.h&gt;

struct Person {
    char nome[10];
    uint8_t age;
    uint8_t height;
};

void main() {
    struct Person person;
    strcpy(person.nome, &#34;Fabio&#34;);
    person.age = 43;
    person.height = 172;

    printf(&#34;%x\n&#34;, &amp;person);

    return;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Por exemplo, podemos declarar uma Struct ou estrutura chamada Person, cujo primeiro elemento vai ser um array de chars de 10 bytes, um nome curtinho. O segundo elemento vai ser um int de 8 bits, ou 1 byte, chamado age, pra ser a idade dessa pessoa. E finalmente o terceiro elemento vai ser a altura ou height, que vai ser um inteiro de 8 bits também.</p>
<p>Essa estrutura define um tipo de dados novo, chamado Person, cujo tamanho total sempre vai ser de 12 bytes. Agora eu posso criar uma variável que vai ser esse tipo e o C vai preencher os valores que vamos passar na sequência correta na fita de bits. Se eu fizer <code>person.age</code> igual a 43, <code>person.height</code> igual a 172 e <code>person.name</code> igual a &ldquo;Fabio&rdquo;, a cadeia de bits vai ficar exatamente assim em hexadecimal. Lembrando que cada dois dígitos em hexa representa 1 byte, começamos com o hexa quatro seis que é a letra &ldquo;F&rdquo;, daí 0x61 que é &ldquo;a&rdquo; daí chega uma sequência de zeros porque &ldquo;Fabio&rdquo; tem menos de 10 bytes.</p>
<p><code>46 61 62 69 6f 00 00 00 00 00 2B AC</code></p>
<p>O penúltimo hexa 2B é a idade 43, e o último hexa AC é 172. A Struct meio que serve como um molde, que encaixa exatamente nessa sequência de bits e quebra os valores pra dentro dos campos que criamos. No caso de idade e altura, como são inteiros de 8 bits sem sinal, sabemos que podemos ter idades de zero até duzentos e cinquenta e cinco e alturas de no máximo duzentos e cinquenta e cinco centímetros, e tirando alguma raríssima exceção, tipo se você for mais alto que o Hulk, isso cobre qualquer pessoa do mundo.</p>
<p>Única coisa nesse trecho de código que talvez deixe você confuso é porque podemos fazer <code>person.age</code> igual 43 mas não podemos fazer <code>person.name</code> igual &ldquo;Fabio&rdquo; e em vez disso eu usei a função que copia strings de duas posições da memória, que é essa <code>strcpy</code>. Só entenda que é assim que se faz em C, mas em outras linguagens como Javascript você faz do jeito mais simples de só usar &ldquo;igual&rdquo;. Coisas desse tipo que linguagens de mais alto nível facilitam. É o que eu chamaria de ergonomia da linguagem.</p>
<p>Mas com o que eu expliquei até agora, você conhece os principais tipos numéricos primitivos como integers e floats, arrays e strings, e agora structs. Um Tuple é como se fosse um Struct anônimo, sem nomes e etiquetas, parecido com um array. Aliás, toda vez que você ver um Tuple num Python da vida, vai achar que é a mesma coisa que um array. Uma Tupla é um conjunto imutável com elementos de tipos diferentes, só isso. Um Array é um conjunto mutável de elementos do mesmo tipo. Pra extrair os elementos de uma tupla, você precisa de um molde que declara qual o tamanho de cada elemento, um molde que vai ser parecido com um Struct.</p>
<p>Estamos chegando no final, e agora com tudo que aprendemos, só falta mais um truque pra vocês começarem a entender melhor como os programas funcionam. Vocês meio que já devem ter entendido que funções nada mais são que sequências de instruções que ficam localizados em algum endereço na memória. A CPU vai executando “linha a linha” e quem dita qual linha é o tal contador de programas. Daí quando uma função chama outra, ela primeiro faz bookmark desse contador na stack, e dá JUMP pro endereço dessa outra função.</p>
<p>Repetindo, é como se cada uma dessas linhas de código ficasse num endereço na memória. Estamos simulando como se fossem as linhas do código no editor de textos. Quando na função <code>main</code> lá embaixo eu chamo a função <code>f1</code>, e o compilador do C gera o binário, ele vai substituir por algo semelhante a um <code>jump</code> ou mesmo <code>goto</code> em linguagens mais antigas, pro endereço da linha da função <code>f1</code>.  No comentário é um pseudo-código de como seria se o C tivesse uma função chamada <code>jump</code>.</p>
<p>E isso é uma das razões de porque precisamos de compiladores. Ia ser chato pra caramba ter que ficar lembrando o endereço de cada função que precisamos. E aí a gente resolve mexer na função, muda de lugar, e isso muda o endereço, daí tem que mudar todo lugar que chama esse endereço na mão. Puta trampo. Em vez disso usamos nomes que representam esses endereços, como nomes de função e nomes de variáveis, e deixamos o compilador traduzir isso em endereços no binário final.</p>
<p>Isso é outro conceito importante: nomes de coisas não precisam existir no binário. Se a gente quiser podemos dizer pro compilador manter os símbolos pra debug. Símbolos são esses nomes. Os campos nome, idade e altura não existem no binário onde estão os valores. É só um linguição de bits e só. Linguagens de mais alto nível às vezes guardam esses símbolos por padrão. São metadados ou dados que explicam os dados, e metadados ocupam espaço.</p>
<p>Mas como não são necessários pra rodar o programa e sim pra debugar depois, não é bom guardar tudo porque seria um desperdício de espaço. Se você já mexeu com coisas como XML ou JSON, eles são grandes e desperdiçam bastante espaço, primeiro porque representam tudo como strings e segundo porque levam os metadados de tudo junto com os dados. Mas isso é um detalhe que vou explorar em outro episódio. Aliás, é por isso que um Google inventou coisas como Protobufs, se você estiver interessado em mais um assunto pra estudar.</p>
<p>No caso do texto do código, nós declaramos símbolos, ou nomes pra endereços e cadeias de bits, pra facilitar a vida do programador de ler o código ou debugar depois, mas a máquina em si não se importa com nada disso. Pro computador é tudo uma cadeia de bits e só. O computador não dá a mínima pra como você chama as coisas ou o significado que dá pra elas. Um código é feito pra outros programadores entenderem. Computadores só entendem os binários sem nomes e sem significados. Entenda esse conceito.</p>
<p>A parte importante é que tudo tem endereços, não só variáveis mas funções também. Em particular, em C, podemos pegar a referência de uma função e passar como argumento pra outra função, da mesma forma como eu passei o endereço da variável <code>hello</code> pro <code>printf</code> imprimir na tela, lembra? Por exemplo, vamos reorganizar esse código de criar struct numa função nova chamada <code>createPerson</code> onde passamos como argumentos o nome, idade, altura e um último argumento que é um ponteiro pra uma função que não retorna nada, então <code>void</code> mas tem como argumento um struct de Person.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;inttypes.h&gt;

struct Person {
    char nome[10];
    uint8_t age;
    uint8_t height;
};

void createPerson(char name[],
  uint8_t age,
  uint8_t height,
  void(*function_pointer)(struct Person)) {
    struct Person person;
    strcpy(person.nome, &#34;Fabio&#34;);
    person.age = 43;
    person.height = 172;

    (*function_pointer)(person);
  }

void printPerson(struct Person person) {
    printf(&#34;Person: %s %d %d\n&#34;,
        person.nome, person.age, person.height);
}

void printPerson2(struct Person person) {
    printf(&#34;nome: %s age: %d height: %d\n&#34;,
        person.nome, person.age, person.height);
}

void main() {
    createPerson(&#34;Fabio&#34;, 43, 172, &amp;printPerson);
    createPerson(&#34;Fabio&#34;, 43, 172, &amp;printPerson2);
    return;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Dentro dela fazemos igualzinho antes, onde declaramos a struct Person, preenchemos os campos mas no final executamos a função que veio nesse endereço chamado <code>function_pointer</code>. Entenda isso. a variável <code>function_pointer</code>, assim como aquela <code>hello2</code> vai ser só uma referência, um endereço pra alguma função que tem as características que declaramos, que retorna <code>void</code> ou seja, nada, e tem uma struct Person como argumento. Ao colocar um asterisco na frente dela, é como se estivéssemos dando copy e paste do nome da função de verdade aqui e executando ela.</p>
<p>A seguir vamos declarar a função pra passar pra esse <code>createPerson</code>. Vamos chamar de <code>printPerson</code>, que retorna <code>void</code> e recebe um <code>Person</code> de argumento e dentro é só um <code>printf</code> como fizemos antes. Mas note que diferente de antes, onde precisamos declarar acima as funções que vamos usar embaixo, estamos declarando o <code>printPerson</code> abaixo da função <code>createPerson</code> porque ela ainda não sabe que é essa função que vamos usar.</p>
<p>Ela só sabe que vai receber uma referência que pode ser pra qualquer outra função. Se a <code>createPerson</code> chamasse direto a <code>printPerson</code> ela precisaria ter sido declarada antes. Mas vamos ver a seguir como eu passo a referência dessa função pra <code>createPerson</code>.</p>
<p>Na função <code>main</code> chamamos a <code>createPerson</code> passando os mesmos valores de antes, &ldquo;Fabio&rdquo;, 43 e 172 e em seguida &amp; comercial e <code>printPerson</code>. Aqui estamos pegando a referência, o endereço da função e passando como argumento. Quando compilamos e executamos vemos que a saída na tela é igual antes.</p>
<p>Esse &amp; comercial <code>printPerson</code> tá pegando o endereço onde a função tá declarada e passando como argumento pra <code>createPerson</code>. É só um integer que faz cast pra uma função. Cast é a ação de declarar que tipo esse número representa pro compilador do C saber o que fazer com ela. Mas só isso não tem graça, vamos declarar uma segunda função <code>printPerson2</code> pra ver como podemos passar uma referência diferente.</p>
<p>Lá em cima, fazemos uma cópia do <code>printPerson</code>, chamamos de <code>printPerson2</code> e vamos só mudar o jeito que o <code>printf</code> mostra os dados. De volta lá embaixo vamos chamar o <code>createPerson</code> de novo, mas passando a referência pra esse novo <code>printPerson2</code>. Depois de compilar e executar, veja que imprime essa nova versão também.</p>
<p>A função <code>createPerson</code> aceita qualquer função compatível, que tenha a mesma assinatura, ou seja, o tipo de retorno e os tipos de argumentos que ele espera. Isso é o que chamamos de assinatura de uma função. Ela só recebe a referência pra função que estiver nesse endereço. Basta essa função ter a assinatura correta, ou seja, aceitar a struct de Person e retornar void, ou nada.</p>
<p>Isso de uma função ser passada como referência pra outra função é o que você já deve ter ouvido falar como um <code>callback</code>. É uma função que vai ser chamada &ldquo;call&rdquo; de volta &ldquo;back&rdquo;. Qualquer um que tenha se interessado por programação funcional sabe que uma característica importante é ter funções que recebem outras funções como argumento. A função <code>createPerson</code> é o que em funcional o povo chama de &ldquo;High Order Function&rdquo;.</p>
<p>Quando em Javascript, Python ou Ruby você usa funções como <code>forEach</code>, <code>map</code>, <code>filter</code>, <code>reduce</code> e outros, eles recebem como argumento a referência pra outra função, normalmente uma função anônima, ou seja, que não tem nome e é declarada dentro dos parênteses de argumento. E com isso você entendeu o primeiro passo pra ter uma linguagem funcional.</p>
<p>Na teoria, sim, você poderia escrever código C do jeito “funcional”, mas ninguém faz isso porque não é prático. Mas com isso você pode imaginar como C poderia ser usado pra criar uma linguagem funcional como um Lisp da vida. É assim que a gente começa a manipular uma linguagem pra aceitar paradigmas que ela não foi projetada pra fazer. E com o que aprendemos até agora eu já posso mostrar mais um passo adiante.</p>
<p>Vamos entender o primeiro passo que leva C pra uma linguagem orientada a objetos como C++ ou Objective-C. O que eu vou mostrar a seguir não é a implementação da verdade, mas só um rascunho de como poderia ser. Quando eu penso em orientação a objetos só penso em duas coisas: um ponteiro pra uma struct e ponteiros pra funções cujo primeiro argumento, o que você aprendeu num Python ou Javascript como <code>self</code> ou <code>this</code>, sendo um ponteiro de volta pra mesma struct.</p>
<p>Vamos refatorar a <code>createPerson</code> primeiro. Até agora ela tá declarando a struct na stack e quando chama a <code>printPerson</code> tá duplicando por causa da passagem por valor. Em vez disso, vamos criar a struct no Heap e economizar espaço no stack fazendo passagem por referência. Pra isso precisamos usar <code>malloc</code> passando o tamanho da struct como parâmetro. E isso pra mim é o que significa <code>instanciar um objeto na memória</code>. Basicamente alocar espaço na heap pra uma struct.</p>
<p>No caso de C, quando criamos qualquer coisa no Heap, precisamos colocar asterisco na frente da variável que guarda essa referência pra acessar o valor, mas no caso de struct em C basta trocar essa notação de &ldquo;ponto&rdquo; pra uma seta com tracinho e sinal de maior. Se você é de C++ ou PHP já viu essa notação e eu acho que ela deriva disso em C mesmo. Pra acessar os campos de uma struct de C que foi alocada na heap, sem precisar usar parênteses e ponto, basta usar a setinha, é a mesma coisa.</p>
<p>Agora vamos tirar o argumento de ponteiro de função do final do <code>createPerson</code>. Em vez disso, vamos mover pra struct de Person. Um novo campo que é um ponteiro de função chamado <code>show</code>. Dentro da <code>createPerson</code> declaramos que o campo <code>show</code> desse person que instanciamos no heap vai apontar pra referência da função <code>printPerson</code> que a gente já tinha. Finalmente, vamos mudar o tipo de retorno da função pra devolver o ponteiro dessa struct e no final podemos dar return do person que acabamos de criar e configurar.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;inttypes.h&gt;
#define Class struct

Class Person {
    char nome[10];
    uint8_t age;
    uint8_t height;
    void(*show)(Class Person *);
};

void person_print(Class Person *self) {
    printf(&#34;nome: %s age: %d height: %d\n&#34;,
        self-&gt;nome, self-&gt;age, self-&gt;height);
}

Class Person * newPerson(char name[],
  uint8_t age,
  uint8_t height) {
    Class Person *self =
      (Class Person *) malloc(sizeof(Class Person));
    strcpy(self-&gt;nome, &#34;Fabio&#34;);
    self-&gt;age = 43;
    self-&gt;height = 172;

    self-&gt;show = &amp;person_print;
    return self;
  }

void main() {
    Class Person *person2 = 
      (Class Person *) newPerson(&#34;Fabio&#34;, 43, 172);

    person2-&gt;show(person2);

    return;
}</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Quem já programa orientado a objetos em alguma linguagem pode estar achando isso familiar. Eu chamaria essa função <code>createPerson</code> de “construtor”. Um constructor é uma função responsável por alocar espaço pra um objeto na memória Heap e configurar os valores iniciais desse objeto, retornando o endereço, ou referência, pra esse objeto.</p>
<p>Agora vamos usar isso na função <code>main</code>. Primeiro vamos armazenar o ponteiro que a <code>createPerson</code> vai criar numa variável que é um ponteiro, um asterisco person. E passamos os valores que queremos como argumento a esse construtor. E pra imprimir esses valores na tela podemos chamar direto o método deste “objeto”. E pra quem não sabe, “método” é o nome que damos a funções associadas a um objeto. O método <code>show</code> já foi configurado no construtor pra ser um ponteiro pra <code>printPerson</code>.</p>
<p>A última refatoração que precisamos fazer é mudar a função <code>printPerson</code> pra usar essa variável <code>self</code> pra acessar os campos de nome, idade e altura. Se você é de Python, deve estar começando a se sentir em casa porque métodos de objetos de Python tem explicitamente o primeiro argumento recebendo <code>self</code>. E é o que estou simulando aqui em C.</p>
<p>Em Javascript e outras linguagens orientadas a objetos, em vez de <code>self</code> chamamos de <code>this</code> mas é mais ou menos a mesma coisa, só que o primeiro argumento é implícito, você não precisa declarar ela. Mas faça de conta que a linguagem tá botando ela lá pra você. Então, só chamando <code>person</code> setinha <code>print</code> e passando <code>person</code> como o argumento <code>self</code> vai tudo funcionar. Qual seria um próximo passo pra ficar mais parecido com uma linguagem orientada a objetos?</p>
<p>Pra quem não sabe, em C tem uma coisa chamada <code>pré-processamento</code>, que é reescrever o código antes de compilar. Se você é de Javascript pense como um “transpiler”. Por exemplo, lá no topo do arquivo podemos declarar uma cerquilha <code>#DEFINE</code> e dizer que toda vez que achar escrito <code>Class</code> pode trocar pra <code>struct</code> antes de compilar. Onde tá <code>struct Person</code> podemos substituir como <code>Class Person</code>. Vamos lá usar a função de procurar e substituir do editor e boom. Olha só como de repente parece que estamos lidando com uma linguagem orientada a objetos de verdade.</p>
<p>Se você aguentou até aqui, espero que tenha conseguido minimamente visualizar o que são os diferentes tipos de dados, as diferenças entre inteiros e floats, arrays,  tuples e structs. Como dados são alocados na stack que é a pilha e como a execução de um programa com funções que chamam outras funções vai sendo empilhado e desempilhado da stack. Como tudo tem endereços ou referências, incluindo funções.</p>
<p>Algumas linguagens expõem referências a funções, mas não permitem manipular essas referências pra apontar pra outras regiões de memória. Javascript é assim. Um Java lá atrás só tinha referência a objetos, por isso a única forma de passar funções pra outras funções era primeiro encapsular numa classe anônima, instanciar e passar a referência do objeto como argumento pra outras funções. Por baixo dos panos é assim que as coisas funcionam.</p>
<p>Pra complementar, recomendo rever os vídeos sobre gerenciamento de memória. Quando fazemos programinhas simples, que alocam poucos dados e não tem nenhuma recursão maluca, o stack é mais que suficiente. E você não precisa lidar com o heap. O problema de alocar coisas no heap é que quando termina a função que fez a alocação, o ponteiro sai do stack, mas o que foi alocado no heap continua lá ocupando espaço se você não der <code>free</code> pra liberar explicitamente. Memória na heap não se desempilha sozinha. Por isso surge a necessidade de um garbage collector ou outros truques como o ARC de Swift pra limpar o heap.</p>
<p>Só que garbage collector não faz milagres. Ele sempre vai reservar mais memória do que realmente precisa e sempre vai causar pausas na execução do programa pra fazer essa limpeza de tempos em tempos. Mesmo se você tiver memória sobrando pra desperdiçar, essas pausas pra limpeza sempre vão ser um problema. E é o que linguagens como Swift ou Rust ou C tentam evitar. Por isso são melhores pra fazer coisas como sistemas operacionais, drivers ou coisas de mais baixo nível que vão ser eficientes no uso de recursos e evitar pausas de manutenção o máximo possível. O mesmo não se pode dizer de Java, C# ou Go.</p>
<p>Linguagens interpretadas como Javascript, Python, Ruby, PHP são extensões bem pesadas em cima de C. Elas adicionam diversas funcionalidades pra facilitar a programação, mas por baixo dos panos o que faz elas funcionarem mais rápido e mais eficiente são bibliotecas escritas em C. Uma biblioteca escrita só em Python ou Javascript nunca vai ser nem tão rápida nem tão eficiente. Por isso, funções como criptografia, funções de I/O pra lidar com arquivos ou pacotes de rede, funções matemáticas e tudo mais é tudo escrito em C. Eu chamo elas de linguagens &ldquo;cola&rdquo;.</p>
<p>Você só escreve a cola em Python, que é uma sintaxe mais simples, pra mexer com funções mais complicadas que estão escritas em C ou C++. Por exemplo, em machine learning, Python não é importante porque as funções de um Tensorflow são todas escritas em C++. Se você usar SciPy pra computação científica, de novo as funções são todas em C++ ou Fortran. Nenhuma linguagem cola é rápida o suficiente pra essas coisas. São boas como cola, pra consumir essas coisas mais fácil.</p>
<p>Se você mexe em machine learning em Python, você é só um consumidor de ferramentas escritas em C++ ou C e faz cola em Python. Não tem nenhum problema nisso, e na prática a maioria de vocês assistindo nunca vai precisar de mais que isso. Linguagens que são &ldquo;cola&rdquo; nunca vão ser boas pra fazer o que eu chamo de &ldquo;sistemas&rdquo;. Coisas como drivers, criptografia, processamento massivo de dados como um banco de dados ou mesmo protocolos de rede eficientes.</p>
<p>Elas sempre vão ser só a cola pra sistemas feitos em C++ ou C. Por isso eu recomendo que você saiba no mínimo uma linguagem de mais baixo nível como C ou Rust. E junto uma linguagem cola pra ter produtividade como Javascript ou Python. Quem só sabe linguagens &ldquo;cola&rdquo; sempre vai achar que o que acontece no baixo nível é &ldquo;mágica&rdquo;.</p>
<p>E com o episódio de hoje eu espero ter conseguido quebrar um pouco dessa &ldquo;mágica&rdquo; e fazer vocês enxergarem suas linguagens favoritas com outros olhos. Claro, tudo que eu falei rápido em um episódio é o que se ensina em no mínimo um semestre em ciências da computação, talvez um ano ou até mais.</p>
<p>Eu só mencionei estruturas de dados simples, não falei de listas ligadas, árvores, red black, AVL e nem cheguei a falar dos algoritmos pra lidar com essas estruturas. Quem sabe em outro episódio no futuro, mas entenda que tudo que eu falei hoje é o básico em ciências da computação.</p>
<p>Se você se considera programador e nunca viu nada do que expliquei hoje, considere estudar e treinar mais. Isso vai te ajudar a subir pro próximo nível na programação. Se ficaram com dúvidas mande nos comentários abaixo, inclusive se já sabem de tudo que eu disse aqui, ajudem a responder às dúvidas dos colegas nos comentários também. Não deixem de assinar o canal e clicar no sininho pra não perder os próximos episódios. Compartilhem o video pra ajudar o canal. A gente se vê, até mais!</p>
<p>Links:</p>
<ul>
<li>Integer (Wikipedia) (<a href="https://en.wikipedia.org/wiki/Integer_%28computer_science%29"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Integer_(computer_science)</a>)</li>
<li>Two’s Complement (Wikipedia) (<a href="https://en.wikipedia.org/wiki/Two%27s_complement"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Two%27s_complement</a>)</li>
<li>How numbers are encoded in JavaScript (<a href="https://2ality.com/2012/04/number-encoding.html#:~:text=JavaScript%20numbers%20are%20all%20floating,binary%20format%2C%20in%2064%20bits"target="_blank" rel="noopener">https://2ality.com/2012/04/number-encoding.html#:~:text=JavaScript%20numbers%20are%20all%20floating,binary%20format%2C%20in%2064%20bits</a>.)</li>
<li>FLOATING POINT VISUALLY EXPLAINED (<a href="https://fabiensanglard.net/floating_point_visually_explained/"target="_blank" rel="noopener">https://fabiensanglard.net/floating_point_visually_explained/</a>)</li>
<li>What Every Computer Scientist Should Know About Floating-Point Arithmetic (What Every Computer Scientist Should Know About Floating-Point Arithmetic (oracle.com))</li>
<li>IEEE-754 Floating Point Converter (IEEE-754 Floating Point Converter (h-schmidt.net))</li>
<li>Number.MAX_SAFE_INTEGER (Number.MAX_SAFE_INTEGER - JavaScript | MDN (mozilla.org))</li>
<li>Signed Binary/Decimal Conversion Using the Two&rsquo;s Complement Representation (Signed Binary/Decimal Conversion (ubc.ca))</li>
<li>C - Pointer arithmetic (C - Pointer arithmetic - Tutorialspoint)</li>
<li>Why Discord is switching from Go to Rust (<a href="https://blog.discord.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f"target="_blank" rel="noopener">https://blog.discord.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f</a>)</li>
</ul>
]]></content:encoded><category>linguagens-de-programacao</category><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #91 - Qual a REAL diferença entre Arquivos Binário e Texto?? 🤔</title><link>https://akitaonrails.github.io/2021/01/20/akitando-91-qual-a-real-diferenca-entre-arquivos-binario-e-texto/</link><guid isPermaLink="true">https://akitaonrails.github.io/2021/01/20/akitando-91-qual-a-real-diferenca-entre-arquivos-binario-e-texto/</guid><pubDate>Wed, 20 Jan 2021 10:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/oSCVb4Ts-G4"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Um arquivo texto É um binário! 😲&lt;/p&gt;
&lt;p&gt;E como um sistema operacional diferencia entre os dois? Porque ele sabe executar um binário compilado de C, sabe executar um script de Python, mas também sabe dar erro se tentamos executar um texto qualquer?&lt;/p&gt;
&lt;p&gt;Como isso funciona de verdade por trás dos panos?&lt;/p&gt;
&lt;p&gt;Hoje é dia de escovar bit, e entendermos o que é ASCII, o que é ELF e muito mais!&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/oSCVb4Ts-G4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Um arquivo texto É um binário! 😲</p>
<p>E como um sistema operacional diferencia entre os dois? Porque ele sabe executar um binário compilado de C, sabe executar um script de Python, mas também sabe dar erro se tentamos executar um texto qualquer?</p>
<p>Como isso funciona de verdade por trás dos panos?</p>
<p>Hoje é dia de escovar bit, e entendermos o que é ASCII, o que é ELF e muito mais!</p>
<p>ERRATA:</p>
<ul>
<li>em 05:29 eu falo &ldquo;porque 10 em decimal é A&rdquo; mas eu quis dizer &ldquo;10 em HEXAdecimal é A&rdquo;</li>
<li>em 13:53 eu falo que depois de 69 é 70, mas tá errado, em hexa depois de 0x69 é 0x6A, depois 0x6B e assim por diante até 0x6F e só depois seria 0x70</li>
</ul>
<p>ÍNDICE:</p>
<ul>
<li>00:00 - Intro</li>
<li>01:14 - Hello World</li>
<li>04:30 - arquivos texto</li>
<li>04:59 - arquivos binários</li>
<li>06:13 - como um computador boota?</li>
<li>08:44 - fontes num Nintendinho</li>
<li>13:29 - ASCII</li>
<li>17:24 - segurança: homografia</li>
<li>19:21 - binários executáveis (ELF)</li>
<li>25:44 - binários JPEG</li>
<li>27:20 - Shells (REPL)</li>
<li>30:10 - Encerramento</li>
</ul>
<p>LINKS:</p>
<ul>
<li>Techquickie: The Magic Behind RAM (<a href="https://www.youtube.com/watch?v=UKTc9toqgU0"target="_blank" rel="noopener">https://www.youtube.com/watch?v=UKTc9toqgU0</a>)</li>
<li>Cyrillic (Unicode block) (<a href="https://en.wikipedia.org/wiki/Cyrillic_%28Unicode_block%29"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Cyrillic_(Unicode_block)</a>)</li>
<li>IDN homograph attack (<a href="https://en.wikipedia.org/wiki/IDN_homograph_attack"target="_blank" rel="noopener">https://en.wikipedia.org/wiki/IDN_homograph_attack</a>)</li>
<li>Memory Prices 1957+ (<a href="https://jcmit.net/memoryprice.htm"target="_blank" rel="noopener">https://jcmit.net/memoryprice.htm</a>)</li>
<li>Introduction to the ELF Format Part II : Understanding Program Headers (Introduction to the ELF Format Part II : Understanding Program Headers (k3170makan.com))</li>
<li>Characters, Symbols and the Unicode Miracle - Computerphile (<a href="https://www.youtube.com/watch?v=MijmeoH9LT4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=MijmeoH9LT4</a>)</li>
<li>The 8-Bit Guy - Commodore History (<a href="https://www.youtube.com/watch?v=eP9y_7it3ZM&amp;list=PLfABUWdDse7Y6LLPlfsHKcvBCgqaudzVY"target="_blank" rel="noopener">https://www.youtube.com/watch?v=eP9y_7it3ZM&list=PLfABUWdDse7Y6LLPlfsHKcvBCgqaudzVY</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Dois videos atrás comecei a falar sobre segurança, mas pra continuar eu preciso começar a complementar o assunto de  introdução a computadores com um pouco mais de escovação de bits. Se você assistiu todos os meus vídeos pelo menos já sabe um pouco de como um computador funciona. Como você pode carregar um programa via uma ROM por exemplo, como ele vai instrução a instrução, preenche registradores com resultados, depois você pode endereçar coisas na RAM e assim por diante.</p>
<p>Nos episódios que falei da máquina universal de Turing e a arquitetura de Von Neumann, você já sabe que uma característica importante é o fato de programas e dados compartilharem o mesmo espaço numa fita e como o computador vai lendo um bit de cada vez dessa fita, seja lendo ou escrevendo nela. Todo iniciante sabe que computadores lidam com bits e bytes. Mesmo assim muitos tem dificuldade de entender o que de fato isso significa. Hoje vou falar um pouco sobre formatos de arquivos, mais especificamente sobre qual a relação de arquivos binários ou textos planos, e no final espero que vocês tenham uma noção melhor de como as coisas funcionam por baixo dos panos. Hoje vamos literalmente escovar bits.</p>
<p>(&hellip;)</p>
<p>Vamos começar com uma coisa muito simples, o famoso Hello World, mas escrito em C, que é esse codigozinho idiota aqui do lado. Em C a gente declara dependência ao arquivo stdio.h ou standard i/o ponto header, porque é um arquivo de cabeçalho. Todo programa em C inicia nessa função <code>main</code> e dentro temos a chamada da função <code>printf</code> que só existe porque incluímos o stdio.h antes. Passamos a string <code>Hello World</code> e finalmente retornamos 0 que indica pro sistema operacional que o programa terminou com sucesso. E é só isso, depois desse ponto o programa termina e sai.</p>
<p>Eu escrevi esse código usando um editor de textos, no caso o Vim no meu Linux. E salvei num arquivo chamado hello.c. Se você for total iniciante poderia pensar &ldquo;ah, isso é um programa, portanto posso tentar rodar esse programa né?&rdquo; É uma pergunta válida. E se tentarmos &ldquo;rodar&rdquo; esse arquivo? Você começou a estudar um pouco de Linux, pra executar alguma coisa que tá no mesmo diretório pode simplesmente escrever ponto barra pra dizer que não é pra procurar no PATH e sim no diretório atual, daí hello ponto c e &hellip; permission denied, fuck.</p>
<p>Mas você sabe como resolver! Google! E como mostra no primeiro link, claro, precisa dar permissão pra execução nesse arquivo. No Windows basta que alguma coisa termine em ponto exe ou ponto bat que executa, mas no Linux precisa fazer <code>chmod +x hello.c</code> e agora dá pra tentar de novo e &hellip; what the fuck, vários erros. “Essa porra de C é difícil mesmo, melhor voltar pro CSS” (ba dum).</p>
<p>Não, tô zoando. Esses erros não são de C. Quando você tenta executar um arquivo de texto na realidade ele tá fazendo o shell executar. Isso é o mesmo que executar <code>bash</code> e passando <code>hello.c</code> como parâmetro. Bash ou Zshell ou Fish ou Powershell são interpretadores, que recebem comandos direto que você digita direto na linha de comando ou via um script, que é o que o bash tá achando que é esse hello ponto c. Os erros que estamos vendo não é de C e sim de Bash.</p>
<p>Já já volto pra interpretadores, mas falando sério, eu espero que a esta altura você saiba que C primeiro precisa ser compilado, que em resumo é transformar esses comandos que eu escrevi num binário compatível com o processador por baixo. E pra isso podemos usar clang ou gcc, mas pra ser old school vou usar gcc. Um simples <code>gcc hello.c -o hello</code>. E pronto, agora posso executar ponto barra hello e boom, Hello World, que era o que eu queria.</p>
<p>Se você já é programador isso deveria ser trivial, mas vamos pensar como iniciantes. Porque isso que eu fiz funciona? No Linux temos comandos como <code>cat</code> que lêem o conteúdo de um arquivo e imprime na tela. Se eu der <code>cat hello.c</code> aparece o que eu escrevi. Mas se eu der <code>cat hello</code> vem esse monte de lixo. O que é esse monte de lixo? Pra entender isso temos que dar um passo pra trás.</p>
<p>Relembrem o computador de Turing. Ele entende uma fita de bits. Toda memória, seja RAM ou ROM, todo SSD ou HD ou pen drive ou, no nosso caso, arquivo texto ou arquivo binário é só isso: uma fita de bits. O comando <code>cat</code> que usamos na verdade faz mais do que só ler um arquivo: ele traduz o conteúdo de um arquivo. E ele é burrinho, a única coisa que ele faz é tentar converter uma fita de bits em uma representação de texto.</p>
<p>Uma coisa que hoje é meio padrão é que representamos texto humanamente legível usando uma tabelona chamada UNICODE. Até pouco tempo atrás, antes de UNICODE se disseminar, usávamos uma tabela menor chamada ASCII. Unicode é um assunto super cabeludo que tem vários posts e videos já explicando por isso não vou detalhar demais, entenda que é complexo. Se você acha que entende tudo de Unicode, você não entende Unicode.</p>
<p>Em vez de usar o comando <code>cat</code> vamos usar o comando <code>xxd</code> que se não me engano já mostrei no video de aprendendo sobre computadores com super mario. Se fizermos <code>xxd -b hello.c</code> vamos ver a fita de bits organizado em colunas de 8 bits que é um byte, 6 bytes de cada vez pra caber na tela. Na esquerda temos a posição desses bytes, contado em hexadecimal, não confundir com decimal. Podemos contar assim: começa na posição zero, daí um, dois, três, quatro, cinco, daí pula pra próxima linha começando na posição seis, continua, sete, oito, nove, “A”, porque dez em hexadecimal é A, daí onze é B e pula de linha e continua na linha seguinte na posição C e assim por diante.</p>
<p>Na coluna da direita temos a tradução desses bytes usando a tabela ASCII. Então vemos o segundo byte por exemplo, zero um um zero um zero zero um que é a letra &ldquo;i&rdquo;. Note que temos outro &ldquo;i&rdquo; na palavra <code>stdio</code> e esse &ldquo;i&rdquo; está no segundo byte da linha que começa no endereço &ldquo;C&rdquo; que falei antes. Viu? Olha como o primeiro &ldquo;i&rdquo; e o segundo &ldquo;i&rdquo; é a mesma sequência zero um um zero um zero zero um. A gente traduz os bytes em letras que conseguimos ler, mas o computador só vê isso, uma fita de bits. Por convenção quebramos a fita em blocos de 8 bits, que chamamos de bytes. E 1 byte, na tabela ASCII, traduz pra uma letra.</p>
<p>O que é uma tabela ASCII? Todo computador hoje vem equipado com essa tabela pré-instalada. Entenda assim: uma CPU sozinha não faz nada. Você liga a energia e ela fica só lá sentada esperando. Relembre o video do Guia mais hardcore de introdução à computação. Nele eu mostro como gravamos um programinha num chip de EPROM e a CPU sempre vai procurar alguma coisa num certo endereço de memória pra começar a executar. De forma simplificada, num computador moderno esse chip de EPROM é o que chamamos de “firmware” ou BIOS. Por iss,o se você já atualizou o firmware sempre vem avisos de não interromper o processo no meio. Porque se falhar a atualização do firmware, o computador vai ficar sem o programa que inicia tudo.</p>
<p>BIOS é acrônimo pra sistema básico de entrada e saída. E firmware é uma classe específica de programas que oferece funções que chamamos de baixo nível. Por exemplo, seu Windows ou Linux tá instalado num HD, mas pra saber que o HD existe e como ler bits do HD e depois identificar que tem pentes de RAM e carregar o Linux na RAM, você precisa de um programa antes. Esse programa é o firmware, que oferece funções básicas pra se comunicar com dispositivos de entrada e saída, como a memória.</p>
<p>Se você assiste canais de montagem de PCs como o Linus Tech Tips, vai ver eles sempre se preocupando num tal de POST depois que o computador liga. POST é acrônimo pra Power On Self Test ou auto-teste depois de ligar. É a BIOS rodando e identificando corretamente todo o hardware. Depois desse teste é que ele começa a sequência de boot do sistema operacional, procurando numa ordem específica tipo pendrive antes do HD por exemplo. E se for HD procurando numa posição específica do HD. No caso do formato antigo MBR ou Master Boot Record, são os primeiros 512 bytes da primeira partição do HD.</p>
<p>Enfim, sem dar muita tangente, uma das coisas que a BIOS carrega é uma tabela de conversão de bits pra letras que um ser humano consegue ler. Essa é a tabela ASCII, por isso logo que você liga o computador, ele tem a habilidade de escrever textos na tela pra mostrar o boot antes mesmo do sistema operacional iniciar. É o que ele usa pra montar a tela de configuração da BIOS quando você aperta F12 por exemplo. Se não ficou claro a importância disso, lembram do episódio de video game? Um videogame bem antigo, tipo nintendinho de 8-bits da vida? Então, essa é uma época onde chips de memória eram bem caros. Um chip de 64 kilobytes podia ser tão caro quanto hoje é um pente de 64 GIGABYTES. Por isso você não podia desperdiçar um byte.</p>
<p>Uma das formas de economizar memória é que a BIOS de um videogame antigo é tão simples que ele sequer sabe converter bytes em letras. Aliás, um console de 8-bits eu acho que nem tinha equivalente de BIOS, bootava direto do cartucho. Já notou que todo jogo antigo tem fontes diferentes? Não é porque o sistema vem com várias fontes, que nem hoje você tem Arial ou Verdana ou Times pra escolher. As tais &ldquo;fontes&rdquo; precisavam vir na ROM do cartucho, de cada jogo. E pra economizar espaço eles só colocavam as letras e símbolos que de fato o jogo fosse usar. Se tivesse alguma letra não precisava, ele pulava. Vamos dar um exemplo, vamos abrir a ROM de um jogo antigo como o Super Mario original com o emulador Mesen.</p>
<p>Só um parêntese aqui, o Mesen é um excelente emulador se você quiser escovar bit de binário de cartuchos porque ele tem várias ferramentas de debugging, você pode escrever assembly de 6502 e ele vai converter pro binário e inserir onde você quiser, pode colocar pontos de parada, vasculhar valores nos registradores e tudo mais. Vale a pena pra quem quiser fuçar mais a fundo. Mas pra agora vamos usar uma ferramenta que mostra o conteúdo de segmentos de sprites do cartucho de forma visual.</p>
<p>Vamos direto pra região de memória do cartucho que, por convenção, se chama CHR ou characters. Olhem aqui as letras desenhadas do jogo, literalmente caracteres. Como eu expliquei no outro video um Nintendo de 8-bits lida com sprites em vez de pixels individuais, que são conjuntos de oito por oito pixels. Por acaso o caracter&quot;1&quot; está na posição 1, a &ldquo;2&rdquo; está na posição 2 e assim por diante. Pense nessa região de memória como hoje seriam as fontes True Type ou Open Type que você de front-end e CSS tá cansado de ver. Fontes modernas carregam em alguma região específica da memória e ocupam espaço.</p>
<p>O problema é que pra representar as letras de oito por oito pixels em memória, só de zero a nove e de A a Z são oito vezes oito vezes trinta e seis letras, o que dá dois mil e trezentos bytes ou mais de 2 kilobytes. A ROM do Super Mario inteiro ocupa 40 kilobytes, então 5% do cartucho já tá ocupado só com essas letras. Por isso evita-se fazer letras maiores, opções de maiúscula e minúscula, porque só de fazer isso ia quase dobrar o espaço usado.</p>
<p>Pra entender a importância de economizar espaço, por volta de 1982, 1 megabyte custava mais de 4 mil dólares. Só esses 2 kilobytes representavam pelo menos 7 a 10 dólares! Consegue imaginar isso? Uma moeda de um quarter ou 25 centavos pra cada letra que eu acabei de mostrar. Em 1990, quase 10 anos depois, o mesmo megabyte caiu de 4 mil dólares pra menos de 100 dólares. E é por isso que só a partir dos anos 90 começa a ficar viável fazer coisas que desperdiçam memória massivamente como interfaces gráficas e fontes variadas pré-instaladas. Nos dias de hoje, 1 megabyte é super insignificante, é só uma fração de centavo, de Real.</p>
<p>Quando os microcomputadores começaram a se popularizar, uma coisa que era meio necessário era ter um mínimo de fontes pré-instaladas pra podermos digitar alguma coisa e pro computador conseguir nos mostrar mensagens na tela. E com o tempo passamos a adotar a convenção da tabela ASCII, pra ser possível transferir um arquivo texto de um computador pra outro de outro fabricante. Se cada fabricante usasse tabelas diferentes, o arquivo texto só ia conseguir ser lido num outro computador do mesmo fabricante.</p>
<p>No caso dos videogames com cartucho como Super Mario que eu mostrei, o código 1 representa o símbolo gráfico 1. Pra escrever meu nome, AKITA, eu representaria na memória como os códigos hexadecimais 0A, 14, 12, 0D e 0A de novo. Isso ocupa 5 bytes, porque cada número em hexadecimal representa 4 bits, dois números são 8 bits, portanto 1 byte. Meu sobrenome tem 5 letras, portanto 5 bytes. Em um byte é possível ir de 00 até FF que seria 256 opções. Mas no nosso caso a tabela termina no código 24. Depois da última letra, do código 25 pra cima ele mapeia pra outros sprites que são os desenhos tipo dos blocos que o Mario quebra, dos sprites que formam personagens como o próprio Mario ou os Goombas.</p>
<p>Pra ter uma imagem na cabeça, o que hoje eu chamaria de tabela de fontes, de uma Arial ou Times, no cartucho de um nintendo é essa área de memória da ROM chamada CHR e as fontes são todos os sprites do cartucho. É como se fizéssemos um jogo só com as letras que aparece no seu teclado, que o povo fazia mesmo, em DOS antigo. Mas num console ou microcomputadores dos anos 80 como os Vic-20, ZX Spectrum, a gente substituia os caracteres de texto pra caracteres “gráficos”. Por isso em teclados de VIC-20 ou Commodore 64 você até já tinha uma tabela alternativa de caracteres, e com eles você podia desenhar na tela sem precisar especificar pixel a pixel toda hora. Pode ser meio complicado de visualizar se você nunca viu isso, então recomendo assistir o canal do 8-Bit Guy, em particular sobre os computadores da Commodore.</p>
<p>Voltando ao nosso exemplo do hello.c, vamos abrir o binário do arquivo texto em formato hexadecimal. É a mesma coisa. Note que o segundo caracter é a letra &ldquo;i&rdquo; que a gente viu em binário agora pouco, em hexadecimal é o código 69. Daí na mesma linha temos o &ldquo;i&rdquo; da palavra &ldquo;stdio&rdquo; que é a terceira letra da direita pra esquerda e, claro, temos o código 69. Na tabela que temos pra representar as letras, o código 69 é &ldquo;i&rdquo;, então o código 70 vai ser &ldquo;j&rdquo;, 71 vai ser &ldquo;k&rdquo; e assim por diante até Z. Por acaso todo PC usa a mesma tabela e o nome dessa tabela é a tal ASCII.</p>
<p>ASCII é abreviação pra American Standard Code Information Interchange. Essa conversão se iniciou na época dos telégrafos, então é lá pelo meio do século XX. E foi estabelecido um padrão de 7-bits pra trocar textos. 7 bits é suficiente pra armazenar 2 elevado a 7 ou seja 128 caracteres. Contando 10 números, mais 26 letras do alfabeto em maiúscula, mais 26 letras em minúscula, já ocupamos metade da tabela. O resto é ocupado por símbolos como os aritméticos de adição ou subtração, parênteses, colchetes e assim por diante. 7-bits é suficiente pra maior parte dos textos escritos em inglês e sobra algum espaço ainda pra alguns caracteres acentuados.</p>
<p>Claro, ASCII, sendo um padrão americano, funciona bem pra qualquer língua próxima do inglês. Português usa uma variação que encaixa coisas como cedilha. Espanhol precisa no “N” com til e interrogação ao contrário. Outros países adotaram tabelas alternativas. Imagina no Japão por exemplo. 128 caracteres não cabe nem uma fração de todos os símbolos que se precisa como os famigerados Kanjis. Pra comportar mais caracteres precisamos de mais bytes e daí nasceram extensões como o padrão EUC que é Extended Unix Code e pro Japão em particular tem o EUC-JP. Pra China tem EUC-CN, pra Coréia tem EUC-KR e assim por diante.</p>
<p>Tecnicamente um EUC-JP é mais compatível com ASCII porque em códigos que começam com 0, ou seja de 7-bits, ele corresponde aos mesmos códigos da tabela ASCII e por isso foi usado em coisas como UNIX versão internacional. No Japão surgiram mais de uma tabela. Apesar da EUC-JP ser mais simples pra usar em conjunto com caracteres ASCII não foi a mais usada. A que eu mais vejo é a Shift-JIS que foi criada, ironicamente, pela ASCII Corporation do Japão e pela Microsoft. Quando se usa caracteres de 2 bytes, o Shift-JIS é uma dor de cabeça quando mistura caracteres ASCII porque tem ambiguidade do mesmo código ser usado pra símbolos diferentes dependendo de como foi codificado.</p>
<p>O importante é entender que línguas como chinês, coreano ou japonês são formados por ideogramas, e não sílabas com consoantes e vogais. Então precisa haver uma forma de mapear milhares de símbolos. Com um único byte podemos mapear não mais que 256 caracteres. Pra manter 1 byte precisam ser usados tabelas diferentes pra mapear o mesmo número pra símbolos diferentes. Você imagina a dor de cabeça de ficar trocando entre tabelas diferentes. Quando usamos 2 bytes, aí as possibilidades aumentam pra 2 elevado a 16, que dá mais de 65 mil símbolos possíveis e aí já cabe quase tudo que precisa. Em Unicode temos UTF-8 pra linguagens ocidentais que se aproxima da tabela ASCII e UTF-16 ou UTF-32 pra outras línguas por exemplo. Quanto mais bytes se usa por caracter, mais espaço é desperdiçado num arquivo de texto.</p>
<p>Agradeça por ser programador num país ocidental que pode usar só ASCII ou UTF-8, porque coisas simples como gravar um arquivo texto é simples. Em chinês ou japonês, especialmente se tiver que lidar com tabelas antigas como EUC-CN em vez de só Unicode, você ia chorar lágrimas de sangue. Imagine fazer coisas como algoritmos de procura de palavras, algoritmos de ordenação de palavras, algoritmos de encontrar palavras similares. Coisas que mesmo em inglês ainda não é perfeito como transcrever um áudio em palavras. É muito mais complicado.</p>
<p>Aproveitando essa tangente vale falar de problemas de segurança que apareciam quando você entende que tá num mundo que representa letras diferente do padrão ASCII. Os símbolos em pixels que desenha na tela, que num nintendinho chamamos de sprites, no mundo de fontes chamamos de glifos. Agora, a letra maiúscula &ldquo;A&rdquo; em latim, ou a mesma letra em cirílico, ou a mesma letra em grego, todas têm a mesma imagem ou glifo de &ldquo;A&rdquo; nosso, mas cada um é um código diferente nas tabelas Unicode. No caso são respectivamente os códigos 41, 410 e 391. Porque isso é importante? Porque eu poderia registrar um domínio que já existe, digamos example ponto com e trocar o código UTF-8 do &ldquo;a&rdquo; minúsculo ASCII pro “a” minúsculo em cirílico. Humanos vão enxergar escrito &ldquo;example&rdquo; mas são duas palavras diferentes, com códigos diferentes.</p>
<p>Não entendeu? Em binário, via UTF-8 ou ASCII, é assim que a palavra <code>example</code> é representado: <code>65 78 61 6d 70 6c 65 0a</code> mas e se trocarmos pelo &ldquo;а&rdquo; em cirílico, que é o alfabeto russo? Ele fica diferente e 1 byte mais longo, assim <code>65 78 d0 b0 6d 70 6c 65 0a</code> esse <code>d0b0</code> é a letra &ldquo;a&rdquo; em cirílico. Se abrirmos com o <code>xxd</code>, que tenta representar segundo a tabela ASCII, ele não sabe que letra é, então bota pontos no lugar. São dois bytes que não representam nada na tabela ASCII e isso quebra a palavra pra gente.</p>
<p>Mas num navegador que entende Unicode, você abre no gmail um e-mail com um link que claramente diz facebook ponto com. Mas o &ldquo;a&rdquo; não é o código 61 e sim o 430 em cirílico. Mas você não tem como saber a diferença só olhando pro glifo. Esse tipo de ataque era possível antigamente mas hoje em dia não mais porque os registras filtram quando você tenta registrar. Era um tipo de spoofing via registro de domínios fakes. É semelhante a um typosquatting que é quando você registra domínios que soam parecido com o original mas com um errinho que pode passar batido se você lê rápido, ou tá acostumado a falar que nem uma criança, por exemplo <code>santader.com</code> em vez de <code>santaNder.com</code>.</p>
<p>Voltando ao nosso exemplo original do hello world. Aprendemos que nosso arquivo <code>hello.c</code> é o que chamamos de um arquivo plain text, ou texto plano, que é um arquivo que contém apenas binários que mapeiam pra algum caracter numa tabela como ASCII. Mas pra todos os efeitos práticos, um arquivo texto também é um arquivo binário. A extensão não modifica nada no arquivo, é só uma convenção. Dentro dele tem uma fita, uma cadeia de bytes onde cada byte, de acordo com a tabela UTF-8 ou ASCII mapeia cada byte pra um glifo, um desenho de uma letra, número ou símbolo qualquer.</p>
<p>Eu estou sendo bem demorado nessa explicação porque vocês precisam entender desde cedo que o que você enxerga como “texto” é apenas uma representação do shell ou do editor de textos, o arquivo que ele abre é um binário como qualquer coisa no sistema. Tudo é binário. O que popularmente chamamos de “binário” é um tipo específico de binário, os executáveis. E agora vou mostrar qual a diferença do arquivo <code>hello.c</code> que é um binário pra texto do binário executável <code>hello</code> que foi gerado pelo <code>gcc</code> compilando o código que escrevemos dentro desse <code>hello.c</code>.</p>
<p>Se usarmos o mesmo comando <code>xxd hello</code> vamos ver um monte de sujeira na tela. Diferente do arquivo texto que nós digitamos, aqui tem só umas letras e símbolos jogados. Mas note que lá no começo, o arquivo começa com um código hexadecimal 7f e depois escreve ELF. Isso indica que este é um binário formato ELF que significa Executable and Linking Format, um formato padrão de executável que data da era dos UNIX originais.</p>
<p>Quando tentamos executar esse binário o sistema operacional, no meu caso o Arch Linux, vai identificar esses primeiros bytes e começar a checar se é um executável ELF válido. Pra isso vai validar o cabeçalho do arquivo, que ocupa um espaço específico de bytes no começo do arquivo. Tem um endereço especial pra identificação de cada coisa. Por exemplo, no 5o byte se tiver o valor 1 significa que é um binário de 32-bits, se for 2 significa que é 64-bits e de fato, temos 2, portanto é 64-bits.</p>
<p>Se você nunca entendeu o que é um protocolo binário, esse cabeçalho é um tipo de protocolo. Ele delimita campos dentro de uma cadeia de bytes. Por exemplo, do byte 0 até o byte 4 precisa ter a palavra <code>ELF</code> em ASCII, no byte 5 temos identificação de 32 ou 64-bits, e assim por diante. Cada campo tem um endereço de começo, um endereço de fim e alguns valores específicos e arbitrários que se espera encontrar nesse espaço, segundo a definição do protocolo ELF.</p>
<p>É tudo só um linguição de bytes, mas se satisfazer esse protocolo, essas regras de posição e valores, vai ser um executável ELF de Linux por exemplo. Um protocolo de rede é a mesma coisa, um linguição de bytes que tem certos campos em certas posições. Uma hora ainda vou falar sobre redes, mas isso deve dar uma noção pra agora. Lembre-se, é um computador de Turing, programa e dados estão todos misturados na mesma fita de bytes.</p>
<p>Continuando, tem um tanto de lugares vazios pra poder adicionar informações extras se precisar numa futura nova versão de ELF, mas o programa de verdade só começa a partir do endereço hexadecimal 0x1000. O que tinha antes eram meta-dados, ou dados que descrevem os dados do binários. E é isso que queremos dizer com dados e programas serem a mesma coisa. É tudo uma fita de dados. Aqui você vê que fica mais denso de bytes diferentes.</p>
<p>Mas note o primeiro, hexadecimal f3 depois 0f daí 1e e fa. é um comando em assembly de Intel x86 64-bits, o comando <code>endbr64</code>. Assim como tínhamos uma tabela de caracters como ASCII, pra saber sobre esse assembly, você precisa saber outra tabela, a que mapeia hexadecimais com comandos de assembly. Cada arquitetura de processadores tem uma diferente. Mesmo no mundo Intel, temos instruções diferentes entre 32-bits e 64-bits, a maioria é compatível mas em 64-bits obviamente temos mais funcionalidades diferentes. Tudo em computadores é sempre mapear bytes pra alguma coisa. Por isso quanto antes você se acostumar a conviver com hexadecimais, melhor.</p>
<p>Diferente de um arquivo texto onde os bytes são traduzidos da tabela UTF-8 pra imprimir os glifos na tela pra gente poder ler, quando o Linux detecta que é um executável ELF, ele valida os metadados do cabeçalho e a partir do endereço 1000 começa a mandar as instruções pro processador. Pra ficar menos complicado de enxergar, em vez do comando <code>xxd</code> podemos usar outra ferramenta que vai traduzir o hexadecimal pros mneumônicos de assembly, no caso o <code>objdump</code>.</p>
<p>Ele já pula o cabeçalho todo e vai direto pro endereço 1000 e veja os mesmos f3 0f 1e fa que é comando endbr64 que falei. Daí começa uma sequência de iniciação que vai executar essas instruções <code>sub</code> de substrair, <code>mov</code> de mover e assim por diante. Mas e um executável de Windows? Se a gente copiar o executável do Mesen que eu tava usando agora pra dentro do Linux podemos ver o conteúdo binário dele com o mesmo <code>xxd</code>.</p>
<p>Olha como é diferente, primeiro ele não começa com <code>ELF</code> e sim com <code>MZ</code>. O cabeçalho é totalmente diferente. A gente não precisa também ficar tentando ler byte a byte do cabeçalho pra saber o que são as coisas. Todos as distribuições de Linux tem um comando chamado <code>file</code> que justamente sabe reconhecer diversos tipos de cabeçalhos de binários e identificar de uma forma que humanos consegue entender. Por exemplo, se fizermos <code>file hello</code> veja que ele identifica corretamente como um executável ELF Intel de 64-bits. Se fizermos <code>file Mesen.exe</code> vemos que identifica como um PE32 ou Portable Executable de 32-bits Intel, em particular é um assembly de .NET Mono.</p>
<p>Todo arquivo no sistema é um linguição de bytes. Se forem bytes que existem na tabela UTF-8, provavelmente é um arquivo texto, como o código do <code>hello.c</code>. Quando compilamos com o <code>gcc</code> ele gera outro linguição de bytes, mas vai ter o formato ELF que é executável de Linux. Daí quando mandamos executar <code>hello</code> ele vai identificar o cabeçalho, validar, descer até o endereço 1000 do arquivo e achar as instruções assembly pra começar a mandar pro processador. Por outro lado temos diversos outros tipos de linguição de dados, por exemplo, uma imagem JPEG que todo mundo conhece, como as fotos que seu smartphone tira.</p>
<p>Vamos abrir um arquivo com <code>xxd</code> pra ver como é. Novamente, temos um linguição de bytes, mas em particular esse começa com ff d8. Se formos até o fim do arquivo temos ff d9. Todo arquivo JPEG começa e termina do mesmo jeito. Indo até o fim, esse ff d9 indica quando o arquivo acaba porque em nenhum lugar ele indica o tamanho total. Mas voltando pro começo, a partir do byte 6 vemos que o <code>xxd</code> reconheceu quatro códigos que mapeiam na tabela ASCII pra JFIF que significa JPEG File Interchange Format. Os bytes ff d8 já identificam o arquivo como JPEG mas tem esse JFIF porque também existe o EXIF que é Exchangeable Image File Format que é um formato similar feito por fabricantes de câmeras digitais de antigamente.</p>
<p>Essa é uma das formas que o sistema operacional reconhece que tipo de arquivo estamos lidando. Se for um binário que tem um linguição de bytes que encaixa no formato ELF, é um executável e, se tiver permissão de execução, tenta executar. Se for um binário com cabeçalho de JFIF é uma imagem JPEG e um programa de ver imagens vai saber os endereços dentro que precisa pra localizar a imagem propriamente dita. E assim por diante pra todo tipo de arquivo. Zips, video, áudio.</p>
<p>E no caso de arquivos texto, eles são binários também, cujos cabeçalhos não são nenhum dos anteriores e podemos tentar mapear byte a byte pra uma tabela como UTF-8. Caso venha só um texto quebrado com lixo no meio de letras, que não parece com palavra nenhuma, pode ser um encoding diferente, digamos um texto antigo em japonês e, nesse caso, se usar a tabela EUC-JP ou Shift-JIS, podemos encontrar palavras em japonês, se o programa que estivermos usando souber usar os glifos do alfabeto japonês.</p>
<p>Por último, vale falar do problema inicial. Por que não podemos executar o código do arquivo <code>hello.c</code> diretamente sem compilar? Primeiro, ele não é um binário ELF nem PE então não contêm instruções em assembly pra passar pro processador. Mas por que eu consigo executar direto um arquivo de Python, ou Perl, ou Javascript? Isso porque normalmente ele tem duas coisas. No caso específico de Linux, vai ter permissão de execução e segundo, na primeira linha vai conter o caminho no sistema pra um interpretador. Chamamos essa linha de shebang ou simplesmente bang. Se abrir um script de Python, você vai ver que costuma ter essa primeira linha neles.</p>
<p>Se só tiver permissão de execução mas não tiver shebang, quem vai tentar executar esse arquivo texto, que agora chamamos de shebang, vai ser o shell onde estamos neste instante. Por exemplo, quando eu abro um Terminal do Arch Linux, configurei pra iniciar o Zshell. Se for um Linux normal ou um Terminal no MacOS, sem configurar nada extra, normalmente vai abrir o famoso Bash. Um Windows vem por padrão com o Powershell. Existem vários interpretadores de terminal. Eu explico mais no episódio sobre WSL 2.</p>
<p>Essa linha de comando é um ambiente de programação. Podemos escrever programinhas. Então toda vez que você cai na tal linha de comando, pode imediatamente escrever código sem abrir um editor de textos separado. Em microcomputadores antigos dos anos 80 como um MSX ou Apple II ou Commodore 64, o equivalente shell deles era o Basic. E como toda linguagem de programação ele tem uma sintaxe, funções e comandos específicos dessa linguagem que, por acaso, não tem nada a ver com a linguagem C. E por isso quando você tenta executar o <code>hello.c</code> ele vai dizer que tem erros de sintaxe. Claro, não é a mesma linguagem. Você mandou essa shell que, digamos, é brasileiro, tentar ler um texto em chinês e aí ele buga mesmo.</p>
<p>A mesma coisa acontece quando você abre o console do Python, ou um console qualquer de Javascript ou Ruby. Daí vai ser um outro shell rodando em cima do shell original, Bash ou Zshell. Todo mundo de Ruby por exemplo conhece o IRB que abre uma linha de comando onde podemos executar direto comandos de Ruby. IRB é um acrônimo pra Interactive Ruby Shell. Está no nome, ele é um shell. Mais especificamente um REPL ou Read-Eval-Print Loop, ou traduzindo, um Loop de leitura, execução e impressão. Ou seja, um programa que fica em loop infinito sempre esperando ler um comando, daí tentar executar, que é um evaluate ou <code>eval</code> desse comando, e imprimir o resultado na tela. É um shell.</p>
<p>Confunde um pouco pra quem está começando porque é difícil distinguir o que são funções nativas dos shells como Zshell ou Bash e o que são binários executáveis que parecem funções. Por exemplo, todo mundo conhece o comando <code>echo</code> que imprime o string que passamos pra ele na tela. Mas fora no Zshell, ele é um executável que fica em barra usr barra echo. Os shells tem bem poucas funções nativas, por exemplo <code>cd</code> pra mudar de diretório ou <code>alias</code> pra criar atalhos.</p>
<p>E por hoje vamos ficar por aqui. Eu acho que uma das coisas que mais facilita a vida de um programador é o quanto antes ele se tornar íntimo do computador que usa. Muitos passam anos só trabalhando com linguagens de alto nível e evitam ao máximo lidar com binários, hexadecimais, pacotes, streams, porque parece uma coisa bizarra, tipo tentar ler chinês. Só que isso limita suas capacidades como programador. E limita bastante. Ser um programador não é receber peças de Lego e sair juntando que nem um idiota, em breve é bom você mesmo saber fazer suas próprias peças de Lego. Se curtiram o video deixem um joinha e compartilhem o video com seus amigos, não deixem de assinar o canal e clicar no sininho pra não perder os próximos. A gente se vê, até mais!</p>
]]></content:encoded><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #76 - Guia DEFINITIVO de Aprendendo a Aprender | A maior BRONCA da sua vida [RATED R]</title><link>https://akitaonrails.github.io/2020/04/01/akitando-76-guia-definitivo-de-aprendendo-a-aprender-a-maior-bronca-da-sua-vida-rated-r/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/04/01/akitando-76-guia-definitivo-de-aprendendo-a-aprender-a-maior-bronca-da-sua-vida-rated-r/</guid><pubDate>Wed, 01 Apr 2020 10:41:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/oUPaJxk6TZ0"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Quem é o tipo de profissional que vai sobreviver à Crise Econômica Pós-COVID-19 na nossa área de desenvolvimento de software? Como se faz pra ser tornar esse profissional?&lt;/p&gt;
&lt;p&gt;Se por acaso eu decidisse fechar meu canal hoje, eu diria que este seria um FINALE digno do que eu produzi até agora.&lt;/p&gt;
&lt;p&gt;Este vídeo vai ser um dos mais longos e talvez até um pouco cansativo em partes mas é porque eu realmente quero martelar pela última vez o que eu venho falando faz um ano e meio sobre o processo de aprendizado, particularmente para iniciantes que querem aprender programação.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/oUPaJxk6TZ0"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Quem é o tipo de profissional que vai sobreviver à Crise Econômica Pós-COVID-19 na nossa área de desenvolvimento de software? Como se faz pra ser tornar esse profissional?</p>
<p>Se por acaso eu decidisse fechar meu canal hoje, eu diria que este seria um FINALE digno do que eu produzi até agora.</p>
<p>Este vídeo vai ser um dos mais longos e talvez até um pouco cansativo em partes mas é porque eu realmente quero martelar pela última vez o que eu venho falando faz um ano e meio sobre o processo de aprendizado, particularmente para iniciantes que querem aprender programação.</p>
<p>Links:</p>
<ul>
<li>42 SP (<a href="https://www.42sp.org.br/"target="_blank" rel="noopener">https://www.42sp.org.br/</a>)</li>
<li>CodeMiner 42 (<a href="https://www.codeminer42.com"target="_blank" rel="noopener">https://www.codeminer42.com</a>)</li>
</ul>
<p>Playlists:</p>
<ul>
<li>Programação para Iniciantes (<a href="https://www.youtube.com/watch?v=O76ZfAIEukE&amp;list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki"target="_blank" rel="noopener">https://www.youtube.com/watch?v=O76ZfAIEukE&list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki</a>)</li>
<li>Carreira (<a href="https://www.youtube.com/watch?v=A2-yU3YjB1U&amp;list=PLdsnXVqbHDUcAWAN3cXHWnM9JEw2gjIN9"target="_blank" rel="noopener">https://www.youtube.com/watch?v=A2-yU3YjB1U&list=PLdsnXVqbHDUcAWAN3cXHWnM9JEw2gjIN9</a>)</li>
<li>Tough Love (<a href="https://www.youtube.com/watch?v=HEaIsKm-pao&amp;list=PLdsnXVqbHDUck2oHncXftVmut6_agAGRC"target="_blank" rel="noopener">https://www.youtube.com/watch?v=HEaIsKm-pao&list=PLdsnXVqbHDUck2oHncXftVmut6_agAGRC</a>)</li>
</ul>
<p>Me siga nas redes sociais:</p>
<ul>
<li>Twitter (<a href="https://twitter.com/akitaonrails"target="_blank" rel="noopener">https://twitter.com/akitaonrails</a>)</li>
<li>Instagram (<a href="https://instagram.com/akitaonrails"target="_blank" rel="noopener">https://instagram.com/akitaonrails</a>)</li>
<li>Facebook (<a href="https://facebook.com/akitaonrails"target="_blank" rel="noopener">https://facebook.com/akitaonrails</a>)</li>
<li>Podcasts (<a href="https://anchor.fm/akitando"target="_blank" rel="noopener">https://anchor.fm/akitando</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Estamos na semana do dia 1o de abril de 2020, esta é minha 3a semana de quarentena por causa da situação do COVID-19. Eu descrevi sobre os possíveis desdobramentos econômicos no vídeo da semana passada e recomendo que dêem uma olhada se ainda não viram pra ter contexto. Aliás, agradecimentos a todos que contribuíram compartilhando porque aquele video ironicamente “viralizou”!  E por isso, finalmente hoje vou fazer meu primeiro vídeo patrocinado! O video de hoje é patrocinado por Skill Share …. Ha! Primeiro de Abril! Vocês sabem que eu não aceito patrocínios.</p>
<p>Como vieram milhares de pessoas novas acho que vale 10 segundos pra explicar rapidamente que este canal é mais voltado a pessoas de tecnologia, em particular aqueles que são ou querem se tornar programadores. Não vai embora! Serve pra quem não é também mas de vez em quando vou puxar mais pra programador! Eu sou programador e empreendedor e tenho quase 30 anos de experiência na área, e o canal é uma forma de compartilhar o que aprendi até agora. O canal tem pouco mais de 1 ano e meio e não é monetizado de propósito, porque eu não faço questão de fazer conteúdos só aumentar público a qualquer custo. Por isso você pode voltar pro primeiro video do canal e começar a assistir tudo hoje porque eu faço conteúdos que sejam válidos em qualquer época. Alguns são mais técnicos, alguns são mais gerais. Vejam a playlist Carreira ou Tough Love, por exemplo.</p>
<p>O tema do vídeo de hoje é educação, mais do que isso, é sobre o que eu considero a forma correta de aprender, não só programação, mas qualquer coisa que seja profissão de prática. O jeito que você não vai achar em praticamente nenhum curso por aí. Se você já assistiu meus videos anteriores, acho que já tem idéia de onde eu vou chegar - e mesmo assim acho que vai ter uma surpresa no final. Já peço desculpas porque vou ser até meio repetitivo em alguns tópicos porque realmente quero marretar esses conceitos de uma vez hoje.</p>
<p>Considerando que muitos são novos no canal e ainda não viram, deixa eu introduzir com um trecho do meu vídeo Pequena Retrospectiva 2018 e Previsões 2019 que publiquei em janeiro de 2019, mais de um ano atrás. Eu vou aumentar a velocidade pra 1.5x em todos os trechos pra ir mais rápido:</p>
<p>(VIDEO &hellip;)</p>
<p>[trecho - ini]
Em termos de carreira na nossa área de tecnologia, estamos num momento de consolidação. Como disse antes, eu não vejo nada particularmente interessante que valha a pena focar todas as suas energias. Já faz pelo menos uns 5 anos que nada de realmente interessante aparece, só vaporware, só hype, mas nada que se provou ainda. Então, não acredite em nenhuma propaganda que se auto-intitula a salvação da lavoura, porque não tem. Só consolidações. A diferença é que eu espero que você tenha investido nos seus estudos nos últimos anos porque se o mercado se retrair, a competição vai aumentar, a demanda vai cair, e o mercado vai começar a separar o joio do trigo.</p>
<p>Por acaso, a entrada no século XXI foi marcado por um grande crash e uma depressão em 2001. Quase 10 anos depois em 2008/2009. E agora em 2019 ou 2020 já temos sinais de que estamos pra passar por algo similar.
[trecho - end]</p>
<p>[trecho - ini]
Resoluções pra 2019? Se a recessão não chegar este ano, aceite a sorte. Use este ano pra investir o máximo que puder nos seus estudos. Em 2020 você vai precisar disso.</p>
<p>E claro, como eu disse, especialista ou não especialista, ainda não existe ninguém que pode prever o futuro com certeza, nem especialista financeiro, nem cartomante. Mas, os sintomas estão aí. Vai bobear? Ah sim, e mudar de país não resolve o problema, porque essa tal próxima crise pode ser global e justamente os países hipster que a molecada gosta vão ser os primeiros a ser afetados.
[trecho - end]</p>
<p>Não, eu não tô querendo dizer que eu previ o que ia acontecer em 2020, obviamente eu não tenho bola de cristal, não sou Bidu e muito menos Nostradamus, que também não previu grande coisa. Mas se um ano atrás parece muito longe, vamos ver um trecho do video de junho de 2019 chamado A Bolha de Startups vai Estourar:</p>
<p>[trecho - ini]
Vamos colocar dessa forma: eu tomaria cuidado em apostar numa tech startup que opera com cash flow negativo, ou seja, que não dá lucro e não tem planos no curto prazo pra reverter. Especialmente se você estiver apostando morar fora do país ou algo assim. Esses planos vão ser cortados muito em breve.
[trecho - end]</p>
<p>[trecho-ini]
Eu gosto de ser conservador, eu detesto ser otimista demais porque os otimistas são os primeiros a cair quando uma crise aparece, especialmente uma que já está dando sinais cada vez mais claros. Eu sou um cético pragmático. Eu já sobrevivi a 2 ou 3 grandes crises. Sobrevivi os anos 90, os anos 2000 e os anos 2010, cada década teve uma crise e eu realmente nunca tive grandes problemas durantes esses períodos de transição. E o ponto de dizer tudo isso é porque durante minha carreira eu segui exatamente a descrição acima sobre a minha profissão. Quando o mercado acumula gente demais e de repente a demanda some, quem você acha que as empresas mantém e quem você acha que elas abandonam?
[trecho - end]</p>
<p>[trecho - ini]
O recado é muito simples: você está vivendo hoje num mercado que globalmente paga mais do que se deveria, fique esperto, essas coisas nunca duram. Se você está sentindo dificuldades hoje, vai ficar pior. Por outro lado, quem está conseguindo se enganar surfando na onda, vai tomar um caldo muito em breve.
[trecho - end]</p>
<p>Está parecendo atual? Vamos ser mais atuais ainda. Na semana do carnaval a revista Exame continuou contribuindo pra idéia errada de que programação é um dos empregos mais bem remunerados e virou piada porque ainda quis fazer uma chamada bem click-bait, ou pega-trouxa em bom português, contando a anedota do estagiário que recusou uma proposta de 10 mil reais. Basicamente todos os casos contados na matéria eram exceções da regra, distorções. E o problema: eles não explicaram o momento de bolha do mercado, que é a razão dessas distorções. Sem querer, uma semana antes dessa matéria sair eu já tinha uma resposta pronta no video Programação Não é Fácil, de 19 de fevereiro de 2020 onde dentre várias coisas eu expliquei:</p>
<p>[trecho - ini]
Pior que isso, mais da metade do valor de um lugar desses é só promessa. Imagine o montante de equity que existe espalhado nesse mercado. É um valor absurdamente grande. Só que isso é uma promessa. Se a startup falir antes de conseguir atingir o ponto de abrir capital e realizar sua valuation, todo esse equity vai valer zero no dia seguinte. Isso mesmo, zero. É uma bolha.
[trecho - end]</p>
<p>[trecho - ini]
Sabe onde isso vai chegar? Da próxima vez que a bolha estourar, e isso pode ser em breve ou pode ser em poucos anos, quem não for programador de verdade, ou seja, quem não souber como de verdade entregar resultados proporcionais ao que ganha, vai ficar sem emprego. Nunca se esqueça: sempre vai existir um indiano que faz o que você faz por menos da metade do preço. Provavelmente pode colocar um chinês junto nessa equação agora também.
[trecho - end]</p>
<p>[trecho - ini]
Sempre tenha em mente, você raramente vale o que você “acha” que vale. Todo mundo acha que deveria ganhar mais. E todo mundo que paga sempre vai achar que deveria pagar menos. Esse é o jogo. E é a lei da oferta e da procura que vai dinamicamente ajustando isso. Só que em períodos de bolha a demanda é desproporcionalmente mais alta, não dá tempo da oferta atender, então o que varia é o preço acima do normal. Em crises é o oposto, a demanda seca, e a oferta fica com estoque sobrando, o que varia é o preço abaixo do normal. Essa é a conta.
[trecho - end]</p>
<p>Tudo que eu mostrei dos meus videos anteriores parece super profético, mas não é bola de cristal. Todo mundo que estava acompanhando sabia que as economias globais montaram uma casa de cartas muito frágil e estava já a perigo de cair com qualquer sopro. Ninguém poderia imaginar que não seria um sopro e sim uma martelada brusca e violenta na forma dessa pandemia. o cenário que nós já prevíamos como difícil a partir de 2020 se tornou quase um apocalipse.</p>
<p>Repetindo, estávamos em uma bolha, que 6 circuit breakers então, e contando, estourou. Se você tem só uns 25, talvez até 30 anos, você conheceu um mundo que só veio inflando desde 2009. Foram 10 anos de exuberância irracional, com centenas de tech startups operando com caixa negativo, dependendo de rounds de investimento pra pagar as contas, com a promessa de um dia poderem dar exit seja abrindo IPO ou vendendo pra outra empresa maior. Essa mamata acabou. Com a crise iniciada com o COVID-19 o dinheiro ficou mais caro. Dólar se tornou o ativo mais importante pra agora. Ou seja, os VCs ou Venture Capitalists, que dependem de levantar fundos, vão ter dificuldade de levantar mais dinheiro. Então as startups que dependiam desse dinheiro agora, ou não vão ter nada, ou se puderem ter vai ser às custas de dar mais equity pros investidores. Como os investidores anteriores tem cláusulas anti-diluição, quem vai ser diluído são os fundadores. E quem tinha stock option, nos dois casos, está pra ver essas opções virando fumaça.</p>
<p>Eu chutaria que se metade sobreviver o próximo ano, deram sorte. Na prática pelo menos um quarto deve fechar as portas. E eu já tenho recebido notícias de vários conhecidos em várias partes do mundo dizendo que as startups estão já cortando um número grande de funcionários. O pior caso que eu ouvi até agora foi de uma startup de Amsterdam que parece já ter demitido 70% do seu quadro, incluindo todos os programadores que trabalhavam remoto aqui do Brasil. Tenho ouvido sobre startups em Berlin e outros lugares do mundo cortando também.</p>
<p>Muitos vão conseguir se recolocar porque são excelentes programadores, com real experiência e cujos códigos e produtividade são diferenciais. Porém, uma parcela considerável são muito ruins. Na ânsia de crescer rápido demais, dezenas de startups começaram a contratar em atacado, inclusive fazendo coisas como acqui-hire, que é basicamente adquirir muitas pessoas de uma só vez, em vez de ter o trabalho de convencer uma a uma pra tirar de outras empresas. É tipo um hostile take-over disfarçado.</p>
<p>Nos próximos meses vamos ver um número crescente de programadores indo pra rua e não tendo mais onde se recolocar. Muitos eram ainda iniciantes que inflaram o ego e acharam que eram tudo aquilo que os recrutadores diziam. Recrutadores esses, que sabem perto de zero do que é programação de verdade. Além disso, muitos programadores de palco, que falam bem e serviam como chamarizes de contratação pros patrocinadores, também vão começar a sumir, porque a maioria falava mais do que realmente sabia programar. Pelo bem ou pelo mal, todo esse circo montado nos últimos dez anos finalmente vai passar por uma correção.</p>
<p>Vou repetir o que eu disse no meu vídeo de fevereiro: a despeito do que muita gente ainda fala, programar Não é fácil. Profissões de prática de fato são muito fáceis de começar. Por exemplo, qualquer idiota consegue começar a desenhar, basta rabiscar qualquer coisa num papel e chamar isso de arte. Porém a barreira pra se tornar um profissional de verdade, com técnica, qualidade, é extremamente alta e não é fazendo um curso qualquer por aí que vai te levar até lá.</p>
<p>E agora chegou a hora de eu falar de cursos comerciais e livros técnicos. Eu tô cansado de receber perguntas toda hora me perguntando que cursos eu indico, ou que livros eu indico. Sério, parem de me perguntar isso, não só pra mim como pra qualquer outro que você considere como influencer. Eu fiz um video inteiro só sobre isso, que foi o Não Terceirize Suas Decisões e onde eu falo por exemplo:</p>
<p>[trecho - ini]
Mas perguntas que claramente tem a expectativa de justificar uma escolha, ou pior, terceirizar a decisão da sua carreira pra mim ou qualquer outro, não faz nenhum sentido. Por que você quer terceirizar as decisões da sua vida pra outra pessoa? Não faça isso. Só porque você vê alguém como eu ou qualquer outra pessoa em cima de um palco, isso não nos torna oniscientes, eu não te conheço, não sei que caminho você trilhou até agora, que dificuldades você teve, eu não sei quais seus objetivos de vida, se é que você tem objetivos. Nem eu, nem ninguém, poderia te dizer o que fazer sem conhecimento da sua história e dos seus objetivos.
[trecho - end]</p>
<p>[trecho - ini]
Se você está pra começar a faculdade, entenda que nos últimos 10 anos você aprendeu a estudar do jeito errado. Eu percebi isso só quando entrei na faculdade também. Por mais de 10 anos da sua vida você aprendeu a seguir um currículo. E você se condicionou a estudar o mínimo necessário e só pouco antes dos trabalhos ou provas. E as frequências das provas é sempre a mesma, provas bimestrais. E você sempre sabia o que estudar, porque já estava pré-definido. Todo mundo estuda o mesmo material, você nunca teve que escolher o que estudar.</p>
<p>Daí você entra na faculdade, e é mais ou menos a mesma coisa. Todo curso tem material pré-definido. Você tem as provas em datas pré-definidas. Talvez uma das poucas atividades que quebrem a rotina seja o Trabalho de Conclusão de Curso, o temido TCC. Que a maioria faz só na última hora mesmo que eu sei. Quem faz iniciação científica talvez tenha tido mais treinamento, mas no geral, você continua seguindo um currículo.</p>
<p>Parem pra pensar nisso: se você nunca repetiu de ano, você tem 21 ou 22 anos, recém formado da faculdade. E você passou uns 14 ou 15 anos da sua vida, ou seja, literalmente sua vida inteira seguindo uma receita pré-definida. É por isso que muita gente reclama quando entra no mercado de trabalho que a faculdade não preparou ele direito. Eu nem vou entrar no mérito da qualidade e da metodologia da educação moderna, e também não adianta chorar sobre o leite derramado. Só aceite que até o fim da faculdade, uma pessoa mediana só aprendeu a tirar 5 pra passar de ano e de repente não tem mais prova bimestral, não tem mais currículo, não tem mais professor “enchendo seu saco”. A partir de agora, todo dia é uma prova. Você só andou de bicicleta de rodinhas e do dia pra noite vai ter que aprender a fazer bicicross e saltar uma rampa por dia.
[trecho - end]</p>
<p>Entendam: você tem uma noção errada sobre o que é aprender. Um curso, online ou presencial, é mais ou menos a mesma coisa que eu expliquei no trecho anterior: é um professor que cospe um monte de passo a passo. Você repete esse passo a passo. No final, talvez, você tenha alguma provinha irrelevante e fácil, e ganha algum certificado de conclusão de curso. Daí, você adiciona no seu LinkedIn e começa a mandar mensagens pra recrutadores. Como o mercado estava desproporcionalmente aquecido, muitos conseguem um emprego, até em tech startups. E por que? Três motivos, 1) os recrutadores não entendem de tecnologia e acreditam em certificados e coisas idiotas assim 2) porque a startup tem meta de crescimento e não meta de lucro, por isso quanto mais ele contrata mais parece que ele cresce e 3) por causa desse ambiente que não tem eficiência como prioridade, muitos que não deviam acabam conseguindo uma posição onde nem tem que fazer grande coisa.</p>
<p>Como existia essa demanda artificial, começaram a aparecer os parasitas pra sugar o máximo possível dessas vacas leiteiras de dinheiro fácil. Eu acredito que existem alguns poucos cursos bem feitos que estão realmente preocupados em ensinar, mas também que muitos são só aproveitadores esperando gente ingênua que acredita em papai noel e não enxerga onde está se metendo, incluindo gente que sequer gosta tanto assim de programação, mas tá com os olhos arregalados em matérias exageradas como da revista Exame que prometeram pra ele: salários de 10 mil reais sem precisar ser muito bom.</p>
<p>E intermediários como influencers, coaches, e tudo mais inventam mais e mais “coisas” pra atrair mais gente. Coisas como Data Science, Machine Learning, Inteligência Artificial, que de fato são assuntos muito interessantes, que em empresas com história séria de engenharia como um Google da vida são usados de forma avançada. Mas na grande maioria das tech startups só se faz o básico. Big data na maioria das empresas é um data lake de logs que a maioria nem sabe muito bem o que fazer. Fazem alguma coisa, claro, mas comparado com o investimento? Acho que não. E a maioria dos “cientistas de dados” no máximo são usuários de ferramentas, então tá tudo certo. A quantidade de cientista de dados que sequer sabem cálculo, álgebra linear, estatística e probabilidade e saem aplicando regressão linear em qualquer coisa é grande. E lógico, pra saber essas coisas precisa de no mínimo uns 2 anos só de matemática, mas a maioria dos cursos por aí, se tiver 6 meses é muita coisa.</p>
<p>Mas como quem contrata não sabe o que tá contratando e quem é contratado não sabe o que tá fazendo e tudo bem porque tem dinheiro infinito de investidor, então foda-se, vamos inflando o mercado porque tá tudo aquecido mesmo. Tem dinheiro de Softbank cujo credor é o governo Japonês, então sua startup tá queimando dinheiro do contribuinte japonês. Tem dinheiro de fundos de pensão, então sua startup tá literalmente tirando dinheiro de velhinhos. Tem fundos soberanos de governo, de novo, dinheiro do contribuinte. Daí que surgem montes de pseudo-programadores politicamente corretos, achando que sua startup tá revolucionando o bem estar do mundo, porque é ingênuo o suficiente pra acreditar no marketing e não sabe que o salário que recebe pra produzir pouco ou nada o dia inteiro, provavelmente vai deixar uma velhinha sem aposentadoria. Como se sentem agora? É uma grande infelicidade que muitas pessoas vão sofrer nesta crise, muito mais do que deveriam, pessoas que realmente estavam se esforçando como podiam. Por outro lado, todos esses parasitas do sistema vão ser expurgados também.</p>
<p>Ou seja, se você tem na cabeça, qual das dezenas de cursos online deveria fazer, talvez Udemy, talvez Pluralsight, talvez outro? A resposta é simples: tanto faz. A partir deste ponto eu quero estruturar a resposta que eu falei do que eu acredito que é o jeito certo que falei na introdução. Eu digo tanto faz porque todo curso online é apenas material de referência e exercícios simples. A maioria simplesmente resume o que tem na documentação oficial da linguagem ou framework e grava em video. Toda vez que alguém me pergunta de um livro eu tenho vontade de responder “você já leu a documentação oficial? Se não, porque diabos tá pensando em livros ou cursos?” E invariavelmente a resposta mais muleta de todas é: ah porque eu só consigo aprender com livros, ou com cursos.</p>
<p>Bullshit. Eu vou dizer o que você realmente quer. Digamos que você queira aprender a arte da pintura. Mas o que você realmente quer é que alguém te dê um livro fácil de colorir; sabe aquele que as crianças gostam que tem numerozinho passo a passo dizendo qual cor colorir em qual espaço? E você quer alguém pra te dizer “nossa, conseguiu completar o passo a passo, você vai ser um Leonardo da Vinci um dia”. É isso que você quer, um elogio barato na forma de uma certificação e um passo a passo que não precise de muito esforço, especialmente se você estiver pagando.</p>
<p>Aliás, perceba a motivação de um curso: é manter o aluno pagante suficientemente contente. Muitas vezes a coisa certa a se fazer seria dizer: “cara, eu realmente acho que você não leva jeito pra programar e sugiro procurar outra coisa”. Mas eu ainda tô pra ver um curso fazer isso com frequência, porque num mercado aquecido eu chutaria que uma boa parcela da classe é de gente que nem deveria estar ali. Mas um curso comercial tem incentivos pra fazer de tudo pra animar as pessoas e fazer elas continuarem até o fim pagando mensalidade. É inevitável.</p>
<p>Falando num caso bem particular que é o meu, pra quem não sabe, eu sou dono de uma empresa de desenvolvimento de software chamada CodeMiner 42, que vai completar 10 anos ano que vem. Eu raramente falo da minha empresa no canal porque a intenção não é fazer propaganda, nem mesmo pra minha própria empresa. Mas pra ilustrar meu ponto eu quero contar uma coisa que nós fazemos e pouca gente sabe. A maioria dos body shops do mercado, os recrutadores que às vezes se intitulam consultorias, saem caçando currículo em LinkedIn e ficam ligando o dia todo pra programador pra tentar contratar. Sem tanto critério mesmo, e muitas vezes tentando roubar gente de empresas consideradas melhores, pra facilitar o trabalho. Eu tô de saco cheio de mesmo receber proposta de recrutador que foi preguiçoso demais até pra ler meu LinkedIn direito e fica me mandando proposta pra ser programador deles.</p>
<p>Aliás, seja recrutador independente ou dentro de RH de empresas grandes, grande parte da culpa do mercado de certificações é deles. Eu tenho zero consideração pela maioria das certificações porque eles só certificam que você assistiu aula e pagou mensalidade, mas não que você aprendeu alguma coisa. Lá por 2001 eu cheguei a estudar pra me certificar como Arquiteto Enterprise pela Sun, mas nem cheguei a fazer a prova porque eu não tava a fim de pagar só por um papel. E a Sun nem existe mais aliás. Eu estudei e comecei a aplicar na prática e só, me lixei pro papel.</p>
<p>Em 2005 minha consultoria queria ter mais gente certificada em PMI, então me pagaram pra fazer o curso e a prova. Foi um puta saco, eu decorei tudo, treinei dezenas de simulados. A prova foi super simples, sério, acho que eu levei 30 ou 40 minutos pra acabar e no final passei. E este, é o meu certificado PMP. Pra ser justo, o PMI não diz que quem é certificado já um bom gerente, ele até tem atividades que você precisa fazer pra se manter como PMP e ele tinha validade de 3 anos. Mas quem contrata raramente pede pra mostrar o diploma. Eu continuei sendo junior em gerenciamento e só depois de anos praticando eu posso dizer que aprendi o suficiente pra me considerar um gerente.</p>
<p>Eu respeito o corpo de conhecimentos do PMI, não me entenda errado, mas eu guardei o papel na gaveta e não pendurado, justamente pra um momento como hoje, porque vou te mostrar o quanto eu valorizo papel. Este é o certificado do curso obrigatório de PMI que tive que fazer (&hellip;) este é o diploma por ter passado na prova de PMI e que me certifica como PMP (&hellip;) e estas outras papeladas fazem parte do guia de PMP incluindo um (argh) código de conduta ….</p>
<p>(&hellip;.)</p>
<p>Dramatizações à parte, falando sério. Na CodeMiner, já faz alguns anos, contratamos estagiários. Normalmente são alunos de universidades federais ou estaduais, por volta do 2o ou 3o ano. Pra conseguir isso abrimos escritórios físicos em 12 cidades do país, de Norte a Sul, incluindo cidades como Natal, Anápolis, Santa Maria, Guarapuava, Ribeirão Preto e mais. Raramente contratamos estagiários que vieram de faculdades particulares. E por que? Porque normalmente a seleção deles é muito ruim. A palavra-chave aqui é seleção.</p>
<p>Entenda, além da qualidade dos professores e currículo, seleção é o fator fundamental que separa as universidades públicas das privadas. A universidade pública, por definição, não tem fins lucrativos no sentido de cobrar mensalidade, já as particulares tem. Em qual você acha que a seleção vai ser mais fácil? Como a concorrência pra entrar numa federal é ordens de grandeza maior do que numa particular, a seleção é muito superior. Por outro lado, muitos cursos particulares sequer tem seleção, significa que pagando, qualquer um pode entrar e, como eles tem incentivo pra manter o cara pagando, vai ser a pior seleção de todas, quando tem.</p>
<p>Além disso, se um aluno conseguiu sobreviver os 2 primeiros anos de uma boa federal de bacharelado em ciências da computação, quer dizer que ele passou por matérias consideradas hiper chatas mas necessárias como cálculo, como álgebra, como algoritmos e estruturas de dados. E se ele fez pelo menos iniciação científica, demonstra ainda mais empenho em trabalhos de pesquisa e melhoria contínua. Ou seja, um aluno de federal que já passou da metade do curso costuma ter bom potencial. E mesmo assim a gente ainda avalia ele antes de contratar.</p>
<p>Eu não estou dizendo que automaticamente todo mundo que faz curso comercial online é ruim. Pelo contrário, já conheci muitos programadores que se tornaram muito bons. Mas normalmente a pessoa que já tem o que precisa e sabe aprender sozinho, não foi o curso que o tornou bom. Com ou sem o curso ele já tem propensão e principalmente vontade de aprender, a despeito da qualidade do curso.</p>
<p>E mesmo depois de tudo isso, um estagiário meu ainda não está preparado pra entrar num projeto de verdade. Raramente é possível alocar um estagiário num projeto no primeiro mês. A maioria fica 3 meses ou mais só estudando. Nesse período ele precisa cumprir as 6 horas dele presencialmente nos nossos escritórios, e se integrar com os funcionários mais experientes. Eu já disse em outros videos que eu acho que nesse estágio de iniciante é extremamente prejudicial ser home-office, porque o aprendizado vai ser ordens de grandeza menor. Ele precisa estar do lado de gente mais experiente.</p>
<p>Durante esse período de estágio, ele participa de projetos internos, aprende a se comunicar com seus pares nos escritórios, aprende a pedir ajuda quando precisa, toma porrada nas revisões de código, é avaliado com alguma frequência pra ver se tá estagnado ou se tá evoluindo. Algumas vezes, quando ele é sozinho mais acelerado, até consegue participar como um programador não cobrado em projetos pequenos de verdade. Quando ele é efetivado como júnior depende muito mais dele do que da gente.</p>
<p>Esse é o período de treinamento no estágio. Nós não oferecemos nenhum material formal de aprendizado, em vez disso nós temos ebooks e algumas contas de cursos online que ele pode fazer. E nesses casos eu aprecio o uso de cursos online: como uma forma resumida de absorver algum assunto muito rápido pra pessoas que já tem uma fundação. Eu mesmo esses dias queria relembrar sobre React, porque eu não sou front e sim back, então assisti os cursos iniciais da Pluralsight na velocidade 2X porque eu acho todo video de curso hiper lento. E em 2 dias eu fiz o curso todo. E eu não estou endorsando a Pluralsight não, foi aleatório.</p>
<p>Além disso ninguém na empresa tem função específica de ser professor, não existe uma estrutura de aula nem palestras que ele precisa assistir, nem nada disso. Nós vamos jogando problemas do dia a dia pra ele resolver e ele precisa demonstrar que tem interesse em usar esse tempo. Inclusive ele está sendo remunerado, pra estudar muito. Como ele tem contato com os programadores experientes que estão em projeto, ele naturalmente começa a entender como os projetos funcionam e como nos comunicamos com clientes, na prática. Não existe um guia ou protocolo de comunicação.</p>
<p>Mais do que isso, nós não temos as figuras formais de gerentes ou qualquer coisa assim. Todo funcionário fala diretamente com o responsável do projeto do lado do cliente, sem um intermediário responsável em micro-gerenciar. Todo funcionário sabe que não deve só receber tarefas e fazer às cegas; aos poucos ele vai aprendendo a questionar as coisas, inclusive se ele deveria estar fazendo o que foi pedido e se não existem formas melhores e mais eficientes pra resolver o mesmo problema. E ele tem autonomia de dizer isso diretamente pro cliente. Isso faz parte do dia a dia de todo Miner. Sem micro-gerenciamento. Eles simplesmente sabem o que tem que fazer. Inclusive quero dizer que estou muito orgulhoso deles porque dia 13 de março comuniquei todo mundo pra antecipar a quarentena por causa da pandemia. Todo mundo começou a trabalhar de casa e todo mundo sabia o que tinha que fazer, sem precisar dar ordens ou instruções extras.</p>
<p>Eu imagino que muitos dos estagiários novos devem estranhar ter tanta liberdade logo no começo, mas ele não pode cruzar os braços, porque com tanta autonomia significa que temos tolerância zero com falta de profissionalismo ou mal caratismo. Zero mesmo, se alguém fizer alguma coisa mal caráter é demissão instantânea. Erros a gente sabe que todo mundo comete, mas se ficar cometendo o mesmo erro com frequência, toda vez, também não vai durar. É comum a gente repetir que se a pessoa se ver de braços cruzados sem fazer nada, ela está errada, porque devia estar caçando coisas pra fazer.</p>
<p>E por que tô contando toda essa história? Porque eu acredito que o jeito certo de aprender é esse: 1) dando problemas pra serem resolvidos 2) não ter nenhum material oficial, e sim forçar as pessoas a saber encontrar os materiais que precisam 3) não ter nenhum supervisor ou chefe que dá mastigado, forçando a criar senso de autonomia e responsabilidade. Pronto, acabei de resumir a metodologia inteira em 3 frases. E por hoje é só, a gente se vê semana que vem …. E, não, tô brincando, deixa eu explicar isso.</p>
<p>Contraste o que eu acabei de falar com o que você conhece normalmente como “cursos”. Um curso tradicional tem material didático específico pro curso, apostilas, passo a passo de tudo que você precisa fazer, e tem uma figura de autoridade na forma de um professor que vai te dizer o que tá fazendo certo ou errado. No final, talvez tenha uma provinha, e ganha um certificado e pronto. Esse formato tem pouca serventia. Os alunos que realmente tem potencial e gostam do assunto vão estudar outros materiais fora do curso, vão fazer experimentos, vão discutir com amigos. Os acomodados que nem sabem porque tão ali, vão seguir o passo a passo e fazer o mínimo esforço pra tirar a média e ganhar o certificado. Ambos no final ganham certificado e por isso eu não uso esse formato e por isso eu não valorizo papel.</p>
<p>Um bom curso deveria ser difícil, extremamente difícil aliás, pra servir de filtro e separar quem realmente quer aprender daqueles que tão ali mais pra agradar o pai que paga o curso, ou porque só quer arranjar logo um emprego fácil que paga bem. Além disso um curso não deveria ter um currículo totalmente fixo; ele deveria ter uma fundação obrigatória de conceitos que não são “cool” de aprender mas que são obrigatórias pra passar pras coisas que as pessoas realmente querem. Assim como engenharia numa federal, onde os dois primeiros anos é igual pra todo mundo e só depois eles escolhem civil ou naval ou elétrica e assim por diante. Mas a fundação deveria ser obrigatória. Não deveria existir a escolha de fazer um curso de Javascript sem o requerimento de ter feito, por exemplo, curso de algoritmo e estruturas de dados antes.</p>
<p>Além disso, não deveria ter um professor falando e os alunos só ouvindo, seja numa classe ou seja online num EAD. A figura do professor deveria ser como eu falei dos meus funcionários mais experientes, eles estão ali do lado do estagiário de suporte mas não tem nada estruturado. É o contrário, é o estagiário que tem que aprender a pedir ajudar e aprender a fazer perguntas inteligentes. Mesma coisa num curso, o aluno deveria só receber um monte de problemas pra resolver, sem livros, sem material didático, sem nenhum passo a passo, e usar seus colegas e professores pra responderem perguntas pontuais. Isso porque a primeira coisa que os alunos deveriam aprender a fazer é formular perguntas que façam sentido.</p>
<p>O mundo não é simplezinho assim, que tudo funciona organizado, bastando saber um passo a passo de coisas e tudo se resolve. Muito pelo contrário, o mundo de verdade é complexo, desorganizado, caótico e só quem consegue ir pra frente é quem sabe fazer as perguntas certas. Inclusive faz parte da idéia do 42 do nome da minha empresa que, se alguém tinha essa curiosidade, sim, vem do Guia do Mochileiro das Galáxias. O que é 42? Como diz no Guia é a resposta pra vida, pro universo e tudo. E o que isso quer dizer? Absolutamente nada, a pergunta foi mal feita e por isso a resposta não tem sentido nenhum. Essa é a moral da história, a resposta certa depende da pergunta correta.</p>
<p>Só que como eu disse no meu video de Não Terceirize suas Decisões: você passou sua vida inteira estudando nesse formato de passo a passo, currículo bem definido, professor que é a autoridade, continuar sendo passivo copiando matéria da lousa e não pensando muito, e se contentando em tirar 5 na prova e passando de ano, ficando com a falsa impressão que tava aprendendo alguma coisa. E é um dos motivos de porque os iniciantes ficam tão impressionados com tech startups de piscinas de bolinhas, que pegam na sua mão, te dão almoço, lanchinho, trocam sua fralda e cuidam de vocês como se fossem crianças. Eu, por outro lado, acredito em contratar adultos, eu não sou creche.</p>
<p>Chega de falar da minha empresa,o objetivo não é fazer propaganda, mas o contexto é que a gente não faz tudo isso desde o começo. Fomos aprendendo enquanto fazíamos, é um processo de aprendizado pra todo mundo. Já discutimos internamente até em fazer alguma coisa como uma CodeMiner Academy alguns anos atrás, com material didático, conceito de turmas e professores e tudo mais. Ainda bem que essa idéia nunca foi pra frente. Intuitivamente tanto eu como meu sócio acreditávamos na idéia de colocar estagiários juntos com sêniors, dar problemas e tarefas, e avaliar como eles resolvem e como eles evoluem ao longo do tempo. E esse acabou se tornando o modus operandi até agora.</p>
<p>Só cursos online é muito pouco. Em alguns momentos eles servem como um pequeno aquecimento. E só cursos são insuficientes, então tem ebooks, posts de blog, ler o código-fonte das coisas e assim por diante. Mais importante, eu não dito pra eles o que eu acho que eles deviam estudar. Muitos de vocês ficam me perguntando que materiais ou cursos eu indico. Entenda, eu não indico nem pros meus funcionários, eu quero que eles se virem sozinhos, porque eu acredito que encontrar o melhor material faz parte do treinamento. Se a pessoa sequer gasta um pouco de tempo e neurônios no exercício de avaliar material, como ele espera um dia virar programador?</p>
<p>Sem querer, o tipo de ambiente que criamos força as pessoas a aprenderem o famoso “se virol”. Essa é definição de Aprendendo a Aprender, é se virar, de verdade. Bicicleta sem rodinhas, caindo e tentando de novo. Eu fiz um video chamado A Dor de Aprender onde eu digo o seguinte:</p>
<p>[trecho - ini]
O prazer de um autodidata é provar pra ele mesmo que ele suporta a dor. A gente sente dor, igual todo mundo, mas em vez de evitar a dor, a gente faz esforço pra se acostumar a sentir dor. É bem doloroso quando você faz um curso, lê um livro, e seu código ainda não funciona ou você nem sabe como fazer um código diferente do que foi ensinado. É super frustrante. E sua primeira reação é o que? O curso é que não deve ter sido bom. Ou deve ter outro livro que vai ensinar de verdade o que precisa saber. Desculpe se eu sou o primeiro a dizer isso: a menos que você esteja disposto a encarar a dor, engolir o choro, esquecer a frustração, e começar a cair e ficar roxo na frente dos outros, não adianta nenhum curso, nenhum livro, nada, você nunca vai aprender. Ou você pára de desperdiçar dinheiro indo atrás de fórmula mágica, ou engole a dor, pára de mimimi, se compromete e foca no objetivo.
[trecho - end]</p>
<p>Meu mantra sempre foi: no pain, no gain. Estávamos numa bolha onde tudo era fácil, então começou a se popularizar a noção errada que ninguém deveria sentir dor, de nenhum tipo, incluindo se sentir ofendido. Tá errado. Se não está doendo, só quer dizer que você não está tentando com força o suficiente. Se você não está se sentindo frustrado, desmotivado, ansioso, estressado de tanto tentar e não alcançar, então não é aprendizado. O mundo não foi feito pra ser fácil, tudo tem que ser conquistado. Conhecimento tem que ser conquistado. Tem uma frase que eu tenho repetido recentemente entre amigos pra ilustrar a próxima crise: tempos difíceis criam pessoas fortes, pessoas fortes criam tempos fáceis, tempos fáceis criam pessoas fracas e pessoas fracas criam tempos difíceis.</p>
<p>Deixando claro, eu não sou contra os diversos cursos comerciais, nem faculdades particulares, nem EAD. Eles funcionam dentro do que se propõe: dar uma introdução de algum assunto de uma forma um pouco mais organizada. O objetivo é usar esses cursos onlines como mais uma ferramenta, pra rapidamente ter uma introdução, sabendo que vai aprender o 1%. Os 99% seguintes você vai ter que caçar sozinho à medida que vai precisando. Não existe nenhum curso que vai ter dar nem perto dos 100%. E vai ser sempre mais difícil se você evitar o esforço de ter fundações sólidas. Se você entende esta verdade, não existe nenhum problema em usar nenhum curso.</p>
<p>Duas coisas que as pessoas me mandam nos comentários dos vídeos ou em mensagens diretas, por que eu não monto um curso? E a resposta é simples: porque cada assunto de tecnologia já tem material suficiente na internet. Tem gente com mais paciência do que eu criando conteúdo didático. Eu não tenho paciência pra repetir o que já existe. E também por isso você raramente vê videos de tutoriais no meu canal. Esse tipo de video envelhece muito rápido. Quando sai uma nova versão, o video já ficou obsoleto. E eu não quero conteúdo que fica obsoleto tão rápido assim. Eu só quero produzir conteúdo que não se encontre facilmente por aí, parte da tal fundação que eu tanto falo.</p>
<p>No começo de 2019 eu comecei uma série de vídeos que era intitulada Começando aos 40 e depois renomeei a playlist pra Programação pra Iniciantes. Ela não ensina Javascript, nem Python, nem nada da moda. Eu explico os conceitos mais básicos. O que são processos? O que são threads? O que é alocação de memória? Quais os diferentes jeitos de alocar memória? O que é um scheduler? Quais os diferentes tipos de schedulers? Qual a diferença de um hypervisor e um container? Eu não consigo entender como alguém pode se dizer programador e não saber esse básico. E é por isso que muita gente tem dificuldade de mudar de linguagem ou ferramentas. Como elas aprenderam só “como” usar a ferramenta mas nunca “por que” a ferramenta existe, toda nova ferramenta confunde elas.</p>
<p>Aprender uma nova linguagem é fácil pra quem tem as fundações. Mas pra quem só fez cursos superficiais, estilo passo a passo, sempre acha difícil mudar de linguagem. E como ele estudou do jeito errado que expliquei, quando ele consegue fazer um código que roda, se apega a isso. A pessoa tende a se tornar escrava da ferramenta que aprendeu primeiro, porque foi difícil. E isso é o primeiro grande erro que todo programador iniciante comete: ele se torna seguidor cego de marcas, criando uma falsa sensação de validação, que seus esforços valeram a pena, e qualquer um que fale diferente tá errado. E eu falei disso lá no começo do canal nos dois vídeos que intitulei “Sua Linguagem Não é Especial”:</p>
<p>[trecho - ini]
Também como disse no episódio de faculdade, eu comecei no fim dos anos 80, passei por Basic, dBase III, Clipper, Turbo Pascal 6, Visual Basic 6, Delphi desde a versão 1.0, Perl desde a versão 5 - se bem que ela nunca saiu da 5, PHP desde a 3, ASP clássico, .NET C# e VB.NET desde a versão 1.0, Java desde a versão 1.0, Javascript desde antes de virar padrão ECMA, Python 2. E isso foi só até o fim dos anos 90.</p>
<p>Se tem uma coisa que vocês devem levar deste episódio é o seguinte: linguagens de programação Não são filosofias de vida. Linguagens de programação são meras ferramentas. Ferramentas foram feitas para servir seus mestres, e não o contrário. Linguagens de programação não merecem lealdade e definitivamente não são religiões. Eu não sou definido pela minha linguagem de programação favorita. Você não é sua linguagem de programação.
[trecho - end]</p>
<p>Independente se você pode fazer uma boa faculdade, ou se só tem condições de fazer pequenos cursos comerciais ou EADs, isso não importa. Todo material é material. Parta deste princípio: muitos programadores como eu começaram sem acesso a nenhum material. A gente precisava primeiro achar alguém que tinha pra pegar emprestado e tirar xerox em papel. Eu aprendi a programar antes da existência da internet. Eu pegava ônibus pra ir longe na casa de alguém que tinha algum programa ou material que eu não tinha pra pegar emprestado. Hoje vocês tem centenas de conteúdos gratuitos na internet e tão de mimimi? Pelamordedeus, você quer aprender esse troço ou não quer? Aprende a se virar.</p>
<p>A conclusão do que é Aprendendo a Aprender é isso: aprender a se virar, sem precisar da validação de ninguém, sem ninguém pra pegar na sua mão ou te dar tapinha nas costas, mergulhar em problemas que você não sabe resolver, sofrer, se frustrar mas continuar sem desistir, apesar da dor. Esse é o filtro. Quem persiste e passa obstáculo atrás de obstáculo, é quem tem maiores chances de chegar em algum lugar. Nada que não te faça sentir dor tem valor. No pain, no gain. Lembram do meu vídeo “Faça aquilo que Ama, só que não”? Se você realmente ama alguma coisa, você não deveria desistir só porque tá doendo. Por outro lado, se você só quer as partes boas, você não ama de verdade, só é preguiçoso.</p>
<p>[trecho - ini]
Você tá frustrado no seu emprego, pensando em mudar de emprego? Você tá frustrado com seu mundo? Quer mudar de mundo? Não adianta. Enquanto você tá frustrado com sua falta de esforço, qualquer emprego, qualquer lugar, vai terminar do mesmo jeito, porque a realidade é que tudo tem partes ruins, todo trabalho tem partes chatas, a VIDA tem muitas partes chatas. Começa fazendo as pequenas coisas direito, e vai se acostumando a parar de justificar sua frustração como sendo culpa da sua família, dos colega, do seu chefe, do dos políticos. Apontar defeitos dos outros é simples, qualquer idiota pode fazer isso. E os seus? Começa a onde realmente importa: tomando controle do que você mesmo faz. Já que vai fazer, faz direito, qualquer coisa. Em vez de dizer pros outros como fazer certo, que tal mostrar pros outros como fazer certo?
[trecho - end]</p>
<p>O maior medo que todo mundo tem quando começa a tentar aprender é se tem falta de talento. Isso é um assunto controverso e existem argumentos diferentes dependendo de pra quem perguntar. Eu realmente não acredito tanto em gente que nasce talentoso, ele pode nascer com propensão a certos tipos de atividade, mas não nasce sabendo. O que diferencia as pessoas que você chama de “talentoso” de você é a quantidade massiva de prática deliberada que ele fez. É o que eu explico nos meus episódios de Talento: Matando Semi-Deuses. Particularmente na parte 2:</p>
<p>[trecho - ini]
Prática deliberada é sobretudo um esforço de foco e concentração. É isso que o torna &ldquo;deliberado&rdquo;. Continuamente procurando exatamente os elementos de performance que são não satisfatórios e então forçando na melhoria especificamente desses elementos. Digamos, em programação, muita gente acha difícil escrever bons testes. Porque não pratica? Escreva centenas de testes. Não só pros projetos do seu trabalho, que como eu já disse, é insuficiente. Escreva, escreva, escreva. Vai sair um monte de porcaria no começo. E pra evoluir você precisa fazer o que Mozart fazia: copiar, testar, avaliar, corrigir e recomeçar, e recomeçar, e recomeçar, centenas de horas.
[trecho - end]</p>
<p>Assistam esses vídeos pra entender que um Einstein ou Mozart não eram deuses, eles eram humanos, e humanos que treinaram dezenas de milhares de horas a mais que um ser humano normal, é por isso que eles tiveram resultados acima do normal. Não porque eles eram deuses, mas porque você não tá disposto a se esforçar como eles. Não desvalorize o esforço que eles tiveram dizendo que era só talento. Se eles são reconhecidos hoje foi resultado do esforço monumental que eles fizeram.</p>
<p>Finalmente, chegamos à parte final deste vídeo. O objetivo de dar mais esse tapa na cara é acordar vocês pra uma nova realidade. A bolha estourou, tá acabando a vida fácil. Eu sei que muita gente assistindo tá até pensando “do que esse cara tá falando, minha vida sempre foi difícil”. Sim, eu sei. Isso foi pro playboy da capital que o pai paga as contas, não se esforça pra nada, só reclama, e ainda se acha vítima da sociedade. Pra quem a vida já tava difícil, sinto dizer que pode piorar. Então, pra quem tem a sorte de ter condições e quer entrar no novo ciclo de tecnologia, prepare as fundações. Gaste o tempo e o esforço necessários, aprenda a se virar.</p>
<p>Sobre cursos e livros, parem de me perguntar recomendações e parem de perguntar pra outros influencers que você sequer sabe se eles realmente sabem programar de verdade. Na prática, qualquer curso e qualquer livro servem. Não é a qualidade do material técnico que faz um programador ser bom. Vou repetir, eu não fiz nenhum curso da atualidade. Quando eu quero saber que livro ler, eu vou no Google e pesquiso “best books of .. Go” e pronto, tirando quando eu conheço o autor, eu vou na primeira opção. E à medida que vou me aprofundando, daí procuro outras referências de partes específicas. Não tô nem aí se influencer fulano ou beltrano recomenda ou não recomenda.</p>
<p>E se tem uma coisa que é básico e você precisa ir estudar e levar a sério o quanto antes é inglês. Não é uma coisa que fazendo um curso você aprende, você precisa incorporar no seu dia a dia. Eu fiz um vídeo inteiro chamado Como eu aprendi Inglês. Quando eu tava na faculdade também male male sabia ler o básico e não falava nada.</p>
<p>[trecho - ini]
TUDO que sai de mais importante na área de tecnologia sai primeiro em INGLES. Sabe o que acontece se você depende de material em português? Você precisa esperar essa tecnologia ganhar público, alguém se arriscar a traduzir material em português e publicar aqui. E todo mundo sabe que todo projeto open source, principalmente nas primeira iterações, muda o TEMPO TODO.
[trecho - end]</p>
<p>[trecho - ini]
Mundo open source é assim mesmo. E se por acaso um novo projeto consegue ganhar o seu público de early adopters e começa a ter demanda, sabe quem ganha mais dinheiro? Quem aprendeu sobre o software antes mesmo de ter saído a versão 1.0. Depois que saiu a versão 4, 5 etc que já tem livro, já tem curso, já tem toneladas de screencast, é quando o taxa/hora vale menos, 2x, 5x, 10x menor do que era pago pra quem se arriscou e aprendeu na versão 0.1 alfa.
[trecho - end]</p>
<p>Isso tudo dito chegou a hora de fazer uma coisa que eu achava que nunca fosse fazer no meu canal: falar de uma escola de programação. Este canal é exclusivamente produzido como se fosse um backup do meu cérebro. Ele tem começo, meio e um dia terá um fim. Eu expliquei isso no meu video sobre o diário de Henry Jones:</p>
<p>[trecho - ini]
Em retrospecto, tudo que eu faço eu faço pra mim, nunca pros outros. Eu sempre fiz tudo sem buscar validação. Eu não preciso muito que os outros digam que estou fazendo certo ou errado. Eu escrevi e gravei sobre porque você não deve procurar fazer só o que ama. Como eu disse naquele vídeo, eu não amo ficar varando noite pra editar vídeo, mas eu gosto de assistir o resultado tipo “da hora, pra um amador como eu, até que esse vídeo não tá vergonhoso, mas eu sei que posso fazer melhor”.</p>
<p>Deve ser muito frustrante quem faz as coisas esperando a validação de alguém. Eu não entendo muito quando as pessoas reclamam que ninguém elogia ou dá feedback positivo no trabalho delas. Me soa muito com uma extrema falta de capacidade de auto-crítica. Eu dou feedback pra mim mesmo. Eu nunca fiz nada porque alguém me motivou. Eu me motivo sozinho. Eu me sentiria muito mal se pra tudo que eu fosse fazer eu precisasse ser validado.
[trecho - end]</p>
<p>Um pouco de história, na França surgiu um dos maiores campus de startups, a Station F no começo dos anos 2010, fundada pelo bilionário Xavier Niel. Não notem minha tentativa pobre de sotaque de francês. Enfim, também na França surgiu uma rede de escolas particulares de programação chamada Equitech fundada em 1999 por Nicolas Sadirac com uma proposta bem à frente do seu tempo onde os estudantes ensinam uns aos outros. Pelo menos na época foi considerada uma das melhores escolas de programação. Em 2014 Xavier resolveu doar 50 milhões de euros pra um novo projeto de educação, uma escola sem fins lucrativos com uma nova metodologia de ensino para formar os melhores programadores. Xavier trouxe Sadirac pra dirigir a primeira unidade e hoje ele continua como diretor-geral. Eu imagino que ele trouxe a experiência de suas próprias escolas particulares Equitec pra essa nova empreitada que eles chamaram de École 42.</p>
<p>Essa escola abriu unidades em várias partes do mundo, incluindo no Brasil em 2019. Eis que em 12 de fevereiro de 2020 um aluno dessa recém formada escola que aqui foi batizada de 42 SP, o Salem, me manda um direct pelo Twitter, que eu vou ler pra vocês aqui:
“Eu sou aluno de uma escola de programação que veio da França para São Paulo e oferece curso de programação de maneira gratuita a todo tipo de pessoa e em qualquer faixa idade. Para você ter uma ideia a média dos alunos é de 36 anos e existem alunos das mais variadas profissões (médicos, arquitetos, geólogos, matemáticos e muitos engenheiros).
Eu por exemplo sou da área de engenharia Civil e estou em busca do meu sonho que é viver de programa&hellip;..rsrsrs
O curso básico começa em programação em Shell, C, Git e assembly que não é nada básico.
Criação de Shell scripts, criação das nossas próprias bibliotecas em C desde memcpy, calloc, atoi, itoa indo até o famoso printf  … O curso dura de 3 anos a 5 anos“</p>
<p>Nas primeiras frases que ele falou em curso, eu já imaginei “puts, mais um curso”. Mas quando ele falou que começam a aprender o shell de Linux, linguagem C, Git, assembly e criando as próprias bibliotecas de C com funções básicas como mem copy, funções como atoi que transforma strings em inteiros e assim por diante, antes de chegar em coisas como Python ou Javascript, certamente chamou minha atenção, porque tirando uma boa faculdade, nenhum curso online que eu opera dessa forma. Então começamos a conversar e o Salem se propôs a falar com a administração da escola pra de repente eu ir visitar.</p>
<p>Daí quem me manda mensagem é um dos fundadores da 42 SP, o Guilherme Décourt, que por acaso eu já cheguei a conhecer brevemente, anos atrás, quando minha empresa prestava serviços pra várias startups da VC Monashees, e o Guilherme era um dos sócios. Então eu fiquei sabendo que ele saiu da Monashees, se uniu com a publicitária Karen Kanaan e conseguiram trazer a École 42 pra cá. Ok, agora eu fiquei mais interessado ainda e eu precisava ver isso com meus próprios olhos. Nós marcamos e poucos dias depois fui visitar a escola, que fica no Alto de Pinheiros aqui em São Paulo, na famosa rua Aspicuelta que todo mundo aqui conhece pelos bares e atividade noturna.</p>
<p>O espaço que eles conseguiram é impressionante, realmente parece uma escola moderna, com dezenas de iMacs em uns dois andares, fora a cobertura. A decoração é moderna e bem artística do jeito que eu gosto. Só pelo espaço eu já gostei, mas claro que só isso não é suficiente, então eles começaram a me contar mais da história. Pra começar, o material de ensino vem toda da École 42 da França, eles vêm até o Brasil pra instalar os servidores com tudo que os alunos vão usar. O sistema é todo gamificado e cada aluno tem um perfil onde ele mesmo pode acompanhar seu progresso.</p>
<p>Ah sim, antes de continuar vale fazer um disclaimer. A 42 SP não me patrocinou pra fazer este vídeo. Nem eu mostrei este vídeo antes de publicar no canal, então eles tão vendo ao mesmo tempo que vocês. Portanto nada do que eu disser considere como oficial, estou apenas relatando minhas impressões pessoais e dando minha opinião. Do mesmo modo, a 42 SP não necessariamente compartilha de todas as minhas opiniões. Somos duas entidades independentes e por isso eu posso dizer que minha opinião não foi enviesada.</p>
<p>Voltando, o conceito da 42 é que eles não tem turmas e nem professores. Mais do que isso, eles não tem apostilas nem material didático próprio. Eles também não obrigam alunos a comprar livros nem nada disso. Cada aluno evolui no seu próprio ritmo, com um requerimento que passa a ser natural de um ajudar o outro. Até parte da avaliação dos alunos é receber feedback online de quem ele ajudou. Assim como na minha empresa, quem tá lá só pra codar e ficar isolado e não ajudar ninguém, ele perde seu seu espaço. Na 42 SP, é um requerimento estar no mesmo espaço físico e ajudar seus pares. Por isso eles não tem intenção de ser um curso online.</p>
<p>As matérias são organizadas no que eles chamam de galáxias. Pense o conteúdo organizado na forma de anéis, os do centro são a fundação obrigatória e à medida que ele vai passando de nível vai abrindo os anéis superiores, até chegar em matérias opcionais onde ele pode escolher, por exemplo se for web, se quer começar aprendendo Ruby ou PHP. Ou ele pode não querer web e se especializar mais em segurança. O importante é que você só abre esses anéis se passar pela fundação, no centro da galáxia. Que é 100% o que eu vim dizendo até agora. No total são 21 níveis, que dependendo da pessoa pode levar 3 ou 4 anos. Ou seja, não é curso superficial de 3 meses. A partir do nível 7 você já poderia ser considerado talvez um nível júnior pro mercado, ou o que na minha empresa seria nível estagiário. Eu ainda não posso opinar sobre isso porque não avaliei um aluno nível 7 pessoalmente, mas pelo que vi parece fazer sentido.</p>
<p>Se você assistiu meu vídeo de Devo Fazer Faculdade - 22 anos depois, eu explico minha teoria das pirâmides do conhecimento. Não é a mesma coisa que os anéis da Galáxia da 42 mas são conceitos similares de conhecimento progressivo:</p>
<p>[trecho - ini]
Daí eu criei uma noção na minha cabeça que pretensiosamente eu chamava de Teoria das Pirâmides. Tudo que eu aprendi até o fim do colégio era o pequeno topo de diversas pirâmides. Pirâmide de matemática. Pirâmide de Português. Eu nunca ia saber tudo sobre tudo. Em vez disso eu falava pra mim mesmo que deveria aprender o topo de muitas pirâmides, e à medida que eu fosse avançando, iria descendo nessas pirâmides. E eu pensei em pirâmides meio como a dificuldade, o topo é menor, a parte mais fácil, a base é maior, as partes mais avançadas, quanto mais você desce na pirâmide, mais difícil fica. Muitos pensam em ir completando uma pirâmide inteira de cada vez e eu sempre achei isso ineficiente.</p>
<p>Antes da faculdade, e até talvez o primeiro ano, eu tentava ler os livros inteiros, mas antes dava, porque não tinha muito mais pra se ler. Na faculdade eu vi que isso não iria acontecer mais. Antes meu mundo se restringia a uma dúzia dessas pirâmides de conhecimento. Foi quando eu parei de tentar ler livros técnicos inteiros, eu só lia a introdução. (pegue o livro) E ia avançando se precisasse. Em vez de ler 1 livro inteiro, era melhor ler o começo de 10 livros. E gastava mais tempo praticando do que lendo.3
[trecho - end]</p>
<p>Agora eu gosto mais da analogia de galáxia também. E nesse mesmo vídeo eu falo sobre um problema que muita gente que faz cursos online e aprendem só o básico enfrentam sem saber:</p>
<p>[trecho - ini]
Existe uma enorme armadilha no começo de carreira: a minha teoria das pirâmides tem outro detalhe: só de aprender o topo da pirâmide, você consegue entregar um projeto. Hoje em dia eu ilustro isso como o problema dos 80/20. Com 20% do conhecimento você consegue resolver 80% dos problemas. Mas pra resolver os últimos 20%, vai precisar dos 80% de conhecimento que ainda não tem.</p>
<p>Com meus pífios 20%, eu entregava projetos. O perigo era eu achar que já era bom, eu entendia isso. O que me mantinha no chão é que pra entregar esses projetos eu varava muitas noites corrigindo bug. Na minha cabeça, se eu não consigo entregar com menos bugs e se eu não consigo entregar só no horário do trabalho, era minha falta de experiência. Esse era meu termômetro de competência.
[trecho - end]</p>
<p>No caso da 42 eles tem um problema similar só que mais pra 30/70, mas a idéia é a mesma. Muita gente a partir do nível 7 já sabe o suficiente pra ser útil num projeto ou startup e consegue um emprego. Ainda mais na bolha que tava. E eu sei a sensação porque eu também abandonei a faculdade. Na minha época começou a Bolha das Pontocom no fim dos anos 90. E que também acabou na Crash do ano 2001. Parece que alguns alunos da 42 chegam nesse nível 7 e com o trabalho acabam desacelerando e até deixando a escola. Isso é o problema velho problema de afobação. Mas no video da semana passada eu declarei que a bolha estourou, e foi isso que eu disse e que vale pra esse pessoal:</p>
<p>[trecho - ini]
Pra quem é jovem e estava afobado porque parecia estar atrasado pra entrar num mercado que não parava de crescer, pause um segundo, os mercados pararam de crescer. Na realidade o que vai acontecer é muita demissão. Por isso o valor de um profissional medíocre vai cair. Lembra? Oferta e demanda. Vai haver muita oferta, muito estoque sobrando, de pessoas que só fizeram cursos básicos ou tiveram formação inadequada e vai crescer a demanda por profissionais bem preparados, que já são raros hoje. Vocês acabaram de ganhar uns 2 anos ou mais pra estudar com calma, criar fundações sólidas, como eu venho repetindo sem parar em vários videos do canal.</p>
<p>E quando a maré virar, o mercado vai precisar de gente bem preparada. Eu disse isso antes e vou dizer de novo: com ou sem crise, o mercado sempre tem espaço pra gente competente de verdade, aquele que realmente faz a diferença no resultado da empresa. E agora você vai ter menos concorrência, porque a maioria quis pegar atalho pra surfar a onda, não fez fundações sólidas, escolheu cursos mais por serem curtos do que por serem bons. Evitaram as coisas difíceis e como o mercado só crescia, eles tinham espaço. Esse espaço vai começar a desaparecer a partir de agora. Eu disse isso no meu vídeo de Programação não é Fácil, se você tem uma posição que não é fundamental pra sobrevivência da empresa, fique preocupado. Claro, com o resgate do FED ainda vão sobrar muitas, mas se tudo der certo, pelo menos as piores vão falir.
[trecho - end]</p>
<p>A vantagem do sistema de não ter turma nem professor é que o seu ritmo não é freado pelo ritmo do aluno mais fraco. Você pode avançar no seu próprio ritmo. Quando tem dúvidas sempre tem alguém na sua frente que pode te ajudar. E por sua vez, sempre tem alguém um passo atrás precisando da sua ajuda. Isso é muito importante porque você exercita colaboração de verdade, coisa que nunca acontece numa sala de aula de curso, nem de faculdade. Aliás, quando eu tava no colégio eu odiava trabalhos em grupo. Só significava que ninguém se esforçava, deixava tudo nas minhas costas pra fazer, e no final só queriam que eu colocasse os nomes deles antes de entregar. É um lixo esse sistema porque não existe motivação pra ninguém colaborar.</p>
<p>E porque na 42 SP seria diferente? E aqui vem a outra parte que me convenceu neles. Eu disse que a 42 SP, assim como a École 42 e todas as outras subsidiárias são organizações sem fins lucrativos, ou seja, eles não vivem de mensalidade dos alunos e sim de doações de fundos de investimento ou de empresas que acreditam na causa. O próprio prédio onde eles estão foi doação do dono do prédio. Os iMacs todos foi um programa da Apple onde eles deram um puta desconto.</p>
<p>Os alunos não pagam nada. É tudo gratuito. Por causa disso eles podem se dar ao luxo de selecionar os alunos que entram e até expulsar quem tá atrapalhando ou nem tá querendo colaborar. É a mesma coisa com minha empresa, porque eu pago salário pra estagiário sem ele estar trabalhando pra nenhum cliente, só pra estudar e colaborar. Por isso se ele não usa o tempo dele pra evoluir, está tomando o lugar de outra pessoa mais esforçada. Tão entendendo os paralelos?</p>
<p>Quando eles abrem inscrições, rola 2 provas online de lógica, sem código. Eu não lembro de cabeça os números então vou só chutar a ordem de grandeza, mas sendo escola gratuita e com pedigrée francês, obviamente milhares de pessoas do país inteiro se inscreveram. Eles estabelecem tipo uma nota de corte e só os 300 ou 400 melhores são escolhidos. Depois disso eles precisam ir pessoalmente pra participar de algumas reuniões presencialmente. Só de não ser curso online, um monte já desiste. E eu gosto desse conceito porque se a pessoa não tem comprometimento nem pra ir lá pessoalmente, provavelmente não tá levando a sério o suficiente, e só nisso muitos já desistem.</p>
<p>Depois dessas reuniões inicia uma fase chamada de Piscina, e até eu quero roubar esse nome agora. Pense se fosse uma escola de natação, a idéia é jogar todo mundo na piscina e deixar se virar pra não afogar. Quem sobrevive vira aluno. Essa piscina é uma imersão presencial de nada menos que 28 dias seguidos, onde de cara recebem dezenas de problemas de programação pra resolver. Isso mesmo, eu achei sensacional, a pessoa chega e recebe um computador, uma conta na escola, a lista de problemas que precisam resolver com código e só. Não tem instrução, não tem aula, não tem material didático, não tem professor apresentando matéria. É um por todos e todos por um. Cada um vai resolvendo, ajudando os outros e avançando como puder. E a escola fica aberta 24 horas por dia todos os dias, então quem quiser pode até varar noite se quiser.</p>
<p>É uma versão bem mais puxada do meu estágio, onde o estagiário não tem nada estruturado, as coisas vão aparecendo e ele vai tendo que se virar. Eu achei esse conceito sensacional porque essa é a seleção final. Então foram tipo 3 etapas de seleção pra separar quase 200 alunos dentre milhares que se inscreveram. Eles fazem o que eu falei que eu gosto das faculdades federais e que os cursos comerciais não fazem: os recursos não são infinitos, e os alunos não pagam mensalidade, portanto eles precisam selecionar quem parece que vai tirar melhor proveito do material disponível. Uma pessoa que tem dinheiro pra pagar mas não tem interesse nem esforço só estaria desperdiçando o lugar de outra pessoa.</p>
<p>Daí eu pedi que eles me mostrassem o pouco material que eles dão pro aluno, a lista de problemas. E de fato, cada problema é um pequeno pdf de umas 3 ou 4 páginas, declarando o problema, declarando os critérios pra passar, o que eles não podem usar, e o que é esperado. Por exemplo, mesmo em faculdade ou tecnólogo que começa com a linguagem C, a gente começa fazendo algoritmos e programinhas simples. E bem naturalmente a vai aprendendo a usar malloc pra alocar memória, free da desalocar, memcpy pra copiar o conteúdo de uma variável em outra variável, sizeof pra saber o tamanho do tipo de uma variável, printf pra printar mensagens formatadas no saída padrão do terminal e assim por diante.</p>
<p>Mas o PDF inicial que eu vi era mais hardcore. Pra começar é tudo em inglês! E isso eu também achei sensacional porque é realmente zero muletas, zero rodinhas na bicicleta. Eles tinham que implementar as próprias funções básicas da biblioteca C, o próprio memcpy, o próprio printf, exatamente como o Salem me contou no Tweet dele. Nem eu nunca tive que fazer isso. E confesso que fiquei com vontade de sentar naquele computador e começar a resolver o problema.</p>
<p>Pensa uma pessoa que nunca programou uma única linha de código na vida ou no máximo fez tutoriais de Javascript, lê esse PDF. E é só isso. No final, quando ele terminar o código, precisa subir no Git da escola onde alguns problemas parece que tem o equivalente de um CI, um continuous integration, que roda um script de teste automatizado pra avaliar e tem professores que fazem a revisão desse código. Então esse aluno precisa, do zero, sem aula e sem material didático, descobrir como usar um editor de textos, descobrir o que é um compilador, descobrir como debugar. Daí precisa aprender sozinho o que é C, como é uma função main básica, o que é um ponteiro, o que é um loop. Daí como funciona o git até conseguir subir o resultado pro repositório da escola. E tudo isso num único problema, logo no primeiro dia, e são centenas deles.</p>
<p>Se conseguir chegar na área de segurança você vai ter que construir seu próprio malware do zero. Se for mexer com redes vai ter que descobrir sozinho o que é OSI até montar seu próprio protocolo. Se for pra games vai ter que montar sua própria engine gráfica do zero. E é assim com todas as áreas de conhecimento. Alunos que começaram do zero depois da piscina, acho que 6 meses depois estão todos usando shell, usando clang, usando Vim de editor e avançando sozinhos. Excelente.</p>
<p>Claro, nem eu e nem eles estão dando garantias. Não é qualquer um que vai conseguir aprender a programar. É o contrário, a 42 é um grande filtro. Quem desistir lá, não vai aprender melhor em outro lugar. Falta de esforço nenhum curso conserta. Quem entrar na 42 tem que estar preparado pra encarar essa realidade de que talvez falte determinação própria. Por outro lado, quem conseguir durar até o nível 21 eu acredito que saia de lá com nível no mínimo igual ou até superior a qualquer um que tenha feito ciências da computação numa boa faculdade federal. Na questão de ter realmente aprendido a aprender, eu acho que talvez seja muito melhor.</p>
<p>Eu pratico modelo semelhante tanto pessoalmente quanto na minha empresa e quando eu vi a 42 eu pensei, “se eu fosse montar uma escola de programação, provavelmente seria exatamente nesse modelo”. E foi uma grata surpresa ter visto alguém que pensou semelhante e anos antes já colocou o modelo em prática. Eu gosto até do nome!</p>
<p>Eu acredito que pessoas em aprendizado precisam de contato direto com outras mais experientes e ao mesmo tempo devem ajudar as menos experientes, e isso só é eficiente num ambiente presencial. Já disse que acho home office bom pra quem já é experiente, mas prejudicial pra quem é iniciante. Porém, com a situação atual de quarentena o processo da 42 infelizmente também foi prejudicado. Todos aqui torcendo pra essa situação se normalizar o quanto antes.</p>
<p>Eu também disse que o processo todo é obrigatoriamente presencial. Significa que quem não puder estar lá durante os 3 ou 4 anos não pode ser aluno. Os recursos são limitados, o espaço é limitado, mas mesmo assim a 42 tem um programa de bolsa parcial ou total dependendo do potencial do aluno e dos fundos que eles tem disponíveis. Alguns alunos estão podendo ir graças a essas bolsas. E aqui eu deixo o convite a qualquer empresa, que vá visitá-los pra de repente também contribuir.</p>
<p>A 42 SP ainda é nova, eles abriram as atividades no meio do ano passado. Mês passado deveria acontecer uma nova piscina pra selecionar mais alunos, mas de novo, essa atividade de imersão teve que ser adiada por motivos óbvios. Finalmente, deixo aqui meus parabéns pra Karen, pro Guilherme, pra Mari que cuida da comunicação. Eles me forneceram as informações que trouxe aqui pra vocês. Agradecimentos ao Salem que fez a indicação. Vou deixar links nas descrições abaixo pra vocês procurarem saber mais sobre eles.</p>
<p>E por hoje é isso aí, o episódio de hoje foi super longo, me desculpem por ter me alongado tanto mas eu achei que este deveria ser o episódio pra eu resgatar parte do que eu já disse desde o começo do canal pra vocês entenderem que esse é um assunto que eu passei literalmente anos pesquisando e refletindo. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video mandem um joinha, não deixem de assinar o canal, clicar no sininho pra não perder os próximos episódios e compartilhar com seus amigos. Eu continuo aqui na quarentena, e quem puder continue seguro e continue em casa. A gente se vê, até mais!</p>
<p>Quem é o tipo de profissional que vai sobreviver à Crise Econômica Pós-COVID-19 na nossa área de desenvolvimento de software? Como se faz pra ser tornar esse profissional?</p>
<p>Se por acaso eu decidisse fechar meu canal hoje, eu diria que este seria um FINALE digno do que eu produzi até agora.</p>
<p>Este vídeo vai ser um dos mais longos e talvez até um pouco cansativo em partes mas é porque eu realmente quero martelar pela última vez o que eu venho falando faz um ano e meio sobre o processo de aprendizado, particularmente para iniciantes que querem aprender programação.</p>
<p>Links:</p>
<ul>
<li>42 SP (<a href="https://www.42sp.org.br/"target="_blank" rel="noopener">https://www.42sp.org.br/</a>)</li>
<li>CodeMiner 42 (<a href="https://www.codeminer42.com"target="_blank" rel="noopener">https://www.codeminer42.com</a>)</li>
</ul>
<p>Playlists:</p>
<ul>
<li>Programação para Iniciantes (<a href="https://www.youtube.com/watch?v=O76ZfAIEukE&amp;list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki"target="_blank" rel="noopener">https://www.youtube.com/watch?v=O76ZfAIEukE&list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki</a>)</li>
<li>Carreira (<a href="https://www.youtube.com/watch?v=A2-yU3YjB1U&amp;list=PLdsnXVqbHDUcAWAN3cXHWnM9JEw2gjIN9"target="_blank" rel="noopener">https://www.youtube.com/watch?v=A2-yU3YjB1U&list=PLdsnXVqbHDUcAWAN3cXHWnM9JEw2gjIN9</a>)</li>
<li>Tough Love (<a href="https://www.youtube.com/watch?v=HEaIsKm-pao&amp;list=PLdsnXVqbHDUck2oHncXftVmut6_agAGRC"target="_blank" rel="noopener">https://www.youtube.com/watch?v=HEaIsKm-pao&list=PLdsnXVqbHDUck2oHncXftVmut6_agAGRC</a>)</li>
</ul>
<p>Me siga nas redes sociais:</p>
<ul>
<li>Twitter (<a href="https://twitter.com/akitaonrails"target="_blank" rel="noopener">https://twitter.com/akitaonrails</a>)</li>
<li>Instagram (<a href="https://instagram.com/akitaonrails"target="_blank" rel="noopener">https://instagram.com/akitaonrails</a>)</li>
<li>Facebook (<a href="https://facebook.com/akitaonrails"target="_blank" rel="noopener">https://facebook.com/akitaonrails</a>)</li>
<li>Podcasts (<a href="https://anchor.fm/akitando"target="_blank" rel="noopener">https://anchor.fm/akitando</a>)</li>
</ul>
]]></content:encoded><category>aprendizado</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #72 - RANT: Programação NÃO É Fácil</title><link>https://akitaonrails.github.io/2020/02/19/akitando-72-rant-programacao-nao-e-facil/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/02/19/akitando-72-rant-programacao-nao-e-facil/</guid><pubDate>Wed, 19 Feb 2020 10:30:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/V7oUDL7E1g4"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIPTION&lt;span class="hx:absolute hx:-mt-20" id="description"&gt;&lt;/span&gt;
&lt;a href="#description" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Faz anos que você ouve falar que &amp;ldquo;programar é fácil&amp;rdquo; ou &amp;ldquo;qualquer um consegue programar&amp;rdquo;. Eu mesmo já disse coisas parecidas.&lt;/p&gt;
&lt;p&gt;Hoje eu quero explicar porque na última década a programação alcançou esse status bizarro de &amp;ldquo;salvador da pátria&amp;rdquo; e porque os mercados estão num momento desproporcional de abundância, e o que isso pode significar pra sua carreira.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/V7oUDL7E1g4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIPTION<span class="hx:absolute hx:-mt-20" id="description"></span>
    <a href="#description" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Faz anos que você ouve falar que &ldquo;programar é fácil&rdquo; ou &ldquo;qualquer um consegue programar&rdquo;. Eu mesmo já disse coisas parecidas.</p>
<p>Hoje eu quero explicar porque na última década a programação alcançou esse status bizarro de &ldquo;salvador da pátria&rdquo; e porque os mercados estão num momento desproporcional de abundância, e o que isso pode significar pra sua carreira.</p>
<p>Warning: quem achou outros vídeos um &ldquo;tapa na cara&rdquo; ou &ldquo;pedrada&rdquo;, entre neste com cuidado porque pode ser pior. Frágeis de ego: eu avisei.</p>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Esta semana, pra variar vou fazer um video mais curto que o normal, me preparando pra tentar fazer algo maior durante o Carnaval. O videozinho que vocês acabaram de ver sou faz uns 6 anos atrás, era 2014 e fui convidado pra participar com um vídeo pra um movimento chamado Ano do Código. Eu tentei o possível pra Não fazer um vídeo tentando dizer o famoso &ldquo;qualquer um consegue programar&rdquo; mas meio que acaba dando pra entender assim, se você não pegar o contexto.</p>
<p>Eu pessoalmente não gosto desse vídeo que eu fiz. E eu acho que muita gente assume que minha mensagem é sempre próxima disso que eu disse. Eu nunca quero dizer isso. Então meu vídeo de hoje vai ser uma divagação sobre esse tema.</p>
<p>(&hellip;)</p>
<p>Em 2014 estávamos no pico do &ldquo;awareness&rdquo; popular sobre desenvolvimento de software. O mundo estava se recuperando da última grande crise financeira que assolou muitos países. E no meio desse momento apocalíptico, que gerou muitos desempregos, fechou muitas empresas, uma categoria parecia emergir como a solução de todos os problemas. E isso foi a programação, especialmente porque o conceito de App Store naquele ponto tinha 4 anos e gerou um boom de apps. E vários apps se tornaram icônicos como Uber ou Airbnb que deram uma alternativa a muita gente que perdeu emprego de conseguir trabalho que antes não existia. Quantas vezes você não viu reportagens nos jornais, de engenheiros, médicos, que perderam empregos e se tornaram motoristas de Uber?</p>
<p>Algo parecido tá acontecendo no Brasil agora. Naquela crise de 2008 e 2009, o governo brasileiro, chamou a crise de &ldquo;marolinha&rdquo; achando que o Brasil era invencível ou imune. Óbvio que não. Vivemos uma bolha artificial e a conta chegou. E por isso o mesmo episódio aconteceu aqui também, com a popularização de aplicativos como iFood, Rappi e outros que estão tendo o mesmo papel do Uber 8 anos atrás. A primeira vez que eu peguei Uber foi em 2012 em São Francisco. Era novidade ainda e a categoria era muito menor.</p>
<p>Muita gente não se lembra, mas o conceito também era diferente, a idéia do Uber não era popularizar o transporte. Era ser um transporte diferenciado de nicho. Pra começar você tinha que dirigir carros pretos mais classudos com os Lincoln. A idéia era você chegar nos lugares &ldquo;like a boss&rdquo;. O que hoje em dia se chamaria de Uber Black era o Uber normal, por isso Uber se chama Uber, aliás. O nome original era UberCab, e Uber vem do alemão e quer dizer algo como “superior”, então seria o táxi superior.</p>
<p>Aliás, foi por volta de 2012 que eu vi muitos dos aplicativos que usamos hoje se popularizando. Foi quando eu usei o Waze pela primeira vez direto em Tel-aviv, em Israel. Todo mundo lá estava usando, mas por aqui ainda era novidade. Geolocalização era uma tecnologia que começou fazia pouco tempo, 4 anos antes em 2008, inaugurado pelo Foursquare na South by Southwest daquele ano. O Google Maps tinha começado pouco tempo antes em 2005. Mas foi com o advento dos iPhone 3G com GPS em 2008 que a população em geral começou a tirar proveito de geolocalização pra mapas e rotas, pra criar geofencing e tudo que hoje em dia é super comum e trivial. Mas faz só pouco mais de 10 anos que tudo isso começou.</p>
<p>Essa tangente foi pra dar contexto daquele momento histórico. Tivemos o nascimento de novas categorias de tecnologia e por coincidência naquela época iniciou uma das maiores crises da história, e nós programadores estávamos no lugar certo e no momento certo pra ganhar as honras de salvadores da pátria. Pra uma parcela considerável de uma população, graças a termos smartphones no bolso e acesso a apps como Uber, ou Airbnb, milhares de pessoas puderam sair do desemprego causado pela crise. E por isso não é estranho que a população em geral visse com bons olhos não só as tecnologias mas as pessoas por trás delas.</p>
<p>Até o presidente Barack Obama na época, empolgado com essa nova alternativa, ajudou a incentivar uma nova geração de programadores. Em 2014 ele entrou forte nessa propaganda, muitos noticiaram quando ele se tornou tipo o primeiro presidente a escrever um código. Outros grandes nomes se uniram a essa causa como Bill Gates. Tecnologia deixou de ser só uma curiosidade, ou um instrumento pra especular fortunas como foi na Bolha do Ano 2000, pra se tornar uma solução social. E o resto, como diriam, é história.</p>
<p>Por isso em 2014 principalmente surgiram vários movimentos pra incentivar o aprendizado de programação como algo tão fundamental como aprender a ler e escrever. Tudo isso é positivo porque a profissão de programação foi finalmente reconhecida pelo que ele já vinha fazendo faz décadas: elevando as capacidades da humanidade.</p>
<p>Porém, isso também teve efeitos colaterais graves. O fato de todo mundo ter se tornado tão positivo à tecnologia acabou dando carta branca e tolerando muitas coisas que acabaram como escândalo anos depois. Vide o notório episódio da venda de dados dos usuários do Facebook pela Cambridge Analitica. Vide as acusações de manipulação da opinião popular pra eleger um presidente. E mesmo assim o Facebook continua firme e forte e crescendo. Por menos que isso, no ano 2000 a Microsoft quase foi obrigada a ser quebrada em múltiplas empresas independentes pelo Supremo Tribunal no caso antitruste.</p>
<p>Com tudo isso Tecnologia se tornou uma nova religião, e os grandes nomes da tecnologia se tornaram seus sacerdotes. Silicon Valley se tornou a nova Meca, e muita gente peregrinou pra lá. E os programadores se tornaram os seguidores cegos dessa nova religião. Diversos efeitos nefastos derivaram disso e continuam causando problemas até hoje.</p>
<p>Sem entrar muito em lei econômica, mas é sempre bom ilustrar com alguns extremos pra ter um modelo na cabeça. Vamos pro pior extremo possível, um monopólio. Ou mesmo algo próximo, um oligopólio, formado por um cartel de empresas que age em conluio. Ou ao contrário do que muitos imaginam, monopólios não são formados apenas por empresários malvadões. Governos são os campeões em gerar monopólios. Em qualquer desses casos o efeito pra um trabalhador comum é extremamente ruim.</p>
<p>Se não existem outras opções de trabalho, todo mundo é obrigado a participar desse jogo de cartas marcadas. O monopólio pode te pagar só mínimo necessário pra sobreviver ou até menos e não tem muito o que você possa fazer, especialmente se o monopólio for estatal. Se sair, não existe outro emprego. Se tentar empreender vai ser massacrado.</p>
<p>Por outro lado, quando você tem fartura, abundância e liquidez no mercado, temos outro efeito interessante. Pense o cenário de Silicon Valley ou qualquer outra dessas Mecas onde se concentraram os sacerdotes da tecnologia. Todo mundo peregrina pra lá com as promessas de salvar o mundo E ficar rico no processo. Não é incomum você ter programadores ganhando 150 mil ou 300 mil ou meio milhão de dólares por ano em São Francisco.</p>
<p>Se fizer a conta de padeiro e converter pra Real a 4.30, os 300 mil seria você ganhar 1.3 milhão de Reais por ano, bruto. Seria um salário de quase 100 mil reais por mês. É claro que chama a atenção. Dentro dos Estados Unidos isso chama atenção, e fora dele em países em desenvolvimento como o nosso, ou países ainda piores que o nosso como Índia, Angola, Nigéria. Claro que todo mundo quer ser programador!</p>
<p>Mas precisa fazer outra conta pra entender o que de fato esses 300 mil dólares do exemplo significam. Em muitos casos, metade disso pode ser só equity. Falando em linhas simples equity é uma promessa. Quando a startup abrir capital, você tem opção preferencial de compra das ações. Você não tem As ações, quando chegar a hora você precisa ter dinheiro pra exercer essa compra ou perder a opção. Isso é a primeira coisa que pouca gente pára pra pensar. Pra exercer essas ações você tem um período de vesting. Ou seja, se sair antes desse período, você perde essas opções. Equity é um mecanismo pra reter pessoas que é bem popular porque a empresa não precisa gastar nada por um bom tempo.</p>
<p>Então digamos que você ainda receba líquido essa metade por ano, ou seja, 150 mil. Isso daria pelo menos 12 mil dólares por mês. Continua sendo um puta dinheirão pros padrões brasileiros. Porém, o mercado não é estático. Se muita gente se concentra num mesmo lugar, ganhando salários cada vez mais altos, a lei da oferta e da procura entra em ação. Todo mundo que peregrinou pra lá agora precisa morar em algum lugar. A procura por imóveis aumenta drasticamente, mas a oferta não tem como aumentar do dia pra noite, portanto o preço dos imóveis aumenta também drasticamente. Então não é incomum achar apartamentos pequenos custando na faixa de 4 mil dólares pra cima.</p>
<p>Um terço desse salário que você achou enorme já foi embora. Então agora você tem 8 mil dólares por mês. Continua sendo um dinheirão. Mas não acaba aí. Digamos alimentação. Aqui no Brasil você pega seu Sodexo ou VR e em São Paulo pode pagar 30 a 40 reais por almoço. Nos Estados Unidos não existe o conceito de vale alimentação, e a refeição equivalente que você comprar na rua vai ser 30 ou 40 dólares. Vezes 22 dias úteis num mês, e se não tomar cuidado, vai perder mais de 600 dólares, só em almoço.</p>
<p>E vai fazendo essa conta pra tudo, luz, água, lavanderia, plano de saúde, academia, vestuário, entretenimento, talvez escola se você tiver filhos. Você pode perder mais 3 mil dólares ou mais nessa brincadeira. Os 8 mil começam a virar 5 mil ou 4 mil. E não se esqueça que também tem impostos. Apesar de serem menos que no Brasil, você ainda precisa pagar. Na faixa entre 80 a 160 mil dólares você deve pagar uns 28%. Então não é 12 mil que você tem líquido por mês, é dois terços disso, ou seja, 8.600.</p>
<p>No final do mês, você achou que tinha 12 mil dólares, mas tire tudo isso e muito mais que você precisa gastar numa das cidades mais caras do mundo, e se tiver sorte, vai sobrar mil dólares, talvez 2 mil. Ainda assim, pro padrão brasileiro, se sobrar mil dólares parece bastante coisa, mas você não pode comparar com o custo de vida brasileiro, que é ordens de grandeza mais barato. Aliás essa é outra coisa que pouca gente faz: só vê o número absoluto. Não considera custo de vida ou impostos.</p>
<p>Daí acontece efeitos bizarros de você ver um americano que ganha teoricamente 5 a 10 vezes mais que você aqui, e reclamando que ganha pouco e não dá pra viver. E se parece exagero, vide exemplos recentes quando a empresa de jogos TellTale Games demitiu dezenas de pessoas do dia pra noite porque eles ficaram sem dinheiro. Um monte de gente que foi pra rua ficou sem ter dinheiro pra pagar o aluguel do mês seguinte. Eles realmente viviam de contra cheque em contra cheque. E essa é a realidade da grande maioria das pessoas, aqui ou lá. Não é diferente.</p>
<p>Na Europa é a mesma coisa. Na Ásia é a mesma coisa. Não existe bala de prata. Se 150 mil dólares for uma média, considere que pelo menos metade da população ganha consideravelmente menos que isso. Médias salariais não dizem nada. O contexto e os custos são completamente diferentes. E claro, os valores e contas que eu fiz aqui são hipotéticos, não adianta ficar jogando nos comentários &ldquo;ah mas meu amigo que eu conheço é diferente&rdquo; eu sei, é um exemplo. E casos isolados não define uma regra geral. A história do “cara que você conhece” ou o seu próprio é apenas isso: uma anedota.</p>
<p>Voltando à história de monopólios que eu falei, onde você realmente trabalha por centavos. A situação de Silicon Valley e outros centros com grandes investimentos é o inverso. Parece que existe abundância, pra todo mundo. E parece que se você ganha menos de 150 mil dólares por ano, você está sendo explorado. Mesmo se for esse o caso. Foi uma escolha sua ir pra lá. Ninguém colocou uma arma na cabeça forçando você a estar lá. E você tem escolhas, estamos num período de abundância. Só que ninguém quer ganhar &ldquo;menos&rdquo;, ou assumir um erro, ou assumir outros riscos. É um problema de ego, não de economia.</p>
<p>Pior que isso, mais da metade do valor de um lugar desses é só promessa. Imagine o montante de equity que existe espalhado nesse mercado. É um valor absurdamente grande. Só que isso é uma promessa. Se a startup falir antes de conseguir atingir o ponto de abrir capital e realizar sua valuation, todo esse equity vai valer zero no dia seguinte. Isso mesmo, zero. É uma bolha.</p>
<p>Tem duas coisas que podem acontecer num cenário desses. A primeira é a bolha estourar. E quando ela estourar o valor de tudo vira pó. Só que agora sobra um exército de programadores hiper caros que, no papel, e só no papel, acha que vale tudo isso de verdade. Só que não vale. Valor não é absoluto, é um produto do mercado. Qualquer empresa que cair a ficha que precisa controlar e cortar custos, em vez de gastar desenfreadamente em mesa de sinuca e piscina de bolinhas e propaganda cara, em busca do sonhado market share, tem alternativas. Umas das alternativas se chama outsourcing, ou terceirização. Pra onde? Pra países onde programadores de qualidades semelhantes custam metade, um terço, ou ainda menos. Nós, aqui no Brasil, os indianos, os ucranianos e assim por diante.</p>
<p>Eu já vi isso acontecer antes. Em 2001 não foi só as torres gêmeas que caíram, caiu também a bolha especulativa da internet. Centenas de programadores que achavam que eram bons de repente não tinham pra onde ir. Foi assim que cresceu o mercado da Índia no começo dos anos 2000, se tornando referência em terceirização de programação e outros serviços como call centers e qualquer coisa que era possível terceirizar. Por isso americano odeia a globalização.</p>
<p>Eu já tinha contado essa história e estou repetindo aqui pra dar contexto. Agora vem o que eu queria dizer no começo. Programação não é salvador da pátria. Ela é só uma profissão, que deve sim, ser levada a sério. Só que passamos os últimos dez anos com o falso estigma que ser programador é uma coisa “nobre” pra sociedade, que vamos resolver todos os problemas do planeta, vamos acabar com a fome, vamos consertar o clima, vamos consertar tudo. E pior, surgiu a noção de que é fácil programar. E não só é fácil programar, mas a procura por programadores aumentou drasticamente por conta de todo esse dinheiro fantasma, toda essa promessa de riqueza, de repente qualquer programador mais ou menos, passou a ganhar mais do que deveria num mercado fora dos padrões.</p>
<p>Sabe onde isso vai chegar? Da próxima vez que a bolha estourar, e isso pode ser em breve ou pode ser em poucos anos, quem não for programador de verdade, ou seja, quem não souber como de verdade entregar resultados proporcionais ao que ganha, vai ficar sem emprego. Nunca se esqueça: sempre vai existir um indiano que faz o que você faz por menos da metade do preço. Provavelmente pode colocar um chinês junto nessa equação agora também.</p>
<p>Sempre tenha em mente, você raramente vale o que você “acha” que vale. Todo mundo acha que deveria ganhar mais. E todo mundo que paga sempre vai achar que deveria pagar menos. Esse é o jogo. E é a lei da oferta e da procura que vai dinamicamente ajustando isso. Só que em períodos de bolha a demanda é desproporcionalmente mais alta, não dá tempo da oferta atender, então o que varia é o preço acima do normal. Em crises é o oposto, a demanda seca, e a oferta fica com estoque sobrando, o que varia é o preço abaixo do normal. Essa é a conta.</p>
<p>O quanto você vale depende da sua qualidade, da oferta e da demanda. E em períodos de demanda desproporcional, mesmo a qualidade não sendo grande coisa, ainda assim existe oportunidade.</p>
<p>Agora, tudo isso que eu usei de exemplo é nos grandes centros. São Francisco, Berlin, Londres, São Paulo, e assim por diante. As pessoas de cidades mais distantes do interior, ainda estão completamente fora dessa realidade. Toda vez que um programador rock star de um grande centro fala das maravilhas de tudo isso, ele está criando uma falsa expectativa. Mercados não melhoram só com discurso.</p>
<p>Como a tal demanda que eu falei é altamente desproporcional, mesmo assim não é tão difícil ouvir falar de casos de programadores que saíram de lugares longínquos e hoje estão morando nesses grandes centros, ganhando seus 150 mil dólares por ano. Esses casos se tornam a propaganda pra um sub-mercado que aparece toda vez durante esses períodos de abundância. Eu sei que estamos num período de abundância quando existe oportunidade pra certificar coach de coach ISO 9001 em instituição nacional de coach por exemplo. Num mercado normal, onde reinaria a eficiência, essa posições simplesmente não existiriam. Então sim, estamos num período de abundância excessiva.</p>
<p>Você tem que tomar cuidado com aproveitadores. Por exemplo, não é de hoje que ouço falar de cursos rápidos e workshops de poucos dias ou semanas, que trazem até pedigree estrangeiro, prometendo a pobres incautos que eles também podem rapidamente usufruir desses altos salários em grandes centros. E a demanda é tão alta, que de fato, alguns deles até conseguem posições, de tão baixo os critérios que muitos recrutadores colocam pra conseguirem suprir a demanda. E isso só alimenta a propaganda enganosa.</p>
<p>Deixa eu ser o estraga prazer. É impossível se tornar um bom programador, do zero, em duas semanas, ou mesmo dois meses. Esse tempo é suficiente pra, no máximo, saber fazer tarefas muito simples. E como eu sei disso? Por que eu faço contratações pra minha empresa e já fiz pra várias outras empresas ao longo de 20 anos. Eu já contratei literalmente centenas de pessoas e avaliei centenas de curriculos e acompanhei a evolução deles. Eu sei uma coisa ou duas sobre contratações e avaliações.</p>
<p>Coloque em perspectiva. Alguém considerado estagiário, já está num curso, seja de ciência da computação ou engenharia de software ou técnico em programação por pelo menos 2 anos. Isso significa uma carga horária mínima de 3 a 4 horas por dia, por uns 8 meses e 22 dias úteis por mês ou no mínimo 700 horas. Sem contar o tempo de estudos, trabalhos, e pesquisa. Um workshop realmente puxado de 8 horas por duas semanas são míseras 80 horas. Não chega nem perto da metade do que um estagiário já estudou.</p>
<p>Se o curso for excepcionalmente bom e se você for excepcionalmente estudioso e aplicado, ainda assim estamos falando de chegar no nível de estagiário. Faça as contas. Não tem como. Do nível estagiário, dependendo de onde ele estagia, as pessoas mais experientes com quem tem contato, os diferentes desafios e estudos extras no estágio, ainda precisa na média de mais 6 meses a 1 ano pra se tornar um júnior. Então estamos falando de uma carga extra de treinamento de mais 6 meses de 22 dias úteis e 6 horas no estágio, ou seja, mais 700 horas.</p>
<p>Ou seja, chutando na média, pra sair do zero até chegar ao primeiro estágio de júnior, estamos falando de uma carga aproximada de 1400 horas entre estudo teórico e treino prático. No mínimo. E eu não estou falando que um curso rápido ou workshop são ruins, é apenas uma questão de expectativas. Eu acho que esses workshops são bons pra dar uma introdução e os primeiros passos, as primeiras 80 a 100 horas de um percurso de 1400 horas. É 5% do percurso. Existem exceções? Casos excepcionais de gente talentosa que consegue em metade desse tempo? Claro que tem, mas por isso chamamos de exceções e não da regra.</p>
<p>Só que a grande maioria das pessoas não faz essas contas simples que eu acabei de fazer. Em vez disso, prefere cegamente seguir alguma palestra motivacional que ouviu de algum fake coach por aí e mergulhar na corrida do ouro sem saber que está indo atrás de ouro de tolo. Quantas histórias eu já vi de pessoas que nem de fato se interessavam tanto pela área, mas foram influenciadas e só depois de ver o tamanho do caminho, se frustraram e desistiram pelo caminho.</p>
<p>Pior ainda os que caminharam o 5% do percurso e tiveram a sorte de entrar na onda da alta demanda e conseguiram alguma posição em algum lugar. Alguns até ficaram bons o suficiente, mas ainda assim não são programadores de verdade. Eu não tenho nenhuma pesquisa cientificamente correta para trazer dados, mas eu não consigo não parar pra pensar no motivo de porque de repente tem tanta gente sofrendo de síndrome do impostor. E porque existem grupos grandes de pessoas em nível básico se comportando na defensiva de suas posições. Porque são posições super frágeis e na maioria das vezes desnecessárias, criadas num momento de alta artificial da demanda. Quando tem dinheiro sobrando, porque se preocupar em eficiência?</p>
<p>Falando como um sobrevivente de umas 3 crises, nos anos 90, nos anos 2000 e nos anos 2010, uma coisa permanece constante. Os que ficam pra trás foram os que estacionaram no básico, cegos por um valorização fora do normal, achando que já são bons o suficiente já que existe demanda por eles. Os que vão pra frente e sobrevivem são os que não colocaram esse valor como base e sim as próprias habilidades de resolver problemas reais, seja lá quais eles sejam. E você só consegue ser flexível pra resolver problemas diferentes quando seu conhecimento tem fundações sólidas, treino sólido. Não importa se é momento de abundância ou momento de crise, um tipo de emprego que nunca acaba são as posições reservadas ao reais solucionadores de problemas.</p>
<p>Muita gente deve estar tomando um balde de água fria e provavelmente me xingando já neste momento. Não culpem o mensageiro. Mas eu diria que é melhor se frustrar antes do que depois quando é tarde demais. Mas agora eu volto à segunda parte do meu vídeo de 2014 e o que eu quis dizer:</p>
<p>(&hellip; video)</p>
<p>Se você ainda não assistiu tudo, eu venho fazendo uma série de vídeos tentando explicar como funciona esse começo, como funciona o mercado e em particular sobre a metodologia de aprender a aprender. Recomendo voltar à playlist de carreira que eu fiz e assistir com calma. Mas deixa eu fazer outra tangente.</p>
<p>Eu sou ruim em esportes. Eu sempre fui, sabe aquele japonês CDF que na educação física é sempre o último que todo mundo escolhe pra colocar no time e termina no máximo como gandula. Pois é, sou eu. Talvez se eu me aplicasse mais eu talvez conseguisse ser alguma coisa melhor. Só que eu não gosto de esportes. Acho chato. Não prende minha atenção por mais que 30 segundos. Eu simplesmente não gosto.</p>
<p>Eu sou ruim de gastronomia. Eu adoro comer, todo tipo de comida do mundo eu como e você vai ter dificuldade de achar qualquer ingrediente que eu me recuse a comer. Quando quero só relaxar e não pensar em nada eu gosto de colocar nos canais Tasty e ficar vendo chefs cozinhando. Porém eu mesmo não gosto de cozinhar. No máximo eu fervo água pra colocar em miojo, se precisar muito eu faço um ovo frito, mas eu não tenho nenhum prazer em cozinhar. De novo, eu me colocar pra cozinhar é me entediar. Não rola.</p>
<p>E assim vai, eu sou ruim em muitas coisas e não tenho nenhuma intenção de investir tempo pra ser bom em nenhuma delas. É uma escolha consciente. Do outro lado da moeda eu gosto de programar. Saber como funciona cada pequena coisinha de cada tecnologia chama minha atenção, me prende por horas, eu já cansei de ficar entretido e só parar quando vejo o sol nascendo, de novo. É um contraste enorme com as coisas que eu não gosto.</p>
<p>Da mesma forma, eu tenho certeza que existem diversas pessoas com gostos totalmente opostos aos meus, que amam esportes e acham programar ou jogar videogames coisas completamente tediosas, maçantes e sem sentido. E elas tem total razão: gosto é que nem bunda, todo mundo tem um. Esporte profissional não é pra qualquer um. Como hobby sim. Programação também não é pra qualquer um. Como hobby sim.</p>
<p>Incentivar a fazer esportes é normal, correto e sempre faz bem pra população em geral. Esportes tem o benefício de ajudar você a se manter saudável, ajuda você a trabalhar em equipe e ajuda você a exercitar sua vontade de ser um pouco melhor. Tem um monte de boas razões pra se fazer. Mesmo assim você não vai me convencer, porque simplesmente não me atrai. Por outro lado, acho que pouca gente tirando as crianças fazem esportes com o objetivo de se tornar o Neymar. Você sabe que é um caso em um milhão. Você pode tentar copiar tudo que ele já fez e as chances de você virar algo próximo de metade um Neymar continua sendo inatingível. Foi uma combinação impossível de repetir de talento e esforço pessoal, timing, e estar no lugar certo na hora certa. Esforço e sorte é que geram sucesso. Não é uma receita que qualquer um pode repetir.</p>
<p>Mesma coisa em qualquer outra profissão de prática. Você sempre pode ter ídolos mas as chances de você se tornar um deles é perto de impossível. Todo mundo sabe disso. Então o que fazer? Simples, não faça propaganda de “você também pode ser o Bill Gates”, é mirar alto demais. Em vez disso desça vários níveis na cadeia, onde existe mais gente e que ainda assim é uma minoria. No caso os rock stars da programação já parece algo mais palpável, então bora fazer propagandas assim. “Você também pode ser um rock star de Silicon Valley.”</p>
<p>Quando eu digo no vídeo de 2014 que é só uma questão de “começar a praticar”, eu não tive tempo de dar toda essa explicação. E quando eu e qualquer outra pessoa fala que programar é fácil e um monte de gente que não tem vocação nem muito menos o interesse ouve isso continuamente, ele acha que o errado é ele. Assim como me faziam pensar que o errado era eu por não saber chutar uma bola. Felizmente desde cedo eu sabia ligar o “foda-se” e simplesmente ignorava 99% dos meninos que tiravam sarro porque eu nunca consegui chutar uma única bola na direção do gol. Eu simplesmente tinha outros interesses, que nos anos 80 basicamente ninguém tinha: programar.</p>
<p>Então a primeira coisa que eu preciso corrigir do meu video é: não é simplesmente dar o primeiro passo. Se tecnologia não prende sua atenção e concentração por horas ininterruptas, onde você simplesmente não vê o tempo passar, e onde se dedicar mil horas ou duas mil horas não é algo que pareça maçante pra você, então sim, só falta dar o primeiro passo e começar. Mas se pra você computação é igual futebol é pra mim, eu nem começaria.</p>
<p>E eu digo isso porque eu já vi um monte de gente começar e depois ficar frustrada e depois vem “eu segui o que o Akita disse, ou o que outro rock star disse, e eles mentiram pra mim, não é fácil assim”. E ele tem razão. A única discordância que vamos ter é que eu tomei cuidado pra minha carreira inteira eu nunca incentivei ninguém a virar programador. De propósito eu deixo de fora qualquer discurso mais otimista e incentivador. Eu simplesmente digo: eu gosto de tecnologia e eu gosto de falar sobre tecnologia e é isso que vou fazer. E ao mesmo tempo faço vários vídeos ilustrando que o mundo de tecnologia não é esse mar de rosas que muitos querem fazer você acreditar.</p>
<p>Um dos filmes que muitos palestrantes já usaram da forma errada é o clássico Ratatouille da Disney. Onde à primeira vista faz parecer que até um mísero rato é capaz de cozinhar melhor que um ser humano a ponto de mudar a opinião de um dos mais exigentes críticos gastronômicos da França. Mas ele é muito claro na mensagem: “nem todo mundo pode se tornar um grande chef, mas um grande chef pode vir de qualquer lugar”. Essa é a mensagem.</p>
<p>Significa que você não precisa ter nascido em São Francisco e estudado em Stanford pra ter chance de ser um grande programador. Você pode ter nascido numa cidadezinha do interior com 2 mil habitantes, estudado sozinho, e chegar no mesmo nível. Mas não é qualquer um. Da mesma forma como o filme é claro: de uma população gigantesca de ratos, apenas 1 demonstrou ter o que era necessário pra atingir isso. No nosso mundo é a mesma coisa. Bill Gates é celebrado até hoje, porque só existiu 1. Só existiu 1 Steve Jobs. Só existe um Jeff Bezos ou Jack Ma.</p>
<p>Você quer ganhar o sonhado salário de 6 dígitos em dólar por ano. Mas não está disposto a investir 2 mil, 4 mil ou, mais corretamente, 10 mil horas pra chegar lá. Sinto te dizer, é certeza absoluta que a menos que aconteça um evento de muita sorte, tipo ganhar na loteria, você não vai chegar.</p>
<p>E pior que isso, num período de hiper abundância que temos hoje. Se você acha que está difícil arranjar boas posições agora, sinto dizer que na próxima depressão vai ficar exponencialmente mais difícil. E enquanto isso você prefere defender que aprender inglês é ser anti-patriota ou qualquer bobagem assim, que é basicamente a desculpa de quem está com preguiça de aprender inglês ou simplesmente - assim como eu em esportes - simplesmente se entedia de tentar. É melhor assumir a realidade do que inventar histórias.</p>
<p>Em momentos de monopólios ou em momentos de depressão, toda frustração e reclamação é válida: é a realidade. Mas em momentos de abundância ver gente reclamando que ganha 5 dígitos em vez de 6, ou que não viaja vezes o suficiente por ano, ou que não consegue trocar de celular a cada 6 meses, é literalmente problema de primeiro mundo de uma geração que ainda não teve a experiência da primeira crise. Porque existem opções. Se elas não estão pulando pra próxima opção, não é falta de opção, é falta de vontade mesmo. Porque ficar no mesmo lugar e reclamando e se sentindo vítima da sociedade é sempre mais fácil do que assumir riscos. E sem assumir riscos, que tipo de resultados você acha que vai ter? Nenhum.</p>
<p>Já diria Einstein que um louco é aquele que fazendo sempre a mesma coisa, espera resultados diferentes. Eu acho que cursos, workshops, coaches e todo o aparato de intermediários que está surfando a onda da abundância está realmente realizando fraude. Eu desaprovo e me enoja ver gente praticando abusos e ativamente tentando enganar os outros. Por outro lado, muita gente simplesmente escolhe acreditar no ouro de tolo, porque se acha mais esperto, porque não quer recompensas com pouco ou nenhum esforço. E nesse caso, eu acho que os dois se merecem. Você quer ser enganado, é uma escolha, ninguém colocou uma arma na sua cabeça.</p>
<p>Pra finalizar, eu acho mó engraçado um monte de programador rock star com salarios de 6 dígitos reclamando de desigualdade. Por experiência aprendam, qualquer pessoa que fala a palavra igualdade só quer ganhar mais. Nada mais que isso e não tem nenhum problema em querer ganhar mais. Mas antes de falar bonito vale lembrar. Você trabalha numa startup que não tem lucro? Da onde acha que vem o dinheiro pra te pagar? Provavelmente de algum fundo de pensão, dinheiro de aposentadoria. Pois é. Eu entendo, todo mundo quer pegar uma fatia maior desse bolo, aproveitando que todo mundo acha que tecnologia ainda é mágica e solta dinheiro assim fácil.</p>
<p>O objetivo dos videos que eu faço é falar sobre o que eu gosto e ao mesmo tempo eu vou intercalando com alguns avisos: o mundo da programação é vasto, tem uma história muito rica que precisa ser respeitada, e possibilidades inexploradas que estão aí para quem tiver o conhecimento e a vontade de perseguí-las. Mas, não é pra todo mundo. Tenha isso em mente. E como eu disse, o episódio de hoje foi mais curto, semana que vem devo falar de algum outro assunto técnico da minha lista. Se ficaram com dúvidas, mande nos comentários abaixo. Se curtiram o vídeo mandem um joinha, não deixem de assinar o canal, clicar no sininho pra não perder os próximos episódios e compartilhar com seus amigos pra ajudar o canal. A gente se vê, até mais!</p>
]]></content:encoded><category>programacao</category><category>aprendizado</category><category>carreira</category><category>akitando</category></item><item><title>[Akitando] #45 - Gerenciamento de Memória (Parte 1) | Entendendo Back-end para Iniciantes (Parte 5)</title><link>https://akitaonrails.github.io/2019/03/27/akitando-45-gerenciamento-de-memoria-parte-1-entendendo-back-end-para-iniciantes-parte-5/</link><guid isPermaLink="true">https://akitaonrails.github.io/2019/03/27/akitando-45-gerenciamento-de-memoria-parte-1-entendendo-back-end-para-iniciantes-parte-5/</guid><pubDate>Wed, 27 Mar 2019 17:01:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/9AK_1gqEfkQ"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Eu disse no episódio anterior que não sabia se ia falar sobre Gerenciamento de Memória, mas acho que não dá pra terminar a série e não falar disso. Então hoje vamos escovar bits um pouco. Como a série é pra iniciantes, vale revisitar um pouco sobre representações binárias e hexadecimal e entender mais sobre como o computador e seus programas enxergam essa tal de &amp;ldquo;memória&amp;rdquo;.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/9AK_1gqEfkQ"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Eu disse no episódio anterior que não sabia se ia falar sobre Gerenciamento de Memória, mas acho que não dá pra terminar a série e não falar disso. Então hoje vamos escovar bits um pouco. Como a série é pra iniciantes, vale revisitar um pouco sobre representações binárias e hexadecimal e entender mais sobre como o computador e seus programas enxergam essa tal de &ldquo;memória&rdquo;.</p>
<p>Hoje quero explicar como os principais alocadores de memória do Linux funcionam e ensinar o que são os principais desafios que envolvem o gerenciamento de memória. Tudo isso vai ser importante pra semana que vem que vou explicar sobre garbage collectors.</p>
<p>Erratas:</p>
<ul>
<li>
<p>aos 11:39 min o áudio fica ruim por 1 minuto. Eu gravo o áudio num gravador externo e mantenho o áudio da câmera pra sincronizar. Mas meu gravador parou nesse minuto e fiquei só com o áudio da câmera, por isso que a qualidade cai, mas é só 1 minuto.</p>
</li>
<li>
<p>a 26:50 min aparece um typo &ldquo;Stacjk&rdquo; que na verdade é &ldquo;Stack&rdquo;</p>
</li>
</ul>
<p>Links</p>
<ul>
<li>The 640K memory limit of MS-DOS (<a href="https://www.xtof.info/blog/?p=985"target="_blank" rel="noopener">https://www.xtof.info/blog/?p=985</a>)</li>
<li>The difference between booting MBR and GPT with GRUB (<a href="https://www.anchor.com.au/blog/2012/10/the-difference-between-booting-mbr-and-gpt-with-grub/"target="_blank" rel="noopener">https://www.anchor.com.au/blog/2012/10/the-difference-between-booting-mbr-and-gpt-with-grub/</a>)</li>
<li>How Linux system boots up? (<a href="https://medium.com/@garimajdamani/how-linux-system-boots-up-f15c9e0f7a96"target="_blank" rel="noopener">https://medium.com/@garimajdamani/how-linux-system-boots-up-f15c9e0f7a96</a>)</li>
<li>Rebasing Win32 DLLs (<a href="http://www.drdobbs.com/rebasing-win32-dlls/184416272"target="_blank" rel="noopener">http://www.drdobbs.com/rebasing-win32-dlls/184416272</a>)</li>
<li>Commodore 64 memory map (<a href="http://www.awsm.de/mem64/"target="_blank" rel="noopener">http://www.awsm.de/mem64/</a>)</li>
<li>Physical Address Extension - PAE Memory and Windows (<a href="https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn613975%28v=vs.85%29"target="_blank" rel="noopener">https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn613975(v=vs.85)</a></li>
<li>A visual guide to Go Memory Allocator from scratch (Golang) (<a href="https://blog.learngoprogramming.com/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed"target="_blank" rel="noopener">https://blog.learngoprogramming.com/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed</a>)</li>
<li>Scalable memory allocation using jemalloc (<a href="https://www.facebook.com/notes/facebook-engineering/scalable-memory-allocation-using-jemalloc/480222803919"target="_blank" rel="noopener">https://www.facebook.com/notes/facebook-engineering/scalable-memory-allocation-using-jemalloc/480222803919</a>)</li>
<li>Understanding glibc malloc (<a href="https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/"target="_blank" rel="noopener">https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/</a>)</li>
</ul>
<p>Olá pessoal, Fabio Akita</p>
<p>Finalmente, estamos pertos de concluir o tema de Back-end dessa série Começando aos 40. Já estamos no décimo episódio pra falar sobre Gerenciamento de Memória. Mas diferente dos episódios passados que estavam dando quase 1 hora de duração, este eu resolvi quebrar em duas partes. Tá bem trabalho editar esse tanto de vídeo toda semana, e mesmo assim vai ser comprido hoje, então prestem atenção!</p>
<p>Durante os últimos episódios eu meio que dei uma introdução a coisas que vocês aprenderiam em  matérias como de sistemas operacionais numa faculdade de Ciências da Computação, então espero que aproveitem os tópicos que eu mencionei pra se aprofundar mais nos estudos desses temas.</p>
<p>Vou dizer que fiquei em dúvidas se deveria ou não me estender no tema de hoje, ele é ainda mais escovação de bits do que os temas anteriores. Mas eu sinto que é outro assunto que a grande maioria dos programadores, não só os iniciantes, até hoje não entendem direito. E o assunto é gerenciamento de memória. Todo mundo acha que porque suas linguagens costumam ter coisas como garbage collector, então é um assunto irrelevante. Mas isso não é verdade. Um programador amador realmente não vai prestar atenção nisso e em várias outras coisas, mas se você realmente tem a intenção de ser um verdadeiro profissional então sim, você precisa dominar esse assunto.</p>
<p>(&hellip;)</p>
<p>Recapitulando, eu já expliquei várias vezes como seu código fonte compila num binário e esse binário é carregado em memória. Também já rapidamente expliquei como CPUs e sistemas operacionais modernos alocam espaços de memória isolados pra cada processo, com endereços virtuais de tal forma que um processo não tem como acessar a memória de outro processo. Como eu já disse antes, se você realmente pretende levar a sério a profissão, precisa entender como seu computador realmente funciona.</p>
<p>Uma coisa que eu nunca mencionei por exemplo é o processo de boot em si, que é bem fascinante. Em hiper resumo, tem diversas etapas, do momento que você aperta o botão de ligar, segue o processo de Power on self test ou POST que você vai ouvir falar bastante se acompanha canais de montar seu computador, tem o teste de memória e outros dispositivos, até chegar no Master Boot Record que é o antigo MBR ou o atual GUID Partition Table ou GPT pra carregar o boot loader, que no caso do Linux seria um GRUB2 por exemplo, e finalmente carregar o binário do Kernel propriamente dito que, por sua vez, vai carregar um systemd, que por sua vez finalmente vai carregar todos os daemons pra terminar de tornar disponível os recursos da máquina pros programas, como montar suas partições do disco.  Se você está estudando Linux, veja os links que deixei na descrição abaixo que detalham esse processo em mais detalhes.</p>
<p>Eu estava pensando em quanto de detalhes quero mostrar hoje, mas se eu for realmente minucioso o episódio vai ficar com horas e horas de duração e vai ser extremamente tedioso. Em vez disso vou delinear os pontos principais e explicar resumidamente, você precisa pesquisar mais detalhes depois nos seus estudos.</p>
<p>Em termos de memória, entenda que você tem os pentes de RAM, o que você normalmente vê como pente de 16GB DDR4, DDR que significa Double Data Rate. De curiosidade eu já falei rapidamente antes que tudo no computador funciona segundo o clock da CPU. Sabe quando a gente fala em CPU de 4 Ghz? Sendo hertz um ciclo, 4 Ghz significa 4 bilhões de ciclos por segundo, pense em clock literalmente como um ciclo ou uma ida e volta de um pendulo, uma frequencia. Double Data Rate significa que é possível puxar dados da memória no topo do ciclo e na parte de baixo do ciclo, em vez de só conseguir puxar dados uma vez por ciclo como era antigamente, então ele tem a chance de puxar duas vezes, por isso é mais rápido, mas hoje em dia a gente só usa DDR de qualquer forma.  Uma diferença pra memórias de servidor são as memórias ECC que significa Error Correcting Code. É uma memória bem mais cara mas que garante que a memória nunca vai ser corrompida, pentes de RAM normais como as que usamos tem chances de devolver 1 bit errado de tempos em tempos, mas é raro, memória ECC de servidor tem uma proteção extra e menos chances.</p>
<p>O que o seu simples programa vê não é só RAM, é mais um “espaço de memória”, a CPU vai cuidar do que vai aonde. Você tem caches L1, L2 e L3 que são memórias pequenas e hiper rápidas que ficam no mesmo chip, pra fora dele você tem um barramento, que vai conectar com dispositivos como os pentes de RAM e com seu HD mecânico ou SSD que também pode servir de memória se conter um arquivo de SWAP. Se você não sabia disso memória é dividida normalmente entre acesso rápido e devagar. L1, L2 e L3 são memórias ultra rápidas. Quanto mais rápido mais caro, lógico, por isso eles são muito pequenos da ordem de até 64 quilobytes de L1, até meio megabyte de L2 e até 8 megabytes de L3. Eles não são memórias pra você usar, o CPU vai usar principalmente como cache pra manter seus pipelines cheios. Depois disso vem a RAM propriamente dita, seus pentes de DDR4, ordens de grandeza mais lentos que os caches, mas de uso geral. E depois vem coisas como o SWAP do seu SSD que é ordens de grandeza mais lento que a RAM.</p>
<p>Eu gostaria muito de explicar em detalhes o que são portas lógicas, como se chega num flip-flop, e como flip-flops podem ser usados pra armazenar bits. Pra ter um modelo na cabeça, pense em memória como um livro, com um espaço reservado pra um índice, e cada linha apontando pra uma página desse livro. Essas linhas são as linhas de endereço. Vamos entender essas linhas de endereço e como elas são organizadas.</p>
<p>Quando falamos que uma CPU é de 64-bits significa que os tais registradores da CPU acomodam números de até 64-bits de tamanho, e além disso temos barramentos, ou seja as rodovias de comunicação entre a CPU e a memória e dispositivos de I/O que também tem um tamanho máximo. 64-bits significa que a CPU consegue lidar com words ou palavras de 64-bits inteiros, que equivale a 2 elevado a 64 que seria o absurdo número de 16 Exabytes.  Pense assim, você tem bytes, quilobytes, megabytes, gigabytes, terabytes, petabytes e exabytes. 16 Exabytes é este numerazão aqui embaixo se for em bytes (18.446.744.073.709.551.616).</p>
<p>Agora, esse numerozão está representado no sistema decimal, que é o que estamos mais acostumados a lidar, mas quando falamos em computador, ele representa tudo em 1 ou 0. Vamos escovar bits um pouco. O número 1 é só 1, o número 2 é 1-0. O número 11 é 1-0-1-1. Pense em binário como a tabuada do 2, o número mais pra direita é 1, o segundo da direita pra esquerda é 2, na sequência vem 4 e depois 8 então 1011 é 8 + 0 + 2 + 1 que é 11, entenderam? Portanto o menor número de 64 bits é basicamente 64 zeros em sequência e o maior número seria 64 1s em sequência.</p>
<p>Obviamente ficar representando tudo em binário no papel é muito longo. Como lidamos com bytes que são conjuntos de 8 bits, é mais fácil lidar com uma representação que é múltipla de 8 ou, melhor ainda, múltipla de 16, que é o que chamamos de hexadecimal. É um sistema que em vez do nosso decimal que vai só até 10 ele vai até 16, mas como números arábicos só tem caracteres de 0 a 9, precisamos usar as letras do alfabeto de A até F pra ir até 16. O mesmo número máximo de 64 bits que eu falei que é 64 vezes o caracter “1”, em hexa seria quatro grupos de quatro Fs.</p>
<p>Tão vendo? Aquele numerozão horroroso em decimal que você jamais vai decorar é muito mais simples em hexadecimal e você consegue literalmente saber de cabeça que vai de 0 até 16 Fs. É muito mais curto. E em binário você tem propriedades matemáticas interessantes, por exemplo, multiplicar um número binário por 2, é simplesmente um shift left, tipo mover tudo uma casa pra esquerda e colocar um zero. Por exemplo o número 11 que eu falei que é 1-0-1-1 vira 1-0-1-1-0 que é 16 + 0 + 4 + 2 + 0 que é 22. Algumas coisas ficam mais simples de calcular.</p>
<p>Você precisa entender que usamos o sistema decimal que vai de 1 até 10 por motivos históricos. Vale pesquisar a história da matemática, você vai encontrar outros sistemas. Um exemplo, se você usar o relógio como parâmetro, é mais fácil contar de 1 até 60. Computadores são 1 ou 0 porque é o sistema mecânico mais simples, pense o interruptor de luz da sua casa, em todo instante ele armazena uma de duas informações: ligado ou desligado. 10 interruptores guardam 10 bits de informação. E os computadores mais rudimentares do passado usavam lâmpadas a vácuo, como o que ilumina seu quarto neste instante. Luz ligada ou desligada. Coloque 10 lâmpadas e você pode visualizar 10 bits de informação.</p>
<p>Continue estudando mais sobre representação binária e hexadecimal, é importante você ter essas ordens de grandeza na cabeça de forma natural, mesmo que seu trabalho não seja fazer aritmética direto nesses sistemas. De qualquer forma, estávamos falando sobre computadores 64-bits. Este número abaixo (16 Fs) é o maior número inteiro que é possível armazenar em uma palavra de 64-bits e voltando às linhas do índice do nosso livro, significa que cada linha de endereço pode apontar números só até esse tamanho e, por consequência, esse tamanhão máximo de RAM ou páginas do nosso livro. Só que isso é teórico.</p>
<p>Nenhuma máquina que eu saiba tem capacidade pra realmente comportar esse tanto de memória real. Um dos motivos é porque embora o processador tenha registradores de 64-bits, o barramento entre a CPU e a memória em processadores Intel, se não me engano, é de 42-bits, e na AMD é de 48-bits, portanto o máximo endereçável é 2 elevado a 48 que seria 256 Terabytes. 2-bits fazem muita diferença, porque é o quadrado do quadrado, então na Intel você conseguiria endereçar no máximo 4 Terabytes.</p>
<p>Isso é ordens de grandeza maior do que em computadores 32-bits da geração passada. E não, 64 não é o dobro de 32-bits, é o quadrado. Lembrando que 32-bits significa 2 elevado a 32, que limita o endereçamento a no máximo 4GB de RAM. Se você tinha computador nos anos 2000 vai lembrar que não dava pra colocar mais que isso de RAM. Se você chegou a ter acesso a servidores com Windows Server 2003 Service Pack 2 Datacenter Edition dava pra ter até 64 GB.</p>
<p>Isso porque havia um truque da Intel em processadores 32-bits chamado PAE ou Physical Address Extension, e dependendo da configuração de hardware e sistema operacional, dava pra ir acho que até um máximo de 128 Gigas mesmo num computador 32-bits. Na prática, os processos num sistema desses continuavam só enxergando 4GB mas era possível ter mais processos ativos porque com PAE você podia swapar alguns processos pra essas áreas extendidas de memória e evitar usar swap de disco por exemplo.</p>
<p>Tudo isso dito, vamos tentar explicar mais sobre como o sistema operacional enxerga essa memória. Até agora sabemos que a memória é como um livro, com linhas de endereço no índice, cada endereço representando uma página do livro, com o endereço máximo dependendo se o computador tem barramento de 48-bits, 42-bits, 36-bits, ou 32-bits e assim por diante. O sistema operacional pode ler e escrever em qualquer endereço de memória. Num sistema operacional muito simples, tipo um Basic num Commodore 64, dava pra acessar diretamente esses endereços pra escrever ou ler. Na verdade existe um porém, você poderia achar que seu programa tem acesso a tudo do endereço 0000 até o endereço FFFF por exemplo, num computador de 16-bits. Mas quando você boota um Commodore, apesar dele poder endereçar 64KB, porque tinha barramento de 16-bits, você vai ver que ele diz que só tem 38.911 bytes livres. Isso porque como em qualquer máquina, nem todos os endereços estão livres pro usuário.</p>
<p>Um pedaço dos endereços é reservado pra kernel, outro pedaço são funcionalidades como endereços de I/O, outro pedaço no caso do Commodore é o próprio interpretador Basic, e o que sobra é onde você pode carregar seus programas. O programa Basic só pode carregar a partir do endereço $0801 até o $A000, se você fizer a conta, A000 é o decimal 40,960 e 0801 é o decimal 2049. Então 40,960 menos 2049 são os 38911 bytes que o sistema declara como disponível.</p>
<p>Isso era na época em que tudo usava endereços reais, até o fim dos anos 80, antes dos processadores Intel 80286. Os computadores modernos a partir dos anos 90 tem o tal modo protegido e memória virtual. Quando o sistema operacional carrega seu programa ele dá pra ele um índice virtual, que vai do endereço virtual 0000 0000 até o FFFF FFFF. Só que o endereço virtual 0000 0000 desse processo, na memória real pode ser um endereço nada a ver, faz de conta, DCBA 9876, mas seu processo não tem idéia disso, só o sistema operacional sabe mapear entre os dois.</p>
<p>Daí você carrega outro programa, ele também ganha outro índice virtual que vai de 0000 0000 até FFFF FFFF só que o 0000 0000 desse programa mapeia pro endereço real BA98 7654 por exemplo. Ambos os programas enxergam o 0000 0000 mas cada um aponta pra um lugar diferente. E por isso os dois programas são ditos isolados, porque não importa que endereço eles tentem apontar, nunca vai ser em cima do endereço do outro processo porque o sistema operacional garante que um endereço real usado não é apontado por mais do que um índice virtual.</p>
<p>A grande vantagem disso é que você pode ter 10 programas, cada um “enxergando” 4 GB de memória inteiro só pra ele, ou seja endereços virtuais de 0000 0000 a FFFF FFFF mas seu computador real pode ter bem menos memória que isso. Na prática a maioria dos programas não vai usar toda a memória disponível, então o sistema operacional compartilha a memória real entre os diversos programas até acabar a memória real. Então seu processo tem só a ilusão de que tem toda essa memória. E o que acontece quando acaba 100% da memória real do sistema, ou seja, toda a RAM e todo o swap no HD? Antigamente seu computador ou ia ficar lento ao ponto de ser inusável, ou programas iam começar a crashear por falta de memória, ou alguma combinação disso.</p>
<p>Num sistema operacional de smartphones você já sabe o que acontece. Num iPhone ou qualquer Android moderno, você vai abrindo programas e não precisa fechar. Quando acaba a memória, os programas menos usados ou os abertos à mais tempo e sem uso, fecham sozinhos, dando espaço pra abrir mais programas. Num Android, que é um derivado de Linux, e mesmo iOS que é derivado de BSD UNIX, existe o OOM Killer ou Out of Memory Killer. Todo Linux tem isso, e é isso que evita que seu celular fique sem memória. É por isso que falamos que em celulares modernos você não precisa ficar fechando manualmente os programas, o OOM Killer vai fazer isso por você.</p>
<p>Voltando aos seus processos, o sistema operacional começa dando zero bytes de memória real pro seu processo. À medida que o processo vai pedindo memória, ele vai alocando memória real, sob-demanda, e mapeando os endereços reais pra endereços virtuais que o processo enxerga. E quando o processo vai devolvendo memória ou quando você fecha o programa, esses endereços reais voltam a ficar disponíveis pra outros processos poderem usar.  Se você simplesmente abre programas de Linux como ps, top ou htop ou o Task Manager no Windows, vai quanto cada programa está alocando. Pra simplificar digamos que você tem 2 programas, cada programa você vê ocupando 1.5 GB. Ou seja, cabe tudo em 3 GB de RAM. Daí na sua cabeça você acha que porque tem 4 GB de RAM, tem memória de sobra, certo? Errado. Um desses programas pode estar muito perto de crashear.</p>
<p>Pra simplificar, vamos considerar ainda um computador de 32-bits nesse exemplo. Eu disse que seu programa enxerga do endereço virtual 0000 0000 até FFFF FFFF. Mas ele Não vai poder usar tudo isso. Num Windows 32-bits de mais de 10 anos atrás, você começa tendo só 2 GB disponível, do começo até a metade, ou seja de 0000 0000 até 7FFF FFFF. Daí pra cima é reservado ao sistema operacional. Lembra como eu falei no Commodore 64 que partes dos endereços são reservados pro Kernel, Basic, I/O e outras coisas? Mesmo coisa em sistemas operacionais modernos. Mesmo num Linux, ele vai reservar de 512MB a 1 GB de endereços. Num Windows Server você podia bootar com um flag especial e compilar os programas com a flag /largeaddressspace pra permitir usar um pouco mais além da metade dos endereços. Não quer dizer que o Windows está realmente usando 2 GB, mas sim que os endereços estão reservados pra ele usar.</p>
<p>Ou seja, num computador 32-bits, apesar de poder mapear até 4GB e mesmo se você tivesse 4GB reais de RAM, nenhum processo seu iria conseguir usar mais que 2GB. Hoje em dia você tem problemas de memória em computadores 64-bits? Imagina quando a gente tinha que programar servidores em 32-bits. Pior ainda, imagina como era na época dos 16-bits. Saber usar memória é até hoje o que diferencia um amador de um profissional de verdade. Pra dar um exemplo, lembram do episódio que eu falei de SAP? Nessa época, acho que era 2003, eles tinham um servidor de aplicações Java, o In-Q-My, ainda em beta, pra carregar aplicações J2EE pesadas como o Enterprise Portals. No boot do Java com os programas SAP por cima, ele carregava tranquilamente um giga e meio.</p>
<p>Se você fosse amador, pensaria, “ah, sussa, máquinas 32-bits carregam até 4GB então tem sobrando”. Se você fosse intermediário pensaria “puta que pariu, só mais 500 Mb e vai bater no limite de 2 GB”. Porém, eu não conseguia fazer esse servidor subir, ele crasheava por falta de memória. Mas eu descobri porque. Lembram que eu falei que o sistema operacional usa parte da memória do processo? Seus programas reusam muitas bibliotecas que o sistema operacional compartilha com os processos, então você tem endereços virtuais que mapeiam pros endereços reais dessas bibliotecas do sistema, incluindo muitas DLLs que todos os processos usam como a LibC da Microsoft ou o Foundation Classes. Pra você entender, o sistema não está duplicando essas bibliotecas em todos os processos, mas os endereços virtuais dos processoa mapeiam pras mesmas bibliotecas. Os processos são isolados, então pra eles enxergarem alguma coisa de fora, os endereços virtuais precisam mapear pra esses recursos compartilhados.</p>
<p>Ainda pensando de forma ingênua, você imaginaria que essa bibliotecas carregam bonitinhas sequencialmente uma atrás da outra, sem desperdiçar nenhum endereço. Lógico que não, não necessariamente. E de fato, algumas dessas bibliotecas apareciam com endereços na primeira metade dos endereços virtuais do processo, ou seja, em cima dos 2 GB reservado pro seu programa. Isso se chama fragmentação de memória. A JVM precisava alocar memória contígua no boot, ou seja com endereços sequenciais, sem buracos no meio. Aliás, alocação de memória sempre aloca pedaços inteiros, sequenciais. Como a memória estava fragmentada, não havia um trecho sequencial limpo de 1.5 GB. E agora?</p>
<p>Felizmente, no Windows você tem como fazer rebase das DLLs, pense mais ou menos, como defragmentar a memória. Exatamente isso, você pode mudar o endereço de carregamento dessas DLLs. Como são bibliotecas dinâmicas, o binário não mapeia um endereço fixo, então você pode mudar elas de lugar. E foi assim que eu consegui subir os programas Java que eu precisava. Quem já trabalhou com servidores 32-bits e programas realmente pesados de Java, com certeza esbarrou com isso, é um problema sabido desde o ano 2000 pelo menos. E pense que em 2003 o site StackOverflow ainda não existia.</p>
<p>Aceite este fato: a memória total do seu sistema não está à disposição do seu processo. Felizmente em máquinas 64-bits de hoje, você tem muito mais que 2 GB de endereços virtuais disponíveis, então pelo menos esse problema já não afeta mais. Tanto que mesmo na época uma das soluções que a SAP falava era: migre pra máquinas 64-bits. Espero que em 2019 ninguém mais esteja usando máquinas 32-bits. O segundo fato que você precisa aceitar: memória fragmenta. A razão é simples. Digamos que sua memória total seja de 10 kb, dividida em chunks ou pedaços de 1 kb. Você começa alocando 3 variáveis de 1 kb cada. Digamos que o alocador aloque os primeiros 3 chunks. Agora digamos que você resolva liberar a segunda variável. Você ficou com 1 kb ocupado, 1 kb livre, e o terceiro kb ocupado.</p>
<p>Agora seu programa resolve que precisa de uma variável de 2 kb. Como o espaço vago do meio não cabe os 2 kb, e repetindo, grave essa regra: o alocador sempre precisa alocar pedaços contíguos, com endereços sequenciais. Então ele só vai ter espaço depois do terceiro chunk. Agora você ficou com um espaço fragmentado. Pense numa escala maior, com milhares de alocacões e desalocações, sua memória vai ficando com buracos no meio do caminho e toda vez que você precisa alocar mais memória do que cabe nesses buracos ele precisa ir lá pra frente. Então um programa que internamente ele enxerga que está alocando só 4 KB na verdade está potencialmente bloqueando 5 KB nesse momento. Fragmentação é uma das coisas que alocador de memória quer evitar.</p>
<p>Quem faz esse trabalho é o alocador de memória. No caso do Linux, mais especificamente da biblioteca glibc, você tem o famoso “malloc”. Eu expliquei nos episódios anteriores que no Linux você pode escolher entre diferentes schedulers de threads como o CFS que hoje é o padrão ou outros como o BFS dependendo de pra que vai usar a máquina. Alocador de memória também, você pode escolher.</p>
<p>O malloc do glibc na verdade é o ptmalloc2 que por sua vez é baseado no dlmalloc, DL porque quem criou essa versão foi o professor Doug Lea. Um alocador de memória é um conjunto de algoritmos e estruturas para manter metadados dessa memória. Um alocador moderno tem vários de problemas importantes pra resolver. Primeiro de tudo, alocar memória precisa ser rápido, estamos falando de frações de milissegundos, ou seja, nanossegundos, porque é uma operação que acontece o tempo todo. Um ptmalloc2 leva uns 300 nanossegundos por operação. Mas não adianta ser rápido se ele “vaza” memória ou seja, usa mais memória do que o necessário, em parte porque não foi inteligente e deixou a memória fragmentar demais. Existem várias syscalls mas em C você normalmente chama pelas funções malloc, passando um tamanho que precisa alocar, e a função free que sinaliza ao sistema operacional que esse endereço pode ser liberado quando puder.</p>
<p>Quando você chama a função malloc, o único parâmetro que passa é quanto de memória quer alocar, e ele devolve como retorno o endereço que ele achou onde cabe um pedaço de dados do tamanho que você pediu. Se você tiver pouca RAM e vários processos fragmentando memória, você vai notar que teoricamente era pra caber mais programas na RAM mas por alguma razão falta memória. Um programa mal escrito pode estar alocando mais memória do que deveria, e não devolvendo. E mesmo devolvendo o sistema ainda pode não ter colocado essa memória à disposição.</p>
<p>Pra piorar, eu já expliquei sobre concorrência e paralelismo e todos os problemas que você enfrenta ao lidar com threads reais, lembra? Existe um outro problema: e se várias threads pedem ao alocador pra reservar memória ao mesmo tempo? Acabamos de criar uma contenção, ou seja, um gargalo. Se o alocador não suportar threads corretamente, o que acontece é um lock do alocador e cada thread tendo que esperar o anterior receber seu pedaço de memória. Na verdade o tal ptmalloc que eu falei é um fork do antigo dlmalloc justamente pra suportar threads.</p>
<p>Só de entender o problema de fragmentação e agora o problema de threads, você deveria começar a entender que fazer uma chamada em malloc não é um troço simples. Pra começar a forma de suportar threads é dividir o índice de endereços disponíveis no que o malloc chama de Arenas. Num Linux 32-bits o padrão é 2 vezes o número de cores. Então num computador quad-core com hyper threading você pode ter até 8 threads e por isso até 16 arenas. De forma simplista se todas as threads pudessem ter qualquer endereço do espaço de 32-bits, o alocador ia precisar criar um lock global e as threads perderiam totalmente sua performance e ficaram mais tempo em fila esperando o alocador do que realmente trabalhando em paralelo. Mas se você tem 4 cores e disser que do endereço 0000 0000 a 3FFF FFFF é da thread 1, do endereço 4000 0000 até 7FFF FFFF é da thread 2 e assim por diante, agora elas não compartilham endereços e você não precisa de um lock. Lembra que eu dei a dica já que a forma de você não ter que lidar com mutexes e locks em concorrência é não compartilhar nada entre as threads?</p>
<p>Agora as Arenas ainda são sub-divididas em Heaps ou montes. Seu programa quando executa pode armazenar dados na stack ou pilha ou no heap. A pilha é literalmente a pilha de execução, seu programa carrega as instruções na stack e pequenas quantidades de dados cabem no stack, se usar demais ou de forma errada vai ter o famoso Stack overflow. Se a memória fosse uma página de papel, pense na stack crescendo de cima pra baixo e o Heap começando de baixo pra cima. Não é exato mas é uma forma de visualizar. Na prática seu programa vai armazenar a maior parte dos dados que precisa pra trabalhar no Heap e na stack podem ficar coisas como valores constantes ou coisas assim.</p>
<p>Uma heap é ainda sub-dividido em múltiplos chunks. Podemos ter chunks muito pequenos de até 80 bytes, chunks de até 512 bytes e chunks grandes de mais de 512 bytes, que é como o ptmalloc organiza. Podemos agrupar os chunks menores em caixas ou bins, no caso os de até 80 bytes no que se chama Fast Bin, os de até 512 bytes num Small bin e os maiores que 512 bytes num Large bin. Por que isso? Pra minimizar fragmentação. Você fragmenta a memória mais rápido se tentar misturar pedaços grandes no meio de pedaços pequenos. É melhor agrupar pedaços de tamanhos similares mais próximos, porque se você desaloca um chunk de 16 bytes no Fast Bin, quando precisar alocar 16 bytes de novo, é mais fácil procurar direto no Fast bin. E se tentar alocar alguma coisa de 1 MB é melhor ir no Large Bin. E no começo você aloca poucos bins, e vai alocando mais à medida que precisar.</p>
<p>Lembre que toda essa organização ainda não está na prática “usando” a memória ainda. Está só criando estruturas que representam caixas de endereços. Daí a alocador vai pegar desses bins, dependendo de que thread está pedindo e que tamanho de memória pediu. Se você tem boa intuição está entendendo que seu processo sempre vai usar um pouco mais de memória do que ele realmente precisa por causa dessa organização e estruturas de suporte que o alocador precisa. Quanto mais tempo um processo fica vivo trabalhando, mais essas atividades de alocar e desalocar memória podem is expandindo, crescendo o heap e causando leaks se o programa for mal escrito, causando fragmentação demais.</p>
<p>Mas o pior não é isso, eu disse que Arenas são divisões para evitar contenção de lock de threads. E se sua aplicação inicialmente carregar 300 MB de estruturas na primeira arena. Mas agora numa segunda fase outra thread precisa trabalhar essas estruturas mas ela vai usar outra arena? Os 300 Mb vão ser copiados de uma arena pra outra porque o ptmalloc não suporta mover memória entre arenas. De repente seu programa inicia usando o dobro do que ele realmente precisa. Esse é um problema real relatado por engenheiros do Google e por causa disso eles criaram um outro alocador de memória, chamado de tcmalloc, que justamente permite cachear dados entre threads e por isso se chama Thread-Caching malloc ou tcmalloc.</p>
<p>Se algum dia esbarrar num tutorial que fala de tcmalloc, lembre que ele é do Google. Ele é mais rápido que o ptmalloc2 do glibc, chegando a ser até 6 vezes mais rápido e usando estruturas de dados mais eficientes, então também usando bem menos memória no geral. E como o tcmalloc implementa as mesmas funções POSIX como o malloc(), free(), calloc(), realloc() e outros. O Google mesmo diz que ele não é necessariamente 100% compatível e alguns programas podem ter problemas, mas na grande maioria, você consegue carregar o tcmalloc e seus programas devem funcionar mais rápido, usando menos memória e, se for um programa que fica de pé por dias seguidos como um servidor de aplicação, ele também deve tender a alocar menos memória no geral.</p>
<p>Tcmalloc foi criado mais de 10 anos atrás, e na mesma época, com o Firefox 3 o alocador de memória do Windows da época fragmentava demais, ou seja, o navegador tendia a crescer no uso de memória como eu já expliquei que acontece, numa ordem de pelo menos 20% ou mais de desperdício. Se o processo usar 1 GB ele vai desperdiçar 200 Mb só em fragmentação. Nessa época um engenheiro chamado Jason Evans queria resolver o problema de gerenciamento de memória de uma linguagem experimental que ele estava criando e pra isso fez um novo alocador. Esse alocador passou a ser usado no Firefox e foi um dos motivos de porque Firefox no Windows conseguia desperdiçar menos memória. Com o tempo esse alocador foi adotado pelo Facebook porque seus servidores também estavam desperdiçando muita memória. Esse alocador foi devidamente nomeado de jemalloc por causa de Jason Evans. Com o tempo o jemalloc se tornou mais rápido, mais robusto e confiável e desperdiçando ainda menos memória que o tcmalloc do Google. Inclusive acho que ele é mais compatível com o ptmalloc2 e você poderia trocar o alocador do seu Linux por jemalloc e tudo vai funcionar melhor.</p>
<p>De curiosidade, a linguagem Rust, assim como o Firefox, são da mesma fundação Mozilla e por isso o Rust desde o começo sempre usou o jemalloc, que é um dos motivos de porque ele é eficiente com memória. A grande maioria das outras linguagens ainda usam o ptmalloc2 do glibc. Linguagens como Python, Ruby também se beneficiam se você fizer o interpretador usar o jemalloc. Vou deixar nas descrições abaixo como fazer isso no Ruby.</p>
<p>Agora, isso vale pra linguagens que ativamente usam o alocador do sistema operacional. C, ou C++, ou Rust que já falei, todos que compilam pra binários nativos vão usar o ptmalloc2 ou o jemalloc hoje em dia. Pra variar, o Go não usa nenhum que já existia. Um ptmalloc2 usa funções de mais baixo nível ainda do sistema operacional como mmap, madvise, munmap, sbrk. O Go reinventa a roda e implementa seu próprio alocador meio inspirado, claro, no tcmalloc do Google. O Go também divide a memória em várias arenas. Esse conjunto de arenas é o que ele chama de Heap. Ele organiza as arenas em páginas de 8kb. Ele também divide esses blocos em bins pra tamanhos diferentes de chunks mas no caso do Go os nomes são diferentes ele tem um Tiny pra objetos menores que 16 bytes, um Small pra objetos menores que 32 kb e um Large pra coisa maiores que 32 kbytes. Esse valores dependem da versão do Go, então não decorem isso, só lembrem que o alocador agrupa blocos de tamanhos similares, como o ptmalloc2 já fazia também. E que é uma das estratégias pra diminuir a fragmentação.</p>
<p>Escovamos bits demais por hoje, vou ter que dividir esse episódio em duas partes de novo. Neste episódio tivemos mais noção de como o sistema operacional realmente organiza a memória, as diferenças de arquiteturas 32-bits ou 64-bits, e os diferentes tipos de alocadores. E como um bônus de termos já discutido sobre threads nos últimos episódios, vimos agora como eles afetam o gerenciamento de memória também. Na semana que vem vamos falar sobre os famosos garbage collectors, que muita gente ainda acha que é mágica, mas na prática não tem idéia de como funcionam.</p>
]]></content:encoded><category>performance</category><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #41 - Entendendo Back-End para Iniciantes em Programação (Parte 2) | Série "Começando aos 40"</title><link>https://akitaonrails.github.io/2019/02/27/akitando-41-entendendo-back-end-para-iniciantes-em-programacao-parte-2-serie-comecando-aos-40/</link><guid isPermaLink="true">https://akitaonrails.github.io/2019/02/27/akitando-41-entendendo-back-end-para-iniciantes-em-programacao-parte-2-serie-comecando-aos-40/</guid><pubDate>Wed, 27 Feb 2019 17:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/N6vgZr1k03g"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Esta é a Parte 2 do tema de Back-end para Iniciantes. Desta vez vamos olhar com mais cuidado sobre gerenciamento de dependências, o que diabos são dependências, e linguagens como Groovy, Scala, Elixir, Go e um pouco de Ruby e Ruby on Rails também.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/N6vgZr1k03g"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esta é a Parte 2 do tema de Back-end para Iniciantes. Desta vez vamos olhar com mais cuidado sobre gerenciamento de dependências, o que diabos são dependências, e linguagens como Groovy, Scala, Elixir, Go e um pouco de Ruby e Ruby on Rails também.</p>
<p>Provavelmente este vai ser o episódio mais difícil deste canal até agora, se você é iniciante, e você vai precisar ver e rever várias vezes, mas se você está levando a sério se tornar um programador, o que vou dizer hoje é de extrema importância pra você entender e estudar bastante.</p>
<p>Além de tudo este é o episódio mais longo deste canal até hoje. Nesta mini-série de &ldquo;Começando aos 40&rdquo; eu estou resumindo e dando o contexto geral do que você aprenderia (ou não) em meses de faculdade e trabalhando na prática. Aproveitem pra entender a idéia geral e puxar todos os assuntos para estudar em mais detalhes sozinho. Mandem suas dúvidas nos comentários também! E não deixem de compartilhar com seus amigos.</p>
<p>Akitando:</p>
<ul>
<li>Playlist de Programação (<a href="https://www.youtube.com/watch?v=WObC_2e0kZk&amp;list=PLdsnXVqbHDUcrE56CH8sXaPF3TTqoBP2z"target="_blank" rel="noopener">https://www.youtube.com/watch?v=WObC_2e0kZk&list=PLdsnXVqbHDUcrE56CH8sXaPF3TTqoBP2z</a>)</li>
<li>Playlist Começando aos 40 (<a href="https://www.youtube.com/watch?v=O76ZfAIEukE&amp;list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki"target="_blank" rel="noopener">https://www.youtube.com/watch?v=O76ZfAIEukE&list=PLdsnXVqbHDUc7htGFobbZoNen3r_wm3ki</a>)</li>
<li>Sua Linguagem NÃO é Especial - Parte 1 (<a href="https://www.youtube.com/watch?v=p9-WuJbVHHc"target="_blank" rel="noopener">https://www.youtube.com/watch?v=p9-WuJbVHHc</a>)</li>
<li>Sua Linguagem NÃO é Especial - Parte 2 (<a href="https://www.youtube.com/watch?v=XcTTajFENHI"target="_blank" rel="noopener">https://www.youtube.com/watch?v=XcTTajFENHI</a>)</li>
</ul>
<p>Links:</p>
<ul>
<li>So, What&rsquo;s wrong with SBT? (<a href="http://www.lihaoyi.com/post/SowhatswrongwithSBT.html"target="_blank" rel="noopener">http://www.lihaoyi.com/post/SowhatswrongwithSBT.html</a>)</li>
<li>Reia (<a href="http://reia-lang.org/"target="_blank" rel="noopener">http://reia-lang.org/</a>)</li>
<li>Go is not Good (<a href="https://github.com/ksimka/go-is-not-good"target="_blank" rel="noopener">https://github.com/ksimka/go-is-not-good</a>)</li>
<li>Why Go is a Poorly Designed Language (<a href="https://medium.com/@tucnak/why-go-is-a-poorly-designed-language-1cc04e5daf2"target="_blank" rel="noopener">https://medium.com/@tucnak/why-go-is-a-poorly-designed-language-1cc04e5daf2</a>)</li>
<li>Why Go is not Good (<a href="http://yager.io/programming/go.html"target="_blank" rel="noopener">http://yager.io/programming/go.html</a>)</li>
</ul>
<p>Me sigam também em outras redes sociais:</p>
<ul>
<li>Twitter (<a href="https://twitter.com/akitaonrails"target="_blank" rel="noopener">https://twitter.com/akitaonrails</a>)</li>
<li>Instagram (<a href="https://instagram.com/akitaonrails"target="_blank" rel="noopener">https://instagram.com/akitaonrails</a>)</li>
<li>Facebook (<a href="https://facebook.com/akitaonrails"target="_blank" rel="noopener">https://facebook.com/akitaonrails</a>)</li>
<li>Quora (<a href="https://www.quora.com/profile/Fabio-Akita"target="_blank" rel="noopener">https://www.quora.com/profile/Fabio-Akita</a>)</li>
<li>Blog (<a href="https://www.akitaonrails.com"target="_blank" rel="noopener">https://www.akitaonrails.com</a>)</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Este já é sexto episódio da série Começando aos 40. O ideal é que vocês assistam todos os outros vídeos da série, e se possível os da playlist de programação que tem a rápida história das linguagens nos vídeos de Sua Linguagem Não é Especial. Eu vou deixar linkado nas descrições abaixo. Continuo bem contente com a repercussão dos últimos vídeos, parece que vocês estão gostando do formato então vou continuar assim até o fim desta série. Hoje por acaso estou sentindo minha garganta dando pra trás, é possível que minha voz comece a falhar até o fim do vídeo, mas vamos lá.</p>
<p>No episódio da semana passada eu expliquei os conceitos mais básicos da computação, sobre instruções de máquina, compilação, interpretadores, como os binários se linkam com suas dependências, lembra? Linkagem estática e dinâmica? Começamos a falar um pouco sobre Java e .NET e máquinas virtuais como JVM. Agora com os conceitos entendidos vamos entender porque eu disse que era importante entender tudo isso antes do que vou falar hoje.</p>
<p>Uma das coisas mais importantes pra um programador iniciante entender é que você nunca vai fazer softwares de verdade totalmente do zero, ou seja, que 100% do código foi só você que escreveu. Você vai ser obrigado a usar bibliotecas dos outros. Vamos expandir o conceito de bibliotecas dinâmicas e entender quão fundo vai o buraco desse coelho.</p>
<p>(&hellip;)</p>
<p>Até esse ponto na história você tinha então linguagens estilo Java, que é muito inspirado em C++ e alguns pontos de Smalltalk com alguns, mas não todos os conceitos de orientação a objetos e o conceito de máquina virtual e gerenciador de memória que também havia em Lisp. Na prática, em vez de orientação a objetos eu argumentaria que Java é uma linguagem mais orientada a classes. Muita coisa em Java não são objetos, começando com a própria classe em si. A orientação a objetos veio evoluindo desde Simula, CLU, C com Classes que originou C++, Smalltalk que foi provavelmente a melhor representação de orientação a objetos, e Java que deu alguns passos pra trás.</p>
<p>Até esse ponto já entendemos o conceito de bibliotecas dinâmicas que podem ser reusada. Bibliotecas em geral são conjuntos de funções que fazem alguma coisa útil como processar imagens, converter datas, formatar PDFs ou qualquer coisa assim que possa ser reusada. Componentes são funcionalidades, como um componente de calendário que tem a parte visual e a programação que controla as datas. Uma biblioteca pode ter vários componentes, por exemplo. A parte visual começou a ficar importante com o advento das interfaces gráficas, com a crescente adoção de ambientes gráficos como o Macintosh original, o OS/2 que foi um filho bastardo da IBM com a Microsoft e finalmente o Windows 3.1. Por acaso modelar componentes como classes e objetos era interessante e foi quando esses dois conceitos começaram a se mesclar.</p>
<p>No começo dos anos 90 um dos conceitos ligados a orientação a objetos começou a aparecer mais que foi a componentização. Em particular na forma de RAD ou Rapid Application Development, Na categoria de RAD foi onde se popularizou o conceito de Integrated Development Environment ou IDEs como os antigos PowerBuilder, Visual Basic, Visual dBase, Access, Delphi. As linguagens por baixo ainda não eram realmente orientadas a objeto como conhecemos mas aí surgiu o Java que trouxe uma evolução. Ainda longe do que era o Smalltalk mas já melhor do que Visual Basic.</p>
<p>Componentização também se tornou uma idéia importante primeiro para evitar reescrever software do zero toda vez e tornar mais fácil reusar software. Mas mais do que isso pra tornar mais fácil comercializar esses componentes. Hoje em dia se você quer uma biblioteca pra, sei lá, imprimir um PDF tem centenas disponíveis de graça no GitHub pra quase todas as linguagens. Mas naquela época a Internet só tava começando, nem 2% da população tinha acesso ainda. E o jeito pra se comercializar era distribuindo em disquetes, encaixotado, em prateleira de lojas. Pra começar, agora que tínhamos um ambiente gráfico mais sofisticado nos sistemas operacionais não dava pra todo programador toda hora ter que fazer tudo do zero. Desenhar um botão fazendo as linhas da borda pixel a pixel. Por isso linguagens como o Microsoft C++ já vem com um framework, o MFC ou Microsoft Foundation Classes e o Delphi vem como VCL ou Visual Components Library. Normalmente são conjuntos de DLLs como já expliquei antes.</p>
<p>Com C++ e MFC podemos criar aplicativos como um Word ou Excel. Mas daí a Microsoft foi além e criou outra tecnologia, o OLE ou Object Linking and Embedding que em resumo é uma forma de incluir componentes visuais complexos dinamicamente num aplicativo. Vocês já sabem o que são bibliotecas dinâmicas, mas do jeito como explicamos você precisa compilar o programa já com os bindings pras bibliotecas em tempo de compilação. Mas como fazer pra instalar um componente num programa que já existe sem recompilar? Uma demonstração impressionante na época era conseguir fazer uma tabela do Excel ser embutido dentro de um documento do Word e ser editável. Em cima do OLE surgiu o OLE control extensions ou OCX. Se você já instalou componentes num Access ou Delphi deve ter visto bibliotecas com extensão OCX que se tornou a principal forma de distribuir componentes em Windows.</p>
<p>Isso foi uma pequena revolução porque também permitia comercializar componentes num formato padrão que podia ser escrito em qualquer linguagem da época e embutida em qualquer aplicativo que suportasse o padrão, incluindo IDEs. Do OLE original pra OCX também se precisou de um modelo para linguagens interagirem com esses componentes. Então nasce o Component Object Model ou COM. É assim que componentização funcionou na época do Visual Basic e Delphi. No mundo Java o equivalente ao COM poderia ser um Java Bean. Hoje OCX é outra coisa, são componentes ActiveX. Assim como no Java toda classe herda de Object ou em Object Pascal toda classe herda de TObject, em COM você implementa a interface IUnknown.</p>
<p>Aqui vale entender a função de uma interface. Numa interface gráfica, tanto faz se você tem uma janela com um botão de OK em Windows, ou em MacOS, ou em GNOME do Linux, a interface é a mesma do ponto de vista do usuário, mas a programação, ou implementação por trás é completamente diferente. A interface garante que quem vai consumir o serviço por trás não precisa se preocupar como ele é construído. A mesma coisa são as interfaces para bibliotecas, nesse caso em vez de ser um elemento visual, se trata de um arquivo em um determinado formato que simplesmente declara que funções, com que argumentos, com que tipos de dados, e que tipo de resultados você espera. Daí você implementa como quiser por trás e quem consome essa biblioteca pode assumir que no mínimo ele vai implementar as funções conforme descritas na interface. Uma classe numa linguagem orientada a objetos é a implementação de alguma interface, como a tal IUnknown do padrão COM que falei antes.</p>
<p>Poderíamos argumentar que o modelo de componentes mais avançado na época, no começo dos anos 90, era a NextStep com sua linguagem Objective C que eu argumentaria que é mais simples, mais elegante e mais orientado a objetos do que C++ ou Object Pascal ou mesmo Java e tinha um conjunto de classes, que eles chamavam de kits como o Foundation Kit, melhor do que o MFC da Microsoft ou VCL da Borland. Pra vocês terem uma idéia de quão à frente do seu tempo ela estava, o desenvolvimento de iOS e MacOS de hoje ainda usa uma evolução direta das mesmas classes até hoje, por isso os nomes das classes como “NSString” ou “NSObject” começam com esse NS que é de NextStep. No fim dos anos 80 e começo dos anos 90, essa idéia de arrastar e soltar componentes direto numa janela gráfica pra criar programas era uma idéia revolucionária. No NextStep que surgiu o lendário primeiro navegador web de Tim Berners Lee, mas não só isso, pra nerds como eu é a Id Software desenvolveu a engine gráfica do jogo Doom. O também lendário John Carmack gostava dos NextCube.</p>
<p>A primeira geração de programas nessa época no fim dos anos 80 eram aplicativos desktop normais, como os feitos em PowerBuilder ou Access que rodavam só localmente em uma máquina. Esses programas normalmente tinham um binário da aplicação e outro arquivo que representava um banco de dados, muitos derivados do primitivo formato DBF (que literalmente significa database file) que usávamos em dBase ou Clipper ou FoxPro. O que a gente chamava de banco de dados era uma estrutura de dados muito simples, pense uma coisa parecida com uma lista ligada de estruturas e um índice primitivo. Numa época que empresas pequenas às vezes tinha só 1 computador pra empresa inteira, isso até funcionava. O banco inteiro era um único arquivo. E se dois usuários em duas máquinas quisessem compartilhar o mesmo banco de dados sem precisar ficar copiando o arquivo toda hora?</p>
<p>Com a popularização dos desktops, principalmente PCs e também com acesso a tecnologias de redes locais, antes ainda da Internet comercial realmente decolar, começa a surgir o conceito de aplicativos distribuídos. Foi com a popularização de tecnologias de redes como da Novell e do protocolo IPX/SPX e o Windows NetBios que permitiam compartilhar arquivos numa rede local que as coisas começaram a mudar. Com essa possibilidade, e se colocássemos o tal arquivo de banco de dados numa pasta compartilhada na rede, daí copiamos o programa na máquina de cada pessoa na rede e quando o programa abre ele pode apontar pro arquivo compartilhado e booom agora todo mundo pode acessar os mesmos dados! Sensacional né? Só que não &hellip;    Puta idéia errada.</p>
<p>Lembram no episódio passado que falei da dor de cabeça que é programar multi-threads porque cada thread tem acesso à memória global e uma pode ficar pisando na memória da outra? Mesma coisa com programas acessando um arquivo compartilhado na rede. ?O que acontece quando um programa tenta escrever no mesmo registro, no mesmo arquivo, que outro programa na rede? Caos!   Foi a era dos arquivos de banco de dados que corrompiam toda hora.</p>
<p>Essas linguagens primárias e as redes da época só tinham uma coisa pra fazer nessa época: bloquear o arquivo inteiro! Ou seja, se alguém decidisse gravar alguma coisa no banco de dados, todos os outros programas precisavam esperar a vez. Não era ideal mas em redes pequenas de 10 ou 20 máquinas não chegava a ser o fim do mundo. Mas o problema é que um arquivo compartilhado não é mágica. Tem um servidor onde fica o arquivo de verdade, na rede as pessoas não tem a cópia inteira do arquivo, ele vai lendo pedaços do arquivo em um stream de dados.</p>
<p>Aliás, esse conceito de stream é importante você entender se ainda não estudou. Se você tem um arquivo de, digamos, 100 GB na rede, e você quer só um pedaço no meio dele, você não precisa baixar o arquivo todo. Você abre um stream, tipo uma corrente ou esteira mesmo e vai puxando um pedaço de cada vez até chegar na parte que quer e aí pode fechar esse stream. Ou você pode abrir o stream direto já no meio do arquivo e ir lendo de lá um pedaço de cada vez. Quem é bem iniciante se confunde com isso porque você consegue listar os arquivos na rede como se estivesse local na sua máquina, mas “ver” os arquivos e “ter” os arquivos são coisas diferentes.</p>
<p>Mas se você tentar ler esse arquivo gigante inteiro, dependendo da velocidade da rede, que é sempre lento, pode levar muitos minutos. E na hora de gravar o servidor de rede precisava não errar onde ia gravar no meio do arquivo. ?E se seu programa dá pau na rede no meio de uma gravação? Ou se a rede dá pau? Ou se o servidor engasga? De repente a gente começou a ter um monte de variáveis a mais pra se preocupar onde antes era simplesmente abrir o arquivo, gravar e fechar.</p>
<p>Durante os anos 90 fomos evoluindo esse conceito de 2 camadas ou cliente-servidor primitivo. O próximo passo foi usar um servidor de banco de dados em vez de só compartilhar um arquivo na rede. Foi assim que começamos a usar bancos como Ingres, Caché, InterBase, IBM DB/2, Oracle e só depois que a Microsoft adquire a Sybase no meio dos anos 90 que ele constrói o SQL Server sobre ele.</p>
<p>A diferença com arquivos compartilhados é que em vez do programa cliente tentar abrir um arquivo na rede ele se conecta antes a outro programa que está remoto, um servidor. Nesse caso um servidor de banco de dados. Isso evita quase totalmente que o arquivo de dados em si se corrompa tão fácil. Esse servidor vai servir como um mediador, os clientes pedem a ele pra fazer operações no arquivo e o mediador vai executando na ordem correta as coisas, e como só ele abre e escreve no arquivo, as chances dele corromper eram muito menores.</p>
<p>Lembra no episódio sobre a história do front-end como eu expliquei que um navegador web é um cliente TCP e o servidor web é um servidor TCP? É a mesma coisa aqui, só que antes de começarmos a usar o protocolo TCP antes usávamos protocolos de rede local como o IPX que falei antes, então o programa em Delphi ou FoxPro podia ser um cliente IPX e o banco de dados era um servidor IPX. Pouco tempo depois que a Internet começou a se popularizar e o Windows finalmente começou a vir com uma pilha TCP/IP que começamos a trocar tudo por TCP.</p>
<p>Uma pequena evolução nessa arquitetura foi com bancos como Oracle ou SQL Server que permitem escrever programas que rodam dentro do servidor de banco de dados, os famigerados Stored Procedures em linguagens como PL/SQL ou T/SQL. Assim começamos a separar parte da lógica que ficava exclusivamente nos programas cliente para o lado do servidor. Isso ajuda em muito a diminuir a complexidade dos programas cliente, diminui a necessidade de ficar atualizando os programas nos desktops toda vez que a lógica de negócios muda. Mas por outro lado causa mais lentidão no banco de dados porque agora além de ter que fazer as operações básicas de ler e escrever dados ele vai precisar processar e computar cálculos e outras lógicas em cima desses dados.</p>
<p>De novo, lembre a dificuldade que era atualizar o programa cliente nos desktops. Você precisava gerar um novo binário e mandar todo mundo desligar tudo das máquinas, ir de máquina em máquina com um disquete pra instalar ou mandar todo mundo baixar do servidor de arquivos na rede. Pior ainda se a empresa tinha filiais em lugares geograficamente separados onde nem todas as filiais se comunicavam com as outras. Lembre-se, internet ainda era uma coisa opcional. A gente tinha redes locais dentro do escritório, mas não necessariamente internet entre os diferentes escritórios. ?E se uma filial começa a rodar o programa mais novo mas outra filial esquece e fica na versão mais velha?</p>
<p>Agora, alguém parou pra pensar: o banco de dados é um servidor de rede. Os programas são clientes que se conectam nesse servidor. Só que o banco faz duas funções: gerencia os dados e roda lógica de negócio com essas stored procedures. Porque não mais um servidor no MEIO do caminho? Daí o cliente se conecta nesse que tem lógica de processamento de dados primeiro, que por sua vez vai se conectar em um segundo servidor, que seria o de banco de dados. Dessa forma conseguimos tanto separar a lógica de negócio e diminuir o tamanho dos programas nos desktops e também tiramos a carga do servidor de banco de dados. Esse é o nascimento da arquitetura que conhecemos como três camadas ou three tiers. Se você assistiu o episódio sobre SAP é aqui que as soluções corporativas começam a se encaixar.</p>
<p>Com a idéia de um servidor de aplicação passamos a pensar mais em interoperabilidade e protocolos de rede. Junte a idéia de componentização, orientação a objetos e a necessidade de componentizar agora um conceito mais abstrato: chamar lógica de negócios em outro servidor. Assim nascem especificações como o COM e Distributed COM ou DCOM que depois seria renomeado como COM+ da Microsoft ou concorrentes como o famigerado CORBA. Na prática eram todas formas de chamadas de procedimento remotos ou o que chamamos hoje de RFC ou RPC, que é remote procedure calls.</p>
<p>Eu já expliquei que pra compilar um programa que depende de uma biblioteca dinâmica precisamos de um arquivo de cabeçalho que declara que funções essa biblioteca tem exposta para ser consumida, a tal da Interface. É exatamente a mesma coisa agora só que em vez de uma biblioteca dinâmica é uma biblioteca remota, mais precisamente um cliente de algum serviço remoto. Não temos como saber o que um servidor de aplicações tem de funções expostas então precisamos de algum tipo de interface que declara quaisfunções, com que argumentos, e que resultados esse servidor de aplicações expõe pra gente, através de que protocolo. Pra isso servem coisas como COM+ ou CORBA que tinham o protocolo IIOP ou Inter-ORB onde ORB significa object request broker, para especificar esse protocolo de comunicação, o formato das mensagens trocadas.</p>
<p>Esse conceito coincide com a fase do Java onde começa a surgir o famigerado J2EE ou Java 2 Enterprise Edition que hoje é chamado só de JEE, sem o dois. Java 2 é engraçado porque tivemos o Java 1, daí ele foi pro Java 1.1 e depois 1.2 e aí nasceu J2EE mas depois as versões foram 1.3, depois 1.4 e acho que só na 1.5 que ele chamou de direto de versão 5. Hoje acho que estamos no Java 10 ou 11 certo? Enfim, o J2EE era uma especificação realmente interessante porque ela consolidava tudo que tínhamos inventado até então em tecnologias de desenvolvimento de aplicações em três camadas e agora também usando tecnologias de internet como o protocolo TCP e HTTP.</p>
<p>Em resumo J2EE especifica o também famigerado servlet que é uma forma de encapsular as operações de HTTP, ele especifica uma forma complexa de gerar aplicações usando um modelo chamado Model 2 que é basicamente o Model - View - Controller ou MVC que você tanto ouve falar hoje. E na parte do model, que costuma ser uma abstração pra uma ou mais tabelas no banco de dados, temos os também famigerados EJB ou Enterprise Java Beans, além dos JMS ou Java Message Service, que encapsulam maneiras de acessar banco de dados remotos e outros tipos de serviços remotos como outros servidores de aplicação. E tudo isso conectado via arquivos de configuração. E nessa época se tornou moda formatar arquivos de configuração no novíssimo formato XML. Em breve a Microsoft ainda vai inventar Web Services usando o protocolo SOAP que trafega os dados todos formatados em XML também. Na verdade começamos a usar XML em tudo que é lugar. E assim começa a era onde passamos a associar tudo que tem XML com muito enterprise e passamos a odiar XML.</p>
<p>Em paralelo a isso, muita nova literatura começou a ser escrita pra ajudar a organizar toda essaa bagunça em metodologias e vocabulários pra conseguir desenhar sistemas complexos orientados a objetos. É quando surgem nomes com Os Tres Amigos, Grady Booch, James Raumbaugh, Ivar Jacobson, cada um com suas idéias de metodologias que se juntaram numa empresa chamada Rational e juntam suas idéias no famigerado Unified Modeling Language ou UML para representar soluções baseadas nessa idéias de programar objetos e componentes. Aliás, UML que podia ser representado em arquivos em que formato? Sim, em XML. A Rational que viria a desenvolver diversas ferramentas como Rose, ClearCase, ClearQuest, e outros. Depois teríamos a famosa gangue dos quatro ou Gang of Four que são Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides que escreveram o agora clássico livro de Design Patterns. O que chamamos hoje de mundo enterprise começa a ganhar forma nessa fase do fim dos anos 90, e ele começa de verdade com J2EE e as metodologias monumentais de engenharia de software orientados a objetos.</p>
<p>Em uma década evoluímos muito rápido de pequenos programas que rodavam só em uma máquina, pra soluções cliente-servidor em 2 camadas e agora a arquitetura em 3 camadas e as sementes para aplicações realmente distribuídas com o advento da Internet. Em paralelo, como já contei antes, tivemos C# com a origem num híbrido de J++ e Object Pascal. Como C# é basicamente a Microsoft que controla e basicamente depende só do Windows, ele conseguiu evoluir bem mais rápido do que Java nos anos seguinte, adicionando muito mais funcionalidades à linguagem que a tornaram mais do que simplesmente uma cópia da sintaxe do Java, tanto em termo de novas sintaxes quanto mais bibliotecas e serviços. COM+ e ActiveX se tornam as formas principais de componentização tanto local quanto remota e CORBA vai começando a desaparecer.</p>
<p>No mundo mais próximo de Linux, Perl já era popular principalmente como linguagem para scriptar coisas como ferramentas para administração de sistemas Linux. Ele veio pouco a pouco sendo substituído por Python, que era uma linguagem mais limpa e mais moderna, que também herdou algumas funcionalidades de orientação a objetos. Ele teve a sorte de pegar o crescimento das distribuições Linux e acabou se tornando a linguagem padrão em muitas distribuições. PHP pegou a onda das aplicações Web e ganhou espaço sendo mais fácil que Perl como sintaxe de linguagem. PHP se uniu a outras tecnologias emergentes no mundo open source como rodar em sistemas Linux, usar o servidor web Apache, e o ainda novato banco de dados MySQL, e assim nasce a pilha de tecnologias ou stack chamado de LAMP.</p>
<p>Mas o interpretador do PHP era realmente um puxadinho, bem ruim, sendo um dos piores em gerenciamento de memória e constantes bugs de segurança, numa época onde ainda estávamos aprendendo sobre segurança agora que começamos a colocar as coisas expostas na internet pública. Fora isso o estilo de programação derivado da filosofia de Larry Wall, criador do Perl, de “quick and dirty” ou “rápido pra desenvolver mas código sujo como resultado” não era atraente pra adoção mais séria da indústria. Mas a bolha da internet acelerou a adoção de todos eles ao mesmo tempo.</p>
<p>Com o crash da bolha demorou alguns anos pras pessoas voltarem a se interessar em novas linguagens. Como eu disse antes, o Manifesto Ágil só foi escrito bem no ano desse crash em 2001. Então o mercado de linguagens que já existiam não tinham muito interesse em adoção em massa de práticas como as ensinadas por metodologias como Extreme Programming ou Cristal. As metodologias num mundo como Java ou C# era ditado pelos fabricantes de ferramentas como a Rational que foi comprada pela IBM, BEA, Oracle, Microsoft. Google estava crescendo rápido mas ainda não tinha tanta influência nesse mercado. Facebook ainda não existia. O mercado passou a associar tecnologias enterprise como “sérias” e tecnologias open source como “amadoras”.</p>
<p>Mas a gente sabia que tinha jeitos mais simples de desenvolver, principalmente se olhar as linguagens interpretadas, mas ainda não havia uma adoção significativa a não ser do PHP, que pra muitos engenheiros era uma linguagem amadora e pouco sofisticada. Foi só quando Ruby começou a ser adotada por muitos dos signatários do Manifesto Ágil como Ward Cunningham, Martin Fowler, Andrew Hunt, Brian Marick, Robert C. Martin, Dave Thomas que as pessoas começaram a mostrar algum interesse e coincidentemente tivemos o lançamento do framework Ruby on Rails em 2004 e finalmente Ruby, que havia sido criado 10 anos antes em 1995 começou a ganhar tração. Diferente de Java ou C# ou PHP, em vez de ter origem na herança de sintaxe do C++ ele procurou inspiração no Smalltalk e Lisp. Isso a tornou diferente o suficiente e com o suficiente de sofisticação para atrair a atenção desses veteranos de cabelo branco.</p>
<p>Já que era muito difícil parar a inércia de gigantes como Java, .NET e PHP, pareceu interessante começar uma comunidade do zero, com uma linguagem sofisticada mas obscura, mas já aplicando as práticas evangelizadas pelas metodologias que seguiam o Manifesto Ágil. Essa Era marca o início da profissionalização das tecnologias open source para desenvolvimento de aplicações, que poucos anos antes eram consideradas mais amadoras pelo mundo enterprise. Em vez de convencer o mundo enterprise, um novo mundo começou a crescer rápido para competir com elas: as tech startups.</p>
<p>O sucesso quase instantâneo do Ruby on Rails para criar os tipos de aplicações que pouco tempo antes só deveriam ser feitos em Java ou C# trouxe uma nova idéia pra indústria: que pra uma linguagem fazer sucesso ela não precisava ser um clone da sintaxe de C++ ou Java ou ter o suporte de grandes nomes como IBM ou Microsoft. Nesse ponto estamos entre 2003 e 2007. Eu diria que esse período de transição é importante porque nos anos 80 surgiu de fato o movimento open source e GNU. Nos anos 90 surgiu o primeiro grande projeto que tornou open source relevante: a kernel do Linux e as distribuições de Linux.</p>
<p>Durante a bolha das ponto coms tivemos sucessos comerciais como o VA Linux e a RedHat. De repente open source não era só um hobby e tinha modelos de negócio viáveis que finalmente botaram pressão nas empresas tradicionais. Mas a manutenção e criação de novos projetos não era ainda uma coisa simples, haviam sites como SourceForge, CodeHaus e outros, mas contribuir em open source ainda tinha uma barreira de entrada muito alta. Lembre-se que GitHub só se torna realmente famoso a partir de 2008.</p>
<p>Em 2003 mesmo outra iniciativa estava começando com o surgimento do Groovy, uma nova linguagem que compila em bytecode pra JVM. Ela tem muita inspiração na sintaxe de linguagens como Python e Ruby e é uma linguagem muito mais agradável de trabalhar do que o Java original. E com o sucesso do Ruby on Rails, tivemos o Groovy on Grails. Mas nesse momento eu acho que a comunidade Java e mesmo a open source ainda não estava preparada pra se adaptar a uma nova linguagem. Um dos problemas de ser uma comunidade gigante é que é muito difícil mudar sua direção, especialmente quando essa direção ainda era meio incerta e experimental. Mesmo assim o Groovy teve um bom nicho e ainda hoje você vai ver Groovy se usa ferramentas como o Gradle. Groovy ganhou fôlego quando entrou no GitHub e quando ganhou patrocínio da Pivotal.</p>
<p>Pra quem não conhece a PivotalLabs foi uma consultoria que, junto com outros nomes emergentes como ThoughtWorks, ajudou a tornar Agile comercial mais visível, tinha na sua base tecnologias Java e Ruby também. Ela cresceu rápido pós 2008 e foi adquirida pela VMWare e depois pela EMC e hoje é uma empresa pública que mudou da área de serviços de consultoria pra produtos corporativos, mais especificamente cloud corporativo. Por 2 anos ela patrocinou o Groovy.</p>
<p>Voltando um pouco na história, até os anos 80 popularizou-se linguagens que chamamos de imperativas como C ou Pascal ou Perl. Elas são simples em estrutura. Você escreve funções que recebem argumentos e devolvem alguma estrutura de dados. Você compõe seus programas com funções que chamam outras funções. Rapidamente você nota que um conjunto de funções que atua em cima de uma mesma estrutura podem ser agrupadas em módulos. Assim nasce a idéia de linguagens como MODULA, precursor do Pascal. Mas então alguém resolve criar um conceito, ou uma abstração que uma estrutura com um grupo de funções pode ser o que chamamos de classes. E podemos criar várias instâncias dessa classe, que chamamos de objetos. Assim começa a nascer programação orientada a objetos.</p>
<p>Daí temos linguagens como Simula, Smalltalk, C++, Objective-C, Java, C#, Python. Organização de objetos pode ser implementada em cima de linguagens imperativas, então C com classes pode virar C++ ou Objective-C. Perl pode ganhar o equivalente a classes usando bless. PHP ganhou classes. Basic ganhou classes em Visual Basic. Pascal ganhou classes rudimentares em Turbo Pascal e depois em Object Pascal que é o Delphi. Até Cobol tem classes hoje em dia.</p>
<p>Em paralelo a isso havia outra área de pesquisas que deriva da linhagem de linguagens funcionais como Lisp, Scheme, ML, que lida com a matemática dessa composição de funções ou lambdas e é definida em Lambda Calculus, que se iniciou com o famoso Alonzo Church, conterrâneo de Alan Turing. Turing aliás, que foi aluno de Church, então você pode ver como as idéias dos dois se misturam e o trabalho de ambos é a fundação do que chamamos de Ciência da Computação. No caso da vertente de Church vamos simplificar assim, uma função recebe um argumento tipo um número ou uma string ou outra coisa, devolve outro tipo de elemento como resultado e, principalmente, tem um nome, e só.</p>
<p>?Mas por que toda função tem que ter um nome? Por que não podemos ter funções sem nome, o que chamamos de funções anônimas, e por que funções não podem receber funções como argumento e devolver funções como resultado? Em C temos algo rudimentar onde podemos passar o que chamávamos de callbacks, ou ponteiros pra memória onde está outra função, mas como eu disse era uma forma rudimentar.</p>
<p>Provavelmente uma das coisas mais diferentes que Ruby trouxe da herança de Lisp foi o conceito de lambdas para o mundo web, mesmo que ainda não tão avançado como era em Lisp, que implementava as idéias de lambda calculus de Church. Podemos chamar de funções anônimas, ou um tipo mais avançado que chamamos de closures ou blocos. Groovy também trouxe lambdas pra Java dentre outras coisas. Mas esse tipo de composição abriu caminho pra coisas como metaprogramação e DSLs ou Domain Specific Languages, que é como se fossem mini-linguagens em cima da linguagem principal. Em vez de somente seguir o que a linguagem dita e se pudéssemos manipular a própria estrutura e sintaxe da linguagem? A capacidade de moldar a linguagem pra ficar com a “cara” que você quisesse. Isso tornou o chato estilo imperativo de programar, em algo bem mais maleável e flexível e divertido, embora isso tenha aumentado mais a complexidade para quem está iniciando. Lambdas vieram pra ficar e depois disso toda nova linguagem e mesmo as antigas adotaram esses recursos. Hoje Java, C# e outros também ganharam lambdas e alguma capacidade de metaprogramação.</p>
<p>Com a virada do século e a aceleração antes do crash que tivemos nesse período, o poder computacional cresceu exponencialmente desde os anos 80, era a consequência da Lei de Moore, que ditava que o poder computacional dobraria mantendo o mesmo preço a cada 12 a 18 meses. Antes nos preocupávamos bem mais com a performance crua dos nossos programas pra tirar o máximo de máquinas caras e fracas, mas agora as máquinas finalmente ficaram poderosas e acessíveis, então passamos a ter surplus ou sobra de processamento. É importante salientar essa mudança de perspectiva. Finalmente em vez de termos que sofrer com linguagens simplistas e burocráticas em nome de economizar performance, porque não passar a pensar em formas de tornar a programação mais agradável?</p>
<p>Antes, linguagens mais simples de trabalhar era quase sinônimo de baixa performance, mas agora que a web provou que performance pura não era o único fator pra escolher uma linguagem, poderíamos começar a experimentar em funcionalidades e a escola de lambda calculus começou a aparecer novamente, graças aos programadores de cabelos brancos que haviam experimentado Lisp ou Scheme nas décadas de 70 a 80. E a tal orientação a objetos também veria uma evolução graças a quem experimentou Smalltalk no mesmo período.</p>
<p>Vale lembrar que Lisp já tinha o conceito de máquina virtual e garbage collector décadas antes de Java. E Smalltalk tinha o conceito de que tudo é realmente objeto e que objetos ficam vivos mesmo se a máquina virtual seja desligada. Pense num VirtualBox ou VMWare quando você sobre outro sistema operacional e então suspende a máquina. O Smalltalk tem esse conceito de suspender a execução sem bootar e limpar a memória, dentro do que ele chama de imagens ou no caso literalmente um banco de dados de objetos. Quando você abre uma imagem de Smalltalk ele pode ter objetos em memória que foram instanciados 30 anos atrás. E você vai compondo novos objetos usando os objetos vivos que já existem. Pensem que louco essa arquitetura.</p>
<p>E falando em arquiteturas exóticas. Uma editora de livros que ganhou notoriedade nessa virada de século foi a The Pragmatic Programmer, mesmo nome do clássico livro de 2 signatários do Manifesto Ágil e que ajudaram a dar credibilidade à adoção de Ruby: Dave Thomas e Andy Hunt. Eles também popularizaram o conceito de que todo programador deveria tentar aprender pelo menos uma nova linguagem por ano, e em 2007 eles publicaram suas experiências com a linguagem Erlang dos anos 80, de Joe Armstrong, de quando trabalhava na Ericsson. Erlang que como eu expliquei em outro episódio tem uma sintaxe muito diferente, herdada de Prolog, e que tinha uma arquitetura que ninguém no mundo web tinha visto ainda: o modelo de Atores. Erlang, como Java, tem uma máquina virtual. Mas diferente da JVM ele vai um passo além: ele tem partes do conceito de lambda calculus sem ser puramente funcional e partes das principais propriedades de objetos sem ser orientada a objetos. Mas em vez de organizar as coisas como classes e objetos, ele organiza como módulos e atores.</p>
<p>Um ator é como se fosse um objeto com seu estado encapsulado e se comunicando com outros atores via passagem de mensagem, diferente do Java, C++ ou C# e mais similar a Smalltalk e Objetive-C. E mais do que isso, num sistema operacional, além de carregar o Kernel ele também carrega serviços ou daemons via um serviço de supervisão como systemd ou initd ou outros dependendo do seu sabor favorito de Unix ou Linux. O Erlang tem algo similar, um sistema de supervisores que iniciam atores e se encarregam do ciclo de vida dos mesmos. Erlang assim como a JVM ou Smalltalk são quase como sistemas operacionais inteiros. Ao contrário dos interpretadores como Perl ou Python ou Ruby que foram feitos pra iniciar rápido e terminar rápido, Erlang e Java funcionam melhor se você iniciar e deixar elas parasitar a máquina toda.</p>
<p>Assim como Java a idéia é subir um único processo de Erlang e deixar que ele gerencie a máquina e seus programas rodando dentro dele. Erlang não foi feito pra ser reinicializado toda hora, e sim pra ficar de pé eternamente, inclusive essa era a grande funcionalidade pra indústria de telecomunicações: que você não estivesse numa ligação e de repente fosse cortado da sua conversa porque alguém precisou subir uma atualização. Ele tem inclusive o conceito de carregar código novo sem precisar necessariamente reinicializar tudo. Na prática é mais ou menos o que Java e J2EE também preferem: ficar de pé sem ficar reinicializando o tempo todo. Ficar de pé eternamente era o grande objetivo. Guardem essa característica porque vai ficar mais óbvio quando falarmos de infraestrutura e Devops mais pra frente. Mas o ponto é que essa linguagem super estranha despertou o interesse em arquiteturas muito diferentes do que estávamos usando.</p>
<p>Em 2009 Martin Odersky trouxe ao mundo o resultado das pesquisas que ele vinha fazendo no mundo de lambda calculus e Java desde os anos 80 e 90 na forma de outra linguagem que compilava em bytecodes Java como o Groovy. Essa linguagem foi Scala. E ele se popularizou muito rápido porque adicionava funcionalidades que tornavam o Java mais palatável, coisas como Traits que em Objective-C são o equivalente a Protocolos e alguns diriam que é uma forma mais limpa de se fazer herança de funcionalidades. Inferência de Tipos que eu já expliquei que vem de Hindley-Milner Type System de linguagens como ML, que levantou outro dilema da programação: a discussão se linguagens de tipagem estática são melhores ou não que tipagem dinâmicos.</p>
<p>Em um super resumo, todos os dados no seu código, variáveis, estruturas, listas, precisam ter tipos. Pense em tipos como moldes de biscoito. Você precisa dizer de antemão qual o tamanho do molde você vai querer, pequeno, grande. No caso de números, vai ser um inteiro de 32 bits? Um inteiro de 64 bits? Um inteiro sem sinal, ou seja, sem números negativos? Isso é importante pra um compilador saber quanto de memória precisa alocar pra cada coisa. Se fizer isso errado vai faltar memória e dar erro ou vai usar memória de forma desnecessária, causando leaks ou vazamentos. Em linguagens dinâmicas como Lisp, Python, Ruby a gente não determina isso no código, o interpretador pode determinar o molde, ou o tipo certo, durante a execução do código, por isso chamamos isso de tipos dinâmicos. Eles têm tipos, só que não estão estaticamente declarados no código como fazíamos em Java ou C#.</p>
<p>Declarar tipos é super tedioso e você pode errar quando está programando também. Simplesmente não declarar e deixar o interpretador decidir só quando já está rodando é muito mais conveniente mas pode causar desperdícios e alguns erros porque ele pode assumir o tipo que você não esperava e você só vai descobrir quando estiver rodando. Inferência de tipos é meio que o meio do caminho dos dois mundos porque a gente não escreve todos os tipos estaticamente no código, ou seja, deixa de ser absurdamente tedioso. Mas o compilador vai tentar adivinhar os tipos em tempo de compilação, daí o binário ou bytecode no final vai conter os tipos certos antes do programa executar. Só isso já torna escrever em Scala muito mais conveniente do que escrever em Java antigo. E Inferência de tipos foi melhorando e hoje se encontra em linguagens novas como Rust, Swift, Kotlin, Typescript.</p>
<p>Mesmo Java, desde a versão 5 você tinha possibilidade de omitir alguns tipos como quando usava a implementação rudimentar de Generics. No Java 8 você pode omitir tipos em declaração de lambdas. E no Java 10 ele ganha inferência de tipos locais como C# também. Como iniciante você vai notar que estudar tipos é muito importante, independente se você vai aprender uma linguagem dinâmica ou estática, se tem inferência de tipos ou não porque mesmo inferência não é mágica, o compilador ainda precisa de algum contexto ou anotação pra inferir o tipo certo. Na prática entenda: escolha o molde errado e seu biscoito vai sair do tamanho errado.</p>
<p>Scala cresceu rápido por um momento mas estagnou. Um grande problema do Scala é que o binário bytecode que ele gera de uma versão de Scala pra outra são incompatíveis. Ou seja, se você tem uma biblioteca compilada pra bytecode de Scala 1 e você faz um programa com Scala 2 e tenta carregar a biblioteca antiga, vai tomar um LinkageError da JVM. Isso era uma puta dor de cabeça: incompatibilidade binária entre coisas compiladas em diferentes versões de Scala. A única forma de solucionar isso é você recompilar tudo de novo sem reusar os binários antigos. É uma escolha de design do criador pra que ele pudesse inovar a linguagem sem se preocupar em ficar dando suporte pra coisas antigas. Hoje em dia o Go meio que exige a mesma coisa: ele prefere que você baixe o código fonte de todas as dependências, em vez de baixar binários pré-compilados, e compile tudo junto de uma só vez.</p>
<p>Aliás, um comentário importante: eu falei lá atrás que você como programador vai precisar sempre se preocupar com as dependências e as versões certas dessas dependências. Lembra da discussão de compilação estática vs compilação dinâmica? Nos anos 80 e 90 fabricantes de ferramentas de desenvolvimento como Borland, Microsoft, BEA, Oracle, traziam tudo junto. Eles que se viraram pra ter todas as dependências que você iria precisar já instalado ou de forma organizada que você pudesse comprar um CD e instalar na sua máquina. E mesmo assim os anos 90 foram infestados do que chamamos de “DLL Hell” com programas diferentes que precisam da mesma DLL mas em versões diferentes mas tudo no mesmo sistema entrando em conflito, literalmente um inferno de DLLs.</p>
<p>Com o advento do mundo open source, de repente você podia baixar bibliotecas gratuitas de código aberto e instalar você mesmo. Mas eles não estavam esperando por isso e virou uma grande bagunça no começo. Quem daquela época nunca copiou um site em PHP que na sua máquina tudo funciona mas quando copia pro servidor ele falha porque esqueceu de também copiar ou instalar as bibliotecas de dependência? Ou no caso de Java esquecia de copiar os tais Jars e a aplicação não queria nem iniciar?</p>
<p>Assim que nascem ferramentas como Maven no Java que é um grande banco de dados de bibliotecas binárias. Agora você tem um repositório centralizado onde quem escrevia bibliotecas poderia postar lá e você como desenvolvedor podia declarar num arquivo em XML, lógico, os nomes e versões das bibliotecas que precisava no seu projeto e o Maven se virava pra baixar tudo que você precisava. E como uma biblioteca pode precisar de outras bibliotecas, a gente costumava brincar que toda vez que precisávamos baixar todas as dependências do projeto, o Maven baixava a internet inteira … duas vezes. Hoje essa posição é do NPM do Javascript. No mundo Microsoft demorou mais pra algo similar aparecer mas no .NET você tem hoje NuGet que inclusive passou a vir pré-instalado no Visual Studio 2012 em diante.</p>
<p>No mundo de programação até esse ponto a gente tinha o Maven no mundo Java, e hoje muitos usam junto o Gradle que é feito em Groovy como eu disse antes. Temos o CPAN no mundo Perl até hoje. No mundo PHP era um híbrido, todo mundo baixava as dependências na mão mesmo tendo coisas como o Pear. Hoje em dia felizmente PHP tem algo mais moderno que é o PHP Composer. No mundo Ruby estávamos evoluindo a idéia de gerenciamento de versões com algo rudimentar implementado dentro do próprio Ruby on Rails, que baixava as dependências direto do GitHub e depois evoluímos pra ferramenta Bundler que na época se tornou o benchmark sobre o qual todo mundo se comparava.</p>
<p>Python preferia usar o próprio sistema de pacotes das distribuições Linux, então era uma zona porque você precisava fazer pacotes RPM ou DEB ou outros pra cada distribuição e você ainda tinha a zona de ferramentas como setuptools e easy_install, que de easy não tinha nada. Aliás, pra uma linguagem que se orgulha de ter um único jeito pra fazer cada coisa, instalar pacotes não era assim. Felizmente o mundo Python tem o PIP agora. No mundo Javascript como já falei nasceu o NPM que ganhou concorrência com o Yarn, co-autorado pelo mesmo autor do Bundler de Ruby. No mundo Elixir existe o Hex. No mundo Rust existe o Cargo. O mundo Go tem o dep, mas aqui a coisa é um pouco mais controversa.</p>
<p>Declarar dependências no seu projeto, instalar de algum repositório e gerenciar os upgrades de versão é uma coisa extremamente importante. Você nunca pode simplesmente atualizar todas as bibliotecas pras versões mais novas, porque seu código vai quebrar. Por outro lado você não pode ficar pra sempre com versões velhas, principalmente se elas tiverem relatos de buracos de segurança. Então você vai precisar atualizar as versões e alterar seu código pra comportar as mudanças. Vai ter vezes que o autor da biblioteca simplesmente desiste de manter sua biblioteca, vai ter buraco de segurança, agora você precisa achar outra biblioteca pra substituir e aí vai precisar reescrever toda a parte do seu código que dependia daquela biblioteca. É uma parte considerável do trabalho de ser um programador e manter um projeto grande.</p>
<p>Isso tudo dito, eu estava falando da incompatibilidade binária do Scala. Assim como Python tem PIP, Ruby tem Bundler o Scala tem o SBT que assim como muitas ferramentas tem a função híbrida de ser um gerenciador de pacotes e também um executor de tarefas. O Scala jogou na mão dos desenvolvedores de bibliotecas gerenciar diferentes binários de cada versão e tem um guia pra tentar manter compatibilidade binária ou o que fazer quando isso não é possível. É meio uma zona porque toda vez que o Scala lança uma versão nova, todo mundo que faz bibliotecas precisa ficar recompilando uma nova versão. Só que é irreal achar que todo mundo vai fazer isso, então você como programador que depende dessas bibliotecas, ou tem que ficar meses esperando todo mundo alcançar a versão nova, ou você mesmo precisa lidar com recompilar manualmente e ver se nada quebra.</p>
<p>Eu mencionei Go porque o Go é diferente da idéia de Java ou Scala, ele não é uma máquina virtual, nem é um interpretador. Ele é mais próximo de C++, ele compila direto num binário nativo e é feito para fazer aplicações e não drivers ou coisas mais baixo nível como fazemos em C. E ele prefere compilação estática pra criar binários que acabam ficando gigantes em tamanho mas que você pode mover pra outro lugar e ele simplesmente funciona. O Go fez uma coisa que a comunidade Ruby on Rails fez em 2008 ou 2009. Ele se integra direto com repositórios Git, em particular o GitHub. Todo desenvolvedor de bibliotecas mantém o código fonte no Github. Você usa o recurso de dep que eu falei pra baixar todas as dependências do GitHub e vai vir todos os código-fonte.</p>
<p>Como o intuito do Go é compilação estática ele precisa de todos os fontes disponíveis pra gerar um binário único. Então a menos que a sintaxe da linguagem não mude de forma drástica de uma versão pra outra, você sempre consegue um binário que não quebra no final sem depender de linkagem dinâmica e LinkageError que o Scala sofre. O Elixir faz algo similar com o Hex, o Rust faz algo similar com o Cargo. A idéia é sempre baixar os código-fontes das dependências e deixar próximo do código do seu próprio projeto e compilar tudo junto depois que baixa em vez de baixar bibliotecas em formato binário como os Jars de Java.</p>
<p>A diferença é que em Java o compilador é notoriamente lento. Em vez de toda vez compilar binários a partir do código fonte, nós compilamos e empacotamos em zips que chamamos de JARs, é o que se publica num Maven por exemplo. Daí você ou manualmente ou via Maven ou SBT no caso do Scala, baixa os JARs pré-compilados. A mesma coisa é no mundo .NET, mas a Microsoft tende a ser melhor em manter compatibilidade binária das suas dependências e agora de gerenciar as diferentes versões de cada uma. Antigamente isso era importante porque não se tinha esse conceito de código aberto, as empresas vendiam bibliotecas e preferiam não abrir o código, na verdade eles faziam o máximo inclusive pra obfuscar os bytecodes gerados pra dificultar alguém fazer engenharia reversa e ver como que ele foi implementado.</p>
<p>Por isso eu salientei a diferença na virada do século da explosão do mundo de código aberto e serviços como GitHub e linguagens interpretadas como PHP, Python, Ruby que precisam ter os códigos disponíveis. Scala ainda acaba herdando essa parte do Java, mas linguagens como Go, Rust e Elixir investiram em fazer compiladores bem mais velozes e baixar dependências na forma de pacotes que embutem o código-fonte e compilar seu programa e as dependências tudo localmente em vez de depender de versões binárias pré-compiladas.</p>
<p>Voltando ao papo de arquiteturas, Groovy e Scala trouxeram ao mundo Java uma sintaxe bem mais moderna do que o antigo Java e isso ajudou a linguagem a evoluir muito da versão 6 até agora. Scala também trouxe a arquitetura de Atores para o mundo Java e somado à The Pragmatic Programmer evangelizando Erlang, trouxe também a possibilidade de ir direto na fonte, já que foi ela que introduziu o conceito de Atores com seu framework OTP ou Open Telecom Platform. Softwares que foram escritos pra Erlang antes também começaram a ganhar a luz do dia, em particular ejabberd e RabbitMQ numa época onde produtos de comunicação como Facebook Messenger ou Whatsapp começaram a aparecer. Erlang, sendo um produto desenhado pra indústria de telecom era um par perfeito pra produtos de comunicação em massa. Mas sejamos honestos, a linguagem do Erlang é horrível de usar nos dias de hoje, talvez ok pros anos 80, mas não pro século XXI.</p>
<p>A comunidade Ruby começou a olhar Erlang e rubistas como Tony Arcieri criou a linguagem Reia. Assim como a JVM do Java roda os bytecodes compilados de linguagens como Groovy e não só do Java puro, o Erlang também tem uma máquina virtual chamada BEAM com seus próprios bytecodes. O Reia foi o primeiro experimento de tentar modernizar a sintaxe do Erlang, nesse caso imitando quase diretamente a sintaxe do Ruby para compilar em bytecodes que rodam no BEAM. Em paralelo a ele surgir outra tentativa de fazer a mesma coisa, desta vez de outro rubista, o brasileiro José Valim com a linguagem Elixir.</p>
<p>O Elixir foi uma tentativa mais avançada de não imitar diretamente o Ruby mas de criar uma sintaxe moderna em cima das capacidades do BEAM do Erlang e também de criar um conjunto de bibliotecas base para possibilitar realmente criar aplicações de verdade. Levou quase 4 anos pra Elixir finalmente se tornar usável de verdade pra fazer aplicações de verdade em produção. Ele aproveita tudo que o Erlang já faz mas com uma sintaxe e um conjunto de bibliotecas que remetem a coisas como Ruby, aumentando muito a produtividade. Também por causa da influência do framework Ruby on Rails surgiu o framework Phoenix para desenvolvimento de aplicações Web.</p>
<p>Ruby, como vocês já devem ter percebido, é uma linguagem que eu pessoalmente gosto. Ela ajudou a influenciar outras linguagens como Groovy, depois da comunidade saiu CoffeeScript que ajudou a influenciar o atual Javascript ES6, e também influenciou a sintaxe do Elixir e do estilo da programação de suas bibliotecas. Em paralelo começamos a experimentar mais com outras linguagens uma vez que o paradigma funcional, baseado no lambda calculus que falei acima começou a ganhar terreno. Linguagens obscuras como Haskell e OCAML começaram a ganhar um pouco mais de terreno, inclusive OCAML influenciando a linguagem F# no mundo .NET. Tudo isso também ajudou a evoluir a própria linguagem Java, agora com mais de 10 anos de idade.</p>
<p>Para finalizar este episódio preciso falar da linguagem Go mais um pouco, que eu já vim citando durante este episódio e o anterior. Todos sabem que é a linguagem do Google, mas eu não gosto muito de Go porque pra mim ela representa um passo pra trás. Ela foi criada em 2009 e ignorou muitos avanços que outras linguagens já estavam fazendo. Por exemplo, a inferência de tipos que eu falei que o Scala popularizou e linguagens modernas como Swift, Rust, C# e mesmo Java começaram a usar é menos poderosa em Go. Os tipos do Go são mais pobres, ele não implementa Traits como Rust. Em uma linguagem criada em 2009 que se poderia escolher tudo do melhor, ela preferiu o caminho mais fácil de escolher permitir o ponteiro nulo que é causa de muitos bugs em muitas linguagens. O sistema de tipos é mais pobre, os Generics são mais pobres. Ela não permite estender e redefinir a linguagem, não suporta sobrescrever coisas como operadores. Ela é de fato uma versão melhor do que um C++, que cresceu tão monstruoso e complexo que é realmente difícil de usar hoje em dia. Mas ela não evoluiu a linhagem das linguagens. Como linguagem ela representa um passo pra trás.</p>
<p>Nenhuma linguagem é perfeita mas cada nova linguagem veio evoluindo em cima dos seus antecessores e o Go é basicamente mais um caso da síndrome do Google de reinventar a roda. Eu quase diria que o Go é no back-end o que o Javascript se tornou no front-end: nós usamos mais porque existem softwares importantes escritos em Go, como o ultra famoso Docker, e agora ela está se tornando grande demais pra falhar, em breve não vai mais ser uma escolha não usarmos. Vou deixar linkado nas descrições abaixo um link com diversos artigos explicando todos os problemas dessa linguagem, ela compete com Javascript em críticas. Porém, não se pode negar que ela de fato trouxe algumas coisas importantes que vou explicar também no próximo episódio.</p>
<p>No próximo episódio eu vou continuar essa história com Go, mais Elixir, um pouco mais de Rust, mais de Javascript, talvez eu fale de Python e principalmente vou tentar explicar mais da importância da Apple nos últimos 20 anos para o desenvolvimento de software e como ela cruza com um evento importante no mundo open source.</p>
<p>A história do Back-end não acabou, eu disse que ia ser longo. No episódio de hoje eu voltei à década de 90 e dei uma breve introdução da evolução das arquiteturas de desenvolvimento de software, retornei mais ao mundo Java e entendemos mais sobre a longa e inacabada novela chamada gerenciamento de dependências, uma praga que vai te perseguir por toda sua carreira de programação e finalmente começamos a ter um gosto das novas linguagens, começando com Groovy, Scala, Erlang, Elixir, e um pouco do Go.</p>
<p>Acho que finalmente passamos da metade deste tema nesta série, não deixem de mandar suas perguntas nos comentários abaixo, se curtiu o vídeo mande um joinha, assinem o canal e pra não perder a continuação dessa história clique no sininho e não deixe de compartilhar com seus amigos. Como semana que vem temos Carnaval é possível que eu tire o feriado pra descansar, vamos ver. Se não nos vermos até lá, bom Carnaval pra todo mundo!</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>backend</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #34 - Você não sabe nada de Enterprise. Conhecendo a SAP!</title><link>https://akitaonrails.github.io/2018/12/26/akitando-34-voce-nao-sabe-nada-de-enterprise-conhecendo-a-sap/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/12/26/akitando-34-voce-nao-sabe-nada-de-enterprise-conhecendo-a-sap/</guid><pubDate>Wed, 26 Dec 2018 17:00:00 -0200</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/FXhcfJnlD2k"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Certamente ninguém ia ver video ontem, então fica meu presente de natal hoje mesmo :-) (26/12)&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/FXhcfJnlD2k"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Certamente ninguém ia ver video ontem, então fica meu presente de natal hoje mesmo :-) (26/12)</p>
<p>Finalmente, um dos episódios mais longos da minha carreira. Vamos entender um dos mercados menos compreendidos por toda a comunidade de programação.</p>
<p>Quase nenhum programador de agência, startup, tem idéia do que realmente é o tão temido mercado &ldquo;enterprise&rdquo;.</p>
<p>Então em vez de ficar falando mal sem saber, vou explicar o que diabos realmente é a SAP, tanto do ponto de vista de história quanto tecnologias.</p>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Finalmente chegou o dia de eu contar uma das minhas histórias mais longas. Eu falei um pouco no vídeo de &ldquo;O que estudar&rdquo; sobre o que é ser um consultor. Então HOJE eu quero explorar mais sobre isso e também sobre um mercado que a grande maioria das pessoas não conhece: o famigerado mundo Enterprise, mais especificamente a vertente da SAP que eu conheci no começo dos anos 2000.</p>
<p>Eu já falei algumas vezes de quando eu estava trabalhando na ponto com PSN que fazia sites de esportes na América Latina. Todo mundo sabe que em 2001 a bolha das ponto com estourou com força, muitos acharam que a internet ia até acabar e eu estava numa dessas ponto com. De repente eu estava na rua, mas não por muito tempo.</p>
<p>Exatamente na semana que tudo explodiu eu recebi uma ligação, meu amigo e mentor Antélio Abe, que eu tinha conhecido anos antes lá por 1997 quando estava trabalhando pela minha agência num projetinho de intranet pra Camargo Corrêa. Em 2001 ele tinha saído da Camargo e estava numa pequena consultoria enterprise chamada Balance e eles estavam precisando de alguém que entendesse de tecnologias Web, coisa que ainda era meio alienígena no mundo enterprise. Ele me ofereceu pra aprender esse tal de SAP, e eu pensei, &ldquo;por que não?&rdquo;</p>
<p>(&hellip;)</p>
<p>Pra fazer esse episódio eu pedi ajuda de novo pro Antélio e somado com o que eu lembro, vou tentar organizar algumas informações que podem ser interessantes. Pra vocês entenderem o Antélio é um consultor “asterisco”, coisa rara quando um consultor é bom em múltiplos módulos funcionais de um ERP. Ele já participou de grandes projetos em empresas como Monsanto, Telemar/OI, Claro, Diageo e dezenas de outras.</p>
<p>Vamos dar uma recapitulada. Embora a SAP não seja nem de longe do tamanho do market cap de uma Microsoft, Google ou Apple, ela está instalada no coração das maiores empresas do mundo. Uma hipérbole que acho que não está muito longe da realidade é que eu digo que pra entender SAP, pegue a lista das 500 maiores empresas do mundo. Eu poderia apostar a maioria, ou quase todas, rodam soluções da SAP no seu backend.</p>
<p>SAP SE significa, do alemão pro inglês, Systems, Applications &amp; Product in Data Processing. Seu quartel general é em Walldorf na Alemanha com escritórios em 180 países e mais de 335 mil clientes. Sua gestão já foi muito centralizada, mas agora está espalhada pelo mundo inteiro, conseguindo suportar clientes 24x7 em qualquer fuso horário.</p>
<p>Em 2017 a receita da SAP foi de mais de 23 bilhões de dólares com lucro de mais de 4 bilhões. Ela tem quase 100 mil funcionários pelo mundo. Dentre as principais figuras da SAP ainda está um de seus co-fundadores, Hasso Platner. Não sei se ainda hoje é assim mas Hasso sempre foi o arqui-inimigo de outro titã do mundo enterprise, o famigerado Larry Ellison, da Oracle. Diz uma lenda urbana que eles disputaram uma corrida de iates e quando o Hasso passou na frente abaixou a calça e mostrou a bunda pro Larry. :-D</p>
<p>(aham) Uma curiosidade é que todo mundo se lembra do lendário laboratório da Xerox Parc, que foi a semente da revolução dos micro computadores dos anos 80, a fonte onde tanto a Apple quanto a Microsoft beberam para sair com coisas como o mouse e a interface gráfica. Mas além deles a Xerox ainda ia deixar outro legado pra indústria.</p>
<p>Segundo nossa amiga Wikipedia, a Xerox estava querendo sair da indústria de computadores até 1975 e pediu à IBM para migrar seus sistemas de negócios para tecnologia IBM. Então, cinco engenheiros da IBM que estavam trabalhando no software do sistema enterprise e lhes foi dito que esse software não seria mais necessário. Em vez de jogar tudo fora, eles decidiram sair da IBM Tech e começar outra empresa.</p>
<p>SAP é mais um dos casos em que o nome da empresa sobrepõe ao nome de seus produtos e sistemas. O nome da empresa inicialmente foi System Analysis and Program Development ou SAPD e seu primeiro cliente foi a Imperial Chemical Industries em Ostringen onde fizeram o software de folha de pagamento de contabilidade para mainframe. Mas em vez de guardar os dados em cartões perfurados como a IBM fazia na época, eles armazenavam locamente num banco de dados lógico. Por isso chamaram o sistema de &ldquo;real-time&rdquo; e é de onde vem a letra R do principal sistema integrado deles que, em 1973, foi lançado como R/98.</p>
<p>Em 1979 lançaram o SAP R/2 estendendo para outros módulos como gerenciamento de materiais e planejamento de produção. Daí, do mainframe eles pularam pra arquitetura cliente/servidor nos anos 90, o que chamávamos de arquitetura em 3 camadas, e com isso o nome foi de R/2 para R/3 em 1995.</p>
<p>No Brasil algumas das primeiras instalações de SAP foi na Dow Química e Dupont, ambas usando o R/2 de mainframe que serviriam de base para construção da localização Brasil. Em termos de SAP, localização envolve não só o óbvio que é traduzir todos os textos do sistema em português, mas também a Tropicalização que envolve regras de negócio específicas do nosso país como as regras tributárias, fiscais, CLT e tudo mais.</p>
<p>A primeira instalação do SAP R/3 no Brasil foi na Philips, que veio via a consultoria francesa Atos Origin que por si só tem uma história interessante, sendo originada do merge de duas empresas francesas e da holandesa Origin. Foi adquirida pela KPMG em 2002 e depois a Atos Origin anunciou a compra da Siemens IT que foi finalizada em 2011 sob o nome só de Atos.</p>
<p>Enfim, no Brasil a Atos Origin tinha sede onde hoje é o prédio da Locaweb em São Paulo. A própria Origin foi tipo uma spin off da área de TI da Philips e quem passou a representar a SAP no Brasil.</p>
<p>Uma coisa que vocês devem ter ouvido falar que aconteceu no fim dos anos 90 foi a corrida desenfreada pelo Bug do Milênio. Eu lembro disso porque eu mesmo trabalhei consertando esse bug em 1999, mas isso pode ser história pra outro dia. De qualquer forma as empresas baseadas em Mainframe analisaram a possibilidade de implementar SAP. Já que ia precisar lidar com o tal Bug do Milênio já aproveita pra substituir o legado por SAP.</p>
<p>Mas aí começou um empurra-empurra entre a então SAP AG da Alemanha e a Origin pra investir na localização Brasil. Ou seja extrair o que se tinha na Philips como um conjunto reusável de templates e customizações para ser o scaffold pra novas instalações. Vou mencionar localização depois mas entenda que isso não é uma coisa barata de fazer. Com esse impasse as multinacionais ameaçaram desistir da SAP, o que forçou a SAP a abrir a SAP Brasil e colocar a Origin de escanteio.</p>
<p>Durante a virada do século, eu vi uma das grandes transições da SAP, do mundo client/server para integrar tecnologias Web. Esse era um dos meus trabalhos. Na minha época estávamos no R/3 versão 4.6c.</p>
<p>Eu costumo explicar o R/3 da seguinte forma: comece imaginando uma máquina virtual, como um JVM. Essa camada parasita e se sobrepõe ao sistema operacional e também ao banco de dados relacional por baixo, como Oracle, DB/2 ou SQL Server. 99% dos consultores não sabem se é um UNIX ou um Windows ou o que rodando, eles só viam o R/3.</p>
<p>Essa máquina virtual é tão completa que ela abstrai o banco de dados relacional inteiro, incluindo a linguagem de acesso, permissões, schemas, dicionário de dados, e todas as ferramentas de administração. Essa é a camada que chamávamos de &ldquo;Basis&rdquo;, em linguajar do mercado o cara de Basis costuma ser tipo o sysadmin ou devops nos dias de hoje. E você acha que já viu banco de dados grande? Não, na minha época uma instalação padrão já pré-configurava mais de 40 mil tabelas (acho que hoje já é dobro disso).</p>
<p>Pense tabelas cujos nomes são acrônimos de palavras em alemão, então você tem tabelas como VBAK e VBAP pra cabeçalho de ordem de venda e ítens. Você em BUKRS pra código de empresa. Ou LIFNR pra fornecedor e assim por diante. Depois de algum tempo você decora muitos acrônimos, é bizarro que mais de 10 anos depois eu ainda lembro de muitos de cabeça.</p>
<p>Os acrônimos originalmente deveriam ser curtos: 4 caracteres para tabelas e 5 caracteres para nomes dos campos, tudo isto para economizar espaço em memória e banco de dados, afinal de contas em 1997 em pleno boom de SAP R/3 o processador mais top na época é um Pentium-II, sistemas unix mais fortes rodavam em 32 bits.</p>
<p>Na minha época havia o minisap que era só a camada Basis com as ferramentas de ABAP mas sem os módulos funcionais. Era mais pros sysadmin e devs poderem ter um sandbox pra brincar e treinar. Ainda existem versões mais novas disponíveis no SAP Trials, acessivel pra quem tem conta na SCN a SAP Community Network, qualquer pessoa pode-se increver, vou explicar isso mais abaixo. Mas pra entender, sem os módulos funcionais, ainda assim pesa nada menos que 15GB pra baixar e precisa de no mínimo 4GB de RAM e 100GB de HD pra instalação. ??? Existem algumas versões alternativas que podem ser instaladas via docker, mas ainda precisam do mesmo espaço → bizarro</p>
<p>Sobre essa máquina virtual roda uma linguagem proprietária chamada ABAP que é um acrônimo em alemão absurdo que significa &ldquo;general report creation processor&rdquo; ou processador de criação de relatório gerais. Ou seja, em muitos aspectos não é muito diferente de um PL/SQL da Oracle ou T-SQL do SQL Server, mas como linguagem ela é bem mais completa e hoje em dia tem recursos como orientação a objetos.</p>
<p>Como gerador de relatórios e também de formulários existe ainda o SAP GUI que é um cliente burro. Via ABAP eu posso construir telas e o que é mandado para o client são as instruções de como desenhar essa tela. Do lado cliente não roda nenhuma lógica de negócio, só lógica de apresentação. Você usa um derivado desse conceito todo dia: o navegador web, que é só um cliente burro que não roda nada e recebe instruções pra desenhar a tela. Pelo menos era assim até embutirem tanto Javascript … enfim, o SAP GUI é o navegador.</p>
<p>(telas)
Por exemplo, esta é a tela de Login, o SAP Logon, vc pode cadastrar login pra vários SAP.
Aqui você ver o Easy Access, os menus pra acessar os programas ou transações, mas na prática ninguém usa isso, todo mundo sabe o código da transação e digita direto. E código de transação é um acrônimo em alemão, SE80 por exemplo é o Object Explorer.</p>
<p>Sobre esse runtime você tem as ferramentas de desenvolvimento, o ABAP Workbench que é o conjunto de ferramentas como editor, dicionário de dados, painter de tela e tudo mais, que é como se fosse seu Visual Studio ou Eclipse de hoje. Falando em Eclipse existe até o ADT que é o ABAP Development Tools que são plugins pro Eclipse, pouca gente usa, por incompatibilidade de servidores, funcionalidades ou por serem reacionários a mudanças e além de demandar uma curva de aprendizado..</p>
<p>Como mencionei antes, os programas são chamados por transações no SAP, o mesmo conceito de shortcuts do windows. E pra mim a coisa mais importante nessa infraestrutura é o Dicionário de Dados (tela) que contém todos os metadados do sistema que você acessa via o Object Navigator ou transaction SE80. Todas as transações são identificadas por um código como esse, é tipo a URL pros programas.</p>
<p>Vou tentar resumir bastante agora, mas por exemplo, no dicionário você tem tabelas. Mas você lembra que eu falei que o Basis abstrai o banco por baixo? Uma tabela em ABAP é uma representação 1 pra 1 com uma tabela no banco se ela for uma tabela que chamamos de &ldquo;transparente&rdquo; mas existem &ldquo;pools&rdquo; que são entidades independentes no dicionário mas agrupados em tabelas físicas maiores ou &ldquo;pools&rdquo; no nível do banco de dados. Você tem cluster tables que são fisicamente agrupadas em clusters baseados em suas chaves primárias, são alternativas para limitações de banco de dados, por exemplo, um tamanho de registro maximo ou de número de campos. Os dados de um registro lógico é guardado em mais do que uma linha no banco de dados, fora as chaves os demais campos ficam serializados em um campo raw. Obviamente com o pior conceito de performance, mas de novo, fica transparente para o workbench de abap o mesmo select. O trade-off para isto é a criação de tabelas secundárias particionadas. não lembro se na prática funcionam como views materializadas em bancos como postgresql.</p>
<p>Mais interessante são os Domains, que armazenam o registro dos elementos de dados. Acho muito engraçado que muito pouca gente sabe que qualquer banco de dados relacional que se preza tem coisas como User-defined types ou custom types. Por exemplo, se eu falo vamos representar um preço numa tabela, a primeira coisa que um programador pensa é: vou criar um campo FLOAT ou INT. No SAP você tem um tipo chamado PRICE e toda tabela que precisa de preço vai ter o tipo PRICE e ponto. Se amanhã o tipo primitivo de PRICE mudar, ela muda pra todo o sistema replicando a alteração para todos os demais objetos dependentes.</p>
<p>Mais ainda, internamente no ABAP digamos que eu queira uma variável no programa pra armazenar o preço que eu puxo de uma tabela. Que tipo vai ser essa variável? Vai ser tipo PRICE, igual o que vem da tabela. E como ABAP compila tipo uma AST mas sua execução é dinâmica, se o tipo PRICE muda, não só as tabelas, mas os programas passam a usar o tipo novo, é plug and play assim. Você acha que já viu boas modelagens de dados, mas comparado com o que se tem numa instalação SAP, chega a ser primitivo como um hello world.</p>
<p>Sendo ainda mais específico, uma tabela tem campos, campos tem elementos de dados, elementos de dados tem domínios, e o domínio contém o tipo de dado para armazenamento de banco de dados, valores permitidos, rotinas de conversão. Por exemplo, o elemento Centro de Custo valor string &ldquo;1000&rdquo; é convertido pra &ldquo;0000001000&rdquo;</p>
<p>então se um usuário preencher &ldquo;0001000&rdquo; ou &ldquo;01000&rdquo;</p>
<p>vai ser tudo reduzido a exatamente o mesmo valor. Então o elemento de dados já traz embutido não só o tipo primitivo mas regras como validação, conversão e inclusive a internacionalização do nome. Basta você falar que o campo é determinado domínio e ele já herda tudo.</p>
<p>Uma aplicação prática:
Um campo pro exemplos, o domínio email: os espaços no início e no fim são suprimidos, o campo é convertido para minúsculo, implementa-se uma regra de validação tipo regex em ABAP e um tamanho máximo.
Qualquer campo que seja exibido na tela do usuário já irá implementar todas estas regras.
Caso um dia o campo precise ser ampliado ou implementar uma regra do tipo @exemplo.com não é mais permitido, TODAS as referências utilizadas são automaticamente herdadas sem a necessidade de search, copy &amp; paste, etc.</p>
<p>&mdash;&gt; Foi o primeiro tapa na minha cara, onde eu aprendi que dar manutenção em programas é muito mais difícil do que escrever programas. E a SAP criou um fluxo de trabalho extremamente eficiente. Permitindo um código base existir e evoluir por quase meio século.</p>
<p>Eu falei de localização antes, e aqui entra domínios e elementos de dados de novo.
Pra quem acha que localização é só traduzir texto na verdade estamos falando de todos os cenários e regras de negócio particulares de um país para atender as necessidades fiscais e contábeis, por exemplo livros fiscais, cálculo e contabilização de impostos, retenção de impostos, obrigações acessórias como SPED contábil, contribuições, REINF, além de cálculo de folha de pagamentos e outras regras derivadas de CLT por exemplo.</p>
<p>Como eu disse que existe essa abstração de elemento de dados, num designer de tela, como você veria num Visual Basic, você não precisa arrastar um Label, editar o texto e daí arrastar um campo de texto e criar as validações. Você arrasta o elemento de dados inteiro e ele já vem certinho o texto internacionalizado, o tipo de campo de input correto e todas as validações e regras de negócio relacionados. É um nível acima do que você imagina como Rapid Application Development ou RAD que um Visual Basic ou Delphi nunca atingiram.</p>
<p>Pois é, lembra que eu falei que nomes de tabelas e campos no banco são tudo acrônimos em alemão? Não em importância porque graças aos elementos de dados no dicionário, cada campo além de tudo tem as traduções nas diversas línguas suportadas, então todas as telas traduzem automaticamente também.</p>
<p>Eu acho interessante porque se você começar a olhar todos os componentes em detalhes, é absolutamente surpreendente que um sistema como esse existe, e faz você, enquanto programador, enxergar o quanto nós somos ruins. Por exemplo, um programador amador, se precisasse fazer um sistema de vendas, começaria pensando um troço besta como uma tabela de produtos, que tem campos como código do produto, nome, quantidade e preço.</p>
<p>Esse é obviamente o jeito idiota de se fazer. Se você for um pouco mais avançado, vai pensar em variante de produtos, SKUs e modificadores de preço como descontos, preço de campanha.</p>
<p>Mas se você for no módulo de vendas do SAP, o famoso SD, você vai ter um sistema de precificação que é uma matriz multidimensional programática que leva em conta as variantes todas (que por si só são outras matrizes) e todos os aspectos geográficos, como setor de atividade, centro de distribuição, e tantos outros parâmetros que modificam desde custo até imposto que vai na composição dos preços. Um produto na verdade são N produtos que custam M preços diferentes dependente de quem faz o pedido, pra onde entrega, como foi manufaturado ou comprado, onde está armazenado, em que cidade, em que estado, de que país.</p>
<p>Eu tive a oportunidade de lidar com diversos módulos do R/3, incluindo sales and distribution ou SD, materials management ou MM, projects ou PS, financials ou FI, human resources ou HR. Como eu disse, eu não era um consultor funcional, eu era um integrador, principalmente pra sistemas Web. O R/3 tinha o equivalente a RPC pra integração ou Remote Procedure Calls, se você for de Java pense em algo como RMI ou Remote Method Invocation, pense a época de DCOM, COM+ ou CORBA. Tudo tecnologia pré-JSON-RPC que temos hoje em Web.</p>
<p>Na minha época, a SAP começou a tentar modernizar tudo pra Web, seguindo a tendência do mundo Java. A SAP compra muitas empresas o tempo todo, o portfólio de aquisição deles é enorme. Uma das empresas foi a In-Q-My de outra figura que ficou muito famosa na época, o Shai Agassi, empreendedor israelense. Muito antes de Elon Musk era Shai Agassi que estava iniciando a tendência de carros elétricos com sua empresa Better Place, que desenvolvia baterias pra carros elétricos e foi fundada em 2007, faliu em 2013, mas pense que foi tipo um pré-Tesla. Acho que meio por isso eu também não fiquei muito surpreso com um Elon Musk tendo conhecido Shai Agassi antes. Com a aquisição ele virou presidente de produtos da SAP e foi um forte candidato a suceder Henning Kagermann como CEO em 2007. Mas nessa batalha o Kagermann se estendeu como CEO até 2009 e Agassi renunciou.</p>
<p>Sob a liderança de Agassi surgiu a plataforma SAP NetWeaver, um pacote complementar ao ERP R/3, que adicionava componentes Web ao legado corporativo. Isso incluiu pacotes como o SAP Enterprise Portals, que foi onde eu me certifiquei e virei especialista. Era um conjunto de aplicações J2EE que rodava no servidor de aplicações da In-Q-My. Diversos outros produtos foram saindo nessa época, os xApps, o Exchange Infrastruture ou XI que era o sistema de filas, a versão menor do ERP pra empresas menores que foi o Business One e muito mais. Foi uma pequena revolução e todo mundo ficava confuso porque era o mundo legado recebendo a porrada do mundo Web. E exatamente nesse momento um cara como eu, que era de Web e aprendendo o legado, virei mosca branca.</p>
<p>Nessa época estávamos entrando na versão 4.7 do R/3. Quando eu estava saindo do mundo SAP eles estavam mudando o nome do produto principal de ERP de novo. De R/3 passou a ser ECC ou Enterprise Core Components. Então hoje em dia você não ouve mais falar de R/3 e sim de ECC.</p>
<p>Além disso eu falei que o Hasso Platner e o Larry Ellison não se bicam, mas uma das combinações mais fortes do mundo Enterprise sempre foi o R/3 rodando com banco de dados Oracle. Era bem bizarro, é meio como é hoje os iPhones da Apple usando telas OLED da Samsung embora eles sejam concorrentes. Hoje o cliente que gerar maior receita de banco de dados oracle no mundo é a própria SAP, que vende sua licença SAP adicionada do custo de licenciamento que é repassado para a Oracle. Houve uma litígio jurídico entre ambas sobre o valor do repasse, a primeira sentença foi de 1,3 Bilhões de USD.</p>
<p>O começo da sua história a SAP não lidou com bancos próprios, sendo como princípio fundamental multiplataforma e multi-banco. Para mitigar esta dependência uma das alternativas foi o famoso ADABAS D, que eles liberaram como open source com licença GPL no ano 2000. Em 2003 a SAP AG e a MySQL AB se uniram e lançaram um novo banco próprio pra SAP chamado de MaxDB. A MySQL saiu da jogada depois de alguns anos e a SAP continuou sozinha com o MaxDB que hoje é closed source. Para “controlar” a dependência sobre o sistema operacional a SAP é uma das acionistas da(o) Suse. Hoje o caminho da SAP é todo direcionado para o SAP HANA que é o novo banco de dados que roda como núcleo dos produtos de inteligência da SAP, é como se fosse um mantra ou uma lavagem celebral, tudo hoje na SAP gira em torno do Hana.</p>
<p>SAP HANA é um produto que vale a pena dar uma olhada, em resumo ele é um banco de dados in-memory (pensa um Redis), orientado a colunas (pensa um Cassandra) e com duas coisas absolutamente importantes: suporte a OLTP e OLAP.
OLTP pense em transações de bancos relacionais: a integridade dos dados é absolutamente importante num sistema enterprise.
E OLAP é a parte analítica, que é suporte a análise multi-dimensional, que é o caso pra Big Data, Data Mining, Data Warehouse. Se você nunca ouviu falar em dimensões, modelo estrela, cubos, não sabe o que é análise de dados ainda. Você acha que com uma mísera query SQL vai conseguir chegar de forma eficiente nos dados de uma multinacional tipo uma Nestlé e agregar os resultados de vendas de todos os países do mundo de uma só vez? Com capacidade de dar drill down do faturamento anual da marca e ir descendo - drill down - até chegar no faturamento de uma loja? Pensa no que significa esse tipo de query, e agora pensa centenas delas pra ter a visão do MUNDO de uma multinacional. Quando virar data scientist não era hipster como é hoje, já se lidava com Big Data em multinacionais.</p>
<p>O S/4 HANA é o primeiro re-code da SAP. Onde o antiquado, combalido mas ativo e forte cinquentão R/3 e suas repaginações segue finalmente para o caminho de legado.
O trocadilho S/4 é proposital da evolução do R para S e do 3 para 4.</p>
<p>Por muitos anos os sistemas SAP foram especializados em lidar com grande quantidade de transações. Vendas, compras, contratos, projetos, manufatura, etc. Onde a prioridade foi funcionalidade com o tradeoff de performance.  Agora que as empresas que implementaram tem essa quantidade massiva de dados, o foco tem sido em tornar esse dados inteligentes. Já que tem todos os dados vitais de uma empresa, porque o sistema já não pode tomar muitas decisões estratégicas? Daí entra o HANA ligado a diversos outros produtos como o TREX o próprio Hadoop e assim por diante.</p>
<p>Voltando a falar do mercado nacional, eu lembro que quando comecei no mercado SAP o mercado top tier era altamente concentrado no que chamávamos de Big Five. Pra explicar, haviam as grandes consultorias de renome que eram quem conseguia fechar contratos gigantes como Petrobrás, Vale. E existiam as quarteirizadas menores como onde eu trabalhava que prestavam serviço via essas grandes. No começo do século as Big Five eram IBM, Arthur Andersen, Price WaterhouseCoopers, Ernst &amp; Young e KPMG.</p>
<p>Mas não demorou muito e a parte de consultoria Arthur Andersen virou Accenture, a Price foi comprada pela IBM, a Ernst &amp; Young foi comprada pela Capgemini. No fim as Big 5 foram consolidadas mais ainda em Big 3.</p>
<p>Digamos que você quer se tornar um consultor, o que fazer? Você precisa passar pela academia, são os cursos de certificação licenciados pela SAP. Existem dois motivos de porque você não tem como ser autodidata no mundo SAP. Primeiro, tenta ir no Google, você não vai achar nada de muito útil online. Toda a base de conhecimento da SAP é fechada, só consultores certificados tem acesso a essa base. Existe tipo uma Deep Web da SAP que ninguém tem acesso, que é a SCN que mencionei no começo.</p>
<p>Fora isso pra acessar essa base e também pra conseguir acessar o sistema das empresas, você tem um SAP ID que é seu RG de consultor e é reconhecido mundialmente e cadastrado na SAP da Alemanha. Sem isso você não tem autorização pra atuar como consultor. Parece que diminuiu um pouco a dificuldade, antes você precisava fazer a academia, hoje tem um tal de Certification Day. Fragmentou um pouco o conceito de academias e bootcamps, hoje tem mais cursos não-oficiais pra assuntos específicos. A época de ouro da SAP no Brasil foi do meio dos anos 90 até o começo dos 2000 eu acho, quando as taxa hora eram exorbitantes. Mas até esse mercado se comoditizou um pouco hoje em dia, mas a exclusividade ainda garante boas taxas.</p>
<p>A certificação é do consultor, e ligado à consultoria que pagou pelo curso ou prova. E são cursos caros. Na minha época acho que uma academia era na casa dos 10 ou 20 mil reais. Pra consultoria isso é importante porque ela precisa de um número mínimo de consultores ligados ao seu CNPJ. Se o consultor trocar de consultoria ele precisa pedir a transferência. É uma burocracia da SAP que ainda mantém um certo controle de como organiza seu mercado. É meio parecido com o que a Microsoft tem com seus MCPs ou MCSEs.</p>
<p>Em começo de carreira o melhor é iniciar como trainee de uma das Big que mencionei, entrar no programa da IBM, Accenture, Deloitte, Capgemini e outras. Elas são pouco divulgadas então tem que cavar um pouco. E não é só pra programadores, na verdade os consultores funcionais são especializados em cada módulo de negócio. Um contador pode virar consultor do módulo financeiro, alguém que se formou em direito trabalhista pode trabalhar no módulo de HR, por exemplo.</p>
<p>Outro ponto que eu achava interessante antigamente era o que a gente coloquialmente chamava de Z/3. Uma das convenções de programação é que tudo que você desenvolvia em ABAP que não era standard a gente começava o nome com Y ou Z, muito mais Z. E um dos principais problemas de consultorias ruins é que em vez de resolver os problemas do jeito certo, via customização dos módulos funcionais, eles resolvem fazer via força-bruta, basicamente um copy e paste de uma transação que já existe em um Z pra mudar duas linhas. Que nem antigamente quem fazia web tosco tinha index.php e index2.php ou coisas assim.</p>
<p>Faça isso por muito tempo e você basicamente perde a habilidade de conseguir fazer upgrade do sistema porque as transações originais vão ser atualizadas, mas as cópias Z vão ficar pra trás. Então se formou um mercado paralelo pra dar manutenção nesses malditos Z/3. E você acha que só empresa pequena que faz isso, não empresas grandes fazem Z demais também. Eu vi vários.</p>
<p>Pra evitar esse cenários, depois da minha época a SAP inventou uma forma melhor pra estender os programas padrão sem ter que clonar em Zs, e isso é chamado de SAP Fiori ou SAP na Web. Eu mesmo ainda não vi como isso funciona, mas deve ajudar a evitar as dores de cabeça de manter um Z/3.</p>
<p>E falando em suporte, um dos grandes mercados pra consultorias de SAP ou Oracle é a parte de suporte. Eles vendem horas de suporte pra grandes empresas. Na minha época não tinha mas agora tem opções como a Rimini Street.</p>
<p>Fazer tudo by the book custa caro. Mas na prática não existe nenhuma trava de funcionamento do sistema, como chave de ativação ou algo assim. E mesmo que tivesse daria pra bypassar porque o código fonte do sistema em ABAP vem no sistema, ele é modificável. Mas só isso não é suficiente, sem o suporte da SAP seu sistema deteriora.</p>
<p>Mas em vez de pagar os 22% de valor de aquisição da licença pra efeito de manutenção muitas empresas optam por não evoluir o SAP, porque os processos em si ficam estáveis e não mudam tanto. Os demais gaps de desenvolvimento eles contratam de suporte alternativo, literalmente mercado negro mesmo. Fica a cargo de empresas como a Remini Street manutenções desse tipo.</p>
<p>Durante minha carreira enterprise eu passei por diversas empresas diferentes. Eu mencionei como ganhei o projeto de SAP Enterprise Portals na Suzano Papel e Celulose no meu vídeo de O que Estudar, mas além disso eu passei quarteirizado por consultorias como Atos Origin, e participei do projeto de merge de telecoms que gerou a Vivo, depois o merge que gerou a Claro, Ultrafértil Fosfértil, C&amp;A, Copersucar, ESAB, Embratel, e outras.</p>
<p>Apesar de ter sido um dos períodos mais estressantes foi também um dos mais interessantes. O trabalho era longe de ser glamuroso. Absolutamente longe de qualquer ideal de tech startup que você já tenha visto, na verdade acho que o total oposto. Não tem hora. Não tem lugar. Uma vez eu estava na Atos Origin falando de não sei que projeto e literalmente numa conversa de bebedouro troquei idéia com um gerente de não sei aonde, e ele falou de um problema que estava tendo no módulo de viagens na instalação da Embratel e, por acaso, eu tinha uma suspeita do que podia ser o problema. Ele disse que ninguém estava conseguindo resolver e quando falei da minha suspeita ele só disse: “porra, você pode ir pro Rio amanhã?” E assim eu fui pro Rio, passei 3 dias e resolvi o problema.</p>
<p>Só pra entender qual era o problema, uma transação SAP tem tela gráfica. Mas ela pode rodar headless. Pensa como rodamos hoje um Selenium, Capybara, com o Chrome headless. Mesma coisa. Eles chamam isso de Job, que roda em background. Agora imagina se uma tela headless de repente sobe um dialog box que não tem como dar cancel, daí obviamente o Job trava. Ninguém parou pra pensar nisso, daí eu achei onde abria dialog, não lembro se fiz algum ABAP uma exit ou algo assim pra tirar o dialog e aí tudo voltou a passar.</p>
<p>Um bom consultor, por definição, tem que pensar fora da caixa, como eu disse, nós temos menos tempo e menos recursos que todo mundo que tentou resolver antes da gente. Por isso que quando um consultor mosca branca troca de consultoria até o cliente tende a mudar de consultoria se precisar pra não perder o consultor. Nas consultorias menores, o consultor é mais importante do que a a consultoria. Isso eu sempre achei legal. Por outro lado gente que reclama demais nunca vai ser um solucionador de problemas - óbvio porque claramente gasta mais tempo reclamando que resolvendo - e, portanto, nunca será consultor porque nós éramos a elite, a swat, os navy seals, quando nos chamam é porque a casa já caiu. Quer trabalho facinho, vai trabalhar em fábrica.</p>
<p>Mas, uma coisa é certa, nenhum programador tem como saber as regras de negócio de grandes empresas sem ter passado por elas, de preferência por várias delas. Eu não sou especialista, mas ter tido a oportunidade de lidar com áreas completamente diferentes como vendas, recursos humanos, financeiro, manufatura, logística, controladoria, me deu uma visão de estrutura de empresas que nenhum MBA, e obviamente, nenhum evento ou workshop ou mentoria de startup jamais vai conseguir dar pra ninguém. Você precisa ter sofrido o mundo enterprise pra entender o mundo enterprise, é impossível saber disso de outra forma.</p>
<p>Como tangente eu acho engraçado quando o recém-formado ou mesmo drop-out “acha” que vai revolucionar qualquer coisa. Não vai. É uma loteria, é sorte, 1 em milhares. A razão é simples: o moleque chega e diz “vou revolucionar o mercado médico”, aí eu pergunto, beleza, quanto tempo você trabalhou na medicina? Em que especialidades? Em quantos hospitais? E ele fala “nunca fui médico”. Eu só balanço a cabeça e mando embora. Nem os próprios médicos entendem o sistema onde eles mesmos trabalham, estando dentro. Ou você tem um sócio médico que compreende os processos, ou esquece.</p>
<p>E não tente se comparar com os grandes. Você não é o Reid Hoffman. Você não é o Jack Ma. Você não é o Elon Musk nem o Shai Agassi. É um absurdo querer se comparar com eles.</p>
<p>Muitos dos processos que eu apliquei nas empresas seguintes que trabalhei, incluindo na minha própria, são derivados do que eu aprendi no mundo SAP. As partes boas eu trouxe, as que eu vi na prática que não funcionavam eu mudei, mas não saiu a idéia do zero da minha cabeça. Foram anos e anos tentando de tudo, falhando, aprendendo porque falhou e tentando de novo. E eu tive a oportunidade de fazer isso em grandes empresas. E mesmo com tudo isso quando comecei minha própria empresa tive problemas. Imagine você começar do absoluto zero e no risco? É como dizer “vou atravessar o Atlântico de caiaque, mas nem sei nadar ainda”. Minha cabeça explode ouvindo estupidez desse nível.</p>
<p>O mundo SAP serviu pra amadurecer minha visão de negócios, corporações e o mercado como um todo, uma nova dimensão que um programador recebendo ordem de serviço numa fábrica jamais vai ter. Minha recomendação é que se você tiver a oportunidade, tente, não vai perder nada. Se eu pudesse voltar no tempo será que eu passaria por todo esse stress de novo? Com certeza!</p>
<p>E é isso aí, hoje foi uma pincelada muito rápida no que eu aprendi em 5 anos nesse mercado, não dá pra detalhar tudo mas acho que isso deve dar uma visão geral, pelo menos uma visão geral segundo o que eu experimentei, tem muito mais que nem eu sei ainda. E vocês, já tiveram experiência no grande mercado enterprise? Compartilhem suas experiências nos comentários abaixo. Se curtiu mandem um joinha, compartilhem o vídeo, assine o canal e clique no sininho. A gente se vê, até mais.</p>
]]></content:encoded><category>negocios</category><category>arquitetura-de-software</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #24 - Sua Linguagem É Especial? Parte 1 em 2001</title><link>https://akitaonrails.github.io/2018/11/06/akitando-24-sua-linguagem-e-especial-parte-1-em-2001/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/11/06/akitando-24-sua-linguagem-e-especial-parte-1-em-2001/</guid><pubDate>Tue, 06 Nov 2018 17:00:00 -0200</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/NwAvovzHRDU"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Muito bem, na série &amp;ldquo;Sua Linguagem NÃO é especial&amp;rdquo; expliquei porque tudo que você acha que é diferente e moderno na sua linguagem já existia décadas atrás.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/NwAvovzHRDU"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Muito bem, na série &ldquo;Sua Linguagem NÃO é especial&rdquo; expliquei porque tudo que você acha que é diferente e moderno na sua linguagem já existia décadas atrás.</p>
<p>MAS, isso dito, nesta nova série eu quero explorar um pouco o outro lado: ninguém disse que você não pode gostar da sua linguagem e, mais importante, dominá-la até o fim.</p>
<p>Veja o que eu fazia quando estava no começo da minha carreira e compare com o que você faz hoje em dia.</p>
<p>Correção: Colo Colo é do Chile, eu falei errado no vídeo. Sorry.</p>
<p>Links de referência:</p>
<ul>
<li>ASP WebForms (<a href="https://github.com/akitaonrails/ASP_Classic_WebForm"target="_blank" rel="noopener">https://github.com/akitaonrails/ASP_Classic_WebForm</a>)</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sua Linguagem É Especial! Parte 1</p>
<p>Se você assistiu meus 2 vídeos intitulados &ldquo;Sua Linguagem NÃO É Especial&rdquo; que conta como muitas das funcionalidades que você achava que só sua linguagem tinha e que eram coisas modernas na verdade vem de linguagens de 30, 40 ou 50 anos atrás.</p>
<p>Dependendo de como você assistir talvez alguns me interpretem sendo meio niilista. Pode parecer que eu estou dizendo pra não se importar com as linguagens que você gosta. Ou não gostar de nenhuma linguagem.</p>
<p>Na verdade sua linguagem favorita É especial mesmo ela NÃO sendo especial.</p>
<p>(&hellip;)</p>
<p>Se você ficou confuso, lembre de qual era meu ponto nos vídeos anteriores: você não é definido pela sua linguagem.</p>
<p>Muita gente coloca suas linguagens e ferramentas num pedestal e agem até defensivamente, querendo esconder, minimizar ou desconversar até as falhas óbvias da sua linguagem ou ferramenta. “Ah, mas a outra linguagem também é ruim em X ou Y”.</p>
<p>Eu sou promíscuo. Eu Não tenho afiliações, eu não tenho lealdade de marcas - eu não sou patrocinado, porque eu defenderia com unhas e dentes, de graça, uma marca que não é minha? -, eu não devo nada a nenhuma empresa. Elas é que devem pra mim e precisam me convencer a usar. Nada que você usa de graça hoje é de graça, lembre-se, se você Não está pagando, o produto é você. Esse é o conceito de freemium.</p>
<p>Além disso existe outra verdade fundamental sobre tecnologia: ela se torna obsoleta muito fácil. Tenho pena de quem era evangelista de Blackberry, já pensou? Ou os tempos difíceis de ser um evangelista de Perl hoje? Onde estão os evangelistas de Solaris? Deve ser sofrido tentar defender o Delphi hoje.</p>
<p>Eu não. Meu maior prazer é aprender, mas muito mais dominar, e dissecar todas as coisas que eu gosto. E jogar fora no minuto em que não me servem mais. Porque alguém acharia útil limitar o alcance do próprio conhecimento e experiência?</p>
<p>A melhor coisa que você pode fazer pra sua carreira é não tomar lado, nunca ter uma posição. No minuto que você faz isso, você se torna vulnerável. Mantenha sua opções abertas. Você sabe que está vulnerável quando alguém fala alguma coisa ruim da sua ferramenta favorita e você se sente ofendido. Se sentir ofendido é uma opção.</p>
<p>Existe uma observação empírica chamada Difusão de Inovação, que é o gráfico de adoção de alguma inovação.</p>
<p>Só vale a pena ser um evangelista se você está entre os Early Adopters e Early Majority. Você não quer ser um evangelista na fase de Late Majority ou Laggard. Defender Delphi hoje é ser um Laggard. Defender iOS em 2007 é Early Adopter. Em 2011 já é Late Majority. Quanto mais no fim dessa curva, menos seu conhecimento tem valor. Entenda que valor de conhecimento é inversamente proporcional à adoção.</p>
<p>Isso dito, deixa eu voltar ao ponto: sua linguagem é especial. Claro que é, como eu mostrei nos vídeos anteriores, é o resultado de uma longa linhagem de linguagens e pesquisas anteriores que culminaram de alguma forma no que você está usando hoje.</p>
<p>O erro é achar que ela vai continuar sendo o estado da arte pra sempre. Claro que não. Em breve seja lá qual linguagem você está usando vai se tornar o próximo Cobol ou Smalltalk.</p>
<p>Neste vídeo e no próximo quero contar duas histórias que aconteceram comigo quando eu tinha 24 anos, pra dar uma perspectiva pra vocês que estão nessa mesma faixa agora.</p>
<p>Se você está no começo de carreira, digamos que você usou Express, ou Django, ou Laravel, ou Rails. Você já não sentiu vontade de escrever seu próprio framework? Claro que sim, todo mundo já passou por isso.</p>
<p>Em 2001, dentre outras coisas, acho que já tinha uns 2 anos que eu usava ASP. Não o ASP.NET, o ASP clássico mesmo. Eu estava trabalhando numa ponto com, a Panamerican Sports Network, ou PSN. Ela fazia parte do grupo Hicks Muse Tate and Furst. Era dona de diversas equipes esportivas na América Latina como Cruzeiro, Corinthians, Figueirense, Colo colo da Colombia, Tigres e Chivas-Rajadas do Mexico, patrocinava o Alan Prost na Formula 1, tinha contratado o Pelé pra um programa de TV - eu lembro de ter ido na festa de lançamento - e no meu escritório em SP que tinha basicamente jornalistas, eles tinham lá colunistas como Sócrates e o Marcelo Fromer.
Eu falei, a bolha das ponto coms era absurda em torneira aberta de dinheiro.</p>
<p>Eu trabalhava na construção de todos esses sites com uma equipe que ficava na Flórida e alguns outros espalhados em outros países como Argentina, e acho que Venezuela. Nesse meio do caminho, a Microsoft estava se preparando pra atacar a dominância do Java. Eu estava muito empolgado com o lançamento do .NET na época. Mas ainda era meio beta. E naquela época as coisas não saíam tão rápido quanto saem hoje em dia.</p>
<p>O ASP que hoje chamamos de clássico, na época era o padrão de fato e de direito. Ele não iria embora por alguns anos ainda mesmo com o .NET. O .NET pra web tinha um framework novo, o ASP.NET Web Forms.</p>
<p>Comparado com o que se tinha no ASP clássico, PHP e o JSP da época, era uma evolução significativa. Em resumo, tinha 2 coisas que eu gostei, na época. A primeira era o próprio Web Forms. Em resumo, ele mantinha uma estrutura de dados que representava o estado da página e toda vez que você dava um POST ele mandava esse estado de volta pro servidor. O Estado ficava num campo hidden escondido no form encodado em Base64. Então a gente manipulava o estado nos callbacks como se fossem atributos num objeto que era serializado e desserializado entre o HTML e o C# e o Web Forms renderizava o HTML e conservava o estado escondido.</p>
<p>Isso era um Page Controller que já é um pattern ultrapassado, isso é pré adoção do modelo MVC que tínhamos no Java no framework Struts, lançado só alguns meses antes, e que era muito melhor. Mas pra quem era de ASP puro, o Page Controller já era um patttern bacana.</p>
<p>A segunda coisa era a idéia de manter sessões em banco de dados. O ASP puro mantinha sessões de usuários em memória. O problema é se você queria escalar horizontalmente. Agora se o load balancer mandasse o usuário pra um servidor diferente, ele perdia a sessão. Então você era obrigado a configurar o load balancer pra usar uma coisa chamada session affinity que fazia o mesmo usuário sempre cair no mesmo servidor pra manter a sessão. Isso era bem ruim na verdade.</p>
<p>No ASP.Net você podia escolher StateServer e com isso manter a sessão no banco de dados, daí podia escalar horizontalmente mais fácil. Isso foi antes de inventarmos o termo “arquitetura shared-nothing”.</p>
<p>O que eu resolvi fazer? Um framework em ASP puro que fazia essas duas coisas. Dá uma olhada. (puxa)</p>
<p>Eu basicamente criei classes pra cada elemento de um form pra representar no lado do servidor. Coloquei coisas que o ASP não tinha nativo como MD5 e Base64.</p>
<p>Eu tinha uma classe que representava uma Page (já que o pattern é o Page Controller onde cada página HTML tinha um controller no back end).</p>
<p>Eu fiz uma classe de Session que eu chamei de SessionPlus pra substituir o Session in memory do ASP por um que gravava em banco.</p>
<p>Eu fiz uma classe pra encapsular até o gerenciamento de upload de arquivos. Antes a gente lidava direto com o blob que vinha num form multipart.</p>
<p>Eu já tinha até o conceito de Validators, eu tinha classes ValidatorRequired que é como o validates presence de um ActiveRecord do Rails e até um Validator Regex com patterns pré-configurados pra regex comuns.</p>
<p>Cada classe cuidava da renderização HTML de cada elemento segundo a parametrização e aí no HTML em si eu precisava colocar o mínimo possível pra posicionar os elementos.</p>
<p>Eu até quis fazer um sistema de challenge-response. Em vez de postar a senha do usuário no form, eu carregava um gerador de MD5 no lado do Javascript. <br>
Daí o framework quando renderizava o HTML do Form também colocava um challenge num campo hidden do form, meio como hoje a gente coloca um meta tag pra evitar cross site request forgery.
Daí antes de submeter o form eu fazia um md5 do usuário, senha e esse challenge, daí no servidor era só fazer o mesmo md5 e comparar, daí eu não trafegava a senha. Ah sim, era md5 porque na época ainda não sabíamos que md5 tinha defeitos, só depois passamos a usar sha1.</p>
<p>Não era um esquema muito sofisticado nem muito seguro na verdade, mas em 2001 meu conhecimento de segurança só ia até aí. Eu tinha programado jeitos de evitar um pouco o cross site, e também duplo post ou post back.</p>
<p>Tudo foi escrito em VBScript! … é eu sei &hellip; que era uma versão menor do Visual Basic 6. Mas eu fui um pouco além. Em vez de deixar esse código junto com o código da aplicação, eu aprendi que era possível encapsular VBScript num XML em formato WSC que era Windows Script Components. Ele funciona como um componente COM binário e eu podia instalar no servidor de aplicação COM+ Components que vinha carregado em todo Windows Server e expor método públicos como CreateInstance e aí eu podia instanciar os objetos no servidor COM+ e usar de uma página ASP.</p>
<p>Normalmente você precisaria usar C++ ou Visual Basic 6 pra fazer componentes COM. Não sei porque, parecia que quase ninguém usava VBScript pra fazer componentes. A falta que fazia um site como stackoverflow …. Pensa que não existia o conceito de um NPM ou Nugget o máximo que tínhamos em open source era CPAN pra Perl, mas em Windows, nada. Ah, e não existia Git e nem Subversion, e vou te dizer que CVS era um parto pra usar.</p>
<p>Eu vou dizer que, pra ser 17 anos atrás, até que não tá tão ruim. Em em PHP ou Perl ainda não tinha muito o conceito de um “web framework” como temos hoje. No Java mesmo tava começando isso.</p>
<p>Agora, a parte ruim? Eu gastei um tempão fazendo os sites do jeito “normal” macarrônico em ASP e em paralelo eu ficava tentando fazer esse framework. Mas quando eu terminei ele, a bolha da internet tava crasheando e no final eu acabei não usando esse framework em nada muito útil.</p>
<p>Eu estava usando VBScript e ASP pra fazer coisas que eles não foram feitos pra fazer. A linguagem em si era bastante limitante. Mas o ponto foi pra dizer que eu fiz tudo que era possível fazer e também tentei dobrar a linguagem além do que deveria.</p>
<p>Foram acho que uns 3 anos programando todo tipo de intranet, extranet, website e tudo mais com ASP. Isso foi no ápice já do Late Majority do mundo ASP na curva de adoção.</p>
<p>ASP Clássico ainda iria durar muito tempo, eu reencontraria projetos em ASP em 2003, 2004 até 2008 e 2009. Mas esse framework pra mim serviu pra demonstrar as limitações do ASP e eu sabia que não havia mais muito o que fazer. O que poderia ser feito já havia sido feito. Era hora de abandonar o navio e foi o que eu fui gradativamente fazendo ao longo de 2002 e 2003.</p>
<p>Mesmo ainda haveria mercado pelos próximos 10 anos, mas já eram os Late Majority começando a virar Laggard, pelo simples fato que a Microsoft já deu sinais de abandonar o ASP pra perseguir o ASP.NET e como ASP não era open source, era o fim da linha.. O crash da internet meio que me forçou a mudar de rumo de qualquer jeito e depois disso eu caí no mundo SAP e Java de cabeça, que é tema pra outro episódio.</p>
<p>Porque eu contei essa história? Porque não importa qual linguagem ou plataforma eu pegasse, eu tentava sempre encontrar os limites. Não só seguir os tutoriais, ou os padrões, mas quebrar os padrões. É o que todo programador open source meio que tenta fazer hoje em dia também. O maior problema é que quando você investe 3 ou 4 anos da sua vida estudando e treinando com afinco, quando você conhece cada detalhe da tecnologia, a zona de conforto é muito sedutor. Você já é o senior, o melhor da tecnologia, poucos sabem tanto quanto você sabe.</p>
<p>Eu tive a sorte de recomeçar como junior em outra plataforma e fazer tudo de novo. Os primeiros 15 anos da minha carreira acho que de 1991 até 2006 foram consecutivos reinícios. Eu fui tecnicamente junior a maior parte da minha carreira, porque eu ficava reiniciando em novas plataformas o tempo todo, só depois de 2008 eu comecei a me aceitar como “senior”. E não foi de propósito, eu disse que a bolha da internet foi um momento interessante. O pico e o crash aconteceram de uma só vez, mas os anos que se antecederam pra chegar na bolha já eram acelerado. Não é muito diferente de como é hoje.</p>
<p>Eu não conhecia o conceito ainda de curva de adoção, mas intuitivamente eu tinha a noção. Mas não foi perda de tempo. Todos os conceitos que eu pratiquei em detalhes fazendo o framework deste episódio serviram pra me ajudar a avaliar melhor os frameworks que vieram depois. O ASP clásico e VBScript morreram, mas os conceitos de gerenciamento de sessão, validadores de form, gerenciadores de upload, separação de lógica server-side e client-side, componentização, serialização de objetos, encoders e o básico de criptografia, continuam sendo conhecimentos válidos. E esses conceitos é só o que tem nesse mini-framework, mas no próximo episódio você vai ver uma coisa um pouco maior que eu fiz alguns meses antes desta história, vocês vão gostar.</p>
<p>Meu código de 2001, comparado com os padrões de hoje em dia, é bem ruim. Bem ruim mesmo. Mas se alguém tiver curiosidade, eu subi esse mini-framework no meu Github, coloquei o link na descrição do vídeo. Não deixem de comentar abaixo, conta pra gente você também já fez seu próprio framework? Se curtiram mandem um joinha, assinem o canal e clique no sininho.</p>
]]></content:encoded><category>desenvolvimento-web</category><category>arquitetura-de-software</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #16 - Sua Linguagem NÃO É Especial! (Parte 2)</title><link>https://akitaonrails.github.io/2018/10/04/akitando-16-sua-linguagem-nao-e-especial-parte-2/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/10/04/akitando-16-sua-linguagem-nao-e-especial-parte-2/</guid><pubDate>Thu, 04 Oct 2018 17:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/XcTTajFENHI"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Depois da semana geek, vamos &amp;ldquo;geekar&amp;rdquo; um pouco na programação também.&lt;/p&gt;
&lt;p&gt;Honestamente essa polarização em torno de linguagens de programação é super cansativa. A turma do funcional vs a turma dos objetos. A turma do javascript, a turma do Go.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/XcTTajFENHI"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Depois da semana geek, vamos &ldquo;geekar&rdquo; um pouco na programação também.</p>
<p>Honestamente essa polarização em torno de linguagens de programação é super cansativa. A turma do funcional vs a turma dos objetos. A turma do javascript, a turma do Go.</p>
<p>Enquanto isso, a grande maioria da população de programadores está aflita, sem saber pra onde correr. Quantas linguagens preciso aprender? 2? 6? 50???</p>
<p>Calma! Vamos começar a colocar ordem nessa bagunça. Hoje vou explicar como fazer isso e porque sua linguagem de programação favorita não é tão especial quanto você pensa!</p>
<p>Não deixe de assistir a Parte 1 antes!</p>
<ul>
<li>Genealogia (<a href="https://github.com/akitaonrails/computer_languages_genealogy_graphs"target="_blank" rel="noopener">https://github.com/akitaonrails/computer_languages_genealogy_graphs</a>)</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Vamos continuar a história que iniciei no episódio anterior. Se você Não assistiu clique no link acima e veja a parte 1, vamos lá, eu espero.</p>
<p>Já viu? Então vamos continuar nossa história das linguagens.</p>
<p>(..)</p>
<p>No episódio anterior falamos da linhagem de linguagens derivadas de ALGOL, que eu chamaria da linguagem A, mas existiu outra A.</p>
<p>Já que falamos em Fortran e linguagem B, existiu uma outra vertente que quis perseguir sintaxes diferentes de notação matemática para se adequar mais a processamento de dados de negócios. O time da famosa Grace Hopper foi um dos que perseguiu esse objetivo entre 1958 e 1959. Vocês devem estar se lembrando: Ahá sim, daí ela inventou o COBOL. BEEE Nope, ela inventou outra linguagem ANTES do COBOL que viria a ser a primeira linguagem focada em se expressar mais próximo do inglês, esse foi FLOW-MATIC também conhecido como B-0 ou Business Language versão 0. Achou B-0 um nome estranho? É porque antes disso Grace Hopper fez extensões pra uma linguagem chamada ARITH-MATIC ou A-2. e antes do A-2 tinha o A-1 e, claro o A-0 também escrito por Hopper, isso lá pra 1951. Então a linhagem completa começa em A-0, A-2, A-3 que são ARITH-MATIC, AT-3 que é MATH-MATIC e B-0 que é FLOW-MATIC antes do COBOL. Todas as anteriores que falei antes são de Hopper, o COBOL não é, ele é inspirado nos trabalhos anteriores de Hopper. Todo mundo decorou COBOL e Hopper mas ninguém nunca ouviu falar dessa história. Não só decorem, busquem as fontes!</p>
<p>Já que mencionei Java e C# muita gente acredita que Java que inventou orientação a objetos, garbage collector, tipagem forte. Bom, vocês já viram que no fim dos anos 50 você já tinha ALGOL, Pascal que tinham tipagem forte. Alguns de vocês talvez tenham ouvido falar da linguagem Simula de 1967 criada por Ole-Johan Dahl e Krysten Nygaard, também chamado de Simulation Language que foi quem introduziu os conceitos de objetos, classes, herança, sub classes, co-rotinas e também o garbage collector. Mas não foi o primeiro, garbage collector. Linguagens como Basic já tinham um tipo primitivo de garbage collector. Mas essa é a parte fácil. Quantos de vocês já ouviram falar numa linguagem chamada CLU?</p>
<p>E eu disse CLU, CE ELE U, só pra garantir. Essa linguagem foi criada no MIT em 1974 por ninguém menos que Barbara Liskov e seus alunos. Quem? Bom, se você é de Java ou C# ou já estudou Uncle Bob conhece o princípio SOLID de orientação a objetos. S de Single Responsability Principle, O de Open/Closed Principle e L de Liskov Substitution Principle. Aí você que nunca parou pra pensar, o que diabos é Liskov? Prazer, Barbara Liskov criadora da linguagem CLU que fez adições no paradigma de programação orientada a objetos como tipos de dados abstratos, iteradores, retorno de múltiplos valores ou parallel assignment, classes com construtores. CLU, pra variar, tem sintaxe derivada de quem? Yep, ALGOL. E se chama CLU porque ele lida com Clusters que é mais ou menos uma Classe hoje.</p>
<p>Falando em funcionalidades, que tal falar sobre regular expressions. Todo mundo conhece hoje em dia né? Toda linguagem que se preza tem uma biblioteca boa de regex, normalmente baseada no padrão do Perl 5. Mas de onde diabos vem aquela maldita sintaxe de regex? Volte pra 1962 e vai encontrar o String Oriented and Symbolic Language ou SNOBOL, uma série de linguagens da Bell Labs - de novo - que culmina no SNOBOL 4, uma linguagem voltada a string de texto e que se diferencia das outras linguagens por ter patterns como first-class citizens. Resumindo a história era uma linguagem muito usada pra manipular texto mas foi caindo em desuso à medida que nos anos 80 e 90 surgiram AWK e o próprio Perl. Mas os patterns de SNOBOL ainda são mais poderosos do que regex hoje, meio como HTML é um sub-caso de SGML ou XML. Lembra do Backus-Nauer Form ou BNF que dá origem à definição de gramática de compiladores? O SNOBOL são quase isso pra patterns. Guarde SNOBOL e vamos pular pra outra linguagem</p>
<p>Nos anos 70 surgiu outra linguagem, agora uma funcional chamada Hope na universidade de edinburgh. Ela é anterior à Miranda ou Haskell e é contemporânea do da família ML de linguagens funcionais, sendo derivada do NPL de 77. E Hope e NPL são notáveis por serem as primeiras linguagens a terem o conceito de call-by-pattern. Guarde essa informação.</p>
<p>Em 1972 você tem a linguagem PROLOG que é um animal muito exótico, finalmente alguma coisa não derivada de ALGOL. Ela tem um paradigma que não é funcional, não é objeto, não é imperativo. É programação lógica, uma linguagem declarativa. Você começa definindo fatos e regras. Tudo é expresso em termos de relações ou relations hoje em dia pense em algo como um SQL. e a computação são queries nas relations. Na teoria de Codd sobre SQL ele se baseia em cálculo relacional - você estudou isso na faculdade né? E o que eu falei de fatos em prolog são dados. Uma relation em teoria relacional é a mesma coisa que uma tabela em SQL ou função relacional em lógica predicativa e a mesma coisa que um tuple-set em teoria dos conjutnso. E uma view de SQL é equivalente a uma regra de prolog.</p>
<p>Mais do que isso, prolog também é uma linguagem, como Hope e NPL baseada em pattern-matching. Mais especificamente, você podia implementar o pattern matching de Snobol em Prolog. Aliás, como Prolog não tem sintaxe derivada de Algol ela é bem feia aos nossos olhos acostumados à linguagem de Algol como Java ou C# ou Python. Tem uma outra linguagem que herda partes dessa sintaxe feia de Prolog, com um sistema de pattern-matching como Snobol e call-by-pattern como Hope.</p>
<p>Muito prazer, seu nome é Erlang, lançado em 1986 por Joe Armstrong. Graças aos céus o José Valim inventou a linguagem Elixir que compila no mesmo bytecode de Erlang. Vocês devem conhecer Elixir e Erlang primeiro como uma linguagem funcional e segundo como uma linguagem de alta concorrência.</p>
<p>Vamos lá, primeiro ela não é uma linguagem puramente funcional. Aliás, Javascript também não é puramente funcional. Elas tem funções, ponto. Funcional são outras linguagens. Alguns de vocês que leram muitos blogs vão correr pra dizer “sim, como Haskell”. Vou mais pra trás, quando falei de Hope eu falei de Miranda que veio depois, que é uma linguagem lazy, puramente funcional, que não tem efeitos colaterais, e é escrita como uma série de equações que define várias funções matemáticas e tipos de dados algebraicos. De curiosidade, o parsing da linguagem faz uso de identação de forma a não precisar de chaves pra delimitar statements. Essa funcionalidade foi inspirada por … aha Python! Você poderia dizer. Não, Python é um bebê, antes dele tivemos pelo menos ISWIM e OCCAM.</p>
<p>ISWIM?  Sim, de 1966, inspirado por … bingo, ALGOL. Na verdade ALGOL 60 e Lisp. ISWIM significa If you See What I Mean ou também I see what you mean, mas isso seria I S W Y M mas ai foi escrito errado como I S W I M ou ISWIM. Ela é mais uma descrição de uma linguagem e não foi implementada, mas ela suas idéias inspiraram a linguagem Hope, depois Miranda, daí Haskell e Clean. Clean que tem uma relação de ser inspirado por Haskell e inspirar Haskell sendo meio um concorrente e ter uma funcionalidade em particular que compete com os monads de Haslell, no caso de Clean ele lida com estado mutável e I/O através de um uniqueness typing system.</p>
<p>Mas além de ISWIM ter código identado que veio a inspirar Python, a outra linguagem desse jeito é OCCAM. E ela também se relaciona com Erlang porque antes de Erlang foi desenhada como uma linguagem focada em concorrência e implementa um troço chamado Communicating Sequential Processes ou CSP. Basicamente a comunicação entre processos através de channels ou canais. O CSP de Occam foi reciclado para um aspecto mais funcional no Erlang através de passagem de mensagens entre processos. E você deve ter ouvido falar de outra linguagem que ficou famoso na atualidade por redescobrir CSP, sim a linguagem Go e suas go-rotinas. Todo mundo que fala de CSP menciona Tony Hoare mas eu nunca vi ninguém lembrar que Hoare inventou OCCAM e foi onde ele implementou CSP primeiro.</p>
<p>E já que mencionei a família ML de linguagens funcionais vale lembrar de uma coisa que surgiu primeiro nessa família lá no começo dos anos 70. Um troço chamado Hindley-Milner type system, um sistema de tipos clássicos de lambda calculus com polimorfismo paramétrico. Você viu isso na faculdade né? E porque isso é interessante?  O que as linguagens Clean, Crystal, D, F#, Go, Haskell, Java a partir da versão 10, Julia, Kotlin, OCaml, Rust, Scala, Swift e Visual Basic tem em comum? Eles tem tipagem forte mas diferente do Java antigo onde você precisava declarar todos os tipos de todas as variáveis explicitamente hoje em dia você não precisa né? E nem por isso a linguagem tem tipagem dinâmica como Python ou Ruby, ela tem tipagem forte através de Inferência de Tipo. Outro nome para inferência de tipo? Hindley-Milner type system. Muito prazer, linguagens ML.</p>
<p>E pra terminar, se você é de Javascript tem mais um aspecto dessa linguagem que não é novo. Que tal JSON ou Javascript Object Notation? Nosso querido Douglas Crockford foi olhar nas páginas da história de outra linguagem, o Relative Expression Based Object Language ou REBOL que é contemporâneo de 1997 desenhado por Carl Sassenrath primariamente feito pro AmigaOS e que usa conceitos de programação de Lisp, Forth, Logo e Self. Antes de Ruby tornar popular o conceito de DSLs ou Domain Specific Languages, é REBOL que foi desenhado especificamente pra DSLs, particularmente pra toolkits gráficos de Amiga.</p>
<p>Você acha que existem quantos paradigmas de programação? Muita gente fica se gabando achando que sabe muito discutindo porque o paradigma funcional é superior ao paradigma de objetos que se acha superior ao paradigma imperativo ou procedural. Meh, vá ver a história da linguagem APL e outras do paradigma de array programming e vai encontrar linguagens boas pra calcular vetores como Mathematica ou o moderno Julia. Se você prestou atenção na minha história já sabe que Prolog é paradigma lógico e declarativo. O mundo é sempre muito maior do que você pensa. Muito maior do que seu Javascript.</p>
<p>Mais ainda, na sua cabeça você acha que Java é velho? Agora que ele tem pouco mais de 20 anos? Fortran é de 1957 e tem versões novas sendo usadas até hoje. Cobol tem versão até hoje e é de 1959 ele inclusive ganhou novas funcionalidades como orientação a objetos. E você acha que elas não são usadas mais? Sabe um dos exemplos que todo mundo adora usar pra falar de Python, a biblioteca de ferramentas matemáticas ScyPy? Sabe porque diabos ela é tão rápida? E se eu te disser que mais de 20% do código fonte de Scypy é C outros 30% do código fonte é FORTRAN! 45% é uma casca de Python pra falar com todo esse C e Fortran. E é uma excelente escolha, porque Python sozinho nunca iria ter tanta performance pra cálculo numérico como Fortran.</p>
<p>Estão entendendo? Saiam do casulo. Pensem fora da caixa. Sua linguagem não foi desenhada por um ser onipresente e onipotente que um belo dia acordou e disse “que se faça Javascript” ou “que se faça Python”. Se você é programador de C# e fica zombando de Delphi, que tal saber que elas vieram do mesmo autor e derivam das mesmas linguagens? Você acha que porque usa Go ou Elixir de repente só recentemente surgiu programação concorrente com processos e channels de CSP? Nunca foram procurar Tony Hoare e linguagens como Occam? Pattern matching, pfff, SNOBOL.</p>
<p>O que eu falei nesses 2 episódios é apenas uma dimensão da história da programação. Em outors episódios vou mostrar como você junta esta dimensão com outras dimensões pra começar a entender as fundações não só de onde vieram suas linguagens favoritas mas o que elas poderão ser no futuro.</p>
<p>O que acharam dessa série em 2 partes? Não deixe de colocar nos comentários o que acharam. Se gostaram mandem um joinha. Assinem o canal e não deixem de clicar no sininho pra não perder os próximos episódios. A gente se vê, até mais!</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>[Akitando] #15 - Sua Linguagem NÃO É Especial! (Parte 1)</title><link>https://akitaonrails.github.io/2018/10/02/akitando-15-sua-linguagem-nao-e-especial-parte-1/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/10/02/akitando-15-sua-linguagem-nao-e-especial-parte-1/</guid><pubDate>Tue, 02 Oct 2018 17:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/p9-WuJbVHHc"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Depois da semana geek, vamos &amp;ldquo;geekar&amp;rdquo; um pouco na programação também.&lt;/p&gt;
&lt;p&gt;Honestamente essa polarização em torno de linguagens de programação é super cansativa. A turma do funcional vs a turma dos objetos. A turma do javascript, a turma do Go.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/p9-WuJbVHHc"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Depois da semana geek, vamos &ldquo;geekar&rdquo; um pouco na programação também.</p>
<p>Honestamente essa polarização em torno de linguagens de programação é super cansativa. A turma do funcional vs a turma dos objetos. A turma do javascript, a turma do Go.</p>
<p>Enquanto isso, a grande maioria da população de programadores está aflita, sem saber pra onde correr. Quantas linguagens preciso aprender? 2? 6? 50???</p>
<p>Calma! Vamos começar a colocar ordem nessa bagunça. Hoje vou explicar como fazer isso e porque sua linguagem de programação favorita não é tão especial quanto você pensa!</p>
<p>Veja hoje a Parte 1 e não deixe de assinar o canal para ver a Parte 2!</p>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Esta semana vamos pular pra assuntos de tecnologia. Mas eu quero colocar em prática o que eu disse semana passada nos episódios geek. Lembra como eu disse que nós geeks não só assistimos as coisas mas gostamos de ficar explorando detalhes, rotas alternativas e até re-editando o que gostamos?</p>
<p>Hoje eu vou mostrar como fazemos isso em tecnologia também. Muitos de vocês hoje devem ter linguagens de programação favoritas. Todo mundo tem pelo menos uma. Como muitos de vocês sabem, eu gosto muito da linguagem Ruby. Porém isso não me torna cego às demais linguagens e eu não digo isso só da boca pra fora.</p>
<p>Também como disse no episódio de faculdade, eu comecei no fim dos anos 80, passei por Basic, dBase III, Clipper, Turbo Pascal 6, Visual Basic 6, Delphi desde a versão 1.0, Perl desde a versão 5 - se bem que ela nunca saiu da 5, PHP desde a 3, ASP clássico, .NET C# e VB.NET desde a versão 1.0, Java desde a versão 1.0, Javascript desde antes de virar padrão ECMA, Python 2. E isso foi só até o fim dos anos 90.</p>
<p>Se tem uma coisa que vocês devem levar deste episódio é o seguinte: linguagens de programação Não são filosofias de vida. Linguagens de programação são meras ferramentas. Ferramentas foram feitas para servir seus mestres, e não o contrário. Linguagens de programação não merecem lealdade e definitivamente não são religiões. Eu não sou definido pela minha linguagem de programação favorita.
Você não é sua linguagem de programação.</p>
<p>(&hellip;)</p>
<p>(crack de dedos) É hora de mostrar aqui quem manda.</p>
<p>A melhor forma de desmistificar qualquer coisa é abrir e dissecar. Ver do que é feito. Ver quem fez. Ver de onde veio. Pare de colocar as coisas num pedestal só porque você não compreende. Nada merece ficar num pedestal, muito menos linguagens de programação.</p>
<p>Antes de mais nada, se eu te perguntar, quais todas as linguagens de programação que existem hoje? Você talvez tenha a seguinte imagem na cabeça (IMAGEM)</p>
<p>Mas a realidade é que esta é a lista de linguagens ATIVAS nesse momento.
Pois é, bem mais do que você imaginava. Existem linguagens em uso neste momento que você sequer ouviu falar. Você precisa expandir seus horizontes. E agora o mundo que já parecia grande parece impossível. Mas não se preocupe, vamos organizar isso.</p>
<p>Se você só conhece uma ou duas linguagens, ou mesmo meia dúzia, faz parecer que cada uma delas é genial e única. Faz parecer que nunca mais ninguém vai chegar numa combinação tão perfeita. Por exemplo, a orientação a protótipos de Javascript, os CSP de Go, o garbage collector do Java, o pattern matching do Elixir.</p>
<p>Vamos começar do começo. Muitos quando pensam em linguagens antigas pensam em Fortran ou Lisp, mas eu começaria por Speedcode ou Speedcoding do lendário John Backus. É uma das primeiras linguagens interpretadas de alto nível. Muita gente acha que COBOL é quem inaugurou a era das linguagens simbólicas que prezava pela facilidade de uso ao usar palavras em vez de mnemônicos como Assembly, como o próprio nome Speed code já diz. Estamos falando de 1953. O objetivo foi facilitar a computação numérica de ponto flutuante para calcular posições astronômicas, trocando facilidade de uso por performance.</p>
<p>O mesmo John Backus depois criaria a linguagem mais famosa dele e que ainda está em uso até hoje, o Formula Translator ou Fortran, de 1957. Agora você sabe que a idéia original veio de Speedcoding. Como disse antes Speedcoding era interpretado e embora com uma linguagem fácil de usar a performance era sofrível, até 20x pior que assembly de máquina e naquela época hardware era proibitivamente caro. Por isso pense em Fortran como uma evolução compilada de Speedcode. Embora uma linguagem de uso geral obviamente ele foi pensado como uma linguagem para cálculo númerico. Se você fez faculdade e aprendeu sobre montadores, aprendeu sobre assembly.</p>
<p>De bônus, muitos ainda pensam que Fortran gera binário mais rápido do que C. Isso foi verdade no começo. Depois do padrão C99 ter colocado o keyword restrict isso já não é mais verdade. A diferença é que Fortran não permite aliasing de pointers. Dois nomes apontando pro mesmo espaço de memória e fazendo overlap. Se você usar restrict em C o mesmo código vai gerar um binário igualmente rápido.</p>
<p>Seguindo a história, você tem o Algorithmic Language ou ALGOL que é uma família de linguagens imperativas. Como o nome diz foi usado para descrever algoritmos, uma evolução do Fortran em termo de linguagem de alto nível. Uma das coisas mais importantes da produção do ALGOL foi a invenção do Backus Normal Form por John Backus de novo que depois foi revisado e extendido por Peter Naur pro ALGOL 60 e renomeado como Backus-Naur Form ou BNF por sugestão do lendário Donald Knuth. BNF é uma técnica de notação para gramáticas livre de contexto usado para descrever e definir sintaxe de linguagens. Se você fez faculdade e aprendeu sobre compiladores então teve que lidar com o Yet Another Compiler-Compiler ou YACC que é padrão em BSD ou o GNU bison.</p>
<p>Se seguirmos para o começo dos anos 1960 encontramos o Combined Programming Language também chamado de Cambridge Programming Language por ter sido desenvolvido na universidade de Cambridge ou Christopher’s Programming Language por ter sido desenhado por Christopher Strachey junto com David Barron. Na prática uma linguagem inspirada em ALGOL 60. Mas a linguagem demorou muito pra ficar pronta, quis fazer muita coisa, ele queria ao mesmo tempo possibilitar programação de baixo nível e ter abstrações de alto nível. No final não foi pra lugar nenhum mas inspirou um derivado mais simples chamado BCPL ou Basic CPL ou também Boostrap CPL voltado mais pra programação de sistemas, particularmente pra escrever compiladores.</p>
<p>A família de linguagens ALGOL daria origem a derivados em particular alguns que você não imaginaria. Niklaus Wirth e Tony Hoare propuseram o ALGOL W como sucessor do ALGOL 60. Esse trabalho inspiraria Wirth a criar uma nova linguagem desenhada pra ser eficiente em tempo de compilação e execução, fortemente tipada, que possibilitaria a criação de estruturas de dados complexas e seria boa para ensinar programação estruturada e algoritmos, e entre 68 e 69 nasce a linguagem Pascal. Sim, Pascal é um derivado direto de ALGOL. Eu aprendi algoritmos e estruturas de dados com esse livro de Wirth.</p>
<p>Dando uma tangente nessa história, nos anos 80 Anders Hejlsberg escreveu o compilador Blue Label Pascal. Depois de ser adquirido pela Borland isso se tornaria o Turbo Pascal, que eu mencionei em outro episódio que foi a linguagem que aprendi na faculdade. Turbo Pascal fez muito sucesso na época, era muito compacto, eficiente e ainda vinha com uma IDE. Muitos programas famosos do Macintosh original foram escritos num dialeto de Turbo Pascal. E da Apple Computer saiu a extensão Object Pascal. É parecido mas não é a mesma coisa que o Object Pascal da Borland que viria a se tornar o famoso Delphi.</p>
<p>Quem contratou Anders Hejlsberg foi a Microsoft e ele criou o Microsoft J++, o derivado de Java da Microsoft. Eu costumo dizer que o atual C# que foi desenhado pelo Anders é o filho bastardo de Delphi com J++.</p>
<p>Voltando ao ALGOL e ao BCPL, como você pode imaginar, é bem adequado que da linguagem ALGOL ou A, venha BCPL que na sequência coincidentemente deu origem à linguagem B por volta de 1969 desenhada pelos lendários Ken Thompson e Dennis Ritchie na Bell Labs. O BCPL, CPL, ALGOL tem cara de Pascal pelos motivos que falei acima, mas Thompson e Ritchie reverteram muita coisa da sintaxe. Por exemplo, em vez de atribuição ser dois pontos e igual passou a ser só igual, eles inventaram os operadores aritméticos de atribuição que é o mais igual ou menos igual além de incrementadores e decrementadores que são os operadores mais mais e menos menos. Enquanto Pascal virou um derivado de tipagem forte de Algol, o B foi feito pra ser sem tipo. Agora adicione a isso a sintaxe de chaves e você tem a próxima linguagem desenhada por Thompsom e Ritchie para suceder o B, a linguagem C.</p>
<p>Agora você sabe de onde veio C e como Pascal é seu primo e como Java e C# são netos bastardos e primos bastardos um do outro, é um verdadeiro bacanal de linguagens.</p>
<p>Mas isso não pára por aqui. Sabe quem mais trabalhou na evolução do ALGOL, o ALGOL 68? Um cara chamado Stephen Richard Bourne, que criou um troço chamado Bourne Shell pra substituir o Thompson Shell ou SH. A linguagem de script é inspirado em ALGOL 68. Falando em shells David Korn criou o Korn Shell ou KSH baseado no Bourne Shell e é um meio do caminho entre ele e o C Shell de Bill Joy - talvez vocês de Java lembrem dele da época da Sun Microsystems. Agora some Bourne Shell, C Shell e Korn Shell implementado no mundo GNU e você tem o Bourne Again Shell ou BASH! Agora você sabe de onde vem o BASH. E só pra finalizar essa tangente, se você pegar BASH, KSH e o TC Shell sai o mais moderno Z Shell que muitos preferem usar hoje. Se você vem de UNIX de verdade e sistemas BSD antigos deve ter encontrado o Bourne Shell original.</p>
<p>Ufa, essa história é bem longa. Mas depois dessa tangente em shells vamos parar por aqui. No próximo episódio eu vou finalizar essa história mas eu acho que você já entendeu onde eu quero chegar.</p>
<p>O mundo de programação é muito maior do que sua linguagem favorita. E linguagens não são estáticos. Elas não nasceram do nada por um criador místico. Todas são derivadas de alguma outra e sabendo de onde elas vieram você pode começar a entender pra onde elas vão evoluir no futuro. O que acharam desse episódio? Se gostaram deixem um joinha, assinem o canal e não deixem de clicar no sininho pra não perder a parte 2 dessa história. A gente se vê, até mais!</p>
]]></content:encoded><category>linguagens-de-programacao</category><category>ciencia-da-computacao</category><category>programacao</category><category>akitando</category></item><item><title>Elixir 101 - Apresentando a Sintaxe</title><link>https://akitaonrails.github.io/2015/11/25/elixir-101-apresentando-a-sintaxe/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/11/25/elixir-101-apresentando-a-sintaxe/</guid><pubDate>Wed, 25 Nov 2015 17:25:00 -0200</pubDate><description>&lt;p&gt;Venho publicando vários artigos nas últimas semanas, dá uma olhada na &lt;a href="http://www.akitaonrails.com/elixir"target="_blank" rel="noopener"&gt;tag &amp;ldquo;Elixir&amp;rdquo;&lt;/a&gt; pra ler todos eles.&lt;/p&gt;
&lt;p&gt;Muitas séries de tutoriais começam apresentando uma linguagem nova pela sintaxe. Eu inverti a ordem. Elixir não é interessante por causa da sintaxe. Erlang já é interessante por si só, por ser uma plataforma muito madura, altamente confiável, altamente concorrente e distribuída. Mas a sintaxe não é pra qualquer um. Não que seja &amp;ldquo;feia&amp;rdquo;, ela é só diferente demais pra quem vem da escola C digerir com facilidade. Ela deriva de Prolog, e este é um pequeno exemplo de um exercício em Prolog:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Venho publicando vários artigos nas últimas semanas, dá uma olhada na <a href="http://www.akitaonrails.com/elixir"target="_blank" rel="noopener">tag &ldquo;Elixir&rdquo;</a> pra ler todos eles.</p>
<p>Muitas séries de tutoriais começam apresentando uma linguagem nova pela sintaxe. Eu inverti a ordem. Elixir não é interessante por causa da sintaxe. Erlang já é interessante por si só, por ser uma plataforma muito madura, altamente confiável, altamente concorrente e distribuída. Mas a sintaxe não é pra qualquer um. Não que seja &ldquo;feia&rdquo;, ela é só diferente demais pra quem vem da escola C digerir com facilidade. Ela deriva de Prolog, e este é um pequeno exemplo de um exercício em Prolog:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-prolog" data-lang="prolog"><span class="line"><span class="cl"><span class="c1">% P03 (*): Find the K&#39;th element of a list.</span>
</span></span><span class="line"><span class="cl"><span class="c1">%     The first element in the list is number 1.</span>
</span></span><span class="line"><span class="cl"><span class="c1">%     Example:</span>
</span></span><span class="line"><span class="cl"><span class="c1">%     ?- element_at(X,[a,b,c,d,e],3).</span>
</span></span><span class="line"><span class="cl"><span class="c1">%     X = c</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">% The first element in the list is number 1.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">% element_at(X,L,K) :- X is the K&#39;th element of the list L</span>
</span></span><span class="line"><span class="cl"><span class="c1">%    (element,list,integer) (?,?,+)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">% Note: nth1(?Index, ?List, ?Elem) is predefined</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">element_at</span><span class="p">(</span><span class="nv">X</span><span class="p">,[</span><span class="nv">X</span><span class="p">|</span><span class="k">_</span><span class="p">],</span><span class="mi">1</span><span class="p">).</span>
</span></span><span class="line"><span class="cl"><span class="nf">element_at</span><span class="p">(</span><span class="nv">X</span><span class="p">,[</span><span class="k">_</span><span class="p">|</span><span class="nv">L</span><span class="p">],</span><span class="nv">K</span><span class="p">)</span> <span class="p">:-</span> <span class="nv">K</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">,</span> <span class="nv">K1</span> <span class="o">is</span> <span class="nv">K</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="nf">element_at</span><span class="p">(</span><span class="nv">X</span><span class="p">,</span><span class="nv">L</span><span class="p">,</span><span class="nv">K1</span><span class="p">).</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Erlang tem uma sintaxe parecida, com a ideia de frases divididas por vírgulas e terminando com um ponto.</p>
<p>O José Valim foi muito esperto: pegou a melhor das plataformas maduras disponíveis e cobriu com uma camada de sintaxe moderna e bibliotecas padrão mais fáceis de usar. Esse é o mesmo problema implementado em Elixir:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defmodule</span> <span class="no">Exercise</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="o">[</span><span class="n">found</span><span class="o">|</span><span class="n">_</span><span class="o">]</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="n">found</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="o">[</span><span class="n">_</span><span class="o">|</span><span class="n">rest</span><span class="o">]</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span> <span class="k">when</span> <span class="n">position</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="n">element_at</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">position</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se eu copiar e colar o código acima num shell IEx, posso testar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(7)&gt; Exercise.element_at([&#34;a&#34;, &#34;b&#34;, &#34;c&#34;, &#34;d&#34;, &#34;e&#34;], 3)
&#34;c&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse exercício simples já mostra alguns dos pontos poderosos de Erlang dos quais o Elixir tira proveito, como pattern matching e recursão.</p>
<p>Antes de mais nada, toda função <strong>precisa</strong> ser definida dentro de um módulo, que você nomeia com <tt>defmodule My.Module do .. end</tt>. Internamente, isso vira o atom &ldquo;Elixir.My.Process&rdquo;. Aninhar módulos é só um nome maior concatenado com pontos.</p>
<p>Daí você define funções públicas com o bloco <tt>def my_function(args) do .. end</tt>, que é só um macro pra mesma construção <tt>def my_function(args), do: &hellip;</tt>. Métodos privados são declarados com <tt>defp</tt>.</p>
<p>Uma função é, na verdade, identificada pelo par nome e aridade. Então acima temos <tt>element_at/2</tt>, o que significa que aceita 2 argumentos. Mas temos 2 funções com a mesma aridade: a diferença é o <strong>pattern matching</strong>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="o">[</span><span class="n">found</span><span class="o">|</span><span class="n">_</span><span class="o">]</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="n">found</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Aqui estamos dizendo: o primeiro argumento será um array, decomponha-o. O primeiro elemento do array será armazenado na variável &ldquo;found&rdquo;, o resto &ldquo;_&rdquo; será ignorado. E o segundo argumento precisa ser o número &ldquo;1&rdquo;. Essa é a descrição do chamado &ldquo;padrão&rdquo; (pattern), que deve &ldquo;casar&rdquo; com os argumentos de entrada recebidos. Essa é a semântica do <strong>&ldquo;call-by-pattern&rdquo;</strong>.</p>
<p>Mas e se quisermos passar uma posição diferente de &ldquo;1&rdquo;? É pra isso que serve a segunda definição:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>def element_at([_|rest], position) when position &gt; 1 do</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora, o primeiro argumento de novo <strong>precisa</strong> ser um array, mas dessa vez não nos importamos com o primeiro elemento, só com o resto do array sem o primeiro elemento. E qualquer posição diferente de &ldquo;1&rdquo; será armazenada na variável &ldquo;position&rdquo;.</p>
<p>Mas essa função é especial, ela tem uma <strong>guarda</strong> que só permite uma <tt>position</tt> maior que 1. E se tentarmos uma posição negativa?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(8)&gt; Exercise.element_at([&#34;a&#34;, &#34;b&#34;, &#34;c&#34;, &#34;d&#34;, &#34;e&#34;], -3)
** (FunctionClauseError) no function clause matching in Exercise.element_at/2
    iex:7: Exercise.element_at([&#34;a&#34;, &#34;b&#34;, &#34;c&#34;, &#34;d&#34;, &#34;e&#34;], -3)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ele diz que nenhuma das cláusulas que passamos casa com nenhuma das definidas acima. Poderíamos ter adicionado uma terceira definição justamente pra capturar esses casos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="n">_list</span><span class="p">,</span> <span class="n">_position</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="kp">nil</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Colocar o underscore &ldquo;_&rdquo; antes do nome da variável é o mesmo que ter só o underscore, mas estamos nomeando pra ficar mais legível. Quaisquer argumentos passados serão simplesmente ignorados. E esse é o caso mais genérico, quando os 2 anteriores não casam.</p>
<p>A linha anterior é o mesmo que escrever:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>def element_at(_list, _position) do
  nil
end</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não vou entrar em macros agora, só saiba que existe mais de uma forma de fazer as coisas em Elixir e que você pode definir essas formas usando o suporte nativo do Erlang a macros, código dinâmico que é compilado em tempo de execução. É a maneira de fazer metaprogramação em Elixir.</p>
<p>Voltando à implementação, a primeira função ainda pode parecer estranha, vamos revisar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="o">[</span><span class="n">_</span><span class="o">|</span><span class="n">rest</span><span class="o">]</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span> <span class="k">when</span> <span class="n">position</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">element_at</span><span class="p">(</span><span class="n">rest</span><span class="p">,</span> <span class="n">position</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O que acontece é: quando chamamos <tt>Exercise.element_at([&ldquo;a&rdquo;, &ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;], 3)</tt>, o primeiro argumento casa com o padrão <tt>[_|rest]</tt>. O primeiro elemento &ldquo;a&rdquo; é descartado e a nova lista <tt>[&ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;]</tt> é armazenada como &ldquo;<tt>rest</tt>&rdquo;.</p>
<p>Por fim, recursamos a chamada decrementando a variável &ldquo;<tt>position</tt>&rdquo;. Então vira <tt>element_at([&ldquo;b&rdquo;, &ldquo;c&rdquo;, &ldquo;d&rdquo;, &ldquo;e&rdquo;], 2)</tt>. E isso se repete até position virar &ldquo;1&rdquo;, quando o pattern matching cai na segunda função, definida assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>def element_at([found|_], 1), do: found</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Nesse caso, o resto do array é casado por padrão e o primeiro elemento, &ldquo;c&rdquo;, é armazenado na variável &ldquo;<tt>found</tt>&rdquo;, o resto do array é descartado. Só chegou aqui porque a posição casou como &ldquo;1&rdquo;, e então a função simplesmente retorna a variável &ldquo;found&rdquo;, que contém o 3º elemento do array original, &ldquo;c&rdquo;.</p>
<p>Isso tudo é bonito e elegante, mas em Elixir podíamos só ter feito esta outra versão:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defmodule</span> <span class="no">Exercise</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">element_at</span><span class="p">(</span><span class="n">list</span><span class="p">,</span> <span class="n">position</span><span class="p">),</span> <span class="k">do</span><span class="p">:</span> <span class="no">Enum</span><span class="o">.</span><span class="n">at</span><span class="p">(</span><span class="n">list</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E pronto! Vários tutoriais vão falar como recursão e pattern matching pra decompor listas resolvem um monte de problemas, mas o Elixir nos dá a conveniência de tratar listas como Enumerables e oferece um módulo <a href="http://elixir-lang.org/docs/stable/elixir/Enum.html"target="_blank" rel="noopener">Enum</a> bem rico, com funções muito úteis como <tt>at/2</tt>, <tt>each/2</tt>, <tt>take/2</tt> e por aí vai. É só escolher o que precisa e você manipula listas como um chefe.</p>
<p>Ah, e por sinal, existe algo chamado <a href="http://elixir-lang.org/getting-started/sigils.html"target="_blank" rel="noopener">Sigil</a> no Elixir. Em vez de escrever a Lista de Strings explicitamente, podíamos ter feito assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(8)&gt; ~w(a b c d e f)
[&#34;a&#34;, &#34;b&#34;, &#34;c&#34;, &#34;d&#34;, &#34;e&#34;, &#34;f&#34;]</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou, se quiséssemos uma Lista de Atoms, podíamos fazer assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(9)&gt; ~w(a b c d e f)a
[:a, :b, :c, :d, :e, :f]</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Lists, Tuples e Keyword Lists<span class="hx:absolute hx:-mt-20" id="lists-tuples-e-keyword-lists"></span>
    <a href="#lists-tuples-e-keyword-lists" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Bom, isso foi simples demais. Você precisa mesmo ter a ideia de pattern matching e os tipos básicos na cabeça pra fluir. Vamos pegar outro trecho do <a href="http://www.akitaonrails.com/2015/11/18/ex-manga-downloadr-um-exercicio-com-elixir"target="_blank" rel="noopener">Ex Manga Downloadr</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defp</span> <span class="n">parse_args</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">parse</span> <span class="o">=</span> <span class="no">OptionParser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">args</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="ss">switches</span><span class="p">:</span> <span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="ss">:string</span><span class="o">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="ss">aliases</span><span class="p">:</span> <span class="o">[</span><span class="ss">n</span><span class="p">:</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">u</span><span class="p">:</span> <span class="ss">:url</span><span class="p">,</span> <span class="ss">d</span><span class="p">:</span> <span class="ss">:directory</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">case</span> <span class="n">parse</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="n">manga_name</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="n">directory</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="n">manga_name</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="n">directory</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="p">}</span> <span class="o">-&gt;</span> <span class="n">process</span><span class="p">(</span><span class="ss">:help</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira parte pode confundir você:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">OptionParser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">args</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="ss">switches</span><span class="p">:</span> <span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="ss">:string</span><span class="o">]</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="ss">aliases</span><span class="p">:</span> <span class="o">[</span><span class="ss">n</span><span class="p">:</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">u</span><span class="p">:</span> <span class="ss">:url</span><span class="p">,</span> <span class="ss">d</span><span class="p">:</span> <span class="ss">:directory</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <tt>OptionParser.parse/2</tt> recebe só 2 argumentos: 2 arrays. Se você vem de Ruby, parece um Hash com colchetes opcionais, traduzindo pra algo parecido com isto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># isto está errado</span>
</span></span><span class="line"><span class="cl"><span class="no">OptionParser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">args</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="ss">switches</span><span class="p">:</span> <span class="p">{</span><span class="nb">name</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="ss">:string</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="ss">:string</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="ss">aliases</span><span class="p">:</span> <span class="p">{</span><span class="ss">n</span><span class="p">:</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">u</span><span class="p">:</span> <span class="ss">:url</span><span class="p">,</span> <span class="ss">d</span><span class="p">:</span> <span class="ss">:directory</span><span class="p">}</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso funciona em Ruby, mas não é o caso em Elixir; existem colchetes opcionais, só que não onde você imagina:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># esta é a versão correta, mais explícita</span>
</span></span><span class="line"><span class="cl"><span class="no">OptionParser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">args</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="o">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="ss">:switches</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="o">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:string</span><span class="p">},</span> <span class="p">{</span><span class="ss">:url</span><span class="p">,</span> <span class="ss">:string</span><span class="p">},</span> <span class="p">{</span><span class="ss">:directory</span><span class="p">,</span> <span class="ss">:string</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="o">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="ss">aliases</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="o">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span><span class="ss">:n</span><span class="p">,</span> <span class="ss">:name</span><span class="p">},</span> <span class="p">{</span><span class="ss">:u</span><span class="p">,</span> <span class="ss">:url</span><span class="p">},</span> <span class="p">{</span><span class="ss">:d</span><span class="p">,</span> <span class="ss">:directory</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="o">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>QUE!?!?</p>
<p>Isso mesmo, o segundo argumento é, na verdade, um array com elementos que são <strong>Tuples</strong>, pareados com chave atom e valor, e alguns dos valores são, eles próprios, arrays com tuples.</p>
<ol>
<li>
<p>em Elixir, Lists são o que normalmente chamamos de Array, uma Linked-List de elementos. Linked-Lists, como você sabe das aulas de Ciência da Computação, são fáceis pra inserir e remover elementos.</p>
</li>
<li>
<p>em Elixir, Tuples são listas fixas e imutáveis com posições fixas, com elementos delimitados pelas chaves &ldquo;{}&rdquo;</p>
</li>
</ol>
<p>Se o exemplo anterior foi demais, vamos dar um passo atrás:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defmodule</span> <span class="no">Teste</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">teste</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="o">[</span><span class="p">{</span><span class="ss">:hello</span><span class="p">,</span> <span class="n">world</span><span class="p">},</span> <span class="p">{</span><span class="ss">:foo</span><span class="p">,</span> <span class="n">bar</span><span class="p">}</span><span class="o">]</span> <span class="o">=</span> <span class="n">opts</span>
</span></span><span class="line"><span class="cl">    <span class="no">IO</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="n">world</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">bar</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora podemos chamar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(13)&gt; Teste.teste hello: &#34;world&#34;, foo: &#34;bar&#34;
world bar</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Que é o mesmo que chamar assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(14)&gt; Teste.teste([{:hello, &#34;world&#34;}, {:foo, &#34;bar&#34;}])
world bar</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso pode confundir, mas é bem intuitivo. Você pode pensar nessa combinação de Lists (&quot;[]&quot;) com elementos Tuple contendo um par atom e valor (&quot;{:key, value}&quot;) como algo que se comporta quase como Hashes do Ruby usados pra argumentos nomeados opcionais.</p>
<p>Aí temos a parte de Pattern Match nos dois exemplos anteriores:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">case</span> <span class="n">parse</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="n">manga_name</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="n">directory</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="n">manga_name</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="n">directory</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span><span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="p">}</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="n">process</span><span class="p">(</span><span class="ss">:help</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">[</span><span class="p">{</span><span class="ss">:hello</span><span class="p">,</span> <span class="n">world</span><span class="p">},</span> <span class="p">{</span><span class="ss">:foo</span><span class="p">,</span> <span class="n">bar</span><span class="p">}</span><span class="o">]</span> <span class="o">=</span> <span class="n">opts</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O último exemplo é só decomposição. O exemplo anterior é pattern match e decomposição. Você casa com base nos atoms e nas posições dentro das tuples dentro da lista. Você casa do caso mais específico pro mais genérico. E, no processo, as variáveis do padrão ficam disponíveis pra usar dentro da cláusula correspondente do case.</p>
<p>Vamos entender o significado desta linha:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="p">{</span><span class="o">[</span><span class="nb">name</span><span class="p">:</span> <span class="n">manga_name</span><span class="p">,</span> <span class="ss">url</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="ss">directory</span><span class="p">:</span> <span class="n">directory</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ela está dizendo: dado o resultado da função <tt>OptionParser.parse/2</tt>, ele precisa ser uma tuple com 3 elementos. O segundo e o terceiro elementos não importam. Mas o primeiro elemento precisa ser uma List com pelo menos 3 tuples. E as chaves de cada tuple precisam ser os atoms <tt>:name</tt>, <tt>:url</tt> e <tt>:directory</tt>. Se estiverem lá, armazene os valores de cada tuple nas variáveis <tt>manga_name</tt>, <tt>url</tt> e <tt>directory</tt>, respectivamente.</p>
<p>Isso pode confundir bastante no início, mas essa combinação de uma List de Tuples é o que se chama <a href="http://elixir-lang.org/getting-started/maps-and-dicts.html#keyword-lists"target="_blank" rel="noopener"><strong>Keyword List</strong></a> e você vai encontrar esse padrão muitas vezes, então acostume-se.</p>
<p>Keyword List parece um Map, mas o Map tem uma sintaxe diferente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">list</span> <span class="o">=</span> <span class="o">[</span><span class="ss">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="ss">b</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="ss">c</span><span class="p">:</span> <span class="mi">3</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">map</span> <span class="o">=</span> <span class="sx">%{:a =&gt; 1, :b =&gt; 2, :c =&gt; 3}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso deve resumir bem:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(1)&gt; list = [a: 1, b: 2, c: 3]
[a: 1, b: 2, c: 3]
iex(2)&gt; map = %{:a =&gt; 1, :b =&gt; 2, :c =&gt; 3}
%{a: 1, b: 2, c: 3}

iex(3)&gt; list[:a]
1
iex(4)&gt; map[:a]
1

iex(5)&gt; list.a
** (ArgumentError) argument error
    :erlang.apply([a: 1, b: 2, c: 3], :a, [])
iex(5)&gt; map.a
1

iex(6)&gt; list2 = [{:a, 1}, {:b, 2}, {:c, 3}]
[a: 1, b: 2, c: 3]
iex(7)&gt; list = list2
[a: 1, b: 2, c: 3]</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Keyword Lists são convenientes como argumentos de função ou valores de retorno. Mas se você quiser processar uma coleção de pares chave-valor, use uma estrutura tipo dicionário, neste caso, um Map. Especialmente se você precisar buscar na coleção pela chave. Eles parecem semelhantes, mas as estruturas internas são diferentes; uma Keyword List não é um Map, é só uma conveniência pra uma lista estática de tuples.</p>
<p>Por fim, se esse padrão casar com a variável <tt>parse</tt> passada no bloco <tt>case</tt>, ele executa <tt>process(manga_name, url, directory)</tt>, passando as 3 variáveis capturadas no match. Caso contrário, segue tentando o próximo padrão do bloco <tt>case</tt>.</p>
<p>A ideia é que o operador &ldquo;=&rdquo; não é uma &ldquo;atribuição&rdquo;, é um casador, você casa um lado com o outro. Leia a mensagem de erro quando um padrão não casa:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(15)&gt; [a, b, c] = 1
** (MatchError) no match of right hand side value: 1</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse é um erro de matching, não um erro de atribuição. Mas se der certo, isso é o que temos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>iex(15)&gt; [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex(16)&gt; a
1
iex(17)&gt; c
3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso é uma decomposição de List. Acontece que, no caso simples, parece uma atribuição de variável, mas é bem mais complexo do que isso.</p>
<h3>Pipelines<span class="hx:absolute hx:-mt-20" id="pipelines"></span>
    <a href="#pipelines" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Usamos exatamente esses conceitos de pattern matching nos elementos retornados do HTML parseado pelo Floki no meu Manga Downloadr:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Floki</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">html</span><span class="p">,</span> <span class="s2">&#34;#listing a&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">|&gt;</span> <span class="no">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">fn</span> <span class="p">{</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="o">[</span><span class="p">{</span><span class="s2">&#34;href&#34;</span><span class="p">,</span> <span class="n">url</span><span class="p">}</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">url</span> <span class="k">end</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O <tt>find/2</tt> pega uma string HTML da página baixada e casa com os seletores CSS do segundo argumento. O resultado é uma List de Tuples representando a estrutura de cada Nó HTML encontrado, neste caso, com este padrão: <tt>{&ldquo;a&rdquo;, [{&ldquo;href&rdquo;, url}], _}</tt></p>
<p>Daí podemos usar <tt>Enum.map/2</tt>. Um map é uma função que recebe cada elemento de uma lista e retorna uma nova lista com novos elementos. O primeiro argumento é a lista original e o segundo é uma função que recebe cada elemento e retorna um novo.</p>
<p>Uma das principais features da linguagem Elixir, que a maioria das linguagens não tem, é o operador <strong>Pipe</strong> (&quot;|&gt;&quot;). Ele se comporta quase como o operador pipe &ldquo;|&rdquo; do UNIX em qualquer shell.</p>
<p>No UNIX a gente costuma fazer coisas tipo &ldquo;<tt>ps -ef | grep PROCESS | grep -v grep | awk &lsquo;{print $2}&rsquo; | xargs kill -9</tt>&rdquo;</p>
<p>Isso é essencialmente o mesmo que fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>ps -ef &gt; /tmp/ps.txt
grep mix /tmp/ps.txt &gt; /tmp/grep.txt
grep -v grep /tmp/grep.txt &gt; /tmp/grep2.txt
awk &#39;{print $2}&#39; /tmp/grep2.txt &gt; /tmp/awk.txt
xargs kill -9 &lt; /tmp/awk.txt</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Cada processo UNIX pode receber algo da entrada padrão (STDIN) e enviar algo pra saída padrão (STDOUT). Podemos redirecionar a saída usando &ldquo;&gt;&rdquo;. Mas, em vez de fazer todos esses passos extras, criando um monte de arquivos temporários inúteis, podemos simplesmente &ldquo;pipear&rdquo; o STDOUT de um comando pro STDIN do próximo.</p>
<p>Elixir usa os mesmos princípios: podemos simplesmente usar o valor de retorno de uma função como o <strong>primeiro argumento</strong> da próxima função. Então o primeiro exemplo desta seção é o mesmo que fazer isto:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">results</span> <span class="o">=</span> <span class="no">Floki</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">html</span><span class="p">,</span> <span class="s2">&#34;#listing a&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="no">Enum</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">results</span><span class="p">,</span> <span class="n">fn</span> <span class="p">{</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="o">[</span><span class="p">{</span><span class="s2">&#34;href&#34;</span><span class="p">,</span> <span class="n">url</span><span class="p">}</span><span class="o">]</span><span class="p">,</span> <span class="n">_</span><span class="p">}</span> <span class="o">-&gt;</span> <span class="n">url</span> <span class="k">end</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>No mesmo projeto ExMangaDownloadr temos este trecho:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defp</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="no">File</span><span class="o">.</span><span class="n">mkdir_p!</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">url</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">chapters</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">pages</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">images_sources</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">process_downloads</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">optimize_images</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">compile_pdfs</span><span class="p">(</span><span class="n">manga_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">|&gt;</span> <span class="n">finish_process</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E acabamos de aprender que isso é o equivalente a fazer o seguinte (estou trapaceando um pouco porque as 3 funções finais do workflow não estão transformando o &ldquo;directory&rdquo; de entrada, só repassando):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl">  <span class="n">defp</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="no">File</span><span class="o">.</span><span class="n">mkdir_p!</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">chapters</span>  <span class="o">=</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">chapters</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">pages</span>     <span class="o">=</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">pages</span><span class="p">(</span><span class="n">chapters</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sources</span>   <span class="o">=</span> <span class="no">Workflow</span><span class="o">.</span><span class="n">images_sources</span><span class="p">(</span><span class="n">pages</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Workflow</span><span class="o">.</span><span class="n">process_downloads</span><span class="p">(</span><span class="n">sources</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Workflow</span><span class="o">.</span><span class="n">optimize_images</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Workflow</span><span class="o">.</span><span class="n">compile_pdfs</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="n">manga_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">finish_process</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou esta versão muito mais feia, que precisamos ler de trás pra frente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">defp</span> <span class="n">process</span><span class="p">(</span><span class="n">manga_name</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">directory</span><span class="p">)</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="no">File</span><span class="o">.</span><span class="n">mkdir_p!</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">finish_process</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="no">Workflow</span><span class="o">.</span><span class="n">compile_pdfs</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="no">Workflow</span><span class="o">.</span><span class="n">optimize_images</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="no">Workflow</span><span class="o">.</span><span class="n">images_sources</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="no">Workflow</span><span class="o">.</span><span class="n">pages</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="no">Workflow</span><span class="o">.</span><span class="n">chapters</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">),</span> <span class="n">manga_name</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Dá pra ver facilmente como o operador Pipe &ldquo;|&gt;&rdquo; deixa qualquer pipeline de transformação muito mais fácil de ler. Sempre que você está partindo de um valor, passando os resultados por uma <strong>cadeia de transformação</strong>, você vai usar esse operador.</p>
<h3>Próximos Passos<span class="hx:absolute hx:-mt-20" id="próximos-passos"></span>
    <a href="#pr%c3%b3ximos-passos" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Os conceitos apresentados neste artigo são os que eu acho que a maioria das pessoas vai achar mais desafiadores no primeiro contato. Se você entender Pattern Matching e Keyword Lists, vai entender todo o resto.</p>
<p>O site oficial oferece um ótimo <a href="http://elixir-lang.org/getting-started/introduction.html"target="_blank" rel="noopener">Getting Started</a> que você precisa ler inteiro.</p>
<p>Por intuição você já sabe a maior parte das coisas. Você tem blocos &ldquo;do .. end&rdquo;, mas ainda não sabe que eles são só macros de conveniência pra passar uma lista de instruções como argumento dentro de uma Keyword List. Os blocos a seguir são equivalentes:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">if</span> <span class="kp">true</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">+</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="kp">true</span><span class="p">,</span> <span class="k">do</span><span class="p">:</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">+</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="kp">true</span><span class="p">,</span> <span class="o">[</span><span class="p">{</span><span class="ss">:do</span><span class="p">,</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">  <span class="n">a</span> <span class="o">+</span> <span class="mi">10</span>
</span></span><span class="line"><span class="cl"><span class="p">)}</span><span class="o">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>De cair o queixo, hein? Existem muitos macros que adicionam açúcar sintático em cima das primitivas.</p>
<p>Em geral, o Valim tornou as poderosas primitivas do Erlang mais acessíveis (Lists, Atoms, Maps, etc) e adicionou abstrações mais altas usando macros (blocos do .. end, o operador pipe, keyword lists, atalhos pra funções anônimas, etc). Essa combinação precisa é o que torna o Elixir muito gostoso de aprender. É como descascar uma cebola: você começa pelas abstrações mais altas e descobre macros de estruturas mais simples por baixo. Você vê uma Keyword List primeiro e descobre Lists de Tuples. Você vê um bloco e descobre outra Keyword List disfarçada por um macro. E assim vai.</p>
<p>Então você tem uma curva de entrada baixa e pode descer fundo na toca do coelho até o ponto em que está estendendo a própria linguagem.</p>
<p>Elixir oferece um design de linguagem muito esperto em cima do núcleo maduro do Erlang, com 25 anos. Isso é mais que esperto, é a escolha inteligente. Continue aprendendo!</p>
]]></content:encoded><category>tutoriais</category><category>elixir-e-erlang</category><category>programacao</category></item><item><title>Minha primeira semana aprendendo Elixir</title><link>https://akitaonrails.github.io/2015/11/03/minha-primeira-semana-aprendendo-elixir/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/11/03/minha-primeira-semana-aprendendo-elixir/</guid><pubDate>Tue, 03 Nov 2015 11:07:00 -0200</pubDate><description>&lt;p&gt;Resolvi me dedicar a aprender Elixir o suficiente para me sentir confortável em encarar alguns projetos pequenos. Depois de uma semana inteira estudando perto de 6 horas por dia (umas 42 horas no total), ainda não estou totalmente confortável, mas acho que os conceitos principais já assentaram e consigo apreciar plenamente o que Elixir tem a oferecer.&lt;/p&gt;
&lt;p&gt;Não é a primeira vez que mexo com Erlang, na verdade. Tive a sorte de participar de um pequeno workshop no QCon San Francisco 2009 com ninguém menos que &lt;a href="http://www.oreilly.com/pub/au/3373"target="_blank" rel="noopener"&gt;Francesco Cesarini&lt;/a&gt;. Graças a ele, consegui entender um pouco da sintaxe peculiar de Erlang, o conceito correto de processos Erlang, como imutabilidade e pattern matching governam o fluxo de programação. Foi muito esclarecedor. Infelizmente, eu não me via fazendo Erlang em tempo integral. Eu só torcia para que aqueles mecanismos estivessem disponíveis em uma linguagem como Ruby&amp;hellip;&lt;/p&gt;</description><content:encoded><![CDATA[<p>Resolvi me dedicar a aprender Elixir o suficiente para me sentir confortável em encarar alguns projetos pequenos. Depois de uma semana inteira estudando perto de 6 horas por dia (umas 42 horas no total), ainda não estou totalmente confortável, mas acho que os conceitos principais já assentaram e consigo apreciar plenamente o que Elixir tem a oferecer.</p>
<p>Não é a primeira vez que mexo com Erlang, na verdade. Tive a sorte de participar de um pequeno workshop no QCon San Francisco 2009 com ninguém menos que <a href="http://www.oreilly.com/pub/au/3373"target="_blank" rel="noopener">Francesco Cesarini</a>. Graças a ele, consegui entender um pouco da sintaxe peculiar de Erlang, o conceito correto de processos Erlang, como imutabilidade e pattern matching governam o fluxo de programação. Foi muito esclarecedor. Infelizmente, eu não me via fazendo Erlang em tempo integral. Eu só torcia para que aqueles mecanismos estivessem disponíveis em uma linguagem como Ruby&hellip;</p>
<p>Entre 2007 e 2009, Erlang teve uma nova renascença entre os aficionados por linguagens por causa do livro <a href="https://pragprog.com/book/jaerlang/programming-erlang"target="_blank" rel="noopener">&ldquo;Programming Erlang&rdquo;</a> lançado pela The Pragmatic Programmers, escrito por ninguém menos que o próprio Joe Armstrong, criador do Erlang. Dave Thomas <a href="http://pragdave.me/blog/2007/04/15/a-first-erlang-program/"target="_blank" rel="noopener">tentou empurrar Erlang</a> com força em 2007, mas nem ele conseguiu vender o motor poderoso de Erlang por causa da apresentação estranha da sintaxe.</p>
<p>Depois de 2009, José Valim teve uma longa jornada para liberar o controverso big rewrite do Rails 3.0 (que felizmente foi um sucesso) e decidiu dar um tempo e tentar algo diferente. A pesquisa dele acabou levando até Erlang pelos motivos que mencionei acima, mas ele decidiu que poderia resolver o problema da &ldquo;sintaxe esquisita&rdquo;. Você pode ver algumas das primeiras palestras dele sobre Elixir nas gravações do Rubyconf Brasil <a href="https://www.eventials.com/locaweb/jose-valim-vamos-falar-sobre-concorrencia/"target="_blank" rel="noopener">2012</a> e <a href="https://www.eventials.com/locaweb/elixir-uma-aproximacao-pragmatica-e-concorrente-a-programacao/"target="_blank" rel="noopener">2013</a>. O beta inicial saiu em 2012 e ele finalmente lançou a 1.0 estável em 2015. Chris McCord conseguiu lançar o Phoenix estável logo em seguida.</p>
<p>Quando ouvi falar disso pela primeira vez, Elixir entrou no meu radar. Mas eu não pulei de cabeça, entre 2009 e 2015 tivemos uma onda de interesse em &ldquo;programação funcional&rdquo; por causa da renascença do Javascript, do lançamento de Scala, Go Lang, Clojure, da promessa de Rust e por aí vai. Então esperei, acompanhando cada um deles com cuidado.</p>
<p>Aí veio 2014 e de repente todo mundo descobriu Erlang, com sua infraestrutura espartana que permitiu que o Whatsapp servisse meio bilhão de usuários com custos absurdamente baixos e fez o Facebook comprá-los por uns gordos USD 19 bilhões! Todo mundo já sabia do caso Whatsapp pelo menos desde 2011, mas só em 2014 que todo mundo se ligou. Mesmo assim, isso ainda não foi suficiente para colocar Erlang nos holofotes.</p>
<p>Quando o Elixir estável foi lançado neste ano, seguido do Phoenix estável, eu sabia que estava na hora de investir um tempo de qualidade nele. O núcleo de Erlang se vende sozinho: todo mundo está fazendo concorrência por meio de imutabilidade e threads leves (ou green threads, estratégia NxM entre green threads e threads reais). Hoje em dia é trivial estourar uma máquina só disparando milhões de processos leves. O difícil mesmo é criar um sistema com potencial de chegar a <a href="http://stackoverflow.com/questions/8426897/erlangs-99-9999999-nine-nines-reliability"target="_blank" rel="noopener">99,9999999% de confiabilidade</a>. Disparar processos é fácil, como você coordena eles na mesma máquina? Como você coordena eles entre máquinas diferentes? Como você atualiza um sistema rodando sem derrubar ele? Como você lida com falhas? Como você supervisiona tudo?</p>
<p>Essas são as perguntas que Erlang resolveu décadas atrás (<a href="http://www.erlang.org/download/armstrong_thesis_2003.pdf"target="_blank" rel="noopener">20 anos atrás</a>) com a hoje famosa OTP, Open Telecom Platform da Ericsson. Algo criado para atender às necessidades de performance e confiabilidade das telecomunicações em larga escala. Quando a gente fala assim, parece que vai ser uma dor de cabeça monumental aprender, algo como o JEE (Java Enterprise Edition), só que pior.</p>
<p>E posso garantir que aprender OTP o suficiente para ser produtivo é, na verdade, <strong>muito</strong> fácil (você não vai conquistar a lendária confiabilidade de 99,9999999% do nada, mas vai conseguir construir algo confiável o bastante). Pense nisso como uma coleção de meia dúzia de módulos, com algumas interfaces de função para implementar, algumas linhas de configuração e basicamente acabou. É tão fácil e leve que muitas bibliotecas pequenas são escritas pensando em OTP e dá para fazer &ldquo;plug and play&rdquo; tranquilamente. Não é uma coisa pesada só de servidor.</p>
<p>Para domar esse poder você precisa aprender Elixir, extraoficialmente uma linguagem com uma semelhança incrível com Ruby, feita para cuspir bytecode Erlang para sua máquina virtual BEAM. Não tem combinação melhor.</p>
<h3>Uma Semana<span class="hx:absolute hx:-mt-20" id="uma-semana"></span>
    <a href="#uma-semana" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Dito tudo isso, vamos ao que interessa. Você definitivamente quer se familiarizar com os conceitos de Programação Funcional como imutabilidade, higher order functions, pattern matching. Fiz uma lista de links para esses conceitos no <a href="http://www.akitaonrails.com/2015/10/28/personal-thoughts-on-the-current-functional-programming-bandwagon"target="_blank" rel="noopener">meu post anterior</a>, recomendo a leitura.</p>
<p>Assumindo que você já é programador em uma linguagem dinâmica (Ruby, Python, Javascript, etc) e quer o crash course rápido. Comece comprando <a href="https://pragprog.com/book/elixir/programming-elixir"target="_blank" rel="noopener">&ldquo;Programming Elixir&rdquo;</a> do Dave Thomas e faça cada pedaço de código e cada exercício na ordem. É um livro tão fácil de ler que você consegue terminar em menos de uma semana. Eu fiz em 3 dias. O site oficial do Elixir-Lang tem uma <a href="http://elixir-lang.org/getting-started/introduction.html"target="_blank" rel="noopener">documentação muito boa</a> também e eles linkam vários <a href="http://elixir-lang.org/learning.html"target="_blank" rel="noopener">bons livros</a> que você vai querer ler depois.</p>
<p>Depois assine o <a href="http://elixirsips.com"target="_blank" rel="noopener">Elixir Sips</a> do Josh Adams. Se você é Rubyista, é como assistir aos Railscasts do Ryan Bates desde o começo de novo. Embora seja mais parecido com o show RubyTapas do Avdi Grimm, com episódios bem curtos só para você ter sua dose semanal de Elixir.</p>
<p>Você pode assistir alguns episódios de graça em baixa resolução, mas recomendo fortemente que você assine e assista as versões em HD. Vale muito a pena. Sobre os episódios, são mais de 200. Eu assisti mais de 130 em 12 horas :-) Então calculo mais 2 dias para assistir tudo.</p>
<p>Você definitivamente deve assistir tudo se conseguir, mas se não conseguir, deixa eu listar os que considero essenciais. Antes de mais nada, lembre-se que o Josh faz isso há um tempão, quando ele começou Elixir estava na versão 0.13 ou abaixo e Erlang na versão 17 ou abaixo.</p>
<p>Por exemplo, o episódio <a href="https://elixirsips.dpdcart.com/subscriber/post?id=815"target="_blank" rel="noopener">171 - Erlang 18 and time</a> destaca a nova API de Time. Você precisa saber disso. O episódio <a href="https://elixirsips.dpdcart.com/subscriber/post?id=460"target="_blank" rel="noopener">056 - Migrating Records to Maps</a> mostra um recurso novo do Erlang 17 e Elixir onde Maps passam a ser preferíveis aos antigos Records. Maps são explicados nos episódios <a href="https://elixirsips.dpdcart.com/subscriber/post?id=453"target="_blank" rel="noopener">054</a> e <a href="https://elixirsips.dpdcart.com/subscriber/post?id=454"target="_blank" rel="noopener">055</a>. Se você for aprender o framework web Phoenix, ele usa o ORM Ecto por baixo e os models do Ecto são Maps, então você precisa saber disso.</p>
<p>Isso significa que os primeiros 180 episódios, no mínimo, estão usando versões anteriores de Erlang, Elixir, Phoenix, etc, e você precisa ter em mente que versões novas terão APIs diferentes. Esse foi um dos motivos pelos quais esperei pelos releases estáveis, porque era natural que os projetos evoluíssem e levassem tempo para ter APIs estáveis, e correr atrás de vários alvos móveis é realmente difícil para iniciantes.</p>
<p>Dito isso, assista a esta lista primeiro:</p>
<ul>
<li>001 - Introduction and Installing Elixir.mp4</li>
<li>002 - Basic Elixir.mp4</li>
<li>003 - Pattern Matching.mp4</li>
<li>004 - Functions.mp4</li>
<li>005 - Mix and Modules.mp4</li>
<li>006 - Unit Testing.mp4</li>
<li>010 - List Comprehensions.mp4</li>
<li>011 - Records.mp4</li>
<li>012 - Processes.mp4</li>
<li>013 - Processes, Part 2.mp4</li>
<li>014 - OTP Part 1_ Servers.mp4</li>
<li>015 - OTP Part 2_ Finite State Machines.mp4</li>
<li>016 - Pipe Operator.mp4</li>
<li>017 - Enum, Part 1.mp4</li>
<li>018 - Enum, Part 2.mp4</li>
<li>019 - Enum, Part 3.mp4</li>
<li>020 - OTP, Part 3 - GenEvent.mp4</li>
<li>022 - OTP, Part 4_ Supervisors.mp4</li>
<li>023 - OTP, Part 5_ Supervisors and Persistent State.mp4</li>
<li>024 - Ecto, Part 1.mp4</li>
<li>025 - Ecto, Part 2_ Dwitter.mp4</li>
<li>026 - Dict, Part 1.mp4</li>
<li>027 - Dict, Part 2.mp4</li>
<li>028 - Parsing XML.mp4</li>
<li>031 - TCP Servers.mp4</li>
<li>032 - Command Line Scripts.mp4</li>
<li>033 - Pry.mp4</li>
<li>041 - File, Part 1.mp4</li>
<li>042 - File, Part 2.mp4</li>
<li>044 - Distribution</li>
<li>045 - Distribution, Part 2</li>
<li>054 - Maps, Part 1.mp4</li>
<li>055 - Maps, Part 2_ Structs.mp4</li>
<li>056 - Migrating Records To Maps.mp4</li>
<li>059 - Custom Mix Tasks.mp4</li>
<li>060 - New Style Comprehensions.mp4</li>
<li>061 - Plug.mp4</li>
<li>063 - Tracing.mp4</li>
<li>065 - SSH.mp4</li>
<li>066 - Plug.Static.mp4</li>
<li>067 - Deploying to Heroku.mp4</li>
<li>068 - Port.mp4</li>
<li>069 - Observer.mp4</li>
<li>070 - Hex.mp4</li>
<li>073 - Process Dictionaries.mp4</li>
<li>074 - ETS.mp4</li>
<li>075 - DETS.mp4</li>
<li>076 - Streams.mp4</li>
<li>077 - Exceptions and Errors.mp4</li>
<li>078 - Agents.mp4</li>
<li>079 - Tasks.mp4</li>
<li>081 - EEx.mp4</li>
<li>082 - Protocols.mp4</li>
<li>083 - pg2.mp4</li>
<li>086 - put_in and get_in.mp4</li>
<li>090 - Websockets Terminal.mp4</li>
<li>091 - Test Coverage.mp4</li>
<li>106 - Text Parsing.mp4</li>
<li>109 - Socket.mp4</li>
<li>112 - Benchfella.mp4</li>
<li>113 - Monitoring Network Traffic.mp4</li>
<li>124 - Typespecs.mp4</li>
<li>125 - Dialyzer.mp4</li>
<li>126 - Piping Into Elixir.mp4</li>
<li>127 - SSH Client Commands.mp4</li>
<li>131 - ExProf.mp4</li>
<li>132 - Randomness in the Erlang VM.mp4</li>
<li>135 - Benchwarmer.mp4</li>
<li>138 - Monitors and Links.mp4</li>
<li>139 - hexdocs.mp4</li>
<li>141 - Set.mp4</li>
<li>142 - escript.mp4</li>
<li>144 - Erlang&rsquo;s <code>calendar</code> module.mp4</li>
<li>145 - good_times.mp4</li>
<li>153 - Phoenix APIs and CORS.mp4</li>
<li>155 - OAuth2_ Code Spelunking.mp4</li>
<li>156 - Interacting with Amazon&rsquo;s APIs with erlcloud.mp4</li>
<li>157 - Playing with the Code Module Part 1 - eval_string.mp4</li>
<li>159 - Simple One for One Supervisors.mp4</li>
<li>160 - MultiDef.mp4</li>
<li>171 - Erlang 18 and Time.mp4</li>
<li>172 - Arc File Uploads.mp4</li>
<li>174 - ElixirFriends_ Saving Tweets with Streams and Filters.mp4</li>
<li>175 - Pagination with Ecto and Phoenix using Scrivener.mp4</li>
<li>176 - Prettying Up ElixirFriends.mp4</li>
<li>178 - Memory Leaks.mp4</li>
<li>179 - Rules Engine.mp4</li>
<li>180 - Collectable.mp4</li>
<li>182 - Phoenix API.mp4</li>
<li>183 - React with Phoenix.mp4</li>
<li>184 - React with Phoenix Channels.mp4</li>
<li>185 - Mix Archives.mp4</li>
<li>186 - Automatically Connecting Nodes.mp4</li>
<li>187 - Compiling a Custom AST Into Elixir Functions.mp4</li>
<li>190 - Testing Phoenix Channels.mp4</li>
<li>193 - Linting with Dogma.mp4</li>
<li>194 - Interoperability_ Ports.mp4</li>
<li>196 - Crashing the BEAM.mp4</li>
<li>200 - Custom Types in Ecto.mp4</li>
<li>201 - Tracing and Debugging with erlyberly.mp4</li>
<li>202 - Exception Monitoring with Honeybadger.io.mp4</li>
<li>203 - plug_auth.mp4</li>
<li>204 - Behaviours.mp4</li>
</ul>
<p>Isso é mais ou menos metade do que tem disponível no Elixir Sips. Todos os outros episódios também são interessantes, mas se você está só começando, essa lista deve ser suficiente para molhar os pés na linguagem.</p>
<p>Quem vem do Rails vai curtir Phoenix e o ecossistema que está crescendo em volta dele. Você já consegue autenticar via <a href="https://github.com/scrogson/oauth2"target="_blank" rel="noopener">OAuth2</a>, fazer paginação no estilo will_paginate com <a href="https://github.com/drewolson/scrivener"target="_blank" rel="noopener">Scrivener</a>, upload de arquivos no estilo carrierwave com <a href="https://github.com/stavro/arc"target="_blank" rel="noopener">Arc</a>, deploy no <a href="http://wsmoak.net/2015/07/05/phoenix-on-heroku.html"target="_blank" rel="noopener">Heroku</a>.</p>
<p>Para mais exercícios, você pode conectar facilmente em endpoints HTTP usando <a href="https://github.com/edgurgel/httpoison"target="_blank" rel="noopener">HTTPoison</a>, parsear HTML com <a href="https://github.com/philss/floki"target="_blank" rel="noopener">Floki</a>, parsear JSON com <a href="https://github.com/devinus/poison"target="_blank" rel="noopener">Poison</a>. Para mais bibliotecas, você pode acompanhar a página no Github chamada <a href="https://github.com/h4cc/awesome-elixir"target="_blank" rel="noopener">Awesome Elixir</a> que lista vários pacotes Elixir novos que você pode usar. Mas garanta que você vai passar pelos conceitos básicos primeiro. Elixir tem um sistema de gerenciamento de tarefas estilo Rake embutido com o Mix, você pode adicionar dependências em um arquivo estilo Gemfile chamado Mix.exs, que todo projeto tem. Você pode adicionar dependências por URLs do Github ou via <a href="https://hex.pm"target="_blank" rel="noopener">Hex.pm</a>, que é como o Rubygems.org.</p>
<p>Nesse processo de aprendizado, os conceitos que considero mais importantes para aprender primeiro são:</p>
<ul>
<li>Sintaxe e conceitos básicos de Elixir (pattern matching, loops via recursão, estado imutável, tipos primitivos incluindo Maps, o pipe operator)</li>
<li>O conceito de processos, nós e a intercomunicação entre processos e nós, incluindo Monitors e Links.</li>
<li>Básico de OTP, aprenda o que são GenServer, GenEvent, GenFSM.</li>
</ul>
<p>Depois de aprender isso, você consegue descobrir como construir aplicações OTP e fazer algo prático para a Web usando Phoenix, em particular você vai querer aprender tudo sobre os Channels do Phoenix, a infraestrutura para WebSockets robustos, rápidos e <a href="http://www.akitaonrails.com/2015/10/29/phoenix-experiment-holding-2-million-websocket-clients"target="_blank" rel="noopener">altamente concorrentes</a>.</p>
<p>É isso. Essa foi a minha primeira semana aprendendo Elixir, e meu próximo passo é me treinar fazendo mais exercícios e também aprendendo mais sobre Phoenix. Mesmo Phoenix sendo inspirado em Rails, ele não é um clone, tem seu próprio conjunto único de conceitos para aprender e isso definitivamente vai ser uma viagem muito interessante.</p>
<p>Se você tiver mais dicas e truques para iniciantes, fique à vontade para comentar abaixo.</p>
]]></content:encoded><category>aprendizado</category><category>elixir-e-erlang</category><category>programacao</category></item><item><title>[Small Bites] Brincando de Crawlers e algumas Dicas Úteis</title><link>https://akitaonrails.github.io/2015/05/15/small-bites-brincando-de-crawlers-e-algumas-dicas-uteis/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/05/15/small-bites-brincando-de-crawlers-e-algumas-dicas-uteis/</guid><pubDate>Fri, 15 May 2015 09:10:00 -0300</pubDate><description>&lt;p&gt;Eu queria fazer uma limpeza geral na minha conta do Slack (que já tinha mais do que o suficiente de imagens-memes entupindo o limite de armazenamento), o problema é que ele não tem um &amp;ldquo;marcar tudo&amp;rdquo; e &amp;ldquo;deletar tudo&amp;rdquo; na interface de administração, mas felizmente ele tem APIs!&lt;/p&gt;
&lt;p&gt;Então eu escrevi &lt;a href="https://gist.github.com/akitaonrails/38cbbc2c37a7c646fe27"target="_blank" rel="noopener"&gt;este pequeno script em Ruby&lt;/a&gt; que tem &lt;strong&gt;4 dicas&lt;/strong&gt; que vale a pena compartilhar:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ruby" data-lang="ruby"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bundler/setup&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="no"&gt;Bundler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;typhoeus/adapters/faraday&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# documentations:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# https://api.slack.com/methods/files.list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# https://api.slack.com/methods/files.delete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;api_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SLACK_API_TOKEN&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;abort&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;no api token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;per_page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/api/files.list?token=%s&amp;amp;ts_from=0&amp;amp;ts_to=now&amp;amp;types=all&amp;amp;count=%s&amp;amp;page=%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Faraday&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:url&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://slack.com/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;faraday&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;faraday&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="ss"&gt;:url_encoded&lt;/span&gt; &lt;span class="c1"&gt;# form-encode POST params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;faraday&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="ss"&gt;:logger&lt;/span&gt; &lt;span class="c1"&gt;# log requests to STDOUT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;faraday&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;adapter&lt;/span&gt; &lt;span class="ss"&gt;:typhoeus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;api_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Oj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;total_pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;paging&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pages&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;to_i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_parallel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;total_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;api_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;files_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="no"&gt;Parallel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;in_threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Oj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="no"&gt;Parallel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;files&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;in_threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;files_ids&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;uri_delete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://slack.com/api/files.delete?token=%s&amp;amp;file=%s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_parallel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;files_ids&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;uri_delete&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;api_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="no"&gt;Oj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Dica 1&lt;span class="hx:absolute hx:-mt-20" id="dica-1"&gt;&lt;/span&gt;
&lt;a href="#dica-1" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Mesmo em pequenos scripts, use &lt;a href="http://bundler.io/bundler_setup.html"target="_blank" rel="noopener"&gt;Bundler&lt;/a&gt;!&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu queria fazer uma limpeza geral na minha conta do Slack (que já tinha mais do que o suficiente de imagens-memes entupindo o limite de armazenamento), o problema é que ele não tem um &ldquo;marcar tudo&rdquo; e &ldquo;deletar tudo&rdquo; na interface de administração, mas felizmente ele tem APIs!</p>
<p>Então eu escrevi <a href="https://gist.github.com/akitaonrails/38cbbc2c37a7c646fe27"target="_blank" rel="noopener">este pequeno script em Ruby</a> que tem <strong>4 dicas</strong> que vale a pena compartilhar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;bundler/setup&#39;</span>
</span></span><span class="line"><span class="cl"><span class="no">Bundler</span><span class="o">.</span><span class="n">require</span><span class="p">(</span><span class="ss">:default</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;typhoeus/adapters/faraday&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># documentations:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://api.slack.com/methods/files.list</span>
</span></span><span class="line"><span class="cl"><span class="c1"># https://api.slack.com/methods/files.delete</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">api_token</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;SLACK_API_TOKEN&#39;</span><span class="o">]</span> <span class="ow">or</span> <span class="nb">abort</span> <span class="s2">&#34;no api token&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">per_page</span> <span class="o">=</span> <span class="mi">500</span>
</span></span><span class="line"><span class="cl"><span class="n">uri</span> <span class="o">=</span> <span class="s2">&#34;/api/files.list?token=%s&amp;ts_from=0&amp;ts_to=now&amp;types=all&amp;count=%s&amp;page=%s&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">conn</span> <span class="o">=</span> <span class="no">Faraday</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:url</span> <span class="o">=&gt;</span> <span class="s1">&#39;https://slack.com/&#39;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">faraday</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">faraday</span><span class="o">.</span><span class="n">request</span>  <span class="ss">:url_encoded</span>             <span class="c1"># form-encode POST params</span>
</span></span><span class="line"><span class="cl">  <span class="n">faraday</span><span class="o">.</span><span class="n">response</span> <span class="ss">:logger</span>                  <span class="c1"># log requests to STDOUT</span>
</span></span><span class="line"><span class="cl">  <span class="n">faraday</span><span class="o">.</span><span class="n">adapter</span>  <span class="ss">:typhoeus</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">get</span><span class="p">(</span> <span class="n">uri</span> <span class="o">%</span> <span class="o">[</span><span class="n">api_token</span><span class="p">,</span> <span class="n">per_page</span><span class="p">,</span> <span class="mi">1</span><span class="o">]</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">json</span> <span class="o">=</span> <span class="no">Oj</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">total_pages</span> <span class="o">=</span> <span class="n">json</span><span class="o">[</span><span class="s2">&#34;paging&#34;</span><span class="o">][</span><span class="s2">&#34;pages&#34;</span><span class="o">].</span><span class="n">to_i</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">responses</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">conn</span><span class="o">.</span><span class="n">in_parallel</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="n">total_pages</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">page</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">responses</span> <span class="o">&lt;&lt;</span> <span class="n">conn</span><span class="o">.</span><span class="n">get</span><span class="p">(</span> <span class="n">uri</span> <span class="o">%</span> <span class="o">[</span><span class="n">api_token</span><span class="p">,</span> <span class="n">per_page</span><span class="p">,</span> <span class="n">page</span><span class="o">]</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">files_ids</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">errors</span> <span class="o">=</span> <span class="o">[]</span>
</span></span><span class="line"><span class="cl"><span class="no">Parallel</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="n">responses</span><span class="p">,</span> <span class="ss">in_threads</span><span class="p">:</span> <span class="mi">10</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">response</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="k">begin</span>
</span></span><span class="line"><span class="cl">    <span class="n">json</span> <span class="o">=</span> <span class="no">Oj</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Parallel</span><span class="o">.</span><span class="n">each</span><span class="p">(</span><span class="n">json</span><span class="o">[</span><span class="s2">&#34;files&#34;</span><span class="o">]</span><span class="p">,</span> <span class="ss">in_threads</span><span class="p">:</span> <span class="mi">10</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">      <span class="n">files_ids</span> <span class="o">&lt;&lt;</span> <span class="n">file</span><span class="o">[</span><span class="s2">&#34;id&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
</span></span><span class="line"><span class="cl">    <span class="n">errors</span> <span class="o">&lt;&lt;</span> <span class="n">e</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">uri_delete</span> <span class="o">=</span> <span class="s2">&#34;https://slack.com/api/files.delete?token=%s&amp;file=%s&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">conn</span><span class="o">.</span><span class="n">in_parallel</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">files_ids</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">file_id</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">responses</span> <span class="o">&lt;&lt;</span> <span class="n">conn</span><span class="o">.</span><span class="n">get</span><span class="p">(</span> <span class="n">uri_delete</span> <span class="o">%</span> <span class="o">[</span><span class="n">api_token</span><span class="p">,</span> <span class="n">file_id</span><span class="o">]</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">puts</span> <span class="n">responses</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">response</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="no">Oj</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">body</span><span class="p">)</span><span class="o">[</span><span class="s2">&#34;ok&#34;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Dica 1<span class="hx:absolute hx:-mt-20" id="dica-1"></span>
    <a href="#dica-1" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Mesmo em pequenos scripts, use <a href="http://bundler.io/bundler_setup.html"target="_blank" rel="noopener">Bundler</a>!</p>
<h3>Dica 2<span class="hx:absolute hx:-mt-20" id="dica-2"></span>
    <a href="#dica-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Para acessar páginas Web, use a gem <a href="https://github.com/lostisland/faraday"target="_blank" rel="noopener">&ldquo;Faraday&rdquo;</a> junto com a gem <a href="https://github.com/typhoeus/typhoeus"target="_blank" rel="noopener">&ldquo;Typhoeus&rdquo;</a>.</p>
<p>Por que Faraday?</p>
<p>Porque ela abstrai diversos clientes HTTP. Você pode mudar entre Net::HTTP ou Excon ou Typhoeus com mínimo esforço e pode ser útil para diferenciar cenários de produção com um adapter e testes com outro adapter, por exemplo.</p>
<p>Por que Typhoeus?</p>
<p>Porque ela é capaz de realizar diversas requisições em paralelo e o que mais queremos num crawler é paralelizar o máximo possível (vide linhas 25..29 e 45..48 para exemplos). O único cuidado é não puxar coisa demais e estourar o acumulador de retornos (no exemplo, o array <tt>responses</tt>).</p>
<p>Para evitar estourar memória em vez de acumular internamente num array como no exemplo, já use a gem &ldquo;Dalli&rdquo; e vá acumulando num Memcached ou acumule num Redis ou MongoDB ou qualquer outro sistema de armazenamento que suporte inserções assíncronas (não bloqueantes, como um RDBMS normal).</p>
<h3>Dica 3<span class="hx:absolute hx:-mt-20" id="dica-3"></span>
    <a href="#dica-3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se estiver recebendo respostas JSON, use um parser rápido como a gem <a href="https://github.com/ohler55/oj"target="_blank" rel="noopener">&ldquo;Oj&rdquo;</a>. Em conjunto com a gem <a href="https://github.com/ohler55/oj_mimic_json"target="_blank" rel="noopener">&ldquo;oj_mimic_json&rdquo;</a> - que você deve colocar junto na Gemfile se for um projeto Rails - ela substitui a padrão gem JSON que o ActiveSupport usa. A Oj é de 2 a 4 vezes mais rápido do que a gem JSON por isso vale a pena usá-la. Claro, ela é rápida assim porque possui uma extension feita em C, ou seja não funciona com JRuby, apenas com MRI.</p>
<h3>Dica 4<span class="hx:absolute hx:-mt-20" id="dica-4"></span>
    <a href="#dica-4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Uma vez que recebemos dezenas de respostas, queremos processá-las o mais rápido possível e fazer um mesmo <tt>responses.each { |response| &hellip; }</tt> é lento porque é linear.</p>
<p>Para resolver isso podemos recorrer à gem <a href="https://github.com/grosser/parallel"target="_blank" rel="noopener">&ldquo;Parallel&rdquo;</a> (vide exemplos nas linhas 33..42). Ela vai iterar pela coleção paralelamente usando threads.</p>
<p>Em Ruby MRI, lembrar que temos o Global Interpreter Lock (GIL) que bloqueia a execução paralela porque a mudança de estados em código C sem mutexes e outras proteções poderia corromper a execução. Então não precisamos nos preocupar com estado global compartilhado sendo alterado em paralelo por múltiplas threads mas por outro lado não temos multithreading real o tempo todo.</p>
<p>Mas temos como usar threads em operações bloqueantes, I/O bound, ou que tem muita espera (operações com arquivos ou rede). Nesse caso, quando uma thread bloquear esperando a resposta de algum I/O, outra thread pode de fato executar em paralelo. E daí o valor de usar threads no caso de crawlers ou scripts que façam import/export em banco de dados, etc.</p>
<p>Para o caso de I/O bound, usar threads. Mas se o caso for algo CPU-bound, de processamento de dados, cálculos, mais pesados, threads não vão ajudar. Para isso em vez da opção <tt>:in_threads</tt> você usa a opção <tt>:in_processes</tt> que vai fazer um <tt>fork()</tt> do seu processo e vai rodar realmente em paralelo em processos independentes e isolados, sem estado compartilhado.</p>
<p>Como desde o Ruby 2.0 ele suporta <a href="https://blog.engineyard.com/2013/ruby-2-0-under-the-hood#copy-on-write"target="_blank" rel="noopener">&ldquo;Copy on Write&rdquo;</a> (ou &ldquo;COW&rdquo;) de tal forma que mesmo duplicando um processo Ruby, ele não vai duplicar a memória, eles vão compartilhar a memória que não muda e cada processo isola somente a memória que ele mudar. Isso torna rodar processos em paralelo não tão caros em termos de consumo de memória e muito mais fáceis de escrever (sem precisar se preocupar com mutexes e semáforos, já que tudo rodará garantidamente isolado).</p>
<p>Ou seja, para casos justamente como um crawler ou um ETL, a gem &ldquo;Parallel&rdquo; pode ser uma mão na roda. Mas sempre meça para saber se as coisas estão realmente paralelas ou se você não está bloqueando suas threads e caindo no caso de execução linear sem saber.</p>
]]></content:encoded><category>ruby</category><category>performance</category><category>programacao</category></item><item><title>[Criptografia] Não use TripleDES/ECB - e uma curiosidade sobre Cipher Key do .Net</title><link>https://akitaonrails.github.io/2014/01/13/criptografia-nao-use-tripledes-ecb-e-uma-curiosidade-sobre-cipher-key-do-net/</link><guid isPermaLink="true">https://akitaonrails.github.io/2014/01/13/criptografia-nao-use-tripledes-ecb-e-uma-curiosidade-sobre-cipher-key-do-net/</guid><pubDate>Mon, 13 Jan 2014 13:01:00 -0200</pubDate><description>&lt;p&gt;Recentemente num de nossos projetos tivemos que lidar com uma integração de dados vindo de um sistema feito em C#. Até aqui nenhum problema. O código que tivemos que usar como referência, vindo de um parceiro de nosso cliente, foi basicamente este:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-C" data-lang="C"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Security&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cryptography&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;EncryptData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;EncryptData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8Encoding&lt;/span&gt; &lt;span class="n"&gt;UTF8&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UTF8Encoding&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MD5CryptoServiceProvider&lt;/span&gt; &lt;span class="n"&gt;HashProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MD5CryptoServiceProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;TDESKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HashProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ComputeHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;abc123&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TripleDESCryptoServiceProvider&lt;/span&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TripleDESCryptoServiceProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TDESKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CipherMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ECB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PaddingMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PKCS7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;DataToEncrypt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ICryptoTransform&lt;/span&gt; &lt;span class="n"&gt;Encryptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateEncryptor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encryptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TransformFinalBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataToEncrypt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataToEncrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;finally&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TDESAlgorithm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HashProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToBase64String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Não estou quebrando confidencialidade simplesmente porque este é um código publicamente conhecido disponível no site &lt;a href="http://www.codeproject.com/Tips/306620/Encryption-Decryption-Function-in-Net-using-MD5Cry"target="_blank" rel="noopener"&gt;CodeProject&lt;/a&gt;, sob licença. &lt;a href="http://www.codeproject.com/info/cpol10.aspx"target="_blank" rel="noopener"&gt;CPOL&lt;/a&gt;. O que eu vi foi uma cópia exata disso. Mas cuidado: grandes empresas, em grandes sistemas usados por milhões de pessoas usam código exatamente como este. (#MEDO)&lt;/p&gt;</description><content:encoded><![CDATA[<p>Recentemente num de nossos projetos tivemos que lidar com uma integração de dados vindo de um sistema feito em C#. Até aqui nenhum problema. O código que tivemos que usar como referência, vindo de um parceiro de nosso cliente, foi basicamente este:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">using</span> <span class="n">System</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">using</span> <span class="n">System</span><span class="p">.</span><span class="n">Security</span><span class="p">.</span><span class="n">Cryptography</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">using</span> <span class="n">System</span><span class="p">.</span><span class="n">Text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">class</span> <span class="n">Program</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">public</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">Main</span><span class="p">(</span><span class="n">String</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="nf">EncryptData</span><span class="p">(</span><span class="s">&#34;hello world&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">public</span> <span class="k">static</span> <span class="n">string</span> <span class="nf">EncryptData</span><span class="p">(</span><span class="n">string</span> <span class="n">Message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">byte</span><span class="p">[]</span> <span class="n">Results</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">System</span><span class="p">.</span><span class="n">Text</span><span class="p">.</span><span class="n">UTF8Encoding</span> <span class="n">UTF8</span> <span class="o">=</span> <span class="n">new</span> <span class="n">System</span><span class="p">.</span><span class="n">Text</span><span class="p">.</span><span class="nf">UTF8Encoding</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">     <span class="n">MD5CryptoServiceProvider</span> <span class="n">HashProvider</span> <span class="o">=</span> <span class="n">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">     <span class="n">byte</span><span class="p">[]</span> <span class="n">TDESKey</span> <span class="o">=</span> <span class="n">HashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="s">&#34;abc123&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">     <span class="n">TripleDESCryptoServiceProvider</span> <span class="n">TDESAlgorithm</span> <span class="o">=</span> <span class="n">new</span> <span class="nf">TripleDESCryptoServiceProvider</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">     <span class="n">TDESAlgorithm</span><span class="p">.</span><span class="n">Key</span> <span class="o">=</span> <span class="n">TDESKey</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">TDESAlgorithm</span><span class="p">.</span><span class="n">Mode</span> <span class="o">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">TDESAlgorithm</span><span class="p">.</span><span class="n">Padding</span> <span class="o">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">byte</span><span class="p">[]</span> <span class="n">DataToEncrypt</span> <span class="o">=</span> <span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">Message</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="n">try</span>
</span></span><span class="line"><span class="cl">     <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">ICryptoTransform</span> <span class="n">Encryptor</span> <span class="o">=</span> <span class="n">TDESAlgorithm</span><span class="p">.</span><span class="nf">CreateEncryptor</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">         <span class="n">Results</span> <span class="o">=</span> <span class="n">Encryptor</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">DataToEncrypt</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">DataToEncrypt</span><span class="p">.</span><span class="n">Length</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="n">finally</span>
</span></span><span class="line"><span class="cl">     <span class="p">{</span>                
</span></span><span class="line"><span class="cl">         <span class="n">TDESAlgorithm</span><span class="p">.</span><span class="nf">Clear</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">         <span class="n">HashProvider</span><span class="p">.</span><span class="nf">Clear</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ToBase64String</span><span class="p">(</span><span class="n">Results</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Não estou quebrando confidencialidade simplesmente porque este é um código publicamente conhecido disponível no site <a href="http://www.codeproject.com/Tips/306620/Encryption-Decryption-Function-in-Net-using-MD5Cry"target="_blank" rel="noopener">CodeProject</a>, sob licença. <a href="http://www.codeproject.com/info/cpol10.aspx"target="_blank" rel="noopener">CPOL</a>. O que eu vi foi uma cópia exata disso. Mas cuidado: grandes empresas, em grandes sistemas usados por milhões de pessoas usam código exatamente como este. (#MEDO)</p>
<p>O ponto de atenção é que este exemplo tenta ser o mais simples possível. Por isso ele escolhe <a href="http://en.wikipedia.org/wiki/Triple_DES"target="_blank" rel="noopener">TripleDES</a> - que é o DES aplicado 3 vezes pra cada bloco de dados -, um dos algoritmos mais antigos e mais simples, em vez de usar algo mais moderno como Rijndael/AES. Pior ainda, TripleDES não seria tão ruim se fosse usado no modo CBC em vez do modo ECB.</p>
<p>Falando em termos de leigo, a diferença é que o modo CBC (Cipher Block Chaining) exige o uso de um <a href="http://bit.ly/1m2TCjI"target="_blank" rel="noopener">Initialization Vector (IV)</a> além da chave de encriptação. Diferente da chave - que deve ser &ldquo;secreta&rdquo; - o IV pode ser público e transmitido remotamente. O modo CBC vai usar esses dois componentes para fazer transformações em cadeia nos dados, adicionando uma camada extra de segurança.</p>
<p>No modo ECB (Electronic Code Book) você só precisa da chave - e por isso todo mundo usa TripleDES em modo ECB para exemplos e tutoriais: porque é mais simples - e aqui vai uma crítica para tutoriais que simplificam demais sem explicar as implicações, especialmente de segurança (!). O modo ECB é considerado inseguro.</p>
<p>Não sou um especialista em segurança, mas em termos leigos o mesmo dado passado pelo TripleDES com a mesma chave gera a mesma saída encriptada. Portanto se eu souber a entrada e saída de alguns dados, posso encontrar padrões que ajudem a decriptar outros dados, e impede o uso de <a href="http://en.wikipedia.org/wiki/Dictionary_attack"target="_blank" rel="noopener">ataques baseados em dicionários</a> e <a href="http://en.wikipedia.org/wiki/Rainbow_table"target="_blank" rel="noopener">rainbow tables</a>. Como um IV novo é gerado para cada vez que encripto no modo CBC (<em>importante:</em> sempre gere um novo IV aleatoriamente - tem métodos pra isso, não reuse IVs), o mesmo dado de entrada não gera duas saída iguais, dificultando muito encontrar padrões que ajudem a quebrar outros dados. É a mesma razão de porque usamos <a href="http://bit.ly/JV5KHv"target="_blank" rel="noopener">&ldquo;salts&rdquo;</a> ao gerar digests de senhas antes de armazenar numa tabela de banco de dados. Esta resposta no <a href="http://security.stackexchange.com/questions/6058/is-real-salt-the-same-as-initialization-vectors"target="_blank" rel="noopener">StackExchange</a> descreve melhor.</p>
<p>Portanto, se possível, use um algoritmo decente como AES-256, como <a href="http://www.codeproject.com/Articles/662187/FIPS-Encryption-Algorithms-and-Implementation-of-A"target="_blank" rel="noopener">neste exemplo</a>. E se for usar TripleDES, pelo menos evite ECB e vá para CBC, mesmo com o trabalho extra de precisar de um IV.</p>
<p>Aliás, se puder também evite MD5 ou SHA1 para gerar digests de senhas. Eles são algoritmos &ldquo;rápidos&rdquo;, quebráveis com rainbow tables e força bruta. Por isso hoje usamos algoritmos que são computacionalmente &ldquo;caros&rdquo; (demorados) como <a href="http://www.warmenhoven.co/2012/03/06/do-not-use-md5-or-sha1-to-simply-hash-db-passwords/"target="_blank" rel="noopener">bcrypt</a>. MD5 e SHA1 são bons pra checar integridade de um download, por exemplo, e isso tem que ser rápido. Mas para evitar força bruta, use um demorado para o digest de senhas.</p>
<h2>A Curiosidade: MD5 da Cipher Key (passphrase)<span class="hx:absolute hx:-mt-20" id="a-curiosidade-md5-da-cipher-key-passphrase"></span>
    <a href="#a-curiosidade-md5-da-cipher-key-passphrase" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Como disse antes, independente da qualidade do código original, precisávamos fazer um em Ruby que gerasse o mesmo resultado. A &ldquo;tradução&rdquo; do código C# anterior em Ruby seria assim (versão simplificada):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;openssl&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;digest/md5&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;base64&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">encrypt_data</span><span class="p">(</span><span class="n">passphrase</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">Cipher</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;des-ede3&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span><span class="o">.</span><span class="n">encrypt</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="no">Digest</span><span class="o">::</span><span class="no">MD5</span><span class="o">.</span><span class="n">digest</span><span class="p">(</span><span class="n">passphrase</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="no">Base64</span><span class="o">.</span><span class="n">encode64</span><span class="p">(</span><span class="n">cipher</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="o">+</span> <span class="n">cipher</span><span class="o">.</span><span class="n">final</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É só isso mesmo. Vamos por partes.</p>
<ul>
<li>Não deixe de ler a <a href="http://ruby-doc.org/stdlib-2.1.0/libdoc/openssl/rdoc/OpenSSL.html"target="_blank" rel="noopener">documentação do OpenSSL</a>, ele explica bem as coisas que vou dizer a seguir.</li>
<li>Pra escolher TripleDES em modo ECB basta instanciar com &ldquo;des-ede3&rdquo;, pra ser CBC seria &ldquo;des-ede3-cbc&rdquo; ou apenas &ldquo;des3&rdquo; (alias)</li>
<li>Por padrão o padding é <a href="http://ruby-doc.org/stdlib-2.1.0/libdoc/openssl/rdoc/OpenSSL/PKCS7.html"target="_blank" rel="noopener">PKCS7</a>, então não precisa especificar.</li>
<li>Sempre chame o método <tt>#encrypt</tt> antes de configurar a chave.</li>
<li>Para pegar o resultado precisa chamar o método <tt>#update</tt> antes e concatenar com <tt>#final</tt>.</li>
<li>Passamos o resultado por Base64 porque ele é binário, se quisermos uma string precisa converter.</li>
</ul>
<p>Se tentar rodar este método ele vai dar o seguinte problema:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>&gt; encrypt_data(&#34;abc123&#34;, &#34;hello world&#34;)
OpenSSL::Cipher::CipherError: key length too short
 from (irb):17:in `key=&#39;
 from (irb):17:in `encrypt_data&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se passar a mesma cipher key e mensagem pra versão .Net ele vai funcionar. Esta é a curiosidade:</p>
<ul>
<li>Tanto a implementação .Net quanto Ruby esperam por padrão uma chave de 24-bytes (192-bits)</li>
<li>Todo digest MD5 tem 16-bytes de tamanho (128-bits)</li>
</ul>
<p>No caso do Ruby, como estou passando uma chave menor que o padrão, ele estoura com o erro acima. Já o .Net faz outra coisa: ele acrescenta os 8-bytes que faltam. O problema é com o que.</p>
<p>Especificamente no .Net ele complementa os 8-bytes restantes com os 8-bytes iniciais do que é passado. Se fosse plain-text, por exemplo, e a chave passada fosse &ldquo;1111111122222222&rdquo;, internamente ele converteria para &ldquo;111111112222222211111111&rdquo;. Isso é dependente de implementação, no caso de PHP, se não estou enganado, ele complementa os 8-bytes restantes com nulo ou zero.</p>
<p>Por isso, pro método em Ruby ficar correto, precisamos fazer assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;openssl&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;digest/md5&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;base64&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">encrypt_data</span><span class="p">(</span><span class="n">passphrase</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">digest</span> <span class="o">=</span> <span class="no">Digest</span><span class="o">::</span><span class="no">MD5</span><span class="o">.</span><span class="n">digest</span><span class="p">(</span><span class="n">passphrase</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span> <span class="o">=</span> <span class="no">OpenSSL</span><span class="o">::</span><span class="no">Cipher</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;des-ede3&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span><span class="o">.</span><span class="n">encrypt</span>
</span></span><span class="line"><span class="cl">  <span class="n">cipher</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">digest</span> <span class="o">+</span> <span class="n">digest</span><span class="o">[</span><span class="mi">0</span><span class="o">..</span><span class="mi">7</span><span class="o">]</span> <span class="c1"># &lt;= eis o truque</span>
</span></span><span class="line"><span class="cl">  <span class="no">Base64</span><span class="o">.</span><span class="n">encode64</span><span class="p">(</span><span class="n">cipher</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="o">+</span> <span class="n">cipher</span><span class="o">.</span><span class="n">final</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Feito isso, o resultado agora será o mesmo do código em C#:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">&gt;</span> <span class="n">encrypt_data</span><span class="p">(</span><span class="s2">&#34;abc123&#34;</span><span class="p">,</span> <span class="s2">&#34;hello world&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="o">=&gt;</span> <span class="s2">&#34;90v60JwFNH+VuIKJgSVWUw==</span><span class="se">\n</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Para comparar, basta compilar e executar na sua máquina (se por acaso for um dev Windows) ou, se não for, ir no site <a href="http://www.compileonline.com/compile_csharp_online.php"target="_blank" rel="noopener">Compile Online</a> que permite compilar e executar código em diversas linguagens diferentes diretamente na Web (dica do <a href="https://twitter.com/_carloslopes"target="_blank" rel="noopener">@_carloslopes</a>).</p>
<p>Em resumo:</p>
<ul>
<li>Só porque está encriptado não quer dizer &ldquo;seguro&rdquo;;</li>
<li>Entenda o que está copiando, não apenas copie;</li>
<li>Não use TripleDES, prefira AES;</li>
<li>Se for usar TripleDES, prefira CBC sobre ECB;</li>
<li>NÃO USE MD5, ou mesmo SHA1 para hashing de senhas, use bcrypt ou outra coisa mais moderna;</li>
<li>O módulo OpenSSL do Ruby vai conseguir replicar praticamente todo código criptografia de outras linguagens, facilitando integrações, mas existem pequenas diferenças a tomar cuidado.</li>
</ul>
]]></content:encoded><category>seguranca</category><category>programacao</category></item><item><title>A Língua Portuguesa-Brasileira Pode Nos Confundir: Standard vs Pattern</title><link>https://akitaonrails.github.io/2013/05/10/a-lingua-portuguesa-brasileira-e-pessima-standard-vs-pattern/</link><guid isPermaLink="true">https://akitaonrails.github.io/2013/05/10/a-lingua-portuguesa-brasileira-e-pessima-standard-vs-pattern/</guid><pubDate>Fri, 10 May 2013 19:18:00 -0300</pubDate><description>&lt;p&gt;&lt;strong&gt;Original de 27/4/2011&lt;/strong&gt;: &lt;a href="http://web.archive.org/web/20160709143544/http://info.abril.com.br/noticias/rede/gestao20/software/a-lingua-portuguesa-brasileira-e-pessima-standard-vs-pattern/"target="_blank" rel="noopener"&gt;Gestão 2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Meu último artigo de tradução, sobre “Padrões: Excelência vs. Mediocridade”, rendeu uma discussão paralela interessante especificamente sobre “Design Patterns”.&lt;/p&gt;
&lt;p&gt;Para quem não é de programação: nos anos 70 surgiu o termo “Design Pattern”, reforçado nos anos 90 pelo “livro do Gang of Four”. Segundo a Wikipedia, em engenharia de software um “design pattern” é uma solução reusável geral para um problema que ocorre comumente em design de software. Um design pattern não é um design fechado e acabado que pode ser transformado diretamente em código. É uma descrição ou template para como resolver um problema que pode ser usado em muitas situações diferentes.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>Original de 27/4/2011</strong>: <a href="http://web.archive.org/web/20160709143544/http://info.abril.com.br/noticias/rede/gestao20/software/a-lingua-portuguesa-brasileira-e-pessima-standard-vs-pattern/"target="_blank" rel="noopener">Gestão 2.0</a></p>
<p>Meu último artigo de tradução, sobre “Padrões: Excelência vs. Mediocridade”, rendeu uma discussão paralela interessante especificamente sobre “Design Patterns”.</p>
<p>Para quem não é de programação: nos anos 70 surgiu o termo “Design Pattern”, reforçado nos anos 90 pelo “livro do Gang of Four”. Segundo a Wikipedia, em engenharia de software um “design pattern” é uma solução reusável geral para um problema que ocorre comumente em design de software. Um design pattern não é um design fechado e acabado que pode ser transformado diretamente em código. É uma descrição ou template para como resolver um problema que pode ser usado em muitas situações diferentes.</p>
<p>Para nós, no Brasil, existe um <em>enorme</em> problema, e a ficha só me caiu por causa da discussão nos comentários daquele artigo. A reclamação foi que traduzi “Design Patterns Standards” como “Padrões de Design”. O Ronald, autor da crítica, levantou um ponto correto: as palavras em inglês <em>“default”</em>, <em>“standard”</em> e <em>“pattern”</em> traduzem todas para a mesma palavra “padrão” em português.</p>
<p>Mas as 3 palavras têm significados muito diferentes:</p>
<p><strong>Default</strong> – uma opção pré-selecionada adotada por um programa de computador ou outro mecanismo quando nenhuma outra alternativa é especificada pelo usuário ou programador. Exemplo: o “default” é 50 linhas</p>
<p><strong>Pattern</strong> – 1) um design decorativo repetitivo (como em “patterns” de cor numa roupa). Um arranjo ou sequência regular em objetos comparáveis ou eventos. Uma forma regular e inteligível ou sequência discernível em certas ações ou situações. 2) um modelo ou design usado como um guia em bordado ou outras atividades artesanais.</p>
<p><strong>Standard</strong> – 1) um nível de qualidade ou realização. Um nível requerido ou concordado de qualidade ou realização. 2) uma ideia ou coisa usada como medida, norma, ou modelo em avaliações comparativas. Princípios de conduta informado por noções de honra e decência. Uma forma de linguagem que é amplamente reconhecida como a forma correta.</p>
<p>Resumindo:</p>
<p><strong>Default</strong> – uma escolha pré-selecionada quando nenhuma outra é selecionada.</p>
<p><strong>Pattern</strong> – um modelo que pode ser observado como recorrente, sem valor de certo ou errado.</p>
<p><strong>Standard</strong> – uma norma, algo que todos concordam como base de comparação ou requerimentos mínimos a serem seguidos.</p>
<p>O problema é que a palavra “padrão”, em português, é usada muito mais com o sentido de “standard”. E muitas vezes o que estamos traduzindo é a palavra “pattern”.</p>
<p>Ou seja, quando alguém fala “Design Pattern”, diz apenas que existe uma “forma” usada com mais frequência do que outras na resolução de problemas de software. Ela não é necessariamente a mais correta, e não existe afirmação de que seja a forma conclusiva. É só a observação de que ela é frequente, regularmente usada. A imagem a seguir mostra padrões no sentido de “patterns” (“mais patterns”):</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/350/complex-repeating-patterns-.jpg" alt="Pattern"  loading="lazy" /></p>
<p>Mas ao traduzir para “Padrões de Design”, entra o sentido português de “padrão” como a forma mais correta, ou minimamente correta, e que por ser uma “norma” deveria ser seguida. A palavra “padrão” soa como em <em>“obrigação de seguir o padrão Portaria nº 288/2005”</em>, ou seja, <em>“obrigação de seguir a norma ou regulamento Portaria nº 288/2005”</em>.</p>
<p>Aí “Design Patterns” ganha conotação de norma ou regulamento, que é exatamente o sentido errado. Pattern é Pattern, Standard é Standard, são coisas completamente diferentes.</p>
<p>E é aí que mora o problema de entendimento entre muita gente. Quem entendeu Design Patterns no sentido de “Pattern” reclama de quem entendeu no sentido de “Standard”. Os dois traduzem como “padrão”, e a discussão entre essas duas pessoas acaba parecendo conversa de louco: <em>“Mas isso é só um padrão (pattern), não precisa ser seguido obrigatoriamente.”</em> – <em>“Não! Isso é um padrão (standard), por isso precisa ser seguido obrigatoriamente!”</em></p>
<p>Observação: notei que algumas pessoas não gostaram muito do título, mas coloquei assim de propósito, para chamar atenção ao assunto. Não estou afirmando que a língua portuguesa é essencialmente ruim e que outras são melhores. Toda língua tem nuances e diferenças que dependem do contexto, da cultura local, dos coloquialismos, dos neologismos, da moda e assim por diante.</p>
<p>Justamente por isso temos que ficar sempre atentos, para não entender as coisas ao pé da letra e aplicá-las sem pensar, partindo de premissas falsas.</p>
]]></content:encoded><category>programacao</category><category>comunicacao</category><category>off-topic</category></item><item><title>[Objective-C] Distribuindo sua Static Library</title><link>https://akitaonrails.github.io/2011/04/24/objective-c-distribuindo-sua-static-library/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/24/objective-c-distribuindo-sua-static-library/</guid><pubDate>Sun, 24 Apr 2011 00:46:00 -0300</pubDate><description>&lt;p&gt;Se você não leu meus &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener"&gt;dois&lt;/a&gt; &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener"&gt;últimos artigos&lt;/a&gt;, recomendo fortemente que leia antes de continuar, porque vou usar o mesmo pet project, &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener"&gt;ObjC Rubyfication&lt;/a&gt;, como exemplo neste artigo. A ideia é simples: você está escrevendo código reutilizável e quer aproveitar isso em mais de um projeto.&lt;/p&gt;
&lt;p&gt;A maior parte do que vou mostrar foi baseada no artigo do &lt;a href="http://www.cocoanetics.com/2010/04/universal-static-libraries/"target="_blank" rel="noopener"&gt;Cocoanetics&lt;/a&gt; sobre universal static libraries. Então, se você prestou atenção no &lt;a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener"&gt;artigo anterior&lt;/a&gt;, viu este screenshot:&lt;/p&gt;
&lt;!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png --&gt;
&lt;p&gt;Eu disse que tinha apenas estes targets configurados: CocoaOniguruma, Kiwi, Rubyfication e RubyficationTests. Mas existem mais 3: CocoaOniguruma SIM, Rubyfication SIM e Build &amp;amp; Merge Libraries. O motivo é simples:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Se você não leu meus <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">dois</a> <a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener">últimos artigos</a>, recomendo fortemente que leia antes de continuar, porque vou usar o mesmo pet project, <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">ObjC Rubyfication</a>, como exemplo neste artigo. A ideia é simples: você está escrevendo código reutilizável e quer aproveitar isso em mais de um projeto.</p>
<p>A maior parte do que vou mostrar foi baseada no artigo do <a href="http://www.cocoanetics.com/2010/04/universal-static-libraries/"target="_blank" rel="noopener">Cocoanetics</a> sobre universal static libraries. Então, se você prestou atenção no <a href="http://www.akitaonrails.com/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas"target="_blank" rel="noopener">artigo anterior</a>, viu este screenshot:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png -->
<p>Eu disse que tinha apenas estes targets configurados: CocoaOniguruma, Kiwi, Rubyfication e RubyficationTests. Mas existem mais 3: CocoaOniguruma SIM, Rubyfication SIM e Build &amp; Merge Libraries. O motivo é simples:</p>
<ul>
<li>O Target &ldquo;CocoaOniguruma&rdquo; gera o binário <tt>libCocoaOniguruma.a</tt>, compatível com o processador ARM do iOS</li>
<li>O Target &ldquo;CocoaOniguruma SIM&rdquo; gera o binário <tt>libCocoaOnigurumaSimulator.a</tt>, compatível com o processador i386 do iPhone Simulator local</li>
<li>O Target &ldquo;Rubyfication&rdquo; gera o binário <tt>libRubyfication.a</tt>, compatível com o processador ARM do iOS</li>
<li>O Target &ldquo;Rubyfication SIM&rdquo; gera o binário <tt>libRubyficationSimulator.a</tt>, compatível com o processador i386 do iPhone Simulator local</li>
<li>O Target &ldquo;Build &amp; Merge Libraries&rdquo; junta os binários específicos de cada target em um único Universal (Fat) Binary, fácil de distribuir e reutilizar.</li>
</ul>
<h2>Conceitos e História<span class="hx:absolute hx:-mt-20" id="conceitos-e-história"></span>
    <a href="#conceitos-e-hist%c3%b3ria" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Cabe uma explicação aqui. Quando você desenvolve aplicações iOS, pode testar diretamente no seu iPhone ou dentro do Simulator. Apple foi muito esperta nesse ponto: qualquer outro fabricante do mercado começaria criando um emulador de processador ARM para rodar em cima do seu i386. Aí pegaria os binários ARM e os executaria dentro desse emulador. O sistema operacional continuaria compilado para ARM, rodando dentro do emulador.</p>
<p>Só que isso é absurdamente lento, impraticável. Quem já experimentou um ambiente de emulação assim sabe o quanto é ridículo. E não confunda com soluções tipo VMWare ou Parallels, que são rápidas porque emulam <strong>o mesmo processador</strong>. Você consegue rodar Windows em cima do Mac porque os processadores e sistemas operacionais hoje suportam VT-x, ou seja, você quase não precisa emular o processador. Agora, todo smartphone e tablet do mercado usa processador ARM, que não tem nada a ver com i386.</p>
<p>Então, como a Apple entregou um emulador de iPhone/iPad super rápido que roda em tempo real no seu Mac? Simples: ela não entregou. Ele se chama &ldquo;Simulator&rdquo; e não &ldquo;Emulator&rdquo; por um motivo: tudo que roda dentro do Simulator é compilado para i386, e não para ARM. Ou seja, o que está rodando ali é um binário real, executando nativamente no seu Mac! Sem emulação alguma. O iOS é bem portável. Da mesma forma que o Mac OS X conseguiu fazer a transição do PowerPC para Intel lá em 2005, o iOS faz o mesmo truque, já que basicamente são o mesmo sistema operacional.</p>
<p>Quando você escolhe o scheme do iPhone no XCode, ele compila para ARM e sobe os bits no seu iPhone para rodar a aplicação. Quando você escolhe o scheme do Simulator no XCode, ele compila para i386, sobe os bits no Simulator e roda nativamente como qualquer outra aplicação no seu Mac.</p>
<p>Voltando ao ponto principal: quando eu distribuo um binário da minha Static Library, tenho que lembrar que o desenvolvedor vai linkar contra ela tanto para deploy no device ARM (iPhone/iPad) quanto no Simulator (i386). Ou seja, eu teria que entregar pelo menos 2 arquivos binários. Mas a Apple foi ainda mais esperta. Aliás, a NeXT foi. Quando eles fizeram a primeira transição do NeXTStep dos processadores Motorola para Intel lá no fim dos anos 80, criaram os <a href="http://en.wikipedia.org/wiki/Fat_binary"target="_blank" rel="noopener">Fat Binaries</a>, que basicamente são um único binário contendo os bits específicos de cada processador num só pacote. Quando a Apple fez a transição do PowerPC para Intel, rebatizaram para <a href="http://en.wikipedia.org/wiki/Universal_binary"target="_blank" rel="noopener">Universal Binaries</a>. E é exatamente isso que precisamos construir agora.</p>
<h2>Operações<span class="hx:absolute hx:-mt-20" id="operações"></span>
    <a href="#opera%c3%a7%c3%b5es" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Já entendemos o que é um Universal Binary. Para facilitar, eu cliquei com o botão direito sobre os targets &ldquo;Rubyfication&rdquo; e &ldquo;CocoaOniguruma&rdquo; e dupliquei. Eles aparecem como &ldquo;Rubyfication copy&rdquo; e &ldquo;CocoaOniguruma copy&rdquo;. Podemos mudar o &ldquo;Product Name&rdquo; nas build settings de cada um para algo mais razoável:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.21.02%20AM_original.png?1303615270" alt=""  loading="lazy" /></p>
<p>No meu caso, renomeei para &ldquo;RubyficationSimulator&rdquo; e &ldquo;CocoaOnigurumaSimulator&rdquo;. Isso vai me dar tanto &ldquo;libRubyficationSimulator.a&rdquo; quanto &ldquo;libCocoaOnigurumaSimulator.a&rdquo;. Como dá para ver no grupo Products:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.23.16%20AM_original.png?1303615348" alt=""  loading="lazy" /></p>
<p><strong>Importante:</strong> lembre que o target Rubyfication tinha o CocoaOniguruma como dependência. Você vai precisar mudar o target &ldquo;Rubyfication SIM&rdquo; para apontar para o novo target &ldquo;CocoaOniguruma SIM&rdquo;! Outra coisa: você precisa forçar os dois novos targets a compilar para &ldquo;Latest Mac OS X&rdquo; na opção <tt>&ldquo;Base <span class="caps">SDK</span>&quot;</tt> do Build Settings de cada um, e &ldquo;32-bit Intel&rdquo; na opção <tt>&ldquo;Architectures&rdquo;</tt>. Isso faz com que sejam compilados para processadores i386. Os targets originais devem ter o <tt>&ldquo;Base <span class="caps">SDK</span>&quot;</tt> em &ldquo;Latest iOS&rdquo; e <tt>&ldquo;Architectures&rdquo;</tt> em &ldquo;Standard (armv6 armv7)&rdquo;.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.54.21%20AM_original.png?1303617223" alt=""  loading="lazy" /></p>
<p>Agora precisamos criar um novo target do tipo &ldquo;Aggregate&rdquo;:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.24.00%20AM_original.png?1303615407" alt=""  loading="lazy" /></p>
<p>Eu chamei de &ldquo;Build &amp; Merge Libraries&rdquo;. Na aba &ldquo;Build Phases&rdquo;, você começa apenas com a fase &ldquo;Target Dependencies&rdquo;. Basta adicionar os novos targets &ldquo;Rubyfication SIM&rdquo; e &ldquo;CocoaOniguruma SIM&rdquo;. Em seguida, adicione mais 3 fases: uma &ldquo;Run Script&rdquo;, uma &ldquo;Copy Files&rdquo; e mais uma &ldquo;Run Script&rdquo; no final.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.25.13%20AM_original.png?1303615678" alt=""  loading="lazy" /></p>
<p>Na fase &ldquo;Copy Files&rdquo; eu adicionei todos os public headers que quero distribuir junto com a universal binary library. O motivo é que outros desenvolvedores vão precisar adicionar esses headers nos próprios projetos para conseguir compilar contra a minha biblioteca. Repare que estou copiando para um &ldquo;Absolute Path&rdquo; definido como <tt>${TARGET_BUILD_DIR}/../Rubyfication</tt>.</p>
<p>E é aí que entra a fase &ldquo;Run Script&rdquo; anterior, que deve ter o seguinte código:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. cria uma nova pasta de saída</span>
</span></span><span class="line"><span class="cl">mkdir -p <span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span>/../Rubyfication
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. combina os arquivos lib das várias plataformas em um só</span>
</span></span><span class="line"><span class="cl">lipo create <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Debug-iphoneos/libRubyfication.a&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Debug-iphonesimulator/libRubyfication.a&#34;</span> -output <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication/libRubyfication</span><span class="si">${</span><span class="nv">BUILD_STYLE</span><span class="si">}</span><span class="s2">.a&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira coisa que ele faz é criar esse novo diretório &ldquo;Rubyfication&rdquo;. O segundo comando usa o <a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/lipo.1.html"target="_blank" rel="noopener">lipo</a>, que junta 2 binários dependentes de processador num único universal binary. Preste atenção nos PATHs se for reutilizar esse script em outro lugar. Pelo menos no XCode 4, é nesses caminhos que ele cria os binários de cada target:</p>
<ul>
<li>${TARGET_BUILD_DIR}/../Debug-iphoneos/libRubyfication.a – a versão ARM</li>
<li>${TARGET_BUILD_DIR}/../Debug-iphonesimulator/libRubyfication.a – a versão i386</li>
<li>${TARGET_BUILD_DIR}/../Rubyfication/libRubyfication-Debug.a – o universal binary resultante que criamos</li>
</ul>
<p>Por fim, o último &ldquo;Run Script&rdquo;, depois da fase &ldquo;Copy Files&rdquo; descrita acima, precisa do seguinte script:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ditto c -k --keepParent <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">TARGET_BUILD_DIR</span><span class="si">}</span><span class="s2">/../Rubyfication.zip&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>&ndash;</p>
<p>Ele apenas cria um arquivo ZIP com a universal binary library e seus public headers companheiros. Qualquer outro desenvolvedor pode pegar esse zip, descompactar e adicionar os arquivos no próprio projeto. Se quiser saber onde esse ZIP foi parar, o jeito mais fácil é ir no project viewer (painel da esquerda) do XCode, abrir o grupo &ldquo;Products&rdquo;, clicar com botão direito no arquivo &ldquo;libRubyfication.a&rdquo; (ou qualquer outro arquivo gerado) e escolher &ldquo;Show in Finder&rdquo;. Daí navegue uma pasta acima na hierarquia (até a pasta &ldquo;Products&rdquo;) e você vai ver algo assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.39.02%20AM_original.png?1303616300" alt=""  loading="lazy" /></p>
<p>E pronto: aí está o seu ZIP com seu universal binary redistribuível novinho em folha!</p>
<h2>Usando o Universal Binary<span class="hx:absolute hx:-mt-20" id="usando-o-universal-binary"></span>
    <a href="#usando-o-universal-binary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Para demonstrar como usar esse ZIP distribuível, eu criei um projeto iOS bem simples e enxuto chamado <a href="https://github.com/akitaonrails/ObjC_OnigurumaDemo"target="_blank" rel="noopener">ObjC_OnigurumaDemo</a>, que você pode baixar do Github e rodar no seu próprio device iOS.</p>
<p>Como dá para ver no screenshot abaixo, eu simplesmente descompactei o ZIP dentro de uma pasta &ldquo;Dependencies&rdquo; no meu projeto iOS e adicionei o universal binary &ldquo;libRubyfication-Debug.a&rdquo; na Library Linking Build Phase:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.42.09%20AM_original.png?1303616506" alt=""  loading="lazy" /></p>
<p>Isso me permite usar qualquer coisa dessa biblioteca no meu projeto, em particular um trecho de código que usa as expressões regulares do Oniguruma:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="p">-</span> <span class="p">(</span><span class="kt">IBAction</span><span class="p">)</span><span class="nf">runRegex:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">sender</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnigRegexp</span><span class="o">*</span> <span class="n">regex</span> <span class="o">=</span> <span class="p">[</span><span class="n">OnigRegexp</span> <span class="nl">compile</span><span class="p">:[</span><span class="n">regexPattern</span> <span class="n">text</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnigResult</span><span class="o">*</span> <span class="n">res</span> <span class="o">=</span> <span class="p">[</span><span class="n">regex</span> <span class="nl">match</span><span class="p">:[</span><span class="n">initialText</span> <span class="n">text</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">    <span class="n">NSMutableString</span><span class="o">*</span> <span class="n">tmpResult</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSMutableString</span> <span class="nl">stringWithString</span><span class="p">:</span><span class="s">@&#34;&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="p">[</span><span class="n">res</span> <span class="n">count</span><span class="p">];</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:</span><span class="s">@&#34;(&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:[</span><span class="n">res</span> <span class="nl">stringAt</span><span class="p">:</span><span class="n">i</span><span class="p">]];</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">tmpResult</span> <span class="nl">appendString</span><span class="p">:</span><span class="s">@&#34;)&#34;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="n">result</span> <span class="nl">setText</span><span class="p">:</span><span class="n">tmpResult</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Essa aplicação de demonstração tem um text-field chamado &ldquo;initialText&rdquo;, onde você pode digitar qualquer string. Aí você prepara uma expressão regular no text-field &ldquo;regexPattern&rdquo; e, ao apertar o botão &ldquo;Run&rdquo;, ele dispara a action acima, que roda a expressão regular contra o texto inicial e escreve os matches entre parênteses na text view &ldquo;result&rdquo;. A aplicação fica assim:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2011/4/24/Screen%20shot%202011-04-24%20at%2012.46.19%20AM_original.png?1303616748" alt=""  loading="lazy" /></p>
<p>E, <em>voilá</em>! Expressão regular ao estilo Ruby 1.9, direto do Oniguruma, dentro de uma aplicação iOS!</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item><item><title>[Objective-C] Categories, Static Libraries e Pegadinhas</title><link>https://akitaonrails.github.io/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/23/objective-c-categories-static-libraries-e-pegadinhas/</guid><pubDate>Sat, 23 Apr 2011 23:44:00 -0300</pubDate><description>&lt;p&gt;Como alguns de vocês já sabem, eu tenho um pequeno pet project chamado &lt;a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener"&gt;ObjC Rubyfication&lt;/a&gt;, um exercício pessoal de escrever uma sintaxe parecida com Ruby dentro de Objective-C. A maior parte do projeto se aproveita do fato de que dá pra reabrir as classes padrão do Objective-C – muito parecido com Ruby, diferente do Java – e inserir nosso próprio código – através de &lt;a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html%23//apple_ref/doc/uid/TP30001163-CH20"target="_blank" rel="noopener"&gt;Categories&lt;/a&gt;, que são parecidas com os módulos do Ruby.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Como alguns de vocês já sabem, eu tenho um pequeno pet project chamado <a href="https://github.com/akitaonrails/ObjC_Rubyfication"target="_blank" rel="noopener">ObjC Rubyfication</a>, um exercício pessoal de escrever uma sintaxe parecida com Ruby dentro de Objective-C. A maior parte do projeto se aproveita do fato de que dá pra reabrir as classes padrão do Objective-C – muito parecido com Ruby, diferente do Java – e inserir nosso próprio código – através de <a href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html%23//apple_ref/doc/uid/TP30001163-CH20"target="_blank" rel="noopener">Categories</a>, que são parecidas com os módulos do Ruby.</p>
<p>A ideia desse pet project é ser uma Static Library que eu possa adicionar facilmente em qualquer outro projeto e ter todas as suas funcionalidades disponíveis. Nesse artigo eu queria mostrar como estou organizando os vários subprojetos dentro de um projeto só (e estou aberto a sugestões e dicas pra melhorar isso, já que ainda estou aprendendo a organizar as coisas dentro de projetos Obj-C) e falar sobre uma pegadinha que me tomou horas pra descobrir e que talvez ajude alguém.</p>
<p>Pra deixar esse exercício ainda mais divertido, eu também adicionei um target separado pra minha suíte de testes unitários (e ver como o XCode dá suporte a testes), depois outro target pro framework BDD <a href="http://kiwi-lib.info/"target="_blank" rel="noopener">Kiwi</a> pra Obj-C, e mais um pro <a href="http://limechat.net/cocoaoniguruma/"target="_blank" rel="noopener">CocoaOniguruma</a> que eu acabei de explicar no <a href="http://www.akitaonrails.com/2011/04/23/objective-c-it%27s-a-unix-system-i-know-this"target="_blank" rel="noopener">artigo anterior</a>.</p>
<p>Eu venho brincando com formas de reorganizar o meu projeto e percebi que estava fazendo errado. Eu estava adicionando todos os arquivos fonte do meu target “Rubyfication” dentro do target Specs. Então tudo compilava direitinho, todas as specs passavam, mas a forma como eu definia as dependências estava errada. É meio complicado de entender no começo, mas deveria ser algo assim:</p>
<ul>
<li>Target CocoaOniguruma: deveria ser uma static library, sem dependências de target e sem bibliotecas binárias pra linkar, apenas com uma dependência do framework Foundation padrão. Ele expõe os headers OnigRegexp.h, OnigRegexpUtility.h e oniguruma.h como public headers.</li>
<li>Target Kiwi: deveria ser outra static library, sem dependências de target e sem bibliotecas binárias pra linkar, apenas com as dependências dos frameworks Foundation e UIKit.</li>
<li>Rubyfication: deveria ser outra static library, com CocoaOniguruma como dependência de target, linkando contra o binário libCocoaOniguruma.a e dependendo do framework Foundation também. Ele expõe todos os seus arquivos <tt>.h</tt> como public headers.</li>
<li>RubyficationTests: deveria ser um Bundle criado junto com o target Rubyfication (você pode especificar se quer um target de testes unitários quando cria novos targets), com Kiwi e Rubyfication como dependências de target, linkando contra os binários libKiwi.a e libRubyfication.a, e os frameworks Foundation e UIKit também.</li>
</ul>
<p>Se você ficar criando novos targets manualmente, o XCode 4 também vai criar um monte de Schemes que você nem precisa. Eu mantenho os meus limpos com apenas o scheme Rubyfication. Você pode acessar o menu “Product” e a opção “Edit Scheme”. Aí o meu Scheme fica assim:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.26.25%20PM_original.png -->
<p>Eu costumo configurar todos os meus build settings pra usar “LLVM Compiler 2.0” pras configurações de Debug e “LLVM GCC 4.2” pras configurações de Release (na verdade, eu faço isso por precaução porque não sei se o pessoal está realmente fazendo deploy de binários em produção compilados com LLVM).</p>
<p>Eu também configuro o <tt>“Targeted Device Family”</tt> pra “iPhone/iPad” e tento deixar o <tt>“iOS Deployment Target”</tt> em “iOS 3.0” sempre que possível. O pessoal normalmente deixa o padrão, que vai ser o release mais recente – atualmente 4.3. Cuidado porque o seu projeto pode não rodar em dispositivos mais antigos desse jeito.</p>
<p>Por fim, eu também garanto que os <tt>“Framework Search Paths”</tt> apontem pra estas opções:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>&#34;$(SDKROOT)/Developer/Library/Frameworks&#34;  
&#34;${DEVELOPER_LIBRARY_DIR}/Frameworks&#34;  </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Tudo compila numa boa desse jeito. Aí eu posso apertar “Command-U” (ou ir no menu “Product”, opção “Test”) pra fazer o build do target “RubyficationTests”. Ele compila todas as dependências de target, linka tudo junto e roda o script final pra executar os testes (você precisa garantir que está selecionando o “Rubyfication – iPhone 4.3 Simulator” no menu de Schemes). Ele vai abrir o Simulator pra rodar as specs.</p>
<p>Mas aí eu estava recebendo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Test Suite &#39;/Users/akitaonrails/Library/Developer/Xcode/DerivedData/Rubyfication-gfqxbgyxicfpxugauehktilpmwzv/Build/Products/Debug-iphonesimulator/RubyficationTests.octest(Tests)&#39; started at 2011-04-24 02:16:27 &#43;0000  
Test Suite &#39;CollectionSpec&#39; started at 2011-04-24 02:16:27 &#43;0000  
Test Case &#39;-[CollectionSpec runSpec]&#39; started.  
2011-04-23 23:16:27.506 otest[40298:903] [__NSArrayI each:]: unrecognized selector sent to instance 0xe51a30  
2011-04-23 23:16:27.508 otest[40298:903] ***** Terminating app due to uncaught exception &#39;NSInvalidArgumentException&#39;, reason: &#39;[__NSArrayI each:]: unrecognized selector sent to instance 0xe51a30&#39;  </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ele diz que uma instância de <tt>NSArray</tt> não está reconhecendo o selector <tt>each:</tt> enviado pra ela no arquivo <tt>CollectionSpec</tt>. Provavelmente é esse trecho:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-objc" data-lang="objc"><span class="line"><span class="cl"><span class="cp"># import &#34;Kiwi.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+functional.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+helpers.h&#34;  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp"># import &#34;NSArray+activesupport.h&#34;
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">SPEC_BEGIN</span><span class="p">(</span><span class="n">CollectionSpec</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">describe</span><span class="p">(</span><span class="s">@&#34;NSArray&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">__block</span> <span class="n">NSArray</span><span class="o">*</span> <span class="n">list</span> <span class="o">=</span> <span class="nb">nil</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">context</span><span class="p">(</span><span class="s">@&#34;Functional&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="n">beforeEach</span><span class="p">(</span><span class="o">^</span><span class="p">{</span> <span class="n">list</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSArray</span> <span class="nl">arrayWithObjects</span><span class="p">:</span><span class="s">@&#34;a&#34;</span><span class="p">,</span> <span class="s">@&#34;b&#34;</span><span class="p">,</span> <span class="s">@&#34;c&#34;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span> <span class="p">});</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">it</span><span class="p">(</span><span class="s">@&#34;should iterate sequentially through the entire collection of items&#34;</span><span class="p">,</span> <span class="o">^</span><span class="p">{</span> <span class="n">NSMutableArray</span><span class="o">*</span> <span class="n">output</span> <span class="o">=</span> <span class="p">[[</span><span class="n">NSMutableArray</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="n">list</span> <span class="nl">each</span><span class="p">:</span><span class="o">^</span><span class="p">(</span><span class="kt">id</span> <span class="n">item</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="n">output</span> <span class="nl">addObject</span><span class="p">:</span><span class="n">item</span><span class="p">];</span> <span class="p">}];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[[</span><span class="n">theValue</span><span class="p">([</span><span class="n">output</span> <span class="n">count</span><span class="p">])</span> <span class="n">should</span><span class="p">]</span> <span class="nl">equal</span><span class="p">:</span><span class="n">theValue</span><span class="p">([</span><span class="n">list</span> <span class="n">count</span><span class="p">])];</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="err">…</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Referência: <a href="https://github.com/akitaonrails/ObjC_Rubyfication/blob/master/RubyficationTests/CollectionSpec.m#L1-22"target="_blank" rel="noopener">CollectionSpec.m</a></p>
<p>Repare que na linha 3 está o import correto onde a category <tt>NSArray(Helpers)</tt> está definida com o método <tt>each:</tt> declarado certinho. O erro está acontecendo na spec da linha 18 do trecho acima.</p>
<p>Agora, isso não era um erro de compilação, era um erro de runtime. Então o import está achando o arquivo correto e compilando, mas algo na fase de linking não está indo bem e em runtime a category <tt>NSArray(Helpers)</tt>, e provavelmente outras categories, não estão disponíveis.</p>
<p>Levou algumas horas de pesquisa, mas finalmente descobri uma flag simples que mudou tudo, a flag de linker <a href="http://developer.apple.com/library/mac/#qa/qa1490/_index.html"target="_blank" rel="noopener">-all_load</a>. Como a documentação diz:</p>
<blockquote>
  <p><strong>Importante:</strong> Para aplicações de 64-bit e iPhone OS, existe um bug no linker que impede o <tt>-ObjC</tt> de carregar arquivos de objeto de static libraries que contêm apenas categories e nenhuma classe. O workaround é usar as flags <tt>-all_load</tt> ou <tt>-force_load</tt>.</p>
<p><tt>-all_load</tt> força o linker a carregar todos os arquivos de objeto de cada archive que ele encontra, mesmo aqueles sem código Objective-C. <tt>-force_load</tt> está disponível no Xcode 3.2 e posteriores. Ele permite um controle mais granular do carregamento de archives. Cada opção <tt>-force_load</tt> deve ser seguida por um caminho pra um archive, e cada arquivo de objeto naquele archive vai ser carregado.</p>

</blockquote>
<p>Então todo target que depende de static libraries externas que carregam Categories tem que adicionar essa flag <tt>-all_load</tt> em “Other Linker Flags”, na categoria “Linking” dentro de “Build Settings” do target, assim:</p>
<!-- broken image (host offline/expired): http://s3.amazonaws.com/akitaonrails/assets/2011/4/23/Screen%20shot%202011-04-23%20at%2011.41.27%20PM_original.png -->
<p>Então tanto o meu target <tt>RubyficationTests</tt> quanto o <tt>Rubyfication</tt> tiveram que receber essa nova flag. E agora todos os testes passam sem problema!</p>
]]></content:encoded><category>apple</category><category>programacao</category><category>tutoriais</category></item></channel></rss>