<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-02-28T03:04:05-03:00</updated><id>/feed.xml</id><title type="html">José Anchieta - Terminal Log</title><subtitle>Welcome! I write about software engineering, AI research, and what I learn from teaching. Pull up a chair and browse around.</subtitle><author><name>Jose Anchieta</name></author><entry xml:lang="pt-br"><title type="html">Os fundamentos matemáticos por trás da Inteligência Artificial</title><link href="/2026/02/28/math-foundations-for-ai/" rel="alternate" type="text/html" title="Os fundamentos matemáticos por trás da Inteligência Artificial" /><published>2026-02-28T12:00:00-03:00</published><updated>2026-02-28T12:00:00-03:00</updated><id>/2026/02/28/math-foundations-for-ai</id><content type="html" xml:base="/2026/02/28/math-foundations-for-ai/"><![CDATA[<h1 id="por-que-matemática-importa-para-ia">Por que matemática importa para IA?</h1>

<p>Começando a estudar Inteligência Artificial recentemente por motivos de mestrado e pós-graduação, rapidamente percebi que frameworks como PyTorch e TensorFlow abstraem muita coisa — mas essa abstração cobra um preço. Sem entender a matemática por trás, você consegue rodar modelos, mas não consegue <strong>debugar</strong>, <strong>otimizar</strong> ou <strong>criar</strong> nada novo.</p>

<p>Este post é um mapa dos principais conceitos matemáticos que sustentam IA, Machine Learning e Deep Learning. Não é um curso completo de cada tópico, mas sim uma explicação de <strong>o que é</strong>, <strong>por que importa</strong> e <strong>onde aparece</strong> na prática.</p>

<p>Para tornar o conteúdo mais prático, o Claude me acompanha ao longo do post com sugestões de exercícios e referências para cada tópico.</p>

<h2 id="1-álgebra-linear">1. Álgebra Linear</h2>

<p>A álgebra linear é a linguagem fundamental da IA. Praticamente tudo — dados, pesos, transformações — é representado como vetores e matrizes.</p>

<h3 id="vetores-e-matrizes">Vetores e Matrizes</h3>

<p>Um vetor é uma lista ordenada de números. Uma imagem 28x28 pixels pode ser representada como um vetor de 784 elementos. Uma matriz é uma tabela de números — os pesos de uma rede neural são armazenados em matrizes.</p>

<p><strong>Onde aparece</strong>: representação de dados, embeddings de texto, imagens como tensores.</p>

<h3 id="multiplicação-de-matrizes">Multiplicação de Matrizes</h3>

<p>A operação mais executada em redes neurais. Quando um input passa por uma camada, o que acontece é uma multiplicação de matrizes seguida de uma função de ativação.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>output = activation(W · input + b)
</code></pre></div></div>

<p>Onde <code class="language-plaintext highlighter-rouge">W</code> é a matriz de pesos e <code class="language-plaintext highlighter-rouge">b</code> é o vetor de bias.</p>

<p><strong>Onde aparece</strong>: forward pass de qualquer rede neural, camadas densas, convoluções.</p>

<h3 id="transposição-e-inversão">Transposição e Inversão</h3>

<p>Transpor uma matriz (trocar linhas por colunas) é usado constantemente em operações de gradiente. A inversão aparece em soluções analíticas como regressão linear.</p>

<p><strong>Onde aparece</strong>: backpropagation, regressão linear, PCA.</p>

<h3 id="autovalores-e-autovetores">Autovalores e Autovetores</h3>

<p>Um autovetor de uma matriz é um vetor que, quando multiplicado pela matriz, muda apenas de escala (não de direção). O fator de escala é o autovalor.</p>

<p><strong>Onde aparece</strong>: PCA (Principal Component Analysis), análise espectral, estabilidade de redes recorrentes.</p>

<h3 id="espaços-vetoriais-e-transformações-lineares">Espaços Vetoriais e Transformações Lineares</h3>

<p>Entender que dados vivem em espaços de alta dimensão e que redes neurais aplicam transformações sucessivas nesses espaços é fundamental para intuir como modelos “aprendem”.</p>

<p><strong>Onde aparece</strong>: embeddings (Word2Vec, BERT), redução de dimensionalidade, atenção em Transformers.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Claude, como faço para praticar álgebra linear no contexto de IA?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Tente este exercício: pegue uma imagem pequena (3x3 pixels em escala de cinza), represente como uma matriz e multiplique por uma matriz identidade, uma de rotação 90° e uma de escala. Veja como a imagem se transforma. Isso é exatamente o que filtros convolucionais fazem. Para se aprofundar, a série <strong>Essence of Linear Algebra</strong> do 3Blue1Brown no YouTube é imbatível — são 15 vídeos curtos que vão mudar sua intuição sobre o assunto.</div>
    </div>
  </div>
</div>

<h2 id="2-cálculo">2. Cálculo</h2>

<p>O cálculo é o motor do aprendizado. Sem ele, não existe treinamento de modelos.</p>

<h3 id="derivadas">Derivadas</h3>

<p>A derivada mede a taxa de mudança de uma função. No contexto de ML, ela responde: “se eu ajustar este peso um pouquinho, quanto a perda (loss) muda?”</p>

<p><strong>Onde aparece</strong>: toda otimização de modelos.</p>

<h3 id="derivadas-parciais">Derivadas Parciais</h3>

<p>Quando a função tem muitas variáveis (e um modelo pode ter bilhões), calculamos derivadas parciais — a derivada em relação a cada variável individualmente.</p>

<p><strong>Onde aparece</strong>: cálculo de gradientes, backpropagation.</p>

<h3 id="regra-da-cadeia">Regra da Cadeia</h3>

<p>A regra da cadeia permite calcular a derivada de funções compostas. Uma rede neural é basicamente uma composição de funções, então a regra da cadeia é o que torna o backpropagation possível.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dL/dw = dL/dy · dy/dz · dz/dw
</code></pre></div></div>

<p><strong>Onde aparece</strong>: backpropagation — é literalmente a base matemática de como redes neurais aprendem.</p>

<h3 id="gradiente">Gradiente</h3>

<p>O gradiente é o vetor de todas as derivadas parciais. Ele aponta na direção de maior crescimento da função. Para minimizar o erro, andamos na direção <strong>oposta</strong> ao gradiente.</p>

<p><strong>Onde aparece</strong>: gradient descent, SGD, Adam, e todos os otimizadores.</p>

<h3 id="integrais">Integrais</h3>

<p>Menos usadas diretamente no dia a dia de ML, mas essenciais para entender distribuições de probabilidade, funções de densidade e normalização.</p>

<p><strong>Onde aparece</strong>: modelos probabilísticos, VAEs (Variational Autoencoders), teoria da informação.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Como faço para praticar cálculo aplicado a redes neurais?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Implemente o backpropagation na mão para uma rede com 1 camada oculta. Use uma função simples como <code>f(x) = sigmoid(w2 * sigmoid(w1 * x + b1) + b2)</code>, calcule a derivada de cada peso usando a regra da cadeia no papel e depois confira com PyTorch usando <code>loss.backward()</code>. É o "aha moment" que faz tudo clicar. O capítulo 4 do livro <strong>Neural Networks and Deep Learning</strong> de Michael Nielsen (disponível online gratuitamente) guia você por esse exercício passo a passo.</div>
    </div>
  </div>
</div>

<h2 id="3-probabilidade-e-estatística">3. Probabilidade e Estatística</h2>

<p>Se álgebra linear é a linguagem e cálculo é o motor, probabilidade é a <strong>lógica</strong> da IA. Quase todo modelo lida com incerteza.</p>

<h3 id="probabilidade-básica">Probabilidade Básica</h3>

<table>
  <tbody>
    <tr>
      <td>Eventos, probabilidade condicional e independência. Entender P(A</td>
      <td>B) — a probabilidade de A dado que B aconteceu — é fundamental.</td>
    </tr>
  </tbody>
</table>

<p><strong>Onde aparece</strong>: classificadores, modelos generativos, qualquer predição com incerteza.</p>

<h3 id="teorema-de-bayes">Teorema de Bayes</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>P(A|B) = P(B|A) · P(A) / P(B)
</code></pre></div></div>

<p>O teorema de Bayes permite atualizar crenças com base em evidências. É a base de classificadores Naive Bayes e de toda a inferência bayesiana.</p>

<p><strong>Onde aparece</strong>: Naive Bayes, filtros de spam, redes bayesianas, inferência probabilística.</p>

<h3 id="distribuições-de-probabilidade">Distribuições de Probabilidade</h3>

<p>As mais importantes para IA:</p>

<ul>
  <li><strong>Normal (Gaussiana)</strong>: inicialização de pesos, ruído, normalização</li>
  <li><strong>Bernoulli</strong>: classificação binária, dropout</li>
  <li><strong>Categórica/Multinomial</strong>: classificação multiclasse, softmax</li>
  <li><strong>Uniforme</strong>: inicialização, amostragem aleatória</li>
</ul>

<p><strong>Onde aparece</strong>: em praticamente tudo — de inicialização de pesos a modelos generativos.</p>

<h3 id="valor-esperado-e-variância">Valor Esperado e Variância</h3>

<p>O valor esperado é a “média ponderada” dos resultados possíveis. A variância mede o quanto os valores se dispersam. Controlar a variância dos gradientes é crucial para treinar modelos estáveis.</p>

<p><strong>Onde aparece</strong>: funções de perda, normalização (batch norm, layer norm), análise de convergência.</p>

<h3 id="maximum-likelihood-estimation-mle">Maximum Likelihood Estimation (MLE)</h3>

<p>A ideia de encontrar os parâmetros que maximizam a probabilidade dos dados observados. É a justificativa teórica por trás de muitas funções de perda.</p>

<p><strong>Onde aparece</strong>: regressão logística, cross-entropy loss, modelos de linguagem.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Como faço para praticar probabilidade para IA?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Tente este problema clássico: um teste médico tem 99% de acurácia e a doença afeta 1 em cada 10.000 pessoas. Se o teste deu positivo, qual a probabilidade real de ter a doença? Aplique Bayes e vai se surpreender — o resultado é contraintuitivo e ilustra perfeitamente por que probabilidade condicional importa. Para ir além, o livro <strong>Think Bayes</strong> de Allen Downey ensina probabilidade bayesiana com Python e está disponível gratuitamente online.</div>
    </div>
  </div>
</div>

<h2 id="4-otimização">4. Otimização</h2>

<p>O treinamento de qualquer modelo de ML é, no fundo, um problema de otimização: encontrar os parâmetros que minimizam uma função de erro.</p>

<h3 id="gradient-descent">Gradient Descent</h3>

<p>O algoritmo mais fundamental de ML. A cada passo, calculamos o gradiente da função de perda e ajustamos os pesos na direção oposta.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>w = w - learning_rate * gradiente
</code></pre></div></div>

<p><strong>Onde aparece</strong>: treinamento de qualquer modelo.</p>

<h3 id="stochastic-gradient-descent-sgd">Stochastic Gradient Descent (SGD)</h3>

<p>Em vez de calcular o gradiente usando todos os dados, usamos mini-batches aleatórios. Isso torna o treinamento viável para datasets grandes e adiciona ruído que ajuda a escapar de mínimos locais.</p>

<p><strong>Onde aparece</strong>: treinamento de redes neurais em escala.</p>

<h3 id="otimizadores-avançados-adam-rmsprop-adagrad">Otimizadores Avançados (Adam, RMSprop, AdaGrad)</h3>

<p>Variações do SGD que adaptam a taxa de aprendizado para cada parâmetro individualmente. Adam é o mais popular e combina momentum com taxas adaptativas.</p>

<p><strong>Onde aparece</strong>: praticamente todo treinamento moderno de deep learning.</p>

<h3 id="funções-de-perda-loss-functions">Funções de Perda (Loss Functions)</h3>

<p>A função que o otimizador tenta minimizar. As mais comuns:</p>

<ul>
  <li><strong>MSE (Mean Squared Error)</strong>: regressão</li>
  <li><strong>Cross-Entropy</strong>: classificação</li>
  <li><strong>Binary Cross-Entropy</strong>: classificação binária</li>
</ul>

<p>Escolher a função de perda certa é tão importante quanto a arquitetura do modelo.</p>

<h3 id="convexidade-e-mínimos-locais">Convexidade e Mínimos Locais</h3>

<p>Uma função convexa tem um único mínimo — fácil de otimizar. Redes neurais têm funções de perda não-convexas com muitos mínimos locais. Entender isso explica por que técnicas como momentum e learning rate scheduling existem.</p>

<p><strong>Onde aparece</strong>: design de treinamento, debugging de convergência.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Como faço para praticar otimização?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Implemente gradient descent do zero em Python para encontrar o mínimo de <code>f(x) = x⁴ - 3x³ + 2</code>. Comece com um x aleatório, calcule a derivada <code>f'(x) = 4x³ - 9x²</code>, e atualize x com diferentes learning rates (0.01, 0.1, 0.5). Plote a trajetória do x sobre a curva — vai visualizar como o learning rate afeta a convergência. Depois, repita com SGD adicionando ruído gaussiano ao gradiente e compare. O curso <strong>Convex Optimization</strong> de Stephen Boyd (Stanford, disponível no YouTube) é a referência definitiva sobre o tema.</div>
    </div>
  </div>
</div>

<h2 id="5-teoria-da-informação">5. Teoria da Informação</h2>

<p>Conceitos da teoria da informação aparecem em funções de perda, compressão de modelos e avaliação de qualidade.</p>

<h3 id="entropia">Entropia</h3>

<p>Mede a quantidade de “surpresa” ou incerteza em uma distribuição. Uma distribuição uniforme tem entropia máxima; uma distribuição concentrada em um valor tem entropia baixa.</p>

<p><strong>Onde aparece</strong>: cross-entropy loss, árvores de decisão, avaliação de modelos de linguagem.</p>

<h3 id="cross-entropy">Cross-Entropy</h3>

<p>Mede a diferença entre duas distribuições de probabilidade. Quando usamos como função de perda, estamos medindo o quão diferente a predição do modelo é da distribuição real.</p>

<p><strong>Onde aparece</strong>: a função de perda mais usada em classificação e modelos de linguagem.</p>

<h3 id="kl-divergence">KL Divergence</h3>

<table>
  <tbody>
    <tr>
      <td>Mede o quão diferente uma distribuição é de outra. É assimétrica — KL(P</td>
      <td> </td>
      <td>Q) ≠ KL(Q</td>
      <td> </td>
      <td>P).</td>
    </tr>
  </tbody>
</table>

<p><strong>Onde aparece</strong>: VAEs, destilação de modelos, RLHF (o fine-tuning por feedback humano).</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Como faço para praticar teoria da informação?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Calcule a entropia de um dado justo (6 lados) e de um dado viciado onde o 6 sai 50% das vezes. Qual tem mais entropia? Depois, calcule a cross-entropy entre a distribuição real do dado viciado e a predição de um modelo que acha que o dado é justo. A diferença entre as duas é a KL Divergence — e é exatamente isso que minimizamos ao treinar modelos. O livro <strong>Information Theory, Inference and Learning Algorithms</strong> de David MacKay é fantástico e gratuito online.</div>
    </div>
  </div>
</div>

<h2 id="6-geometria-e-topologia-noções">6. Geometria e Topologia (noções)</h2>

<h3 id="distâncias-e-similaridade">Distâncias e Similaridade</h3>

<ul>
  <li><strong>Distância Euclidiana</strong>: distância “em linha reta” entre dois pontos</li>
  <li><strong>Similaridade do Cosseno</strong>: mede o ângulo entre dois vetores, ignorando magnitude</li>
  <li><strong>Distância de Manhattan</strong>: soma das diferenças absolutas</li>
</ul>

<p><strong>Onde aparece</strong>: K-NN, clustering, busca por similaridade em embeddings, RAG.</p>

<h3 id="espaços-de-alta-dimensão">Espaços de Alta Dimensão</h3>

<p>A intuição humana falha em dimensões altas. Fenômenos como a “maldição da dimensionalidade” — onde os dados ficam esparsos e distâncias perdem significado — são reais e afetam o design de modelos.</p>

<p><strong>Onde aparece</strong>: embeddings, redução de dimensionalidade, regularização.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Como faço para praticar conceitos de distância e similaridade?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Pegue 5 frases curtas, gere embeddings com um modelo como o <code>sentence-transformers</code> e calcule a similaridade do cosseno entre todos os pares. Ordene do mais similar ao menos similar e veja se bate com a sua intuição. Depois, tente com a distância euclidiana e compare os rankings. Você vai notar que cosseno é melhor para comparar "direção" (significado) enquanto euclidiana é sensível à magnitude. É assim que sistemas de busca semântica e RAG funcionam na prática.</div>
    </div>
  </div>
</div>

<h2 id="roteiro-de-estudo-sugerido">Roteiro de estudo sugerido</h2>

<p>Para quem quer construir uma base sólida, sugiro esta ordem:</p>

<ol>
  <li><strong>Álgebra Linear</strong> — comece aqui. Vetores, matrizes, multiplicação</li>
  <li><strong>Cálculo</strong> — derivadas, regra da cadeia, gradientes</li>
  <li><strong>Probabilidade</strong> — distribuições, Bayes, MLE</li>
  <li><strong>Otimização</strong> — gradient descent e variações</li>
  <li><strong>Teoria da Informação</strong> — entropia, cross-entropy</li>
</ol>

<h3 id="recursos-recomendados">Recursos recomendados</h3>

<ul>
  <li><strong>Mathematics for Machine Learning</strong> (Deisenroth, Faisal, Ong) — livro gratuito online, cobre tudo com foco em ML</li>
  <li><strong>3Blue1Brown</strong> (YouTube) — as melhores visualizações de álgebra linear e cálculo que existem</li>
  <li><strong>Khan Academy</strong> — para revisar fundamentos que ficaram enferrujados</li>
  <li><strong>Deep Learning Book</strong> (Goodfellow, Bengio, Courville) — capítulos 2-4 cobrem a matemática essencial</li>
</ul>

<h2 id="conclusão">Conclusão</h2>

<p>Você não precisa ser matemático para trabalhar com IA, mas precisa ser <strong>amigo</strong> da matemática. Entender esses conceitos transforma a experiência de “usar frameworks como caixa preta” para “entender o que está acontecendo e por quê”.</p>

<p>No mestrado, percebi que a maioria dos papers e técnicas novas são variações criativas desses mesmos fundamentos. Quem domina a base matemática consegue ler papers, implementar arquiteturas novas e — mais importante — saber <strong>por que</strong> algo funciona ou não funciona.</p>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Valeu pela ajuda, Claude. Acho que ficou um bom mapa para quem está começando.</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Ficou ótimo! E lembra: não precisa dominar tudo de uma vez. Vá praticando conforme os conceitos aparecem nos seus projetos e papers do mestrado. A matemática faz muito mais sentido quando tem um problema real motivando o estudo.</div>
    </div>
  </div>
</div>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Uma última dúvida, Claude. Quais são os pré-requisitos matemáticos para conseguir estudar esses tópicos? O que eu preciso saber antes de mergulhar na matemática da IA?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Boa pergunta — e a resposta é mais acessível do que parece. A base que você precisa ter é a matemática do ensino médio bem consolidada:<br /><br /><strong>1. Aritmética e operações básicas</strong> — frações, potências, raízes, notação científica. Parece trivial, mas é o alicerce de tudo.<br /><br /><strong>2. Funções</strong> — entender o que é uma função, domínio, imagem, gráficos. Funções lineares, quadráticas, exponenciais e logarítmicas. Sem isso, derivadas e gradientes não fazem sentido.<br /><br /><strong>3. Equações e sistemas lineares</strong> — resolver sistemas de equações é literalmente o que álgebra linear generaliza com matrizes. Se você sabe resolver 2 equações com 2 incógnitas, já tem a intuição certa.<br /><br /><strong>4. Trigonometria básica</strong> — seno, cosseno e a noção de ângulo entre vetores. A similaridade do cosseno, usada em embeddings e busca semântica, vem diretamente daqui.<br /><br /><strong>5. Noções de conjuntos e lógica</strong> — união, interseção, pertinência. Ajuda muito na hora de entender probabilidade e teoria da informação.<br /><br /><strong>6. Geometria analítica</strong> — pontos, retas, distância entre pontos no plano cartesiano. É a versão 2D do que depois vira espaços de alta dimensão.<br /><br />Se algum desses pontos está enferrujado, a <strong>Khan Academy</strong> cobre tudo de forma gratuita e progressiva. Dedique 2-3 semanas revisando esses fundamentos e depois os tópicos deste post vão fluir muito melhor. A verdade é que a barreira de entrada para a matemática de IA não é ser um gênio — é ter paciência para solidificar a base.</div>
    </div>
  </div>
</div>

<div class="chat">
  <div class="chat-message jose">
    <div class="chat-avatar">JA</div>
    <div>
      <div class="chat-name">José</div>
      <div class="chat-bubble">Recomenda algum livro em português que cubra todos ou a maior parte desses pré-requisitos?</div>
    </div>
  </div>
  <div class="chat-message claude">
    <div class="chat-avatar">C</div>
    <div>
      <div class="chat-name">Claude</div>
      <div class="chat-bubble">Recomendo o <strong>"Fundamentos de Matemática Elementar"</strong> do Gelson Iezzi e coautores. É uma coleção clássica brasileira em 11 volumes que cobre praticamente tudo: conjuntos, funções, trigonometria, logaritmos, sistemas lineares, geometria analítica e mais. Os volumes mais relevantes para quem quer se preparar para a matemática de IA são:<br /><br />• <strong>Vol. 1</strong> — Conjuntos, Funções<br />• <strong>Vol. 3</strong> — Trigonometria<br />• <strong>Vol. 4</strong> — Sequências, Matrizes, Determinantes e Sistemas<br />• <strong>Vol. 7</strong> — Geometria Analítica<br /><br />É o livro que a maioria dos cursos de exatas no Brasil usa como referência. A linguagem é clara, tem muitos exercícios resolvidos e vai te dar uma base sólida para depois atacar álgebra linear e cálculo com confiança. Se quiser algo mais compacto e direto ao ponto, o <strong>"Pré-Cálculo"</strong> do Valdir Bezerra (editora LTC) condensa tudo que você precisa em um único volume com foco em preparar para cálculo e álgebra linear.</div>
    </div>
  </div>
</div>]]></content><author><name>anchietajunior</name></author><category term="AI" /><category term="Mathematics" /><category term="ai" /><category term="machine-learning" /><category term="deep-learning" /><category term="math" /><summary type="html"><![CDATA[Por que matemática importa para IA?]]></summary></entry><entry xml:lang="pt-br"><title type="html">Meu setup do Claude Code: como uso IA no terminal para programar</title><link href="/2026/02/28/my-claude-code-setup/" rel="alternate" type="text/html" title="Meu setup do Claude Code: como uso IA no terminal para programar" /><published>2026-02-28T00:00:00-03:00</published><updated>2026-02-28T00:00:00-03:00</updated><id>/2026/02/28/my-claude-code-setup</id><content type="html" xml:base="/2026/02/28/my-claude-code-setup/"><![CDATA[<h1 id="claude-code-no-meu-dia-a-dia">Claude Code no meu dia a dia</h1>

<p>Nos últimos meses, o <strong>Claude Code</strong> se tornou uma das ferramentas mais presentes no meu fluxo de trabalho como desenvolvedor. Diferente de assistentes que funcionam dentro de IDEs com autocomplete, o Claude Code roda direto no terminal — e isso muda completamente a forma como eu interajo com ele.</p>

<p>Neste post, vou compartilhar como está meu setup atual, quais plugins uso, como configurei permissões e a status line customizada que me ajuda a monitorar o contexto da conversa.</p>

<h2 id="o-que-é-o-claude-code">O que é o Claude Code?</h2>

<p>O Claude Code é a CLI oficial da Anthropic para o Claude. Ele funciona como um agente de engenharia de software que pode:</p>

<ul>
  <li>Ler, criar e editar arquivos no seu projeto</li>
  <li>Executar comandos no terminal</li>
  <li>Pesquisar na web e buscar documentação</li>
  <li>Navegar pelo codebase com ferramentas como Glob e Grep</li>
  <li>Criar commits, abrir PRs e interagir com o GitHub</li>
  <li>Lançar sub-agentes para tarefas paralelas</li>
</ul>

<p>A versão que estou usando atualmente é a <strong>2.1.61</strong>.</p>

<h2 id="minha-configuração-settingsjson">Minha configuração (<code class="language-plaintext highlighter-rouge">settings.json</code>)</h2>

<p>O coração da configuração fica em <code class="language-plaintext highlighter-rouge">~/.claude/settings.json</code>. Aqui está o meu:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"env"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"permissions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"allow"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="s2">"Bash(bin/rails test:*)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"Bash(bin/rails db:migrate*)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"Bash(bundle exec rubocop*)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"Bash(bun:*)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"Bash(foreman start)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"Bash(git:*)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"WebSearch"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"WebFetch(domain:api.stripe.com)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"WebFetch(domain:qbench.net)"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"WebFetch(domain:github.com)"</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"enabledPlugins"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"compound-engineering@every-marketplace"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
    </span><span class="nl">"ralph-loop@claude-plugins-official"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"skipDangerousModePermissionPrompt"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="permissões">Permissões</h3>

<p>Uma das partes mais importantes do setup são as <strong>permissões pré-aprovadas</strong>. Sem elas, o Claude Code pede confirmação para cada comando executado no terminal, o que pode ser bem lento no fluxo de trabalho. Eu configurei permissões para:</p>

<ul>
  <li><strong>Rails</strong>: rodar testes (<code class="language-plaintext highlighter-rouge">bin/rails test:*</code>) e migrações (<code class="language-plaintext highlighter-rouge">bin/rails db:migrate*</code>)</li>
  <li><strong>Rubocop</strong>: executar o linter livremente</li>
  <li><strong>Bun</strong>: gerenciamento de pacotes JavaScript</li>
  <li><strong>Foreman</strong>: iniciar o servidor de desenvolvimento</li>
  <li><strong>Git</strong>: todos os comandos git</li>
  <li><strong>Web</strong>: pesquisa na web e fetch de domínios específicos (Stripe, GitHub)</li>
</ul>

<p>Isso me dá um equilíbrio entre produtividade e segurança — o Claude pode executar comandos comuns sem pedir permissão, mas qualquer coisa fora desse escopo ainda precisa da minha aprovação.</p>

<h3 id="agent-teams-experimental">Agent Teams (experimental)</h3>

<p>A variável <code class="language-plaintext highlighter-rouge">CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS</code> habilita o recurso de times de agentes. Isso permite que o Claude Code lance múltiplos agentes que trabalham em paralelo, se comunicam entre si e dividem tarefas complexas. É útil para projetos maiores onde diferentes partes do trabalho podem ser feitas simultaneamente.</p>

<h3 id="agent-teams--tmux-paralelismo-real">Agent Teams + tmux: paralelismo real</h3>

<p>Uma das combinações mais poderosas que descobri é usar <strong>Agent Teams com tmux</strong>. A ideia é simples: em vez de rodar tudo em um único painel do terminal, eu abro uma sessão tmux com múltiplos painéis e deixo cada agente trabalhando de forma visível.</p>

<p>Na prática, o fluxo funciona assim:</p>

<ol>
  <li>Abro uma sessão tmux e divido a tela em painéis</li>
  <li>No painel principal, inicio o Claude Code como líder do time</li>
  <li>Quando ele lança sub-agentes, cada um aparece em seu próprio processo</li>
  <li>Consigo acompanhar visualmente o que cada agente está fazendo em tempo real</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Criar sessão tmux com layout para agent teams</span>
tmux new-session <span class="nt">-s</span> claude <span class="nt">-d</span>
tmux split-window <span class="nt">-h</span>
tmux split-window <span class="nt">-v</span>
tmux <span class="k">select</span><span class="nt">-pane</span> <span class="nt">-t</span> 0
tmux split-window <span class="nt">-v</span>
tmux attach <span class="nt">-t</span> claude
</code></pre></div></div>

<p>Com esse layout de 4 painéis, consigo monitorar o agente principal e até 3 sub-agentes simultaneamente. É como ter um time de desenvolvedores trabalhando na sua tela.</p>

<p>O que torna isso prático:</p>

<ul>
  <li><strong>Visibilidade</strong>: vejo exatamente o que cada agente está fazendo, sem precisar esperar o resultado final</li>
  <li><strong>Controle</strong>: se um agente tomar um caminho errado, posso identificar rapidamente</li>
  <li><strong>Produtividade</strong>: enquanto um agente pesquisa documentação, outro pode estar editando código e um terceiro rodando testes</li>
</ul>

<p>Um exemplo real: ao importar e traduzir 20 posts para este blog, o Claude Code dividiu o trabalho entre 3 agentes — cada um traduziu um lote de posts em paralelo. O que levaria vários minutos sequencialmente foi resolvido em uma fração do tempo.</p>

<p>Para quem já usa tmux no dia a dia, a integração é natural. E para quem não usa, esse é um ótimo motivo para começar.</p>

<h2 id="plugins">Plugins</h2>

<p>Atualmente uso dois plugins:</p>

<h3 id="compound-engineering-every-marketplace">Compound Engineering (Every Marketplace)</h3>

<p>O plugin <code class="language-plaintext highlighter-rouge">compound-engineering</code> adiciona uma grande quantidade de agentes especializados e skills ao Claude Code. Alguns que uso com frequência:</p>

<ul>
  <li><strong>Agentes de review</strong>: revisão de código com diferentes perspectivas (Rails, segurança, performance, arquitetura)</li>
  <li><strong>Design Iterator</strong>: para refinar interfaces iterativamente</li>
  <li><strong>Framework Docs Researcher</strong>: busca documentação atualizada de libraries</li>
  <li><strong>Context7</strong>: integração com documentação e code examples atualizados de qualquer library</li>
</ul>

<h3 id="ralph-loop">Ralph Loop</h3>

<p>O plugin <code class="language-plaintext highlighter-rouge">ralph-loop</code> permite criar loops autônomos onde o Claude Code continua trabalhando em uma tarefa sem precisar de input constante. Útil para tarefas mais longas.</p>

<h2 id="status-line-customizada">Status Line customizada</h2>

<p>Uma das customizações que mais gosto é a <strong>status line</strong> no terminal. Ela mostra em tempo real:</p>

<ul>
  <li>O <strong>modelo</strong> sendo usado (Opus, Sonnet, Haiku)</li>
  <li>O <strong>diretório</strong> do projeto atual</li>
  <li>O <strong>branch</strong> do git ativo</li>
  <li>Uma <strong>barra de progresso</strong> do contexto utilizado</li>
  <li>O <strong>horário</strong> atual</li>
</ul>

<p>A configuração fica no <code class="language-plaintext highlighter-rouge">settings.json</code>, na chave <code class="language-plaintext highlighter-rouge">statusLine</code>:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"statusLine"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"command"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"&lt;conteúdo do script abaixo&gt;"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>O comando em si é um shell script. Para facilitar a leitura, aqui está ele formatado:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">input</span><span class="o">=</span><span class="si">$(</span><span class="nb">cat</span><span class="si">)</span>

<span class="c"># Extrai informações do JSON de input</span>
<span class="nv">model</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$input</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.model.display_name'</span><span class="si">)</span>
<span class="nv">cwd</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$input</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.workspace.current_dir'</span><span class="si">)</span>
<span class="nv">dir_name</span><span class="o">=</span><span class="si">$(</span><span class="nb">basename</span> <span class="s2">"</span><span class="nv">$cwd</span><span class="s2">"</span><span class="si">)</span>

<span class="c"># Detecta branch do git</span>
<span class="nv">git_info</span><span class="o">=</span><span class="s2">""</span>
<span class="k">if </span>git <span class="nt">-C</span> <span class="s2">"</span><span class="nv">$cwd</span><span class="s2">"</span> rev-parse <span class="nt">--git-dir</span> <span class="o">&gt;</span> /dev/null 2&gt;&amp;1<span class="p">;</span> <span class="k">then
  </span><span class="nv">branch</span><span class="o">=</span><span class="si">$(</span>git <span class="nt">-C</span> <span class="s2">"</span><span class="nv">$cwd</span><span class="s2">"</span> <span class="nt">--no-optional-locks</span> branch <span class="nt">--show-current</span> 2&gt;/dev/null <span class="o">||</span> <span class="nb">echo</span> <span class="s2">"detached"</span><span class="si">)</span>
  <span class="nv">git_info</span><span class="o">=</span><span class="s2">" - 🌿 </span><span class="k">${</span><span class="nv">branch</span><span class="k">}</span><span class="s2">"</span>
<span class="k">fi</span>

<span class="c"># Monta barra de progresso do contexto</span>
<span class="nv">progress_bar</span><span class="o">=</span><span class="s2">""</span>
<span class="nv">remaining</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$input</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.context_window.remaining_percentage // empty'</span><span class="si">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-n</span> <span class="s2">"</span><span class="nv">$remaining</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
  </span><span class="nv">used</span><span class="o">=</span><span class="si">$(</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$input</span><span class="s2">"</span> | jq <span class="nt">-r</span> <span class="s1">'.context_window.used_percentage // 0'</span><span class="si">)</span>
  <span class="nv">used_int</span><span class="o">=</span><span class="k">${</span><span class="nv">used</span><span class="p">%.*</span><span class="k">}</span>
  <span class="nv">bar_length</span><span class="o">=</span>20
  <span class="nv">filled</span><span class="o">=</span><span class="k">$((</span>used_int <span class="o">*</span> bar_length <span class="o">/</span> <span class="m">100</span><span class="k">))</span>
  <span class="nv">empty</span><span class="o">=</span><span class="k">$((</span>bar_length <span class="o">-</span> filled<span class="k">))</span>
  <span class="nv">bar</span><span class="o">=</span><span class="s2">""</span>
  <span class="k">for</span> <span class="o">((</span><span class="nv">i</span><span class="o">=</span>0<span class="p">;</span> i&lt;filled<span class="p">;</span> i++<span class="o">))</span><span class="p">;</span> <span class="k">do </span><span class="nv">bar</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">bar</span><span class="k">}</span><span class="s2">█"</span><span class="p">;</span> <span class="k">done
  for</span> <span class="o">((</span><span class="nv">i</span><span class="o">=</span>0<span class="p">;</span> i&lt;empty<span class="p">;</span> i++<span class="o">))</span><span class="p">;</span> <span class="k">do </span><span class="nv">bar</span><span class="o">=</span><span class="s2">"</span><span class="k">${</span><span class="nv">bar</span><span class="k">}</span><span class="s2">░"</span><span class="p">;</span> <span class="k">done
  </span><span class="nv">progress_bar</span><span class="o">=</span><span class="si">$(</span><span class="nb">printf</span> <span class="s2">"[</span><span class="se">\0</span><span class="s2">33[32m%s</span><span class="se">\0</span><span class="s2">33[0m] %d%%"</span> <span class="s2">"</span><span class="nv">$bar</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$used_int</span><span class="s2">"</span><span class="si">)</span>
<span class="k">fi

</span><span class="nb">time</span><span class="o">=</span><span class="si">$(</span><span class="nb">date</span> +%H:%M:%S<span class="si">)</span>

<span class="c"># Output: linha 1 = modelo + diretório + branch</span>
<span class="c">#         linha 2 = barra de contexto + horário</span>
<span class="nb">printf</span> <span class="s2">"%s - 📁 %s%s</span><span class="se">\n</span><span class="s2">%s - %s"</span> <span class="se">\</span>
  <span class="s2">"</span><span class="nv">$model</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$dir_name</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$git_info</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$progress_bar</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$time</span><span class="s2">"</span>
</code></pre></div></div>

<p>O Claude Code passa um JSON via stdin com informações sobre o modelo, diretório e uso de contexto. O script lê esse JSON com <code class="language-plaintext highlighter-rouge">jq</code>, monta uma barra visual e exibe tudo na status line.</p>

<p>A barra de contexto é especialmente útil: conforme a conversa cresce, o Claude Code consome mais da janela de contexto. Quando a barra está quase cheia, sei que é hora de iniciar uma nova conversa ou comprimir o contexto.</p>

<h2 id="como-uso-no-dia-a-dia">Como uso no dia a dia</h2>

<p>Meu fluxo típico com o Claude Code:</p>

<ol>
  <li><strong>Abro o terminal no diretório do projeto</strong> e digito <code class="language-plaintext highlighter-rouge">claude</code></li>
  <li><strong>Descrevo a tarefa</strong> em linguagem natural — pode ser em português ou inglês</li>
  <li><strong>Reviso as mudanças</strong> que ele propõe antes de aprovar</li>
  <li><strong>Peço commits e PRs</strong> quando estou satisfeito com o resultado</li>
  <li><strong>Uso <code class="language-plaintext highlighter-rouge">/help</code></strong> quando preciso lembrar de funcionalidades</li>
</ol>

<h3 id="dicas-práticas">Dicas práticas</h3>

<ul>
  <li><strong>Seja específico</strong>: quanto mais contexto você der, melhor o resultado</li>
  <li><strong>Use o modo plan</strong> para tarefas complexas — ele analisa o codebase antes de fazer mudanças</li>
  <li><strong>Aproveite os sub-agentes</strong>: para pesquisa ou tarefas paralelas, o Claude Code pode lançar agentes especializados</li>
  <li><strong>Configure permissões</strong>: poupa muito tempo não ter que aprovar cada <code class="language-plaintext highlighter-rouge">git status</code></li>
  <li><strong>Monitore o contexto</strong>: conversas muito longas perdem qualidade. Comece uma nova quando necessário</li>
</ul>

<h2 id="conclusão">Conclusão</h2>

<p>O Claude Code mudou significativamente como eu trabalho. A combinação de acesso ao terminal, leitura do codebase e capacidade de executar comandos faz dele muito mais do que um chatbot — é um par de programação que realmente entende o projeto.</p>

<p>Se você é desenvolvedor e ainda não experimentou, recomendo fortemente. E se já usa, invista tempo configurando as permissões e a status line — faz toda a diferença na produtividade.</p>]]></content><author><name>anchietajunior</name></author><category term="AI" /><category term="Tools" /><category term="claude-code" /><category term="ai" /><category term="productivity" /><category term="setup" /><summary type="html"><![CDATA[Claude Code no meu dia a dia]]></summary></entry><entry xml:lang="pt-br"><title type="html">Mergulho profundo no CurrentAttributes do Rails</title><link href="/2025/12/18/current_attributes/" rel="alternate" type="text/html" title="Mergulho profundo no CurrentAttributes do Rails" /><published>2025-12-18T13:00:00-03:00</published><updated>2025-12-18T13:00:00-03:00</updated><id>/2025/12/18/current_attributes</id><content type="html" xml:base="/2025/12/18/current_attributes/"><![CDATA[<h1 id="entendendo-contexto-de-execução-no-rails">Entendendo Contexto de Execução no Rails</h1>

<p>Estou criando alguns posts de estudos particulares com ajuda de IA e decidi começar a compartlhar um pouco do que tenho aprendido utilizando IA.</p>

<h2 id="processos-threads-fibers-e-activesupportcurrentattributes">Processos, Threads, Fibers e ActiveSupport::CurrentAttributes</h2>

<p>Quem trabalha com Rails há algum tempo inevitavelmente esbarra em conceitos como Current.user, concorrência, vazamento de contexto e comportamentos estranhos que só aparecem em produção. Muitas vezes esses problemas são atribuídos a “Rails magic”, quando na verdade eles nascem de um entendimento incompleto sobre como o código Rails é executado em tempo de execução.</p>

<p>Este texto tem um objetivo simples: explicar, de forma progressiva e conectada, como processos, threads e fibers se relacionam no Rails moderno e como o framework usa essa estrutura para compartilhar contexto com segurança através do ActiveSupport::CurrentAttributes.</p>

<h2 id="processos-o-primeiro-nível-de-isolamento">Processos: o primeiro nível de isolamento</h2>

<p>Um processo é a unidade mais isolada de execução fornecida pelo sistema operacional. Quando um processo é criado, ele recebe seu próprio espaço de memória, seu próprio identificador (PID) e não compartilha variáveis, objetos ou estado com outros processos.</p>

<p>No contexto de Rails, isso significa que cada worker de um servidor web em modo cluster (como Puma) ou cada processo do Sidekiq roda em um processo separado. Mesmo que dois processos estejam executando o mesmo código Rails, eles não enxergam a memória um do outro. Se um processo altera um objeto em memória, os demais processos não sabem que isso aconteceu.</p>

<p>Uma boa analogia é pensar no processo como uma casa: tudo o que está dentro dela pertence apenas àquela casa. Outras casas podem ser idênticas, mas não compartilham móveis.</p>

<p>Essa característica é o motivo pelo qual nenhum estado em memória — incluindo CurrentAttributes — pode atravessar processos. Se algo precisa ser compartilhado entre processos, ele precisa ser persistido em um banco, cache externo ou fila.</p>

<h2 id="threads-concorrência-dentro-do-mesmo-processo">Threads: concorrência dentro do mesmo processo</h2>

<p>Dentro de um processo, o sistema operacional permite a criação de threads. Uma thread é um fluxo de execução independente, mas que compartilha a mesma memória do processo que a criou.</p>

<p>No Rails, cada request é atribuído a uma thread do servidor web. Em um processo Puma com múltiplas threads, vários requests podem estar sendo processados simultaneamente, todos compartilhando as mesmas classes, constantes e heap de memória.</p>

<p>A grande diferença entre processo e thread é que threads compartilham memória, mas não compartilham execução. Cada thread tem sua própria stack, seu próprio contador de instruções e seu próprio Thread.current. Além disso, threads são preemptivas: o sistema operacional pode interromper uma thread a qualquer momento para dar espaço a outra.</p>

<p>Uma analogia útil é pensar na thread como pessoas andando dentro da mesma casa. Elas compartilham os mesmos móveis, mas cada uma tem sua própria linha de pensamento e pode ser interrompida no meio de uma ação.</p>

<p>Essa característica é essencial para entender por que o Rails não pode usar variáveis globais simples para armazenar dados como current_user. Em um ambiente multi-thread, isso causaria vazamento de dados entre requests.</p>

<h2 id="fibers-concorrência-cooperativa-e-previsível">Fibers: concorrência cooperativa e previsível</h2>

<p>Fibers são frequentemente confundidas com threads, mas elas resolvem um problema diferente. Uma fiber é uma unidade leve de execução gerenciada pelo próprio Ruby, não pelo sistema operacional. Diferente das threads, fibers não são preemptivas: elas só pausam quando o código explicitamente permite.</p>

<p>Fibers vivem dentro de uma thread e nunca executam em paralelo. O que elas permitem é que múltiplas operações façam progresso enquanto aguardam I/O, sem bloquear a thread inteira. Isso é especialmente útil para servidores web e sistemas que lidam com muitas operações de rede.</p>

<p>No Rails moderno, fibers são usadas para suportar I/O assíncrono, ActionCable, Turbo Streams e outras formas de concorrência cooperativa. O modelo real de execução passa a ser: um processo contendo várias threads, e cada thread podendo alternar entre múltiplas fibers.</p>

<p>Uma boa analogia é imaginar uma thread como um trilho de trem e fibers como vagões. Apenas um vagão anda por vez, mas vários podem se revezar no mesmo trilho de forma organizada e previsível.</p>

<h2 id="o-ciclo-de-vida-de-um-request-no-rails">O ciclo de vida de um request no Rails</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sistema Operacional
 └── Processo (PID)
      ├── Thread 1
      ├── Thread 2
      ├── Thread 3
      └── ...
</code></pre></div></div>

<p>Com esses conceitos em mente, fica mais fácil entender o request lifecycle no Rails. Quando um request chega ao servidor web, ele é atribuído a uma thread específica. Todo o código do Rails — middlewares, controllers, models, services e callbacks — executa dentro dessa thread.</p>

<p>Durante a execução, o Rails pode suspender e retomar a execução usando fibers, especialmente quando há operações de I/O. Mesmo assim, o contexto do request permanece associado à execução correta.</p>

<p>Esse detalhe é fundamental: todo request Rails sempre tem uma thread associada, mesmo quando fibers entram em cena. Fibers não eliminam threads; elas apenas permitem um uso mais eficiente delas.</p>

<h2 id="activesupportcurrentattributes-contexto-atrelado-à-execução">ActiveSupport::CurrentAttributes: contexto atrelado à execução</h2>

<p>O ActiveSupport::CurrentAttributes existe para resolver um problema prático: como disponibilizar dados de contexto — como usuário atual, conta, fuso horário ou request ID — em qualquer camada da aplicação sem passar parâmetros por toda parte e sem usar variáveis globais perigosas?</p>

<p>A solução do Rails é tratar contexto como algo associado à execução, não a objetos específicos. Internamente, o Rails armazena esses dados em um storage ligado à thread e, no Rails moderno, também integrado ao contexto de fibers por meio do ActiveSupport::ExecutionContext.</p>

<p>Quando você define Current.user = current_user no início do request, esse valor fica disponível em qualquer ponto do código que esteja executando naquele mesmo contexto. Models, services e callbacks conseguem acessá-lo porque estão rodando dentro da mesma thread (e fibers associadas).</p>

<p>Esse contexto é automaticamente limpo ao final do request. Isso é essencial porque threads são reutilizadas. Sem esse reset, dados de um request poderiam vazar para o próximo.</p>

<h2 id="até-onde-vai-o-contexto">Até onde vai o contexto</h2>

<p>É importante entender os limites desse mecanismo. CurrentAttributes não atravessa processos. Ele também não sobrevive a background jobs, filas ou qualquer fronteira temporal. Quando um job começa, ele roda em outro processo ou thread, com um contexto completamente novo.</p>

<p>Por isso, qualquer dado necessário fora do request lifecycle deve ser passado explicitamente. O Current é uma ferramenta poderosa, mas apenas dentro do escopo correto.</p>

<h2 id="leituras">Leituras</h2>

<p>O ciclo de vida de uma request por exemplo vive dentro de uma thread. O contexto é preservado no Rails através de <a href="https://github.com/rails/rails/blob/3d2510359c37b2d84a8b33b0b3964ae60f6653f0/activesupport/lib/active_support/execution_context.rb">ExecutionContext</a></p>

<h2 id="conclusão">Conclusão</h2>

<p>Entender processos, threads e fibers não é um detalhe acadêmico: é o que permite escrever aplicações Rails previsíveis, seguras e escaláveis. ActiveSupport::CurrentAttributes funciona porque o Rails trata contexto como parte do fluxo de execução, respeitando os limites impostos pelo sistema operacional e pelo Ruby.</p>

<p>Quando esses conceitos estão claros, desaparecem os mistérios do tipo “funciona local, quebra em produção”. O que sobra é arquitetura, concorrência e decisões conscientes — exatamente o tipo de entendimento que diferencia quem apenas usa Rails de quem realmente o domina.</p>]]></content><author><name>anchietajunior</name></author><category term="Rails" /><category term="ActiveSupport" /><category term="rails" /><category term="activesupport" /><summary type="html"><![CDATA[Entendendo Contexto de Execução no Rails]]></summary></entry><entry xml:lang="en"><title type="html">Deploying a Ruby on Rails app to DigitalOcean with a managed Database.</title><link href="/2024/12/08/kamal-app-managed-db/" rel="alternate" type="text/html" title="Deploying a Ruby on Rails app to DigitalOcean with a managed Database." /><published>2024-12-08T01:00:00-03:00</published><updated>2024-12-08T01:00:00-03:00</updated><id>/2024/12/08/kamal-app-managed-db</id><content type="html" xml:base="/2024/12/08/kamal-app-managed-db/"><![CDATA[<p><img src="https://i.ibb.co/WcjMWr2/3c6700b4-2080-4b38-aa87-1f105c2bb47c.webp" alt="Kamal Managed" /></p>

<p>Exploring Kamal (2) and how to deploy Ruby on Rails applications to DigitalOcean (or any other cloud service) using a managed database service, i started testing some configurations/deploy and my idea now is definitely create more posts about Kamal and share more information here in my personal blog about it.</p>

<h2 id="what-is-kamal">What is Kamal?</h2>

<p><a href="https://kamal-deploy.org/">The official Kamal website</a> says:</p>

<p>“Kamal offers zero-downtime deploys, rolling restarts, asset bridging, remote builds, accessory service management, and everything else you need to deploy and manage your web app in production with Docker. Originally built for Rails apps, Kamal will work with any type of web app that can be containerized.”</p>

<h2 id="why-i-like-this">Why i like this?</h2>

<p>Honestly i used Capistrano for a long time and i liked that. When I first heard Kamal described as a Capistrano-like tool for deploying containerized applications, I got pretty excited about the idea. But in my view, that’s not the best way to define it. For me, Kamal is a great tool for anyone looking to deploy containerized apps without having to rely on Kubernetes—or who just doesn’t need it.</p>

<h2 id="things-to-start-understanding-kamal-before-using-it">Things to start understanding Kamal before using it</h2>

<p>Kamal is now in version 2, here are some things i think are very important to understand.</p>

<ul>
  <li>Docker (Containers, Orchestration)</li>
  <li>SSH (SSHKit)</li>
  <li>Reverse proxies (Kamal used Traefik in version 1 but now it uses Kamal-proxy)</li>
  <li>Load balances</li>
  <li>YAML files syntax</li>
</ul>

<h3 id="managed-databases-vs-database-container">Managed databases vs Database container</h3>

<p>Using Kamal you can choose adding accessories (containers) or use a managed database service we can find in multiple cloud services like AWS, GCP or DigitalOcean which i’m using right now for my apps.</p>

<p>I actually choose a managed database service because it’s easier to create backups, setup connections and etc, it’s all handled by the cloud service you choose. That’s the reason for me and my small apps i’ve being creating.</p>

<h2 id="the-example">The example</h2>

<p>When using Ruby on Rails 8, Kamal is by default in your app and you can check some files to see how it works.</p>

<ul>
  <li>config/deploy.yml</li>
  <li>.kamal/secrets</li>
  <li>.kamal/hooks</li>
  <li>Dockerfile</li>
  <li>bin/docker-entrypoint</li>
</ul>

<p>And this is my current config/deploy.yml file to deploy an app to Digital Ocean using the Digital Ocean managed database service, off course you need to create the database and droplet first. I added some comments sou you can use the file and understand what’s happening out there.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Name of the Project</span>
<span class="na">service</span><span class="pi">:</span> <span class="s">nice_project</span>

<span class="c1"># Name of the image, by default it will use DockerHub</span>
<span class="na">image</span><span class="pi">:</span> <span class="s">joseanchieta/nice_project</span>

<span class="c1"># IP Servers, you can set just one or how many you want</span>
<span class="na">servers</span><span class="pi">:</span>
  <span class="na">web</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">192.168.0.1</span>

<span class="c1"># Your DockerHub/Other service username</span>
<span class="na">registry</span><span class="pi">:</span>
  <span class="na">username</span><span class="pi">:</span> <span class="s">joseanchieta</span>
  <span class="c1"># You can find this variable inside .kamal/secrets</span>
  <span class="na">password</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">KAMAL_REGISTRY_PASSWORD</span>

<span class="c1"># Secrets come from .kamal/secrets.</span>
<span class="na">env</span><span class="pi">:</span>
  <span class="na">secret</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">RAILS_MASTER_KEY</span>
    <span class="pi">-</span> <span class="s">PRODUCTION_DB_HOST</span>
    <span class="pi">-</span> <span class="s">KAMAL_REGISTRY_PASSWORD</span>
  <span class="na">clear</span><span class="pi">:</span>
    <span class="na">SOLID_QUEUE_IN_PUMA</span><span class="pi">:</span> <span class="kc">true</span>

    <span class="c1"># IP or address of the database service, this is an example using</span>
    <span class="c1"># Digital Ocean</span>
    <span class="c1"># In database.yml &gt;&gt; production you should have something like this:</span>
    <span class="c1"># production:</span>
    <span class="c1">#   adapter: postgresql</span>
    <span class="c1">#   encoding: unicode</span>
    <span class="c1">#   pool: &lt;%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %&gt;</span>
    <span class="c1">#   database: production_database_name</span>
    <span class="c1">#   url: &lt;%= ENV["PRODUCTION_DB_HOST"] %&gt;</span>
    <span class="na">DB_HOST</span><span class="pi">:</span> <span class="s">db-postgresql-nyc3-something123.ondigitalocean.com</span>

<span class="c1"># These commands are helpful, you can type in your terminal:</span>
<span class="c1"># kamal console</span>
<span class="c1"># kamal shell</span>
<span class="c1"># kamal logs</span>
<span class="na">aliases</span><span class="pi">:</span>
  <span class="na">console</span><span class="pi">:</span> <span class="s">app exec --interactive --reuse "bin/rails console"</span>
  <span class="na">shell</span><span class="pi">:</span> <span class="s">app exec --interactive --reuse "bash"</span>
  <span class="na">logs</span><span class="pi">:</span> <span class="s">app logs -f</span>
  <span class="na">dbc</span><span class="pi">:</span> <span class="s">app exec --interactive --reuse "bin/rails dbconsole"</span>

<span class="na">volumes</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s2">"</span><span class="s">nice_project:/rails/storage"</span>

<span class="na">asset_path</span><span class="pi">:</span> <span class="s">/rails/public/assets</span>

<span class="na">builder</span><span class="pi">:</span>
  <span class="na">arch</span><span class="pi">:</span> <span class="s">amd64</span>
</code></pre></div></div>]]></content><author><name>joseanchieta</name></author><category term="Ruby" /><category term="Kamal" /><category term="DigitalOcean" /><category term="Deploy" /><category term="PostgreSQL" /><category term="ruby" /><category term="kamal" /><category term="deploy" /><category term="postgresql" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i.ibb.co/WcjMWr2/3c6700b4-2080-4b38-aa87-1f105c2bb47c.webp" /><media:content medium="image" url="https://i.ibb.co/WcjMWr2/3c6700b4-2080-4b38-aa87-1f105c2bb47c.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">Criando iOS apps utilizando Rails e Turbo Native</title><link href="/2023/11/29/creating-turbo-native-apps/" rel="alternate" type="text/html" title="Criando iOS apps utilizando Rails e Turbo Native" /><published>2023-11-29T13:00:00-03:00</published><updated>2023-11-29T13:00:00-03:00</updated><id>/2023/11/29/creating-turbo-native-apps</id><content type="html" xml:base="/2023/11/29/creating-turbo-native-apps/"><![CDATA[<p><a href="https://postimg.cc/Q9dkj5q4"><img src="https://i.postimg.cc/V6j7BW08/ios.png" alt="ios.png" /></a></p>

<h2 id="um-novo-horizonte-para-o-que-pode-ser-feito-com-rails">Um novo horizonte para o que pode ser feito com Rails.</h2>

<p>Desde o início dos anúncios sobre Hotwire e Turbo, venho acompanhando e formando minhas opiniões a respeito. Confesso que de primeira, fiquei cético e achei que seria apenas mais uma coisa de Javascript para aprender, <code class="language-plaintext highlighter-rouge">eu estava terrivelmente enganado</code>.</p>

<p>Após assistir as palestras do RailsWorld realizado em Berlim no mês passado, percebi de vez que a forma
como vejo o ecossistema Rails, mudou muito. Hoje existe um horizonte de possibilidades para criação de 
aplicações web com Rails com um cardápio grande de opções: Esbuild, ImportMaps, Hotwire,
Kamal e etc. Estou bem animado com todas as alternativas que temos e que teremos em breve no ecossistema Rails.</p>

<h2 id="turbo-native">Turbo Native</h2>

<p>Há a algum tempo, venho acompanhando o perfil no Twitter (X) do Joe Masilotti, The turbo native guy como ele
se auto proclama. Esse era o ponto no qual eu mais duvidava, “aplicativos de celular com Rails?, não me parece uma boa ideia”. Esse pensamento surgiu em mim diante de tantas discussões a respeito de React Native e Flutter, parecem duas torcidas rivais e fervorosas para provar qual a melhor tecnologia.</p>

<p>O Joe foi um dos palestrantes do Rails World e na minha opinião, entregou uma das melhores palestras do evento. Este post basicamente replica e acrescenta algumas considerações ao que foi visto na palestra do Joe. Deixarei o link da palestra ao final deste post e o link para o Twitter do Joe também, vale bastante a pena segui-lo.</p>

<h2 id="como-funciona-isso-e-por-que">Como funciona isso e por que?</h2>

<p>Bom, pra quem conhece o conceito de webview em aplicações mobile, não é nada revolucionário. Resumindo de forma muito simples, é um app mobile que exibe um app web. Ou seja, teremos uma aplicação web Rails sendo exibida dentro de um app mobile, neste caso específico iOS.</p>

<p>Já ouvi várias coisas negativas sobre a abordagem de webview, desde que ouvi pela primeira vez sobre ferramentas como Ionic lá em 2014. Concordo com grande parte dos pontos negativos que ouvi naquela época, porém temos de levar em consideração que não estamos mais em 2014 e os devices mudaram muito, principalmente em capacidade de processamento, memória e etc.</p>

<p>Tendo tudo isso em mente, tenho a impressão que estamos entrando em uma nova era do desenvolvimento de software em que as pessoas estão cada vez mais pragmáticas e simplistas, isso faz parte de um conjunto de teorias, pensamentos e opiniões que venho acompanhando e que faz sentido (para mim). Acredito que muito vem dos resultados falhos de overengineering que obtivemos nos últimos anos com separação de back e front, microservices e etc sem que haja de fato um motivo real para aderir a estas técnicas.</p>

<p>Joe cita na palestra um outro exemplo, empresas/pessoas criando apps nativos visando performance e extrair o máximo dos devices sem que haja a necessidade real disso, ou seja, grande parte dos apps mobile não precisam extrair o máximo do aparelho, elas precisam renderizar algumas views, realizar algumas operações de crud e etc. Mais uma vez, estou de acordo com isso e pra mim o uso do Turbo Native faz sentido neste momento.</p>

<h2 id="criando-o-projeto">Criando o projeto</h2>

<p>Vamos começar criando um projeto simples em Rails, o intuito do post é criar um app rails e fazer com que o mesmo apareça em um iOS simulator (infelizmente apenas para usuários de Mac, mas sinta-se a vontade para fazer o mesmo para apps Android).</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails new iosapp <span class="nt">-T</span> <span class="nt">-css</span> tailwind
</code></pre></div></div>
<p>Vamos adicionar apenas um scaffold ao projeto para que possamos ver o resultado no simulador do iOS.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails g scaffold Post title body:text
</code></pre></div></div>

<p>Execute as migrações:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails db:migrate
</code></pre></div></div>

<p>Adicione um root_path (root_url) no arquivo <code class="language-plaintext highlighter-rouge">routes.rb</code>:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">root</span> <span class="s2">"posts#index"</span>
</code></pre></div></div>
<p>Execute o app:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./bin/dev
</code></pre></div></div>

<p>Agora acesse o seu browser em <code class="language-plaintext highlighter-rouge">localhost:3000</code> e crie alguns posts.</p>

<p>Assim está o meu app no browser após adicionar alguns estilos utilizando Tailwind:</p>

<p><img src="https://i.postimg.cc/662TcqFT/Screenshot-2023-11-30-at-13-49-00.png" alt="iosturbo index" /></p>

<h2 id="criando-o-app-ios">Criando o app iOS</h2>

<p>Neste passo é necessário ter o XCode instalado e estar utilizando um Mac. Abra o XCode, no menu principal clique em File, New, Project.</p>

<p><a href="https://postimg.cc/Y4Jb8wsx"><img src="https://i.postimg.cc/QtMw88gv/Screenshot-2023-11-30-at-14-04-20.png" alt="Criando o projeto" /></a></p>

<p>Na caixa de seleção “Choose a template for your new project” selecione iOS » App e clique em Next. Aqui você terá algumas opções para preencher que são obrigatórias, no nosso caso pode desmarcar a opção <code class="language-plaintext highlighter-rouge">Include Tests</code> e na caixa de Interface, selecione StoryBoard.</p>

<p><a href="https://postimg.cc/rDRh4mhp"><img src="https://i.postimg.cc/3xnzP0m2/Screenshot-2023-11-30-at-14-09-32.png" alt="Configurações" /></a></p>

<h3 id="acrescentando-o-turbo-native-como-dependência-do-projeto">Acrescentando o Turbo Native como dependência do projeto</h3>

<p>Clique no menu File novamente, encontre a opção <code class="language-plaintext highlighter-rouge">Add Package Dependecies</code>, clique nesta opção e selecione o Turbo Native, caso o Turbo Native não apareça para você, digite a url do github no campo <code class="language-plaintext highlighter-rouge">Enter Package URL</code>.</p>

<p>URL: <code class="language-plaintext highlighter-rouge">github.com/hotwired/turbo-ios</code></p>

<p><a href="https://postimg.cc/G9TyPyFG"><img src="https://i.postimg.cc/wx0Qp53f/Screenshot-2023-11-30-at-14-24-27.png" alt="Dependência Turbo Native" /></a></p>

<p>O único passo necessário por agora é alterar o arquivo swift <code class="language-plaintext highlighter-rouge">SceneDelegate</code> que se encontra na árvore de arquivos exibida no Xcode.</p>

<p>O código ficará da seguinte forma:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">Turbo</span>
<span class="kd">import</span> <span class="kt">WebKit</span>
<span class="kd">import</span> <span class="kt">UIKit</span>

<span class="k">let</span> <span class="nv">rootUrl</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"http://127.0.0.1:3000/"</span><span class="p">)</span><span class="o">!</span>

<span class="kd">class</span> <span class="kt">SceneDelegate</span><span class="p">:</span> <span class="kt">UIResponder</span><span class="p">,</span> <span class="kt">UIWindowSceneDelegate</span> <span class="p">{</span>

    <span class="k">var</span> <span class="nv">window</span><span class="p">:</span> <span class="kt">UIWindow</span><span class="p">?</span>
    
    <span class="kd">private</span> <span class="k">let</span> <span class="nv">navigationController</span> <span class="o">=</span> <span class="kt">UINavigationController</span><span class="p">()</span>

    <span class="kd">private</span> <span class="kd">lazy</span> <span class="k">var</span> <span class="nv">session</span> <span class="o">=</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">config</span> <span class="o">=</span> <span class="kt">WKWebViewConfiguration</span><span class="p">()</span>
        <span class="n">config</span><span class="o">.</span><span class="n">applicationNameForUserAgent</span> <span class="o">=</span> <span class="s">"Turbo Native iOS"</span>
        
       <span class="k">let</span> <span class="nv">session</span> <span class="o">=</span> <span class="kt">Session</span><span class="p">(</span><span class="nv">webViewConfiguration</span><span class="p">:</span> <span class="n">config</span><span class="p">)</span>
       <span class="n">session</span><span class="o">.</span><span class="n">delegate</span> <span class="o">=</span> <span class="k">self</span>
       <span class="k">return</span> <span class="n">session</span>
    <span class="p">}()</span>

    <span class="c1">// When the app launches</span>
    <span class="kd">func</span> <span class="nf">scene</span><span class="p">(</span><span class="n">_</span> <span class="nv">scene</span><span class="p">:</span> <span class="kt">UIScene</span><span class="p">,</span> <span class="n">willConnectTo</span> <span class="nv">session</span><span class="p">:</span> <span class="kt">UISceneSession</span><span class="p">,</span> <span class="n">options</span> <span class="nv">connectionOptions</span><span class="p">:</span> <span class="kt">UIScene</span><span class="o">.</span><span class="kt">ConnectionOptions</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">window</span><span class="p">?</span><span class="o">.</span><span class="n">rootViewController</span> <span class="o">=</span> <span class="n">navigationController</span>
        
        <span class="k">let</span> <span class="nv">proposal</span> <span class="o">=</span> <span class="kt">VisitProposal</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="n">rootUrl</span><span class="p">,</span> <span class="nv">options</span><span class="p">:</span> <span class="kt">VisitOptions</span><span class="p">())</span>
        <span class="nf">visit</span><span class="p">(</span><span class="nv">proposal</span><span class="p">:</span> <span class="n">proposal</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="c1">// 1. Create Screen</span>
    <span class="c1">// 2. Push the Screen</span>
    <span class="c1">// 3. Render the HTML</span>
    <span class="kd">private</span> <span class="kd">func</span> <span class="nf">visit</span><span class="p">(</span><span class="nv">proposal</span><span class="p">:</span> <span class="kt">VisitProposal</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">let</span> <span class="nv">visitable</span> <span class="o">=</span> <span class="kt">VisitableViewController</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="n">proposal</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
        <span class="n">navigationController</span><span class="o">.</span><span class="nf">pushViewController</span><span class="p">(</span><span class="n">visitable</span><span class="p">,</span> <span class="nv">animated</span><span class="p">:</span> <span class="kc">true</span><span class="p">)</span>
        <span class="n">session</span><span class="o">.</span><span class="nf">visit</span><span class="p">(</span><span class="n">visitable</span><span class="p">,</span> <span class="nv">options</span><span class="p">:</span> <span class="n">proposal</span><span class="o">.</span><span class="n">options</span><span class="p">)</span>
    <span class="p">}</span>
 <span class="p">}</span>

<span class="kd">extension</span> <span class="kt">SceneDelegate</span><span class="p">:</span> <span class="kt">SessionDelegate</span><span class="p">{</span>
    <span class="c1">// Web view dies</span>
    <span class="kd">func</span> <span class="nf">sessionWebViewProcessDidTerminate</span><span class="p">(</span><span class="n">_</span> <span class="nv">session</span><span class="p">:</span> <span class="kt">Session</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">session</span><span class="o">.</span><span class="nf">reload</span><span class="p">()</span>
    <span class="p">}</span>
    
    <span class="c1">// Link is clicked</span>
    <span class="kd">func</span> <span class="nf">session</span><span class="p">(</span><span class="n">_</span> <span class="nv">session</span><span class="p">:</span> <span class="kt">Session</span><span class="p">,</span> <span class="n">didProposeVisit</span> <span class="nv">proposal</span><span class="p">:</span> <span class="kt">VisitProposal</span><span class="p">){</span>
        <span class="nf">visit</span><span class="p">(</span><span class="nv">proposal</span><span class="p">:</span> <span class="n">proposal</span><span class="p">)</span>
    <span class="p">}</span>
    
    <span class="c1">// Link fails</span>
    <span class="kd">func</span> <span class="nf">session</span><span class="p">(</span><span class="n">_</span> <span class="nv">session</span><span class="p">:</span> <span class="kt">Session</span><span class="p">,</span> <span class="n">didFailRequestForVisitable</span> <span class="nv">visitable</span><span class="p">:</span> <span class="kt">Visitable</span><span class="p">,</span> <span class="nv">error</span><span class="p">:</span> <span class="kt">Error</span><span class="p">){</span>
        <span class="nf">print</span><span class="p">(</span><span class="s">"Failed to visit: </span><span class="se">\(</span><span class="n">error</span><span class="o">.</span><span class="n">localizedDescription</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
    <span class="p">}</span>
    
<span class="p">}</span>
</code></pre></div></div>

<p>Aqui, temos algumas coisas relacionadas a navegação do app (que ficam muito bem explicadas pelo Joe no vídeo na Palestra) e logo no começo é possível ver que estamos apontando para algo no endereço <code class="language-plaintext highlighter-rouge">localhost:3000</code>. Sim, é aqui que indicamos ao app iOS onde buscar o seu <code class="language-plaintext highlighter-rouge">conteúdo</code>.</p>

<p>Agora vamos executar o simulador, isso pode ser feito com o atalho: <code class="language-plaintext highlighter-rouge">Command + R</code></p>

<p>E olha só que maravilha!</p>

<p><a href="https://postimg.cc/fVHdHYBK"><img src="https://i.postimg.cc/43G1x5cr/Screenshot-2023-11-30-at-14-31-47.png" alt="iOS simulador" /></a></p>

<p>Nossa aplicação Rails sendo executada como um app mobile iOS. Sensacional!</p>

<h2 id="conclusão">Conclusão</h2>

<p>Este foi um pequeno exemplo de como é rápido criar um app iOS rodando uma aplicação Rails e isso é só o começo, imagina que para algumas atualizações basta apenas atualizar a aplicação Rails e isso já será refletido no App.</p>

<h3 id="considerações">Considerações</h3>

<p>Como eu disse anteriormente, isso não é a solução para todos os problemas. Mas é uma boa solução para vários.
Reitero que é importante assistir a palestra do Joe, onde ele passa mais detalhes e passa até outras coisas como upload de imagens.</p>

<p>É isso, espero que gostem!</p>

<h2 id="referências">Referências</h2>

<p>Palestra: <a href="https://www.youtube.com/watch?v=hAq05KSra2g&amp;t=339s&amp;ab_channel=RubyonRails" target="_blank">Joe Masilotti - Just enough Turbo Native to be dangerous - Rails World 2023</a></p>

<p>Link para o Workshop do Joe Masilotti: <a href="https://masilotti.com/turbo-native-workshop/">Workshop</a></p>

<p>Link para Post no blog do Joe: <a href="https://masilotti.com/hide-web-rendered-content-on-turbo-native-apps/">Masilotti</a></p>]]></content><author><name>joséanchieta</name></author><category term="Turbo" /><category term="rails" /><category term="turbo" /><category term="ios" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i.postimg.cc/V6j7BW08/ios.png" /><media:content medium="image" url="https://i.postimg.cc/V6j7BW08/ios.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">A atenção é minha ferramenta mais valiosa para a produtividade como desenvolvedor de software</title><link href="/2020/11/08/attention-and-productivity/" rel="alternate" type="text/html" title="A atenção é minha ferramenta mais valiosa para a produtividade como desenvolvedor de software" /><published>2020-11-08T13:00:00-03:00</published><updated>2020-11-08T13:00:00-03:00</updated><id>/2020/11/08/attention-and-productivity</id><content type="html" xml:base="/2020/11/08/attention-and-productivity/"><![CDATA[<p><img src="https://images.unsplash.com/photo-1519389950473-47ba0277781c?ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&amp;auto=format&amp;fit=crop&amp;w=2070&amp;q=80" alt="Image" /></p>

<h3 id="essa-é-uma-tradução-e-adaptação-desse-artigo">Essa é uma tradução e adaptação desse <a href="https://zwbetz.com/attention-is-my-most-valuable-asset-for-productivity-as-a-software-developer/">artigo</a>.</h3>

<p>Como apreciador das obras que inspiraram esse post e como uma pessoa que sempre está em busca de um melhor desempenho, gostei bastante desse artigo que cita inclusive algumas medidas que tomei em minha vida em busca de produtividade e resolvi traduzi-lo. Espero que gostem.</p>

<hr />

<p>Como uma função bem escrita, prefiro parar de executar cedo se nenhuma condição for válida. Então, se você discorda dessas definições e suposições, agora é um bom momento para parar de ler.</p>

<ul>
  <li>
    <p><strong><em>Produtividade sustentável:</em></strong> A taxa máxima de produção de trabalho de qualidade, sem prejuízo para o bem-estar do desenvolvedor.</p>
  </li>
  <li>
    <p><strong><em>Trabalho de qualidade:</em></strong> software que atende aos requisitos, é valioso para os usuários, pode ser mantido e é o mais livre de bugs possível.</p>
  </li>
  <li>
    <p><strong><em>Atenção:</em></strong> A capacidade mental limitada de se concentrar em uma tarefa.</p>
  </li>
  <li>
    <p>A produtividade sustentável é desejada.</p>
  </li>
  <li>
    <p>Atenção é essencial para a produtividade sustentável.</p>
  </li>
</ul>

<p>Meu fluxo mais produtivo de trabalho é mais ou menos assim: identificar o problema a ser resolvido; pense no problema e deixe as idéias se infiltrarem; pesquise, discuta e experimente essas idéias; implementar e testar a solução; entregar e manter a solução.</p>

<p>Este ciclo pode se repetir muitas vezes ao dia. Ou eu poderia passar dias preso em uma única etapa do ciclo. Cada etapa deste ciclo requer atenção. Quanto mais atenção posso dedicar, mais ciclos posso concluir e mais produtivo sou.</p>

<p>Por quanto tempo você pode se concentrar em uma tarefa varia de pessoa para pessoa. Algumas pessoas são muito boas logo de cara, outras nem tanto. Independente das suas características, acredito que o foco (o ato de priorizar sua atenção) é uma habilidade e, como qualquer habilidade, pode ser melhorada com a prática.</p>

<p>Então, como você pode aumentar suas reservas de atenção? O melhor retorno para seu investimento é organizar seu mundo exterior de forma que seja o mais livre possível de distrações. Depois de fazer isso, você terá mais tempo para praticar e, portanto, mais tempo para melhorar.</p>

<p><strong><em>Construa força física.</em></strong> O dano causado por ficar sentado 8 horas ou mais por dia é subestimado. Você precisa encontrar uma maneira de compensar esses danos, especialmente se planeja trabalhar nessa área por décadas. Se você não fizer mais nada, faça levantamento de peso. Existem poucos movimentos mais primitivos do que pegar um objeto pesado do chão e levantá-lo. Você pode aprender a técnica correta em minutos. Eu gosto mais de levantamento de peso porque você pode fazê-los com segurança, com pesos elevados, até ficar cansado. Também gosto da força das mãos, das costas e do quadril que eles proporcionam, para dificultar ainda mais os danos ao sentar-se.</p>

<p><strong><em>Torne o seu local de trabalho enfadonho e organizado.</em></strong> Meu escritório é um quarto extra. As paredes estão vazias. Não há TV. Há uma mesa, cadeira, laptop, suporte para laptop, teclado, mouse e mouse pad. Há uma janela que permite a entrada de luz suficiente para que eu não sinta que estou perdendo um dia lindo, mas não muita luz para causar brilho na tela. Se eu precisar trabalhar com papel, ele é imediatamente arquivado em algum lugar quando terminar. Como eu disse, chato e arrumado.</p>

<p><strong><em>Deixe seu smartphone mudo.</em></strong> Meu telefone está com todas as notificações desabilitadas, exceto para chamadas e mensagens de texto. Bem, e alertas do National Hurricane Center, já que moro na Louisiana. A menos que você seja minha esposa, você sabe que eu não respondo a mensagens de texto imediatamente, é assim que as coisas são. Desativei minhas contas de mídia social há algum tempo. Mas, se você os tiver, desligar as notificações deve ajudar a diminuir o desejo de verificá-los compulsivamente.</p>

<p><strong><em>Tenha um sistema operacional minimalista.</em></strong> Os aplicativos que uso com menos frequência estão a uma combinação de teclas de distância. Diante disso, meu dock tem apenas os aplicativos que uso diariamente:</p>

<ul>
  <li>Sistema de arquivos</li>
  <li>Browser</li>
  <li>Terminal</li>
  <li>Editor de texto para código de front-end e notas</li>
  <li>IDE para código de back-end</li>
  <li>IDE para banco de dados</li>
  <li>Visualizador de diferenças em arquivos para controle de versão</li>
  <li>Cliente de email</li>
  <li>Cliente de mensagem instantânea</li>
</ul>

<p>Minha área de trabalho alterna entre os estados limpo e sujo. Arquivos com os quais estou trabalhando no momento na área de trabalho. Em seguida, eles são arquivados em pastas adequadas quando concluídos.</p>

<p><strong><em>Organize os favoritos do seu navegador.</em></strong> Quando leio algo útil que talvez precise consultar mais tarde, eu deixo arquivado em uma pasta geral. Em seguida, itens mais específicos obtêm suas próprias pastas. Os links acessados ​​com frequência ficam visíveis na minha barra de favoritos em sua própria pasta.</p>

<p><strong><em>Minimize as reuniões.</em></strong> Olha, eu sei que algumas coisas fazem sentido discutir cara a cara, ou voz a voz. Mas se não, você não precisa de uma reunião. Um e-mail ou mensagem instantânea será suficiente.</p>

<p><strong><em>Finalmente, use o Método Eisenhower para categorizar suas tarefas.</em></strong> Imagine 4 categorias:</p>

<ul>
  <li>Importante e Urgente</li>
  <li>Importante e Não Urgente</li>
  <li>Não Importante e Urgente</li>
  <li>Não Importante e Não Urgente</li>
</ul>

<p><strong><em>Tarefas Importantes e Urgentes precisam ser tratadas.</em></strong> Para mim, esses são geralmente os principais problemas de produção.</p>

<p><strong><em>Tarefas Importantes e não Urgentes devem absorver a maior parte do seu tempo.</em></strong> Para mim, este é o velho trabalho de desenvolvimento de implementar recursos, corrigir bugs e tornar o código existente mais fácil de manter e melhorar seu desempenho. Também estão incluídos a construção de relacionamentos com outras pessoas e o planejamento futuro.</p>

<p><strong><em>Tarefas Não Importantes e Urgentes são ladrões de atenção desagradáveis.</em></strong> Eles gritam com você imediatamente, mas oferecem pouco valor em troca. Você deve saber do que estou falando. Para mim, essas são na maioria das vezes perguntas mal feitas por outras pessoas, que exigem mais trabalho para determinar o que está realmente sendo perguntado, em vez de descobrir qual deveria ser a resposta. Também estão incluídas reuniões de última hora e colegas de trabalho muito faladores.</p>

<p><strong><em>As tarefas Não Importantes e Não Urgentes geralmente não são conhecidas por seus usuários.</em></strong> Ler atualizações da documentação de um projeto por exemplo. O fato é que eles são um investimento em você mesmo, o que significa um “você” mais produtivo no futuro. Portanto, não se esqueça de se dedicar a eles um pouco em seus momentos de folga.</p>

<p><strong><em>Leitura adicional.</em></strong> Se você não sabe quem é Cal Newport, está perdendo. Ele tem um blog inteiro dedicado a esse tipo de coisa, e já escreveu livros como Deep Work e Digital Minimalism. Aqui estão alguns dos meus artigos favoritos dele:</p>

<ul>
  <li><a href="https://www.calnewport.com/blog/2009/02/04/have-we-lost-our-tolerance-for-a-little-boredom/">Have We Lost Our Tolerance For a Little Boredom?</a></li>
  <li><a href="https://www.calnewport.com/blog/2010/06/10/is-allowing-your-child-to-study-while-on-facebook-morally-equivalent-to-drinking-while-pregnant/">Is Allowing Your Child to Study While on Facebook Morally Irresponsible?</a></li>
  <li><a href="https://www.calnewport.com/blog/2008/04/07/monday-master-class-how-to-reduce-stress-and-get-more-done-by-building-an-autopilot-schedule/">Monday Master Class: How to Reduce Stress and Get More Done By Building an Autopilot Schedule</a></li>
  <li><a href="https://www.calnewport.com/blog/2009/11/24/are-passions-serendipitously-discovered-or-painstakingly-constructed/">Are Passions Serendipitously Discovered or Painstakingly Constructed?</a></li>
  <li><a href="https://www.calnewport.com/blog/2018/06/08/jerry-seinfelds-closed-door/">Jerry Seinfeld’s Closed Door</a></li>
</ul>]]></content><author><name>anchietajunior</name></author><category term="Miscellaneous" /><category term="productivity" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://images.unsplash.com/photo-1519389950473-47ba0277781c?ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&amp;auto=format&amp;fit=crop&amp;w=2070&amp;q=80" /><media:content medium="image" url="https://images.unsplash.com/photo-1519389950473-47ba0277781c?ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&amp;auto=format&amp;fit=crop&amp;w=2070&amp;q=80" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">O lado humano do code review</title><link href="/2020/09/22/human-code-review/" rel="alternate" type="text/html" title="O lado humano do code review" /><published>2020-09-22T13:00:00-03:00</published><updated>2020-09-22T13:00:00-03:00</updated><id>/2020/09/22/human-code-review</id><content type="html" xml:base="/2020/09/22/human-code-review/"><![CDATA[<p><img class="post-image" src="https://d33x644h9xoqir.cloudfront.net/wp-content/uploads/sites/2/2019/02/como-construir-relacoes-produtivas-com-seus-colegas-de-trabalho.jpg" /></p>

<p>Em primeiro lugar, pensar no lado humano não é desencorajar a fazer code review, pelo contrário,
estou apenas alertando para possíveis problemas causados pelo code review quando feito sem estar consciente
de alguns fatores. Fatores estes que estão mais ligados a parte humana do que a parte técnica.</p>

<p>Algumas premissas do code review ficaram fixas na minha cabeça depois de passar por algumas equipes
muito boas em fazer code review e outras nem tanto, de qualquer forma o meu objetivo em relação aos
code reviews e várias outras coisas da vida é fugir da superficialidade e dar contexto ou um sentido
para as minhas ações, então vamos a algumas lições que aprendi:</p>

<h2 id="o-principal-objetivo-e-a-razão">O principal objetivo e a razão</h2>

<p>Algumas vezes podemos esquecer disso, mas o principal objetivo de um code review é manter a qualidade
do código, consequentemente melhorando a qualidade/confiabilidade do projeto. Quando se está fixado na
mente que o principal objetivo é a qualidade do projeto, cria-se uma missão em comum com os seus colegas
de equipe, que gera companheirismo e empatia.</p>

<p>Sempre que for revisar o código de alguém, lembre-se desse objetivo, é comum o code review acabar virando
apenas uma crítica sem um objetivo, ou seja, quando uma crítica é feita com uma razão forte, provavelmente,
será melhor aceita, já quando feita apenas pensando em código e sem empatia alguma por quem fez, existe
uma grande probabilidade que se torne uma coisa desagradável, até mesmo tenha um tom ríspido ou agressivo,
o que não traz benefício algum para a equipe.</p>

<p>Assim penso, acima de code reviews e lutas de ego entre programadores, está o bom relacionamento e sintonia
entre a equipe. Hoje tenho uma certeza, prefiro trabalhar em empresas que se importam mais com o bom
relacionamento dos colaboradores do que com as críticas feitas nos code reviews, já que tenho uma impressão
(quase certeza) de que esses ambientes acabam entregando melhores produtos aos seus clientes e são ambientes
muito melhores para se trabalhar e crescer como pessoa, além de fazer com o que os colaboradores sintam vontade
de permanecer por anos e anos nesses lugares.</p>

<h2 id="empatia-enviando-a-mensagem">Empatia, enviando a mensagem</h2>

<p>A empatia é o elo que liga uma crítica a um ambiente cordial e respeitoso entre colegas de equipe.
Tive companheiros de equipe que faziam críticas tão boas e de uma forma tão sutil que eu tinha vontade de recebe-las
todos os dias (várias vezes aos dias), por sentir que aquilo estava me fazendo evoluir como programador e
como pessoa. Ao ver a cordialidade embutida na crítica, aquilo acabava me contagiando e criando um efeito dominó,
eu sentia vontade de tratar os meus colegas com toda aquela gentileza que recebi através de críticas. Isso não tem preço.</p>

<p>Por outro lado, quando a empatia não faz parte das peças do jogo, o mais comum é que se crie um ambiente de
disputa, nada cordial e até agressivo. Não consigo enxergar de que forma isso traz benefícios para a equipe ou
empresa, já que o maior patrimônio das empresas, são as pessoas e não o código. Se as pessoas não estão
pensando no seu colega antes de fazer uma crítica, já existe um erro que deveria ser revisado antes mesmo
do code review.</p>

<h2 id="foco-no-problema-recebendo-a-mensagem">Foco no problema, recebendo a mensagem</h2>

<p>Do outro lado da ponta está o receptor, quem recebe a mensagem precisa estar preparado e adaptado ao pensamento
de que críticas construtivas te fazem evoluir, e isso é tão importante quanto a forma com a mensagem é enviada.
Não adianta enviar uma mensagem cordial e gentil se do outro lado é entendida como um “jab de direita”.
Focar sempre nos problemas e não em pessoas é um bom exercício para se tornar um expert em receber críticas e
transforma-las em um degrau na sua evolução.</p>

<h2 id="conlusão">Conlusão</h2>

<p>Sempre estou me fazendo algumas perguntas como:</p>

<ul>
  <li>Estou fazendo o meu melhor?</li>
  <li>Estou pensando no meu colega?</li>
  <li>Estou usando as melhores palavras?</li>
  <li>Estou pensando em todo o contexto?</li>
</ul>

<p>Essa auto-reflexão te deixa mais consciente para não enviar uma mensagem ou receber recebe-la
de uma forma errada. Cautela sempre é bom, pensar no próximo é melhor ainda, esses são ingredientes
de um bolo que sempre corre riscos de não ficar bom, porém se utilizar os ingredientes certos e fizer
com carinho, a chance de dar errado diminui muito. Graças a minha esposa, aprendi isso.</p>

<p>Pra mim, a mesma coisa vale para code reviews, os ingredientes são bem conhecidos e são fáceis de encontrar,
basta saber dosar e sempre jogar duas xícaras de chá cheias de empatia que o risco do bolo ficar murcho ou sem sabor,
é bem menor.</p>

<p>É isso, dattebayo.</p>]]></content><author><name>anchietajunior</name></author><category term="Miscellaneous" /><category term="Code Review" /><category term="development" /><category term="code-review" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://d33x644h9xoqir.cloudfront.net/wp-content/uploads/sites/2/2019/02/como-construir-relacoes-produtivas-com-seus-colegas-de-trabalho.jpg" /><media:content medium="image" url="https://d33x644h9xoqir.cloudfront.net/wp-content/uploads/sites/2/2019/02/como-construir-relacoes-produtivas-com-seus-colegas-de-trabalho.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">Elixir - Minhas primeiras impressões</title><link href="/2020/08/10/first-impressions/" rel="alternate" type="text/html" title="Elixir - Minhas primeiras impressões" /><published>2020-08-10T13:00:00-03:00</published><updated>2020-08-10T13:00:00-03:00</updated><id>/2020/08/10/first-impressions</id><content type="html" xml:base="/2020/08/10/first-impressions/"><![CDATA[<p><img src="https://i.ibb.co/vPkM8KH/elixir-hello.png" alt="Elixir" /></p>

<p>Já faz um tempo que minha curiosidade sobre linguagens funcionais vem aumentando, li a respeito e vi vários vídeos sobre Scala, OCaml, GO, Clojure e Elixir. Todas me parecem ter algum aspecto interessante e que vale a pena estudar, porém por vir do mundo Ruby o Elixir acabou vencendo na escala de interesse e curiosidade.</p>

<p>Tenho visto nas minhas newsletters várias vagas Ruby/Elixir e isso é uma vantagem por estar um pouco conectado com a minha rotina atual, então comprei alguns cursos na Udemy e comecei a assistir algumas aulas.</p>

<p>Em um dos cursos, tinha um projeto FizzBuzz (algorítmo conhecido em exercícios) usando Elixir e as primeiras impressões sobre a linguagem foram ótimas, algumas coisas como pattern matching e pipe operator chamam a atenção logo de cara.</p>

<p>Além disso a facilidade de criar projetos como esse utilizando o mix é bem interessante. Criando um projeto elixir usando o mix por padrão algumas coisas bem legais já estarão presentes como testes.</p>

<p>A possibilidade de replicação de funções para tratar casos diferentes é uma coisa que me deixou “com a orelha em pé”, ainda não decidi se acho isso bom ou ruim, mas ao menos é bem interessante.</p>

<p>Outra coisa muito boa da linguagem é o uso constante dos módulos e a aridade das funções, já percebi que são coisas que não se vive sem quando se está programando em Elixir.</p>

<p><a href="https://github.com/anchietajunior/elixir-fizzbuzz">Aqui está o código do mini-projeto FizzBuzz</a>, sem dúvidas pretendo continuar meus estudos na linguagem e adiciona-la as minhas ferramentas, quem sabe até se tornar minha linguagem número 1, vejo muito potencial pra isso.</p>

<h3 id="cursos-na-udemy">Cursos na Udemy</h3>

<ul>
  <li><a href="https://www.udemy.com/course/programacao-funcional-com-elixir/">Programação Funcional com Elixir</a> - Jackson Pires</li>
  <li><a href="https://www.udemy.com/course/elixir-e-phoenix-do-zero/">Elixir e Phoenix do zero! Crie sua primeira API Phoenix.</a> - Rafael F. Camarda</li>
</ul>]]></content><author><name>anchietajunior</name></author><category term="Elixir" /><category term="elixir" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i.ibb.co/vPkM8KH/elixir-hello.png" /><media:content medium="image" url="https://i.ibb.co/vPkM8KH/elixir-hello.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">Rails 6 e ActionText</title><link href="/2020/07/18/action-text-start/" rel="alternate" type="text/html" title="Rails 6 e ActionText" /><published>2020-07-18T13:00:00-03:00</published><updated>2020-07-18T13:00:00-03:00</updated><id>/2020/07/18/action-text-start</id><content type="html" xml:base="/2020/07/18/action-text-start/"><![CDATA[<p><img src="https://i.ibb.co/vDZ2CPM/action-text.png" alt="ActionText" /></p>

<p>Uma das ultimas novidades acrescentadas ao ecossistema do Rails é o framework <a href="https://guiarails.com.br/action_text_overview.html">ActionText</a>, e nesse post vou falar um pouco sobre o meu primeiro contato com essa nova ferramenta que trás uma boa alternativa na edição e criação de textos ricos, além de upload de conteúdo direto para o <a href="https://edgeguides.rubyonrails.org/active_storage_overview.html">ActiveStorage</a> no melhor estilo WYSIWYG. Nesse caso utilizando o <a href="https://github.com/basecamp/trix">Trix editor</a>, ferramenta desenvolvida pela Basecamp, empresa do DHH.</p>

<h4 id="versões">Versões</h4>

<ul>
  <li>Ruby 2.7.1</li>
  <li>Rails 6</li>
</ul>

<h2 id="novo-projeto-rails-6">Novo Projeto Rails 6</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails new texts <span class="nt">-T</span>
<span class="nb">cd </span>texts
bundle <span class="nb">install
</span>rails db:create
</code></pre></div></div>

<h2 id="gerando-um-novo-posts-scaffold">Gerando um novo Posts scaffold</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails g scaffold Post title
rails db:migrate
</code></pre></div></div>
<p>Talvez soe estranho adicionar apenas o título aqui, mas o conteúdo do post virá através do ActionText que terá sua prṍpria estrutura de dados. Também vou definir a index/posts como rota padrão no arquivo <strong><em>routes.rb</em></strong></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span>
  <span class="n">resources</span> <span class="ss">:posts</span>
  <span class="n">root</span> <span class="s2">"posts#index"</span>
<span class="k">end</span>
</code></pre></div></div>

<h2 id="instalando-actiontext">Instalando ActionText</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails action_text:install
</code></pre></div></div>

<h2 id="adicionando-rich-text-aos-posts">Adicionando Rich Text aos posts</h2>

<p>Depois de instalado o action_text, agora de volta ao código do projeto, basta adicionar a referência de um novo campo com “texto rico” ao <strong><em>models/post.rb</em></strong>, vou chamar esse campo de <strong><em>body</em></strong>, mas poderia ser <strong><em>content</em></strong> ou qualquer outro nome apropriado.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Post</span> <span class="o">&lt;</span> <span class="no">ApplicationRecord</span>
  <span class="n">has_rich_text</span> <span class="ss">:body</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Pra conseguir passar os valores do campo <strong><em>body</em></strong> é necessário permitir esse valor no <strong><em>controllers/posts_controller.rb</em></strong></p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">PostsController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="c1"># implementation</span>

  <span class="k">def</span> <span class="nf">post_params</span>
    <span class="n">params</span><span class="p">.</span><span class="nf">require</span><span class="p">(</span><span class="ss">:post</span><span class="p">).</span><span class="nf">permit</span><span class="p">(</span><span class="ss">:title</span><span class="p">,</span> <span class="ss">:body</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Consequentemente será necessário acrescentar o novo campo também no formulário dos posts em <strong><em>views/posts/_form.html.erb</em></strong>…</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">&gt;</span>
  <span class="cp">&lt;%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:body</span> <span class="cp">%&gt;</span>
  <span class="cp">&lt;%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">rich_text_area</span> <span class="ss">:body</span> <span class="cp">%&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<p>…e no arquivo <strong><em>views/posts/show.html.erb</em></strong> pra exibir o conteúdo do campo body.</p>

<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"body"</span><span class="nt">&gt;</span>
  <span class="cp">&lt;%=</span> <span class="vi">@post</span><span class="p">.</span><span class="nf">body</span> <span class="cp">%&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<h2 id="migrando">Migrando</h2>

<p>É necessária uma nova migração, já que o model Post agora terá um novo rich_text field.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails db:migrate
</code></pre></div></div>

<h2 id="testando">Testando</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails server
</code></pre></div></div>

<h2 id="extra">Extra</h2>

<p>Para fazer uploads de imagem pra dentro do editor, pode ser necessário instalar o <a href="https://imagemagick.org/index.php">Image Magick</a> na sua máquina pra que tudo funcione corretamente.</p>

<p>Além disso, descomente a seguinte linha no seu Gemfile:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gem</span> <span class="s1">'image_processing'</span><span class="p">,</span> <span class="s1">'~&gt; 1.2'</span>
</code></pre></div></div>

<p>e depois instale a biblioteca caso ainda não tenha feito:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">install</span>
</code></pre></div></div>

<p>That’s it!</p>

<p>Pra quem conheceu o Rails com aquela jogada de “Crie um blog em n minutos”, a introdução do ActionText dá a impressão que a ideia agora é criar um blog em segundos, rs.</p>]]></content><author><name>anchietajunior</name></author><category term="Rails" /><category term="ActionText" /><category term="rails" /><category term="actiontext" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i.ibb.co/vDZ2CPM/action-text.png" /><media:content medium="image" url="https://i.ibb.co/vDZ2CPM/action-text.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry xml:lang="pt-br"><title type="html">Recursividade com Ruby</title><link href="/2020/05/30/recursion/" rel="alternate" type="text/html" title="Recursividade com Ruby" /><published>2020-05-30T00:33:00-03:00</published><updated>2020-05-30T00:33:00-03:00</updated><id>/2020/05/30/recursion</id><content type="html" xml:base="/2020/05/30/recursion/"><![CDATA[<p><img src="https://i.ibb.co/BrqwTJL/ruby-algorithm.png" alt="Algorith" /></p>

<p>Voltando a ler algumas coisas da época da faculdade e tentando aprender coisas novas sobre algoritmos e estruturas de dados, me deparo com um dos primeiros conceitos que vemos ao entrar na área de programação: Recursividade.</p>

<p>Traduzindo de uma forma bem grosseira e comum, Recursividade é quando uma função chama a si própria. Alguns exemplos bem comuns são os algoritmos da Sequência de Fibonacci e Cálculo Fatorial. Mas vai um pouco além disso, também é importante conhecer sobre a Pilha de chamada e como o computador aloca valores através das chamadas de funções na memória.</p>

<p>Particularmente, sempre vi Recursividade como um bom exercício para estudar algoritmos, mesmo que em alguns casos um simples loop seja suficiente pra resolver um problema, porém utilizando Recursividade uma nova carta na sua manga é adicionada ao entender bem esse conceito, pra isso vamos a alguns exemplos:</p>

<h2 id="1---somar-todos-os-números-de-um-array-utilizando-recursividade">1 - Somar todos os números de um array utilizando Recursividade.</h2>

<p>Dado um array de números inteiros, vamos somar todos os itens e retornar o valor da soma.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">soma_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
  <span class="k">if</span> <span class="n">arr</span><span class="p">.</span><span class="nf">size</span> <span class="o">&lt;=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">arr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
  <span class="k">else</span>
    <span class="k">return</span> <span class="n">arr</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="n">soma_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Aqui fiz apenas uma verificação pra saber se o tamanho do array recebido é menor ou igual a 1, caso seja, retorne o primeiro e único item do array. Caso o tamanho do array seja maior que 1, retorne uma soma do primeiro item do array mais uma nova chamada da função. Dessa forma, temos o nosso primeiro exemplo de recursividade.</p>

<p>Então, pra entender melhor, vamos analisar o que acontece aqui utilizando um exemplo de um array [1, 2].</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">arr</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>

<span class="n">soma_array</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span>

<span class="c1"># =&gt; 3</span>
</code></pre></div></div>

<p>Na primeira vez que a função for executada, o array possui 2 itens, 1 e 2. Então cai na condição do Else por ter mais de um item. Nessa condição eu executo um slice!(0), ou seja, removo o primeiro item do array, no caso o número 1 e chamo novamente a função soma_array, então algo como:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">1</span> <span class="o">+</span> <span class="n">soma_array</span><span class="p">([</span><span class="mi">2</span><span class="p">])</span>
</code></pre></div></div>

<p>E agora ao ser executada novamente o array possui apenas um item, então a função retorna o número 2, voltando ao contexto da primeira chamada da função:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>

<span class="c1"># =&gt; 3</span>
</code></pre></div></div>

<p>A mesma coisa acontece caso o array possua vários itens.</p>

<h2 id="2---fatorial-n">2 - Fatorial (n!)</h2>

<p><strong><em>Fatorial é um número natural inteiro positivo, o qual é representado por n!</em></strong></p>

<p><strong><em>O fatorial de um número é calculado pela multiplicação desse número por todos os seus antecessores até chegar ao número 1. Note que nesses produtos, o zero (0) é excluído.</em></strong></p>

<p><strong><em>O fatorial é representado por:</em></strong></p>

<p><strong><em>n! = n . (n – 1) . (n – 2) . (n – 3)!</em></strong></p>

<p><a href="https://www.todamateria.com.br/fatorial/">Referência</a></p>

<p>Sabendo agora um pouco sobre fatorial, vamos escrever uma função que execute isso de forma recursiva.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fatorial</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
  <span class="k">if</span> <span class="n">number</span> <span class="o">==</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="mi">1</span>
  <span class="k">else</span>
    <span class="k">return</span> <span class="n">number</span> <span class="o">*</span> <span class="n">fatorial</span><span class="p">(</span><span class="n">number</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Então se utilizarmos o número 3 como parâmetro, teremos o seguinte:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fatorial</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>

<span class="c1"># =&gt; 6</span>
</code></pre></div></div>

<p>Como nosso argumento é 3, faremos uma multiplicação 3 x (3-1) através da primeira chamada recursiva da função e em seguinda uma outra multiplicação na segunda chamada recursiva, ficando um cálculo parecido com esse na visão do computador:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(3 * (3-1)) * (2-1)
</code></pre></div></div>

<p>Lendo o livro <strong><em>Entendendo algoritmos</em></strong>, pude analisar as chamadas de uma função recursiva como uma pilha de caixas, conhecida como Pilha de chamadas. No caso a primeira chamada com o número 3 é guardada em memória, em seguida a chamada com o número 2 e por ultimo com o número 1, dessa forma as caixas vão sendo removidas até voltar ao contexto original da primeira chamada da função.</p>

<h2 id="3---sequência-de-fibonacci">3 - Sequência de Fibonacci</h2>

<p>Talvez o exemplo mais comum quando o assunto é recursividade, principalmente em faculdades.</p>

<p><strong><em>Sequência de Fibonacci é a sequência numérica proposta pelo matemático Leonardo Pisa, mais conhecido como Fibonacci:</em></strong></p>

<p><strong><em>1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …</em></strong></p>

<p><strong><em>Foi a partir de um problema criado por ele que o mesmo detectou a existência de uma regularidade matemática.</em></strong></p>

<p><strong><em>Trata-se do exemplo clássico dos coelhos, em que Fibonacci descreve o crescimento de uma população desses animais.</em></strong></p>

<p><strong><em>A sequência é definida mediante a seguinte fórmula:</em></strong></p>

<p><strong><em>Fn = Fn - 1 + Fn - 2</em></strong></p>

<p><a href="https://www.todamateria.com.br/sequencia-de-fibonacci/">Referência</a></p>

<p>Então, vamos criar esse ultimo exemplo em Ruby, lembrando que existem várias maneiras de transformar esses conceitos em código.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
  <span class="n">number</span> <span class="o">&lt;=</span> <span class="mi">1</span> <span class="p">?</span> <span class="n">number</span> <span class="p">:</span> <span class="n">fib</span><span class="p">(</span><span class="n">number</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">number</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>

<p>Aqui decidi utilizar a praticidade do Ruby em retornar a ultima expressão de um escopo pra fazer a função fib. Podemos ver que a condicional analisa se o número recebido é menor ou igual a 1, caso seja retorne o número, caso não, faça uma soma utilizando a mesma função duas vezes, a primeira parte utilizando o <strong><em>number - 1</em></strong> e a segunda o <strong><em>number - 2</em></strong> como descrito na fórmula da sequência de Fibonnaci.</p>

<p>É isso, até a próxima.</p>]]></content><author><name>anchietajunior</name></author><category term="Algorithms" /><category term="algorithm" /><category term="ruby" /><category term="recursion" /><summary type="html"><![CDATA[]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://i.ibb.co/BrqwTJL/ruby-algorithm.png" /><media:content medium="image" url="https://i.ibb.co/BrqwTJL/ruby-algorithm.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>