<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Plínio Balduino</title>
    <description>The latest articles on DEV Community by Plínio Balduino (@pbalduino).</description>
    <link>https://dev.to/pbalduino</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F335931%2F5ae6241b-74de-4c8e-bedb-a14e2fcd8d0d.jpg</url>
      <title>DEV Community: Plínio Balduino</title>
      <link>https://dev.to/pbalduino</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pbalduino"/>
    <language>en</language>
    <item>
      <title>[pt-BR] Como um programa vira um processo: entendendo processos com o meniOS</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Wed, 26 Aug 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/pbalduino/pt-br-como-um-programa-vira-um-processo-entendendo-processos-com-o-menios-2i3n</link>
      <guid>https://dev.to/pbalduino/pt-br-como-um-programa-vira-um-processo-entendendo-processos-com-o-menios-2i3n</guid>
      <description>&lt;p&gt;Há alguns anos publiquei o artigo &lt;a href="https://dev.to/pbalduino/criando-um-sistema-operacional-quase-do-zero-27m8"&gt;Criando um sistema operacional (quase) do zero&lt;/a&gt;, contando os primeiros passos do meniOS. Naquela época, fazer o kernel inicializar, configurar algumas estruturas básicas e colocar alguma coisa na tela já representava uma parte considerável da diversão.&lt;/p&gt;

&lt;p&gt;O projeto continuou crescendo e, hoje, o meniOS consegue executar programas em &lt;em&gt;user space&lt;/em&gt;, possui um scheduler preemptivo, memória virtual por processo, filesystem, shell, sinais, pipes e outras funcionalidades que fazem com que ele se pareça um pouco mais com aquilo que normalmente chamamos de sistema operacional e um pouco menos com um programa muito complicado que tomou conta do computador.&lt;/p&gt;

&lt;p&gt;Dizer que um sistema operacional "executa programas", entretanto, esconde uma quantidade considerável de trabalho. Quando clicamos em um ícone ou digitamos um comando no terminal, estamos acostumados a pensar que simplesmente mandamos o computador executar aquele programa, mas entre o arquivo armazenado no disco e suas instruções sendo executadas pela CPU existe uma abstração fundamental fornecida pelo sistema operacional: &lt;strong&gt;o processo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Este é o primeiro passo de uma pequena descida ao submundo do desenvolvimento de sistemas operacionais. Ainda estamos relativamente perto da superfície.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programa e processo não são a mesma coisa
&lt;/h2&gt;

&lt;p&gt;Imagine um executável chamado &lt;code&gt;hello&lt;/code&gt;. Enquanto ele está armazenado no disco, temos basicamente um arquivo contendo código, dados e algumas informações que permitem ao sistema operacional entender como esse conteúdo deve ser carregado. No caso do meniOS, assim como no Linux e em vários outros sistemas Unix-like, os executáveis usam o formato ELF. Por enquanto, ELF pode continuar sendo apenas uma sigla misteriosa; voltaremos a ele quando estivermos alguns degraus abaixo.&lt;/p&gt;

&lt;p&gt;O importante neste momento é perceber que o arquivo armazenado no disco é o &lt;strong&gt;programa&lt;/strong&gt;, enquanto cada instância desse programa em execução é um &lt;strong&gt;processo&lt;/strong&gt;. Podemos ter dez cópias de &lt;code&gt;hello&lt;/code&gt; no disco sem que nenhuma delas esteja sendo executada e, da mesma forma, podemos ter apenas um &lt;code&gt;/bin/hello&lt;/code&gt; e executá-lo várias vezes simultaneamente.&lt;/p&gt;

&lt;p&gt;Essa distinção aparentemente simples muda completamente o problema que o sistema operacional precisa resolver. Um programa pode ser tratado essencialmente como informação armazenada, enquanto um processo precisa representar uma execução em andamento ou pronta para continuar quando receber tempo de CPU. Isso significa que o kernel precisa manter informações sobre sua identidade, seu estado, os recursos que pertencem a ele e o ponto em que sua execução deverá continuar.&lt;/p&gt;

&lt;p&gt;No meniOS, boa parte dessas informações fica em uma estrutura chamada &lt;code&gt;proc_info_t&lt;/code&gt;. A estrutura real possui muitos campos, mas podemos reduzir alguns deles para enxergar melhor a ideia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;proc_info_t&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;proc_info_p&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;proc_state_t&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="n"&gt;cpu_state_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cpu_state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;phys_addr_t&lt;/span&gt; &lt;span class="n"&gt;address_space_root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;file_descriptor_entry_t&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PROC_MAX_FILES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PROC_CWD_MAX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;exit_code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;proc_info_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já existe bastante coisa escondida nesse pequeno trecho. O &lt;code&gt;pid&lt;/code&gt; identifica o processo, enquanto &lt;code&gt;state&lt;/code&gt; registra seu estado atual e &lt;code&gt;cpu_state&lt;/code&gt; mantém informações necessárias para continuar sua execução. Também aparecem referências ao espaço de memória do processo, aos arquivos que ele mantém abertos, ao seu diretório corrente e até ao processo que o criou.&lt;/p&gt;

&lt;p&gt;Alguns desses conceitos merecem artigos inteiros e, por enquanto, não precisamos entender todos eles. O importante é perceber que um processo não é simplesmente "um programa carregado na memória": ele é uma estrutura mantida pelo sistema operacional para representar e controlar uma execução.&lt;/p&gt;

&lt;p&gt;Se você já usou Linux, macOS ou outro sistema Unix-like, provavelmente já encontrou um PID ao executar comandos como &lt;code&gt;ps&lt;/code&gt;. Poderíamos ter, por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PID   COMMAND
1     init
7     mosh
12    hello
13    hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os processos 12 e 13 estão executando o mesmo programa, mas continuam sendo processos independentes. Cada um pode estar em um ponto diferente da execução, possuir dados diferentes na memória, manter arquivos diferentes abertos e terminar com resultados diferentes.&lt;/p&gt;

&lt;p&gt;O meniOS também atribui um PID a cada novo processo. Em uma das partes da criação de um processo filho encontramos algo tão simples quanto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last_pid&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso fornece uma identidade ao novo processo, mas ainda precisamos entender de onde ele veio e como chegou ao ponto em que pode executar um programa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando um processo com &lt;code&gt;fork()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sistemas Unix-like tradicionalmente oferecem uma operação chamada &lt;code&gt;fork()&lt;/code&gt;, cujo nome descreve razoavelmente bem o que acontece: a execução chega a determinado ponto e se divide em dois caminhos. Um programa pode fazer algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;pid_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// processo filho&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// processo pai&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O aspecto inicialmente estranho de &lt;code&gt;fork()&lt;/code&gt; é que existe apenas uma chamada no código, mas, se ela for bem-sucedida, passam a existir dois processos continuando a execução a partir daquele ponto. O processo original, que chamamos de pai, recebe como resultado o PID do processo recém-criado, enquanto o filho observa &lt;code&gt;fork()&lt;/code&gt; retornando &lt;code&gt;0&lt;/code&gt;. Essa diferença permite que o mesmo trecho de código descubra em qual dos dois processos está sendo executado.&lt;/p&gt;

&lt;p&gt;Se o pai receber &lt;code&gt;42&lt;/code&gt; como resultado, por exemplo, significa que o novo processo possui PID 42. Quando o processo 42 continuar sua execução, entretanto, o valor retornado por &lt;code&gt;fork()&lt;/code&gt; será zero.&lt;/p&gt;

&lt;p&gt;Não existe alguma característica especial da linguagem C capaz de fazer uma função retornar dois valores diferentes. Quem produz esse comportamento é o sistema operacional, criando dois contextos de execução e preparando cada um deles para observar um resultado diferente.&lt;/p&gt;

&lt;p&gt;No meniOS, isso pode ser visto diretamente na implementação de &lt;code&gt;proc_fork()&lt;/code&gt;. Entre outras tarefas, o kernel cria uma nova estrutura para o filho, atribui um PID, prepara uma nova pilha do kernel, replica informações herdadas do pai e cria um espaço de endereçamento para o novo processo. A memória virtual do processo pai também é clonada para que o filho possa continuar a execução com uma visão inicialmente equivalente dos dados que existiam antes do &lt;code&gt;fork()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Essa última frase esconde uma quantidade razoável de complexidade. Clonar memória de processos envolve memória virtual, páginas, page tables e várias outras coisas que não precisamos trazer para a conversa agora. Para este primeiro degrau basta assumir que o meniOS consegue preparar para o filho uma cópia apropriada do ambiente de execução do pai.&lt;/p&gt;

&lt;p&gt;Há, entretanto, um detalhe da implementação que vale observar desde já. O kernel copia para o filho o estado da CPU existente no momento da chamada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;cpu_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syscall_frame_t&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois modifica o registrador que será usado para devolver o resultado da operação ao processo filho:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;cpu_state&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o filho voltar a executar em &lt;em&gt;user space&lt;/em&gt;, continuará praticamente do ponto em que o pai estava, mas enxergará o retorno de &lt;code&gt;fork()&lt;/code&gt; como zero. O pai, por sua vez, receberá o PID atribuído ao filho.&lt;/p&gt;

&lt;p&gt;Esse pequeno detalhe é uma boa demonstração de algo que aparece repetidamente quando começamos a olhar por baixo das abstrações fornecidas por um sistema operacional. Aquilo que parece um comportamento peculiar de uma API frequentemente corresponde a alguma manipulação bastante concreta do estado da máquina.&lt;/p&gt;

&lt;p&gt;Há ainda outra consequência importante: depois de &lt;code&gt;fork()&lt;/code&gt;, pai e filho continuam executando o mesmo programa. Se quem chamou &lt;code&gt;fork()&lt;/code&gt; era um shell, acabamos de criar outro processo executando uma cópia daquele shell, o que ainda não resolve nosso problema inicial de executar &lt;code&gt;/bin/hello&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;É nesse ponto que entra &lt;code&gt;exec()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trocando o programa com &lt;code&gt;exec()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Uma confusão bastante comum é imaginar que &lt;code&gt;execve()&lt;/code&gt; cria outro processo, quando sua função é diferente: ela substitui o programa que está sendo executado pelo processo atual. O PID continua sendo o mesmo, mas o espaço de memória destinado ao programa é reconstruído para receber o novo executável e a execução passa a continuar a partir do ponto de entrada desse programa.&lt;/p&gt;

&lt;p&gt;Podemos visualizar a combinação de &lt;code&gt;fork()&lt;/code&gt; e &lt;code&gt;execve()&lt;/code&gt; desta maneira:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    fork()
                      |
               +------+------+
               |             |
             shell         shell
             (pai)         (filho)
                              |
                           execve()
                              |
                            hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No meniOS, a substituição da imagem passa por &lt;code&gt;proc_exec_image()&lt;/code&gt;. O kernel prepara um novo espaço de endereçamento, cria uma nova pilha de &lt;em&gt;user space&lt;/em&gt;, carrega o executável e determina em qual endereço a execução deverá começar. Depois que a nova imagem está pronta, os antigos mapeamentos pertencentes ao programa anterior podem ser descartados e o contexto do processo passa a apontar para o ponto de entrada do novo executável.&lt;/p&gt;

&lt;p&gt;O código real contém operações como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack_top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack_top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rip&lt;/code&gt; é o registrador que indica à CPU qual instrução deverá ser executada. Ao configurá-lo com o &lt;em&gt;entry point&lt;/em&gt; obtido do executável, o kernel está preparando o processo para que, quando voltar a &lt;em&gt;user space&lt;/em&gt;, sua execução continue no novo programa.&lt;/p&gt;

&lt;p&gt;Também estamos escondendo bastante coisa aqui. Ainda não explicamos como o meniOS interpreta um arquivo ELF, como cria o novo espaço de memória, o que exatamente significa voltar para &lt;em&gt;user space&lt;/em&gt; ou por que existem registradores chamados &lt;code&gt;rip&lt;/code&gt; e &lt;code&gt;rsp&lt;/code&gt;. Esses detalhes não são irrelevantes; estamos apenas adiando a explicação até que tenhamos construído o vocabulário necessário.&lt;/p&gt;

&lt;p&gt;Por enquanto, uma regra resume bem as duas operações: &lt;strong&gt;&lt;code&gt;fork()&lt;/code&gt; cria outro processo a partir de um processo existente, enquanto &lt;code&gt;exec()&lt;/code&gt; substitui o programa executado pelo processo atual.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pode parecer estranho realizar duas operações quando o objetivo final era simplesmente executar outro programa. Por que não pedir diretamente ao kernel que crie um novo processo executando &lt;code&gt;/bin/hello&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Existem sistemas e APIs que trabalham com modelos mais próximos dessa ideia, mas a separação entre &lt;code&gt;fork()&lt;/code&gt; e &lt;code&gt;exec()&lt;/code&gt; oferece uma propriedade bastante conveniente: há um intervalo entre criar o filho e substituir seu programa, e nesse intervalo o filho pode preparar o ambiente no qual o novo executável será iniciado.&lt;/p&gt;

&lt;p&gt;Um shell pode aproveitar esse momento para modificar a entrada ou a saída do processo. É assim que uma construção como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hello &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; output.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pode ser implementada. O shell cria um processo filho, altera sua saída padrão para apontar para &lt;code&gt;output.txt&lt;/code&gt; e somente então executa o novo programa. &lt;code&gt;hello&lt;/code&gt; não precisa saber que existe um arquivo envolvido; para ele, escrever na saída padrão continua sendo apenas escrever na saída padrão.&lt;/p&gt;

&lt;p&gt;A mesma ideia pode ser estendida para pipes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;arquivo.txt | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O shell cria os processos necessários, conecta a saída de um deles à entrada do outro e depois substitui cada processo filho pelo executável correspondente. O &lt;code&gt;mosh&lt;/code&gt;, shell do meniOS, utiliza exatamente esse tipo de mecanismo, mas acompanhar o caminho completo de um comando dentro do shell será assunto para o próximo artigo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do &lt;code&gt;fork()&lt;/code&gt; ao &lt;code&gt;waitpid()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Agora conseguimos criar um processo e substituir o programa que ele executa, mas ainda falta uma parte importante do seu ciclo de vida. Em algum momento, o programa terminará, seja porque chegou normalmente ao final de sua execução, porque chamou &lt;code&gt;exit()&lt;/code&gt; explicitamente ou porque alguma outra condição provocou seu encerramento. Quando isso acontece, o kernel ainda precisa preservar informações suficientes para que o processo pai descubra o que aconteceu com seu filho.&lt;/p&gt;

&lt;p&gt;É aí que aparece &lt;code&gt;waitpid()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;waitpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa chamada permite que um processo espere pela mudança de estado de um filho e obtenha informações sobre seu término. Para um shell, esse comportamento é particularmente importante porque, quando executamos um programa em primeiro plano, normalmente esperamos que o prompt somente volte depois que aquele programa terminar.&lt;/p&gt;

&lt;p&gt;Podemos finalmente montar uma versão simplificada do ciclo completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shell
  |
  +-- fork()
  |      |
  |      +-- filho
  |            |
  |          execve()
  |            |
  |          hello
  |            |
  |           exit()
  |
  +-- waitpid()
          |
          +-- filho terminou
          |
       novo prompt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A realidade é um pouco mais sofisticada porque o pai nem sempre precisa ficar bloqueado esperando, processos podem ser interrompidos ou continuar em &lt;em&gt;background&lt;/em&gt;, sinais podem alterar seu comportamento e o kernel precisa lidar com estados intermediários. O próprio meniOS possui estados como &lt;code&gt;NEW&lt;/code&gt;, &lt;code&gt;READY&lt;/code&gt;, &lt;code&gt;RUNNING&lt;/code&gt;, &lt;code&gt;WAITING&lt;/code&gt;, &lt;code&gt;SLEEPING&lt;/code&gt;, &lt;code&gt;ZOMBIE&lt;/code&gt;, &lt;code&gt;STOPPED&lt;/code&gt; e &lt;code&gt;TERMINATED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Um desses nomes costuma chamar atenção: &lt;code&gt;ZOMBIE&lt;/code&gt;. Apesar do nome dramático, um processo zumbi não está andando pelo sistema operacional em busca de outros processos para devorar. Ele simplesmente terminou sua execução, mas algumas informações sobre seu término ainda precisam ser mantidas porque o processo pai não as coletou. Quando o pai executa &lt;code&gt;wait()&lt;/code&gt; ou &lt;code&gt;waitpid()&lt;/code&gt;, pode obter o status do filho e permitir que o kernel finalmente conclua a limpeza das estruturas restantes.&lt;/p&gt;

&lt;p&gt;Com isso, aquilo que inicialmente parecia ser apenas "executar um programa" já pode ser descrito com um pouco mais de precisão. Existe um processo executando o shell, esse processo cria um filho com &lt;code&gt;fork()&lt;/code&gt;, o filho herda parte do contexto do pai e pode preparar seu ambiente antes de usar &lt;code&gt;exec()&lt;/code&gt; para substituir sua imagem pelo programa desejado. O novo programa executa mantendo a identidade daquele processo e, quando termina, o kernel registra seu estado para que o pai possa observá-lo através de &lt;code&gt;wait()&lt;/code&gt; ou &lt;code&gt;waitpid()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que ainda estamos escondendo
&lt;/h2&gt;

&lt;p&gt;Chegamos até aqui simplificando deliberadamente várias etapas. Quando dissemos que um processo possui memória própria, não explicamos como dois processos podem usar os mesmos endereços virtuais sem necessariamente acessar a mesma memória física. Quando copiamos &lt;code&gt;cpu_state&lt;/code&gt;, também não vimos quais registradores fazem parte desse estado nem como o kernel consegue interromper um processo e continuar sua execução posteriormente.&lt;/p&gt;

&lt;p&gt;Também passamos rapidamente por uma questão ainda mais fundamental: quando um programa chama &lt;code&gt;fork()&lt;/code&gt;, &lt;code&gt;execve()&lt;/code&gt; ou &lt;code&gt;waitpid()&lt;/code&gt;, como uma aplicação executando fora do kernel consegue pedir que o kernel faça alguma coisa? A resposta envolve as chamadas de sistema, ou &lt;em&gt;syscalls&lt;/em&gt;, e a fronteira entre &lt;em&gt;user space&lt;/em&gt; e &lt;em&gt;kernel space&lt;/em&gt;, outro ponto em que a escada começa a descer de maneira mais perceptível.&lt;/p&gt;

&lt;p&gt;O executável também permaneceu quase inteiramente como uma caixa-preta. Sabemos que o meniOS trabalha com ELF e que existe um &lt;em&gt;entry point&lt;/em&gt;, mas ainda não discutimos como o kernel encontra código e dados dentro do arquivo e os coloca nos locais adequados da memória. Da mesma maneira, dissemos algumas vezes que um processo "recebe tempo de CPU" sem explicar quem toma essa decisão ou como vários processos conseguem compartilhar um único processador sem cooperar voluntariamente entre si.&lt;/p&gt;

&lt;p&gt;Cada uma dessas simplificações esconde outra parte do sistema operacional e, consequentemente, outro possível degrau da nossa descida. Neste primeiro, entretanto, já temos um modelo suficientemente bom para responder à pergunta que abriu o artigo: um programa é código e dados armazenados, enquanto um processo é a representação, mantida pelo sistema operacional, de uma execução desse programa.&lt;/p&gt;

&lt;p&gt;No modelo adotado pelo meniOS, &lt;code&gt;fork()&lt;/code&gt; cria um novo processo a partir de um existente, &lt;code&gt;exec()&lt;/code&gt; substitui o programa executado por esse processo e &lt;code&gt;waitpid()&lt;/code&gt; permite que o pai acompanhe o que aconteceu com seu filho. Essas três operações, combinadas, estão por trás de algo tão cotidiano quanto digitar o nome de um programa no terminal e pressionar Enter.&lt;/p&gt;

&lt;p&gt;No próximo degrau podemos fazer justamente isso: acompanhar um comando desde o momento em que é digitado no &lt;code&gt;mosh&lt;/code&gt; até a criação e execução do processo correspondente. A partir daí, começaremos a encontrar algumas das abstrações que convenientemente deixamos escondidas neste artigo.&lt;/p&gt;

</description>
      <category>ptbr</category>
      <category>osdev</category>
      <category>operating</category>
      <category>menios</category>
    </item>
    <item>
      <title>[pt-BR] Clean Code passado a limpo - Parte 1</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Sun, 23 Aug 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/pbalduino/pt-br-clean-code-passado-a-limpo-2n4h</link>
      <guid>https://dev.to/pbalduino/pt-br-clean-code-passado-a-limpo-2n4h</guid>
      <description>&lt;h2&gt;
  
  
  Uma leitura crítica, sem dogmas e sem espantalhos
&lt;/h2&gt;

&lt;p&gt;Muito se fala sobre &lt;em&gt;Clean Code&lt;/em&gt;, publicado no Brasil como &lt;em&gt;Código Limpo&lt;/em&gt;. Entre iniciantes e desenvolvedores de nível pleno, é comum encontrar quem adote suas recomendações de maneira dogmática, como se o livro fosse um tratado de verdades absolutas. No outro extremo, profissionais mais experientes frequentemente o descartam por completo e parecem dispostos a queimá-lo na fogueira erguida do outro lado dessas mesmas verdades absolutas. Em ambos os casos, a leitura crítica acaba substituída por uma conclusão tomada de antemão.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Para esta série, usarei a edição original em inglês. Tenho uma longa e desastrosa experiência com traduções da Alta Books e minha recomendação continua sendo direta: aprendam inglês e leiam o original. Já escrevi sobre isso e não pretendo retomar essa discussão aqui. Para quem trabalha com desenvolvimento de software, a capacidade de ler textos técnicos em inglês é fundamental.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Robert “Uncle Bob” Martin sustenta publicamente posições que considero indefensáveis e que atraem um público politicamente conservador, para dizer o mínimo. A discussão em torno desses posicionamentos é legítima, mas não será o objeto desta série. Vou me limitar à análise da obra, mantendo uma distância saudável de seu autor.&lt;/p&gt;

&lt;h2&gt;
  
  
  O livro, a escola e o mito
&lt;/h2&gt;

&lt;p&gt;Poucos livros sobre desenvolvimento de software alcançaram uma presença cultural comparável à de &lt;em&gt;Clean Code&lt;/em&gt;. Suas recomendações aparecem em entrevistas de emprego, revisões de código, guias internos, cursos, vídeos e discussões sobre senioridade. Termos como funções pequenas, nomes significativos, responsabilidade única e ausência de duplicação passaram a circular de forma relativamente independente do livro, muitas vezes reduzidos a regras que cabem em uma publicação curta ou em um comentário de &lt;em&gt;pull request&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Essa popularidade produziu uma versão simplificada da obra. Nela, Robert Martin aparece como o autor de um conjunto fechado de mandamentos sobre como todo código deveria ser escrito. Algumas pessoas adotam esses mandamentos como critérios objetivos de qualidade; outras os rejeitam como dogmas ultrapassados, geralmente sem dedicar muita atenção ao argumento original, ao contexto dos exemplos ou às ressalvas feitas pelo próprio livro.&lt;/p&gt;

&lt;p&gt;A leitura de &lt;em&gt;Clean Code&lt;/em&gt; revela uma obra mais complexa. Seu tom é frequentemente categórico e algumas conclusões ultrapassam aquilo que seus exemplos conseguem demonstrar, mas o livro também reconhece que representa uma escola específica de desenvolvimento de software. A tensão entre essas duas posturas, a declaração de que não existe uma verdade absoluta e a apresentação de determinadas opiniões como absolutos, atravessa toda a obra e ajuda a explicar tanto sua influência quanto boa parte das críticas que recebeu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Antes do livro, a Object Mentor
&lt;/h3&gt;

&lt;p&gt;A Object Mentor foi uma empresa de consultoria e treinamento em desenvolvimento de software &lt;a href="https://www.linkedin.com/company/object-mentor" rel="noopener noreferrer"&gt;fundada em 1991&lt;/a&gt; por Robert C. Martin. Em sua &lt;a href="https://www.cleancoder.com/files/about.md" rel="noopener noreferrer"&gt;biografia atual&lt;/a&gt;, Martin também identifica Jim Newkirk como cofundador. Ao longo de sua existência, a empresa ofereceu treinamento em C++, Java, orientação a objetos e princípios de design e, posteriormente, passou a atuar fortemente com Extreme Programming e metodologias ágeis. Seus serviços incluíam consultoria, treinamento, mentoria e desenvolvimento de software. A Object Mentor encerrou suas atividades em 2008, no mesmo ano em que a primeira edição de &lt;em&gt;Clean Code&lt;/em&gt; foi publicada.&lt;/p&gt;

&lt;p&gt;Esse contexto ajuda a compreender o significado da expressão “Object Mentor School of Clean Code” (“Escola de Código Limpo da Object Mentor”, em tradução livre), usada no primeiro capítulo. A escola mencionada por Martin correspondia às práticas que ele e seus colegas aplicavam, ensinavam e comercializavam por meio de uma consultoria. A própria folha de rosto apresenta os colaboradores do livro como “The Object Mentors” (“Os mentores da Object Mentor”, em tradução livre), reforçando que a obra registra uma visão desenvolvida coletivamente dentro daquela empresa.&lt;/p&gt;

&lt;p&gt;Isso também explica o caráter pragmático do livro. &lt;em&gt;Clean Code&lt;/em&gt; não se apresenta como uma pesquisa acadêmica nem procura construir suas recomendações a partir de estudos controlados sobre legibilidade, manutenção ou produtividade. Sua matéria-prima é a experiência acumulada pelos autores em projetos, treinamentos e consultorias. O conhecimento oferecido nasce da prática profissional, da observação e da repetição de soluções que, segundo eles, produziram bons resultados.&lt;/p&gt;

&lt;p&gt;Experiência é uma fonte legítima de conhecimento técnico, especialmente em uma atividade na qual contexto, equipe e domínio exercem influência considerável. Ainda assim, uma prática que funcionou repetidamente dentro de uma consultoria continua precisando ser examinada antes de se transformar em uma regra geral. Parte do trabalho desta série será identificar quando o livro apresenta uma experiência como experiência e quando a transforma em uma conclusão universal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Um livro que exige trabalho
&lt;/h3&gt;

&lt;p&gt;A introdução de &lt;em&gt;Clean Code&lt;/em&gt; também contradiz a maneira superficial como a obra costuma ser consumida. Martin descreve o aprendizado da escrita de código como uma combinação de conhecimento e prática. Princípios, padrões e heurísticas teriam pouco valor quando separados do exercício de ler, modificar e compreender código real.&lt;/p&gt;

&lt;p&gt;O livro foi dividido em três partes com essa finalidade. A primeira apresenta princípios, práticas e padrões. A segunda reúne estudos de caso nos quais códigos existentes são sucessivamente alterados. A terceira organiza os &lt;em&gt;smells&lt;/em&gt; e as heurísticas identificadas durante essas refatorações. Martin afirma que o valor dessas heurísticas depende da relação entre cada uma delas e as decisões tomadas nos estudos de caso. O leitor que ignora os exemplos e consome apenas as regras perde, segundo a própria introdução, a parte mais importante da obra.&lt;/p&gt;

&lt;p&gt;Esse detalhe é especialmente relevante porque a versão popular de &lt;em&gt;Clean Code&lt;/em&gt; costuma fazer exatamente aquilo que o livro desaconselha. As heurísticas são retiradas dos exemplos, resumidas em frases curtas e aplicadas em contextos nos quais o raciocínio que as produziu já não está presente. Uma função deve ser pequena, uma classe deve ter uma única responsabilidade e um comentário deve ser evitado, mas raramente se discute como reconhecer os limites dessas recomendações, quais custos surgem de sua aplicação ou que características do código original levaram os autores àquela decisão.&lt;/p&gt;

&lt;p&gt;Uma análise justa da obra precisa observar os estudos de caso e verificar se as transformações propostas realmente produzem os benefícios prometidos. Os capítulos “Successive Refinement” (“Refinamento sucessivo”, em tradução livre), “JUnit Internals” (“Aspectos internos do JUnit”, em tradução livre) e “Refactoring SerialDate” (“Refatorando SerialDate”, em tradução livre) serão particularmente importantes porque apresentam o refinamento sucessivo de código, a análise interna do JUnit e a refatoração da classe &lt;code&gt;SerialDate&lt;/code&gt;. Quando chegarmos a eles, poderemos avaliar &lt;em&gt;Clean Code&lt;/em&gt; por meio do código que o próprio livro oferece como demonstração de suas ideias.&lt;/p&gt;

&lt;h3&gt;
  
  
  A escola que admite ser escola
&lt;/h3&gt;

&lt;p&gt;Na seção “Schools of Thought” (“Escolas de pensamento”, em tradução livre), no capítulo “Clean Code” (“Código limpo”, em tradução livre), Martin apresenta uma das passagens mais importantes do livro. Ele compara escolas de desenvolvimento de software a escolas de artes marciais. Cada uma possui suas técnicas, seus mestres e sua maneira de praticar, sem que isso conceda a qualquer uma delas o monopólio da verdade.&lt;/p&gt;

&lt;p&gt;Martin pede que o leitor considere o livro uma descrição da escola de código limpo da Object Mentor. Ele admite que muitas recomendações são controversas, prevê que o leitor poderá discordar vigorosamente de algumas delas e reconhece que outras escolas possuem a mesma legitimidade profissional. Também afirma que os autores não podem reivindicar autoridade final sobre o assunto.&lt;/p&gt;

&lt;p&gt;Essa passagem precisa fazer parte de qualquer crítica honesta a &lt;em&gt;Clean Code&lt;/em&gt;. A obra não esconde sua origem nem afirma que a Object Mentor tenha descoberto a única maneira profissional de escrever software. O livro recomenda, inclusive, que o leitor conheça outros mestres e amplie sua prática para além daquela escola.&lt;/p&gt;

&lt;p&gt;O problema surge dentro da própria formulação dessa ressalva. Martin declara que as opiniões do livro serão apresentadas como absolutos e que ele não pretende se desculpar pela estridência. Para os autores, naquele momento de suas carreiras, aquelas recomendações eram absolutas dentro da escola que haviam construído. Em poucos parágrafos, o texto pede que o leitor reconheça a legitimidade de outras abordagens e, ao mesmo tempo, prepara o terreno para defender suas próprias escolhas com uma linguagem deliberadamente categórica.&lt;/p&gt;

&lt;p&gt;Essa tensão tem uma consequência prática importante. Uma pessoa em início de carreira, e muitas vezes até em um estágio intermediário, ainda está formando o repertório e o discernimento necessários para consumir essas recomendações com um grão de sal. Sem experiência suficiente para reconhecer os contextos, as exceções e os custos envolvidos, torna-se difícil separar um princípio amplamente aplicável de uma heurística circunstancial, uma preferência estilística ou uma opinião particular dos autores e de sua escola de pensamento. Quando essas distinções são apresentadas por profissionais reconhecidos, em um livro que associa suas práticas à qualidade e ao profissionalismo, a tendência é incorporá-las como regras antes de desenvolver os instrumentos necessários para questioná-las. É nesse ponto que começa o problema.&lt;/p&gt;

&lt;p&gt;A comparação com artes marciais ajuda a compreender a proposta, mas também estabelece uma relação peculiar entre mestre e aprendiz. O estudante deve se dedicar às técnicas de uma escola, praticá-las até incorporá-las e, somente depois, procurar outros mestres. Essa estrutura favorece um período inicial de aceitação no qual as regras são tratadas como corretas dentro do sistema que lhes dá origem. Para uma atividade técnica, entretanto, a coerência interna de uma escola não encerra a discussão sobre os efeitos de suas recomendações.&lt;/p&gt;

&lt;p&gt;A ressalva de “Schools of Thought” protege o livro de uma leitura excessivamente literal, mas não transforma todas as afirmações posteriores em simples preferências pessoais. Sempre que Martin associar uma prática à única maneira de trabalhar com rapidez, à definição de código limpo ou à própria condição de profissional, haverá uma afirmação que pode e deve ser examinada tecnicamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  O custo de uma bagunça
&lt;/h3&gt;

&lt;p&gt;O capítulo começa com uma premissa difícil de contestar: código ruim possui um custo. Na seção “The Total Cost of Owning a Mess” (“O custo total de manter uma bagunça”, em tradução livre), Martin descreve sistemas nos quais cada alteração quebra outras partes e equipes cuja produtividade diminui à medida que a base de código se torna mais difícil de compreender. Qualquer pessoa que tenha trabalhado por tempo suficiente em sistemas legados provavelmente reconhecerá alguma parte dessa descrição.&lt;/p&gt;

&lt;p&gt;Na subseção “The Grand Redesign in the Sky” (“A grande reescrita dos sonhos”, em tradução livre), uma equipe tenta substituir integralmente um sistema cuja manutenção se tornou inviável. O título sugere uma solução idealizada, atraente em princípio, mas irrealista ou dificilmente alcançável. Enquanto o novo sistema procura reproduzir as funcionalidades existentes, o antigo continua recebendo alterações, fazendo com que a substituição persiga um alvo em movimento. Martin afirma já ter visto esse processo durar dez anos e terminar com a nova equipe pedindo a reescrita do sistema que deveria substituir o anterior.&lt;/p&gt;

&lt;p&gt;Eu vi uma versão surpreendentemente literal dessa história. Trabalhei em uma empresa que mantinha uma das maiores bases de código Erlang do mundo. Em determinado momento, foi descoberto um bug que comprometia diretamente o uso do produto e a empresa ainda não havia encontrado, dentro ou fora da equipe, alguém que conseguisse corrigi-lo. Diante disso, decidiu iniciar uma grande reescrita em Java.&lt;/p&gt;

&lt;p&gt;A decisão criou duas facções antagônicas dentro da empresa. Uma continuava responsável pelo sistema original em Erlang, enquanto a outra trabalhava em seu futuro substituto. Como o produto não podia deixar de evoluir durante a reescrita, os dois sistemas passaram a receber novas funcionalidades, cada um com sua própria equipe e seu próprio &lt;em&gt;backlog&lt;/em&gt;. O sistema em Java tentava alcançar uma base em Erlang que continuava se movendo, exatamente como na situação descrita por Martin.&lt;/p&gt;

&lt;p&gt;A reescrita nunca terminou. Em algum momento, a empresa contratou alguém maluco e habilidoso o suficiente para encontrar e corrigir o bug no sistema original. A justificativa técnica que havia iniciado o projeto desapareceu, mas já era tarde demais para voltar atrás. A reescrita havia acumulado investimento, equipes, compromissos e dependências suficientes para adquirir vida própria.&lt;/p&gt;

&lt;p&gt;Como os dois sistemas continuaram existindo, um terceiro projeto precisou ser criado para servir como camada de abstração entre eles e o restante da empresa. A arquitetura final passou a incluir o sistema original, seu substituto incompleto e uma nova camada destinada a esconder a coexistência dos dois. A iniciativa que deveria substituir uma base considerada impossível de manter terminou ampliando a quantidade de sistemas, equipes e interfaces que precisavam ser mantidos.&lt;/p&gt;

&lt;p&gt;Minha experiência torna a narrativa de Martin imediatamente reconhecível, mas continua sendo um caso particular. Ela demonstra que uma grande reescrita pode assumir essa dinâmica, sem estabelecer que toda reescrita seguirá o mesmo caminho. Também não permite concluir que a dificuldade para corrigir o bug tenha sido causada exclusivamente pela qualidade do código em Erlang. Escassez de conhecimento, decisões arquiteturais, perda de contexto histórico e características do próprio domínio podem ter contribuído para o problema. A correspondência mais clara com o relato de &lt;em&gt;Clean Code&lt;/em&gt; está na tentativa de substituir integralmente um sistema que continuava evoluindo e no custo organizacional acumulado enquanto o novo sistema perseguia esse alvo móvel.&lt;/p&gt;

&lt;p&gt;A situação descrita é plausível e bastante conhecida na indústria. O problema está na maneira como parte do argumento é construída. O livro também apresenta a história de uma empresa que teria sido levada ao fracasso pela deterioração de seu código, sem identificá-la ou oferecer elementos que permitam verificar a relação de causalidade. O gráfico que representa a queda de produtividade funciona como ilustração, sem dados ou método que o transformem em evidência. A familiaridade da narrativa ajuda o leitor a reconhecer o problema, mas não demonstra que código ruim tenha sido a causa determinante da falência daquela empresa ou que toda base de código desorganizada seguirá a mesma trajetória.&lt;/p&gt;

&lt;h3&gt;
  
  
  A moralização da qualidade do código
&lt;/h3&gt;

&lt;p&gt;A discussão se torna ainda mais categórica na seção “Attitude” (“Atitude”, em tradução livre). Martin atribui aos programadores uma parcela considerável da responsabilidade pela degradação do código e rejeita explicações baseadas em prazos, mudanças de requisitos, decisões gerenciais ou pressões comerciais. Sua intenção parece ser combater a postura passiva de quem culpa a organização enquanto continua produzindo código difícil de manter. Essa cobrança por responsabilidade profissional possui valor, principalmente em ambientes nos quais desenvolvedores evitam comunicar riscos ou aceitam decisões técnicas que sabem ser prejudiciais.&lt;/p&gt;

&lt;p&gt;A analogia usada para sustentar o argumento compara o programador a um médico que se recusaria a realizar uma cirurgia sem lavar as mãos, mesmo que o paciente exigisse rapidez. A comparação concede força moral à posição do desenvolvedor, mas aproxima duas situações com riscos, responsabilidades e níveis de autoridade bastante diferentes. Uma decisão sobre higiene cirúrgica possui evidências médicas, protocolos estabelecidos e consequências diretas para a vida do paciente. Uma discussão sobre duplicação, tamanho de funções ou prazo de entrega costuma envolver incerteza, compromissos comerciais e alternativas tecnicamente defensáveis.&lt;/p&gt;

&lt;p&gt;Ao afirmar que ceder à vontade de gestores que não compreendem os riscos é uma atitude não profissional, o livro desloca parte da discussão técnica para o terreno moral e cria um problema potencialmente perigoso. O desenvolvedor não é dono do sistema, do orçamento ou da empresa e raramente possui autoridade para decidir sozinho quanto risco o negócio deve aceitar. Sua responsabilidade profissional inclui identificar as consequências técnicas, comunicá-las de forma compreensível, propor alternativas e participar da decisão, mas isso não lhe concede controle absoluto sobre prioridades, prazos e investimentos.&lt;/p&gt;

&lt;p&gt;Maturidade profissional, nesse contexto, não consiste em defender uma concepção particular de código limpo a ferro e fogo. Ela aparece na capacidade de negociar uma solução que considere as necessidades técnicas e comerciais, talvez reduzindo o escopo, registrando uma dívida técnica, delimitando a vida útil de uma solução provisória ou combinando condições para uma correção posterior. Uma postura inflexível pode colocar o emprego do desenvolvedor em risco, prejudicar o projeto e reduzir sua influência sobre decisões futuras, sem necessariamente produzir um sistema melhor.&lt;/p&gt;

&lt;p&gt;Há situações em que a recusa é uma obrigação, especialmente diante de riscos à segurança, violações legais, fraude ou consequências graves para outras pessoas. A maioria das divergências sobre qualidade interna de código, entretanto, não possui a mesma natureza da higiene necessária antes de uma cirurgia. Ao usar essa analogia, Martin transforma uma negociação sujeita a contexto e compromisso em um teste moral de profissionalismo.&lt;/p&gt;

&lt;p&gt;Na seção “The Primal Conundrum” (“O dilema fundamental”, em tradução livre), Martin declara que a única maneira de cumprir um prazo e trabalhar rapidamente consiste em manter o código tão limpo quanto possível durante todo o tempo. A expressão “única maneira” transforma uma recomendação razoável sobre manutenção em uma afirmação universal que o capítulo não demonstra. Ela também ignora que decisões profissionais são tomadas dentro de organizações, sob restrições técnicas, financeiras e humanas que não desaparecem apenas porque o desenvolvedor está convencido de que sua solução é a mais correta.&lt;/p&gt;

&lt;p&gt;Uma solução provisória, conscientemente limitada e acompanhada de riscos conhecidos, pode ser a decisão profissional mais adequada. Protótipos descartáveis, respostas emergenciais, experimentos, migrações transitórias e sistemas com vida útil curta não recebem necessariamente o mesmo investimento destinado a uma plataforma que deverá ser mantida por décadas. A dificuldade está em evitar que o provisório se torne permanente sem que ninguém perceba, mas essa possibilidade não elimina a necessidade de avaliar custos, prazo e expectativa de vida do software.&lt;/p&gt;

&lt;h3&gt;
  
  
  O nascimento do mito
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Clean Code&lt;/em&gt; oferece uma combinação poderosa para a formação de um cânone. O livro apresenta problemas que quase todos os desenvolvedores reconhecem, associa suas soluções à experiência de profissionais respeitados e emprega uma linguagem moral ligada a cuidado, disciplina e profissionalismo. Ao mesmo tempo, fornece regras fáceis de memorizar e exemplos que parecem confirmar uma visão coerente sobre como o código deveria ser escrito.&lt;/p&gt;

&lt;p&gt;A ressalva de que existem outras escolas exige uma leitura mais cuidadosa do que afirmações sobre a única maneira de trabalhar rapidamente ou sobre a relação entre testes e limpeza. Quando as ideias circulam fora do livro, as formulações categóricas sobrevivem com mais facilidade do que as limitações apresentadas no primeiro capítulo. O resultado é uma versão de &lt;em&gt;Clean Code&lt;/em&gt; formada por mandamentos, frequentemente aplicada sem os estudos de caso, sem a reflexão proposta na introdução e sem o reconhecimento de que a própria obra se apresenta como produto de uma escola específica.&lt;/p&gt;

&lt;p&gt;Essa transformação não pode ser atribuída exclusivamente aos leitores. Martin reconhece a pluralidade de abordagens, mas escolhe defender suas opiniões como absolutos dentro de sua escola. O mito de &lt;em&gt;Clean Code&lt;/em&gt; como fonte definitiva nasce do encontro entre uma comunidade interessada em respostas claras e um livro disposto a oferecê-las com grande confiança.&lt;/p&gt;

&lt;p&gt;A leitura adotada nesta série aceitará a advertência feita pelo próprio autor. A Object Mentor não possuía autoridade final sobre desenvolvimento de software, suas práticas foram construídas dentro de um contexto histórico e profissional específico e suas recomendações podem conviver com outras escolas. Essa abertura não impedirá uma análise crítica das passagens em que preferências são apresentadas como necessidades, experiências são usadas como prova e escolhas técnicas recebem um peso moral maior do que seus argumentos conseguem sustentar.&lt;/p&gt;

&lt;p&gt;A melhor defesa e a crítica mais consistente de &lt;em&gt;Clean Code&lt;/em&gt; começam no mesmo lugar: a leitura daquilo que o livro realmente diz.&lt;/p&gt;

</description>
      <category>ptbr</category>
      <category>cleancode</category>
      <category>architecture</category>
      <category>opinion</category>
    </item>
    <item>
      <title>[pt-BR] AWS Landing Zones na prática - Parte 1</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Wed, 19 Aug 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/pbalduino/aws-landing-zones-na-pratica-parte-1-3847</link>
      <guid>https://dev.to/pbalduino/aws-landing-zones-na-pratica-parte-1-3847</guid>
      <description>&lt;p&gt;Quando uma organização começa a utilizar AWS, é relativamente comum que tudo nasça dentro de uma única conta.&lt;/p&gt;

&lt;p&gt;No começo, isso parece razoável. Uma conta contém algumas VPCs, aplicações, bancos de dados, buckets e usuários. Com o crescimento do ambiente, porém, começam a surgir perguntas mais difíceis:&lt;/p&gt;

&lt;p&gt;Produção e desenvolvimento deveriam estar na mesma conta?, Onde devem ficar os logs de auditoria?, Como impedir que uma equipe desative controles de segurança?, Como conceder acesso a dezenas ou centenas de contas?, Como garantir que novas contas sejam criadas seguindo os mesmos padrões?, Como aplicar políticas corporativas sem configurar cada conta individualmente? e Como separar workloads, segurança, infraestrutura compartilhada e billing?.&lt;/p&gt;

&lt;p&gt;É nesse contexto que surge o conceito de &lt;strong&gt;Landing Zone&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é uma Landing Zone?
&lt;/h2&gt;

&lt;p&gt;A AWS define uma Landing Zone como um &lt;strong&gt;framework de orquestração para o ambiente AWS fundamental da organização&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ela estabelece uma baseline para aspectos como:&lt;/p&gt;

&lt;p&gt;arquitetura multi-account, Identity and Access Management, governança, segurança de dados, arquitetura de rede, logging, estrutura de contas, billing e mecanismos de customização..&lt;/p&gt;

&lt;p&gt;Portanto, uma Landing Zone não é simplesmente uma VPC preparada para receber aplicações.&lt;/p&gt;

&lt;p&gt;Também não é apenas uma estrutura de AWS Organizations.&lt;/p&gt;

&lt;p&gt;E não é sinônimo de AWS Control Tower.&lt;/p&gt;

&lt;p&gt;Uma maneira útil de pensar no conceito é:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Landing Zone é a fundação sobre a qual os workloads da organização serão construídos.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antes de migrarmos ou criarmos aplicações, estabelecemos as regras do terreno.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uma arquitetura multi-account
&lt;/h2&gt;

&lt;p&gt;Um dos princípios centrais de uma Landing Zone é utilizar &lt;strong&gt;AWS Accounts como fronteiras de isolamento&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em vez de construir algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Account
├── VPC Development
├── VPC Staging
├── VPC Production
├── Security
├── Logs
└── Shared Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;podemos estabelecer uma estrutura semelhante a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Organization
│
├── Security OU
│   ├── Log Archive Account
│   └── Audit Account
│
├── Infrastructure OU
│   ├── Network Account
│   └── Shared Services Account
│
├── Workloads OU
│   ├── Development Account
│   ├── Staging Account
│   └── Production Account
│
└── Sandbox OU
    ├── Developer A
    └── Developer B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa separação cria fronteiras mais fortes entre workloads e responsabilidades.&lt;/p&gt;

&lt;p&gt;Uma falha de configuração em uma conta de desenvolvimento, por exemplo, não precisa conceder acesso aos recursos da conta de produção.&lt;/p&gt;

&lt;p&gt;A AWS recomenda que workloads de produção não sejam executados na management account de uma organização gerenciada pelo Control Tower.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que uma Landing Zone deve resolver?
&lt;/h2&gt;

&lt;p&gt;Segundo a AWS Prescriptive Guidance, a configuração inicial deve tratar pelo menos de estrutura de contas, identidade, governança, segurança, rede, logging, billing e mecanismos de customização.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estrutura de contas
&lt;/h3&gt;

&lt;p&gt;É necessário definir como as AWS Accounts serão organizadas e quais Organizational Units (OUs) serão utilizadas.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Root
├── Security
├── Infrastructure
├── Workloads
└── Sandbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Estrutura de rede
&lt;/h3&gt;

&lt;p&gt;A Landing Zone deve estabelecer padrões de conectividade e governança para componentes como:&lt;/p&gt;

&lt;p&gt;VPCs, subnets, DNS, Transit Gateway, conectividade híbrida, Direct Connect, VPN, firewalls e IP Address Management..&lt;/p&gt;

&lt;p&gt;Ela não precisa necessariamente criar toda a infraestrutura de rede de cada workload, mas deve definir como essa infraestrutura será organizada e governada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identity
&lt;/h3&gt;

&lt;p&gt;Também é necessário definir como pessoas e sistemas acessam as contas.&lt;/p&gt;

&lt;p&gt;Isso normalmente envolve:&lt;/p&gt;

&lt;p&gt;IAM, IAM Identity Center, roles, permission sets e federação com provedores de identidade corporativos..&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging e auditoria
&lt;/h3&gt;

&lt;p&gt;Logs de auditoria não deveriam existir apenas dentro da própria conta que está sendo auditada.&lt;/p&gt;

&lt;p&gt;Uma arquitetura comum centraliza esses registros em uma conta dedicada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application Accounts
        │
        ├── CloudTrail
        ├── AWS Config
        └── Security Logs
                │
                ▼
        Log Archive Account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso reduz a possibilidade de um comprometimento da conta de workload resultar também na destruição das evidências necessárias para auditoria ou investigação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Governance
&lt;/h3&gt;

&lt;p&gt;A organização precisa determinar quais ações são permitidas ou proibidas.&lt;/p&gt;

&lt;p&gt;AWS Organizations permite, por exemplo, utilizar &lt;strong&gt;Service Control Policies (SCPs)&lt;/strong&gt; para estabelecer limites máximos de permissões.&lt;/p&gt;

&lt;p&gt;Em vez de depender de cada equipe para configurar individualmente todos os controles, podemos estabelecer políticas organizacionais como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Workloads não podem desabilitar determinados mecanismos de segurança.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Landing Zone não é Control Tower
&lt;/h2&gt;

&lt;p&gt;Essa distinção é importante.&lt;/p&gt;

&lt;p&gt;A documentação da AWS diferencia duas abordagens principais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;uma &lt;strong&gt;service-based landing zone&lt;/strong&gt;, utilizando AWS Control Tower;&lt;/li&gt;
&lt;li&gt;uma &lt;strong&gt;customized landing zone&lt;/strong&gt;, construída pela própria organização.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O AWS Control Tower é, portanto, uma implementação gerenciada do conceito de Landing Zone — não o conceito em si.&lt;/p&gt;

&lt;h2&gt;
  
  
  Landing Zone com AWS Control Tower
&lt;/h2&gt;

&lt;p&gt;O AWS Control Tower automatiza boa parte da criação e governança de um ambiente multi-account.&lt;/p&gt;

&lt;p&gt;Ele orquestra diferentes serviços AWS envolvidos nessa fundação, incluindo AWS Organizations, IAM Identity Center, AWS Service Catalog, AWS CloudTrail e AWS Config.&lt;/p&gt;

&lt;p&gt;Uma estrutura inicial típica inclui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Management Account
│
└── AWS Organization
    │
    ├── Security OU
    │   ├── Log Archive
    │   └── Audit
    │
    └── Workload OUs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;strong&gt;Log Archive Account&lt;/strong&gt; funciona como repositório central para logs, enquanto o &lt;strong&gt;Audit Account&lt;/strong&gt; fornece capacidades destinadas às equipes de segurança e compliance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controls
&lt;/h3&gt;

&lt;p&gt;Outro componente importante são os &lt;strong&gt;Controls&lt;/strong&gt;, anteriormente conhecidos principalmente como &lt;em&gt;guardrails&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Eles representam mecanismos de governança aplicados ao ambiente. O Control Tower trabalha com controles de diferentes comportamentos, incluindo:&lt;/p&gt;

&lt;p&gt;preventive, detective e proactive..&lt;/p&gt;

&lt;p&gt;Um control pode impedir determinadas operações, enquanto outro pode detectar recursos que deixaram de atender a uma regra.&lt;/p&gt;

&lt;p&gt;Isso muda a natureza da governança:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Provisionar → Configurar → Torcer para ninguém alterar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;passa a ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Provisionar
     ↓
Aplicar baseline
     ↓
Monitorar continuamente
     ↓
Detectar ou impedir desvios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Account Factory
&lt;/h3&gt;

&lt;p&gt;Outro recurso importante é o &lt;strong&gt;Account Factory&lt;/strong&gt;, usado para padronizar o provisionamento de novas contas.&lt;/p&gt;

&lt;p&gt;Em vez de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ticket → Cloud Team → configuração manual → nova conta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;podemos caminhar para:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Solicitação
     ↓
Account Factory
     ↓
AWS Account
     ↓
Baseline
     ↓
OU
     ↓
Controls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso se torna especialmente relevante em organizações que administram dezenas ou centenas de AWS Accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Landing Zone customizada
&lt;/h2&gt;

&lt;p&gt;Também é possível construir uma Landing Zone sem utilizar Control Tower.&lt;/p&gt;

&lt;p&gt;Nesse cenário, podemos combinar diretamente serviços como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Organizations
+
Organizational Units
+
SCPs
+
IAM Identity Center
+
CloudTrail
+
AWS Config
+
Security Hub
+
GuardDuty
+
VPC / Transit Gateway
+
Infrastructure as Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform, CloudFormation ou outras ferramentas podem então automatizar essa arquitetura.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Terraform
   │
   ├── AWS Organizations
   ├── Organizational Units
   ├── Accounts
   ├── SCPs
   ├── IAM
   ├── Logging
   └── Networking
   │
   ▼
Custom Landing Zone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse modelo, a organização possui maior liberdade sobre a implementação.&lt;/p&gt;

&lt;p&gt;O preço dessa liberdade é assumir também a responsabilidade pela evolução, manutenção, testes, upgrades e tratamento de drift da plataforma.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control Tower versus Landing Zone customizada
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspecto&lt;/th&gt;
&lt;th&gt;Control Tower&lt;/th&gt;
&lt;th&gt;Customizada&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provisionamento inicial&lt;/td&gt;
&lt;td&gt;Mais simples&lt;/td&gt;
&lt;td&gt;Mais complexo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS best practices&lt;/td&gt;
&lt;td&gt;Incorporadas ao modelo&lt;/td&gt;
&lt;td&gt;Precisam ser implementadas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibilidade&lt;/td&gt;
&lt;td&gt;Alta, dentro do modelo do serviço&lt;/td&gt;
&lt;td&gt;Muito alta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Governança&lt;/td&gt;
&lt;td&gt;Controls integrados&lt;/td&gt;
&lt;td&gt;Implementação própria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Account provisioning&lt;/td&gt;
&lt;td&gt;Account Factory&lt;/td&gt;
&lt;td&gt;Pipeline próprio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manutenção&lt;/td&gt;
&lt;td&gt;Parcialmente gerenciada pela AWS&lt;/td&gt;
&lt;td&gt;Responsabilidade da equipe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Curva de aprendizado&lt;/td&gt;
&lt;td&gt;Menor&lt;/td&gt;
&lt;td&gt;Maior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customização extrema&lt;/td&gt;
&lt;td&gt;Pode exigir adaptações&lt;/td&gt;
&lt;td&gt;Natural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drift management&lt;/td&gt;
&lt;td&gt;Integrado ao modelo do Control Tower&lt;/td&gt;
&lt;td&gt;Precisa ser projetado&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integração com legado&lt;/td&gt;
&lt;td&gt;Pode exigir adaptação&lt;/td&gt;
&lt;td&gt;Maior liberdade&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Essa comparação não significa que Control Tower seja uma solução para iniciantes e uma Landing Zone customizada seja uma solução para arquitetos experientes.&lt;/p&gt;

&lt;p&gt;A decisão é arquitetural.&lt;/p&gt;

&lt;p&gt;Uma organização grande pode preferir Control Tower justamente para &lt;strong&gt;reduzir a quantidade de plataforma que precisa manter internamente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Outra organização pode possuir requisitos de rede, compliance, identidade ou provisionamento tão específicos que uma implementação customizada faça mais sentido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantagens
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Isolamento
&lt;/h3&gt;

&lt;p&gt;AWS Accounts tornam-se fronteiras de segurança.&lt;/p&gt;

&lt;p&gt;Um comprometimento em uma conta de desenvolvimento não implica automaticamente comprometimento da conta de produção.&lt;/p&gt;

&lt;h3&gt;
  
  
  Governança centralizada
&lt;/h3&gt;

&lt;p&gt;Políticas podem ser aplicadas no nível da organização ou de uma OU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Organization
     │
     ├── SCPs
     ├── Controls
     ├── Identity
     └── Logging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso reduz configurações divergentes entre contas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Escalabilidade organizacional
&lt;/h3&gt;

&lt;p&gt;Criar a décima conta manualmente talvez seja aceitável.&lt;/p&gt;

&lt;p&gt;Criar a conta número 500 dessa maneira provavelmente não será.&lt;/p&gt;

&lt;p&gt;Uma Landing Zone transforma a criação e configuração de contas em uma capacidade da plataforma.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segurança
&lt;/h3&gt;

&lt;p&gt;A separação entre workloads, security, audit, logging e infrastructure reduz o &lt;em&gt;blast radius&lt;/em&gt; e melhora a segregação de responsabilidades.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migrações
&lt;/h3&gt;

&lt;p&gt;Landing Zones são particularmente importantes em programas de cloud migration.&lt;/p&gt;

&lt;p&gt;Antes de migrar centenas de workloads, cria-se uma fundação comum para recebê-los.&lt;/p&gt;

&lt;p&gt;A AWS Prescriptive Guidance trata a Landing Zone como uma base segura para suportar migração e posterior customização do ambiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Desvantagens
&lt;/h2&gt;

&lt;p&gt;Landing Zones também possuem custos arquiteturais.&lt;/p&gt;

&lt;h3&gt;
  
  
  Complexidade
&lt;/h3&gt;

&lt;p&gt;Uma arquitetura multi-account introduz conceitos adicionais:&lt;/p&gt;

&lt;p&gt;cross-account IAM, SCPs, Organizations, resource sharing, centralized networking, centralized logging e account lifecycle..&lt;/p&gt;

&lt;p&gt;Para uma aplicação pequena, isso pode representar complexidade desnecessária.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custo operacional
&lt;/h3&gt;

&lt;p&gt;Mais contas normalmente significam mais infraestrutura compartilhada e serviços de governança.&lt;/p&gt;

&lt;p&gt;Logs, AWS Config, NAT Gateways, Transit Gateway, serviços de segurança e observabilidade podem gerar custos relevantes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Troubleshooting
&lt;/h3&gt;

&lt;p&gt;Em uma arquitetura simples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o troubleshooting tende a permanecer dentro de uma conta.&lt;/p&gt;

&lt;p&gt;Em uma arquitetura corporativa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application Account
        ↓
Transit Gateway
        ↓
Network Account
        ↓
Firewall
        ↓
Shared Services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o problema pode atravessar várias fronteiras administrativas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrições de governança
&lt;/h3&gt;

&lt;p&gt;Governança forte também pode reduzir autonomia.&lt;/p&gt;

&lt;p&gt;Um desenvolvedor pode possuir &lt;code&gt;AdministratorAccess&lt;/code&gt; dentro de uma conta e ainda assim não conseguir executar determinada operação porque uma SCP estabelece um limite organizacional.&lt;/p&gt;

&lt;p&gt;Isso é proposital, mas pode gerar atrito se a Landing Zone for mal projetada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quando usar?
&lt;/h2&gt;

&lt;p&gt;Landing Zones fazem bastante sentido quando existe:&lt;/p&gt;

&lt;p&gt;estratégia multi-account, múltiplos ambientes, vários times, workloads críticos, requisitos de compliance, necessidade de auditoria, migração de múltiplos sistemas, necessidade de padronização e crescimento significativo esperado..&lt;/p&gt;

&lt;p&gt;Para um cenário como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uma aplicação
+
uma equipe pequena
+
uma conta AWS
+
baixo requisito regulatório
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;uma Landing Zone completa pode ser excessiva.&lt;/p&gt;

&lt;p&gt;Para um cenário como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;50 aplicações
+
20 equipes
+
produção
+
requisitos regulatórios
+
múltiplas regiões
+
centenas de AWS Accounts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a ausência de uma estratégia de Landing Zone tende a se tornar um problema arquitetural.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control Tower ou customizada?
&lt;/h2&gt;

&lt;p&gt;Uma pergunta inicial razoável é:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Existe alguma exigência concreta que impeça ou torne inadequado o uso do Control Tower?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se a resposta for &lt;strong&gt;não&lt;/strong&gt;, Control Tower normalmente merece ser considerado primeiro.&lt;/p&gt;

&lt;p&gt;A AWS gerencia parte importante da orquestração e fornece controles, Account Factory e uma baseline baseada nas práticas recomendadas da plataforma.&lt;/p&gt;

&lt;p&gt;Uma Landing Zone customizada passa a ser particularmente interessante quando requisitos organizacionais não se encaixam adequadamente nesse modelo.&lt;/p&gt;

&lt;p&gt;Existe ainda uma terceira possibilidade bastante importante: &lt;strong&gt;Control Tower + customizações&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Não precisamos escolher exclusivamente entre:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Control Tower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tudo construído manualmente
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Control Tower
       │
       ├── baseline
       ├── governance
       ├── account lifecycle
       │
       ▼
Customizações
       │
       ├── Terraform
       ├── CloudFormation
       ├── networking
       ├── security tooling
       └── corporate standards
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para muitas organizações, esse é um ponto de equilíbrio interessante entre padronização e flexibilidade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nas próximas partes
&lt;/h2&gt;

&lt;p&gt;Agora temos uma distinção fundamental:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Landing Zone ≠ AWS Control Tower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Control Tower é uma das formas de implementar e operar uma Landing Zone.&lt;/p&gt;

&lt;p&gt;Na &lt;strong&gt;Parte 2&lt;/strong&gt;, construiremos uma Landing Zone programaticamente utilizando &lt;strong&gt;AWS CLI&lt;/strong&gt;, explorando AWS Organizations, AWS Control Tower, o Landing Zone Manifest e o acompanhamento das operações assíncronas.&lt;/p&gt;

&lt;p&gt;Na &lt;strong&gt;Parte 3&lt;/strong&gt;, abordaremos a implementação utilizando &lt;strong&gt;Terraform&lt;/strong&gt;, transformando a fundação da organização em Infrastructure as Code e discutindo uma questão importante: &lt;strong&gt;quem deve ser responsável pelo lifecycle da Landing Zone — Terraform ou Control Tower?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Também veremos como o recurso &lt;code&gt;aws_controltower_landing_zone&lt;/code&gt; do AWS Provider for Terraform permite administrar uma Landing Zone do Control Tower por Infrastructure as Code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/strategy-migration/aws-landing-zone.html" rel="noopener noreferrer"&gt;AWS Prescriptive Guidance — Set up a secure AWS landing zone&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html" rel="noopener noreferrer"&gt;AWS Control Tower User Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/controltower/latest/userguide/how-control-tower-works.html" rel="noopener noreferrer"&gt;AWS Control Tower — How AWS Control Tower works&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cli/latest/reference/controltower/create-landing-zone.html" rel="noopener noreferrer"&gt;AWS CLI — &lt;code&gt;controltower create-landing-zone&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/controltower_landing_zone" rel="noopener noreferrer"&gt;Terraform AWS Provider — &lt;code&gt;aws_controltower_landing_zone&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ptbr</category>
      <category>aws</category>
      <category>architecture</category>
    </item>
    <item>
      <title>[pt-BR] Depurando um crash de use-after-free no meniOS</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Tue, 14 Oct 2025 22:32:52 +0000</pubDate>
      <link>https://dev.to/pbalduino/depurando-um-crash-de-use-after-free-no-menios-2140</link>
      <guid>https://dev.to/pbalduino/depurando-um-crash-de-use-after-free-no-menios-2140</guid>
      <description>&lt;p&gt;Há uns dois anos, escrevi aqui que estava escrevendo um sistema operacional chamado meniOS, quase do zero. (&lt;a href="https://dev.to/pbalduino/criando-um-sistema-operacional-quase-do-zero-27m8"&gt;Leia aqui&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Novamente fiquei um bom tempo parado, com a vida e a correria engolindo nossos momentos de lazer, mas voltei a brincar com ele.&lt;/p&gt;

&lt;p&gt;A coisa avançou bastante nos últimos tempos, e atualmente é possível executar pequenos binários fora do kernel, na área chamada user space, onde rodam quase todos os softwares que usamos no dia a dia.&lt;/p&gt;

&lt;p&gt;Conforme o sistema vai crescendo, cada vez mais partes vão trabalhando juntas e dependendo umas das outras, e vai ficando cada vez mais difícil entender porque um erro acontece.&lt;/p&gt;

&lt;p&gt;Para ajudar a navegar entre vários e vários logs cheios de números hexadecimais que eu mesmo mandei imprimir mas não entendia muito bem o que significavam, criei esse pequeno guia, que mostra, passo a passo, como diagnosticar um crash provocado por acesso a memória já liberada (&lt;em&gt;use-after-free&lt;/em&gt;). O objetivo é destacar o processo e as ferramentas que uso no meniOS, como &lt;code&gt;nm&lt;/code&gt;, &lt;code&gt;objdump&lt;/code&gt; e um script em Python com &lt;code&gt;pyelftools&lt;/code&gt;, para transformar um endereço de falha em uma linha de código. Ao final, teremos um roteiro reaproveitável para incidentes parecidos.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prepare o cenário
&lt;/h2&gt;

&lt;p&gt;O binário de exemplo é intencionalmente falho: ele libera um ponteiro e logo em seguida tenta escrever naquele endereço. Não por coincidência, essa é uma das principais causas de tela azul no Windows, ou seja lá que cor estejam usando hoje em dia.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"malloc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dereferencing freed pointer...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Use-after-free: provoca crash&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: %c&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compilar com símbolos de depuração deixa o código-fonte acessível na desmontagem e nas tabelas DWARF; esse formato armazena metadados de depuração no ELF, incluindo o mapeamento entre endereços de instruções, arquivos e números de linha, o que é essencial para relacionar endereços a trechos de código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcc &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O0&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt; use_after_free.c &lt;span class="nt"&gt;-o&lt;/span&gt; use_after_free
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O meniOS executa binários no formato ELF, sigla para Executable and Linkable Format. Esse contêiner descreve cabeçalhos, seções e tabelas necessárias para carregar o programa na memória, incluindo as tabelas de símbolos que &lt;code&gt;nm&lt;/code&gt; lê e as seções de código que &lt;code&gt;objdump&lt;/code&gt; desmonta. Como o ELF também embute as extensões de depuração DWARF geradas pelo compilador, conseguimos cruzar endereços de instruções com arquivos de origem e, a partir disso, chegar rapidamente à linha com defeito.&lt;/p&gt;

&lt;p&gt;Enquanto não há suporte a bibliotecas compartilhadas (&lt;code&gt;.so&lt;/code&gt;), cada aplicativo do meniOS é entregue como um executável ELF independente. Compilo esses binários na máquina host e copio o resultado para a mesma imagem de disco utilizada no boot do sistema, mantendo o fluxo de build simples e previsível.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Reproduza o crash e capture o endereço
&lt;/h2&gt;

&lt;p&gt;Executando o programa no meniOS, ou no ambiente host caso esteja testando localmente, o kernel interrompe o processo assim que detecta o acesso inválido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dereferencing freed pointer...
  User page fault at 0x0000555555555000 (present=yes write=yes), terminating pid=17
proc_exit: Process init/use_after_free exited with status 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o crash é coletado via console serial do meniOS, o log inclui ainda o contexto de sistema de chamadas. Logo antes da falha, a saída típica de &lt;code&gt;write(1, …)&lt;/code&gt; registra o ponto para o qual a execução retornaria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syscall_dispatch: pid=17 number=1 rip=40112f cs=3b rsp=bfdfd0
syscall_dispatch: post-handler rip=401168 cs=3b rsp=bfdf10 rax=32
mosh: process terminated by signal 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anote dois dados essenciais: &lt;code&gt;rip=0x401168&lt;/code&gt;, que aponta para a instrução que falhou, e o nome do binário (&lt;code&gt;use_after_free&lt;/code&gt;), porque é nele que vou procurar a origem.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Descubra o símbolo com &lt;code&gt;nm&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Comece localizando qual função cobre o endereço problemático. O &lt;code&gt;nm&lt;/code&gt; lista a tabela de símbolos do executável, indicando o intervalo de cada função.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nm &lt;span class="nt"&gt;-an&lt;/span&gt; use_after_free | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saída típica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000000004010f0 t _start
0000000000401120 T main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main&lt;/code&gt; começa em &lt;code&gt;0x401120&lt;/code&gt;. Como &lt;code&gt;0x401168&lt;/code&gt; ainda está próximo, é razoável assumir que a falha ocorreu dentro dessa função, mas é prudente confirmar.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Navegue no assembly com &lt;code&gt;objdump&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;objdump&lt;/code&gt; permite correlacionar instruções com o código-fonte. Use as opções &lt;code&gt;--source&lt;/code&gt; e &lt;code&gt;--line-numbers&lt;/code&gt; para misturar C e assembly; limite a saída a um trecho curto com &lt;code&gt;sed&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;objdump &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--no-show-raw-insn&lt;/span&gt; &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nt"&gt;--line-numbers&lt;/span&gt; use_after_free &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'35,60p'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trecho relevante:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use_after_free.c:16
    *ptr = 'A';  // Use-after-free: provoca crash
  401164:  mov    -0x8(%rbp),%rax
  401168:  movb   $0x41,(%rax)          ; 0x41 == 'A'

use_after_free.c:17
    printf("Value: %c\n", *ptr);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso confirma visualmente: a instrução em &lt;code&gt;0x401168&lt;/code&gt; é exatamente a escrita com &lt;code&gt;'A'&lt;/code&gt;. Se o log apontar um endereço alguns bytes adiante, use o mesmo procedimento para encontrar a linha correspondente.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Resolver linha e arquivo com Python + &lt;code&gt;pyelftools&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;As tabelas DWARF do executável guardam, para cada unidade de compilação, a sequência de endereços e as respectivas linhas do código-fonte. Para automatizar o mapeamento de endereços, um script curto em Python consulta esse material. Esse procedimento economiza tempo quando coleto crashes em lote ou quando quero integrar a análise em pipelines de CI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;elftools.elf.elffile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ELFFile&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ELFFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dwarf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_dwarf_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cu&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dwarf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iter_CUs&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;lineprog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dwarf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line_program_for_CU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lineprog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_entries&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_sequence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;file_entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lineprog&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_entry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_top_DIE&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DW_AT_comp_dir&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;comp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;comp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp_dir&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir_index&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="n"&gt;include_dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lineprog&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;include_directory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                        &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;comp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;include_dirs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir_index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                        &lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="n"&gt;full_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;full_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;
                &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;file_entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lineprog&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_entry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_top_DIE&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DW_AT_comp_dir&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;comp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;comp_dir_attr&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
                &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;comp_dir&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir_index&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;include_dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lineprog&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;include_directory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                    &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;comp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;include_dirs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dir_index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file_entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;full_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;full_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Uso: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &amp;lt;ELF&amp;gt; &amp;lt;endereco_hex&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raw_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Endereço não encontrado.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./resolve_addr.py use_after_free 0x401168
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Saída:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/path/para/use_after_free.c:16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integre o script ao seu fluxo de crash dumps no meniOS: basta salvar o endereço de &lt;code&gt;rip&lt;/code&gt; e, depois, usar a ferramenta para apontar diretamente para a linha culpada.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Confirme a correção
&lt;/h2&gt;

&lt;p&gt;Depois de identificar a origem, ajuste o código para evitar o uso após &lt;code&gt;free&lt;/code&gt;. Um fix simples é atrasar a chamada de &lt;code&gt;free&lt;/code&gt; ou zerar o ponteiro antes de qualquer acesso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dereferencing freed pointer...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: %c&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recompile, execute e confirme que o crash desapareceu. Aproveite para rodar o binário antigo novamente e validar que seu processo de depuração continua funcionando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dicas extras
&lt;/h2&gt;

&lt;p&gt;Garanta que o console serial do meniOS esteja ligado durante os testes. Como o sistema roda hoje em emuladores QEMU ou Bochs, redireciono a porta serial primária para &lt;code&gt;com1.log&lt;/code&gt; (ou &lt;code&gt;com1bochs.log&lt;/code&gt;, no caso do Bochs); esse console funciona como uma janela de logs do kernel, exibindo tudo o que o sistema imprime por &lt;code&gt;kprintf&lt;/code&gt;, incluindo o endereço de instrução, o PID e a syscall ativa no momento do crash; como cada serviço roda em um executável ELF independente, repita o procedimento com o binário correspondente na imagem do meniOS; se quiser detectar problemas dessa classe automaticamente em paralelo no host, compile versões instrumentadas com AddressSanitizer e execute-as no Linux ou no macOS, onde o runtime já está disponível.&lt;/p&gt;

&lt;p&gt;Seguindo esses passos você transforma um crash misterioso em uma linha específica do código-fonte.&lt;/p&gt;

&lt;p&gt;Achei importante documentar isso aqui para, caso eu pare novamente de brincar com isso, ao voltar eu consiga me virar com certa rapidez. E também para que você, leitor(a) se sinta convidado(a) a participar desse desenvolvimento.&lt;/p&gt;

</description>
      <category>operatingsystem</category>
      <category>osdev</category>
      <category>ptbr</category>
      <category>opensource</category>
    </item>
    <item>
      <title>[pt-BR] Criando um sistema operacional (quase) do zero</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Wed, 20 Sep 2023 17:16:53 +0000</pubDate>
      <link>https://dev.to/pbalduino/criando-um-sistema-operacional-quase-do-zero-27m8</link>
      <guid>https://dev.to/pbalduino/criando-um-sistema-operacional-quase-do-zero-27m8</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Há uns três anos, sem nenhum bom motivo, eu resolvi que iria escrever um sistema operacional do zero. Comecei com o bootloader, depois parti para o kernel e fiquei empacado. Bateu o desânimo, a falta de tempo, e o projeto ficou lá, abandonado.&lt;/p&gt;

&lt;p&gt;Recentemente, novamente sem qualquer bom motivo, resolvi resgatar esse projeto e usar as lições aprendidas no processo e nesses anos afastado.&lt;/p&gt;

&lt;p&gt;Meu plano ao escrever aqui é compartilhar os aprendizados, em Português, e explicar passo a passo o que é cada uma das partes envolvidas que fazem o seu computador funcionar e permitem que você esteja lendo este texto agora.&lt;/p&gt;

&lt;p&gt;Não garanto que eu vá chegar ao final, já que desenvolver um sistema operacional é um trabalho gigantesco, mas já será uma grande vitória se isso aqui servir de material de pesquisa para os(as) próximos desenvolvedores(as) que se aventurarem nessa tarefa.&lt;/p&gt;

&lt;p&gt;Espero também cobrir uma lacuna nos materiais online, que geralmente estão obsoletos ou incorretos ou mal explicados ou geralmente as três situações ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;A ideia também é ir adicionando aqui os links para os próximos passos, então salve este post aqui nos seus favoritos para facilitar a leitura.&lt;/p&gt;

</description>
      <category>operatingsystem</category>
      <category>opensource</category>
      <category>ptbr</category>
      <category>osdev</category>
    </item>
    <item>
      <title>[pt-BR] Usando o shell além do básico</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Wed, 01 Jun 2022 01:10:37 +0000</pubDate>
      <link>https://dev.to/pbalduino/pt-br-usando-o-shell-alem-do-basico-1adc</link>
      <guid>https://dev.to/pbalduino/pt-br-usando-o-shell-alem-do-basico-1adc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Imagem: &lt;a href="https://www.deviantart.com/shiiftyshift/art/Hackerman-643435212" rel="noopener noreferrer"&gt;Hackerman&lt;/a&gt;, de shiiftyshift.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tudo bem, talvez não sejam realmente indispensáveis, mas aprendê-las vai fazer com que você se sinta a própria Hackerperson.&lt;/p&gt;

&lt;p&gt;Quando você lida com um sistema operacional compatível com POSIX (alguma variação de UNIX, BSD, Linux, MacOS X, etc), internamente existem dois canais principais para entrada e saída de dados: o &lt;em&gt;stdin&lt;/em&gt; e o &lt;em&gt;stdout&lt;/em&gt;. Existem mais, mas vamos focar nesses dois.&lt;/p&gt;

&lt;p&gt;Um executável pode ler dados de &lt;em&gt;stdin&lt;/em&gt; e gravar dados em &lt;em&gt;stdout&lt;/em&gt;. Um exemplo disso acontecendo é quando o programa lê dados do teclado e grava, ou exibe, na tela.&lt;/p&gt;

&lt;p&gt;O pulo do gato acontece quando você conecta o &lt;em&gt;stdout&lt;/em&gt; de um programa com o &lt;em&gt;stdin&lt;/em&gt; de outro usando um recurso chamado pipe (cano ou encanamento). O que um programa exibiria na tela passa a ser enviado para o &lt;em&gt;stdin&lt;/em&gt; do programa seguinte, que processa aquelas entradas e devolve para o &lt;em&gt;stdout&lt;/em&gt;. Você pode conectar inúmeros programas uns nos outros através do &lt;em&gt;pipe&lt;/em&gt;, fazendo com que cada pecinha resolva uma parte do problema, transformado o dado e passando para o próximo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst4ymex0c304uykwumv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst4ymex0c304uykwumv3.png" alt="O fundamento mais básico da computação" width="546" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para nosso exemplo, vamos baixar um arquivo com praticamente todas as palavras da Língua Portuguesa &lt;a href="https://github.com/pythonprobr/palavras/raw/master/palavras.txt" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Executando &lt;code&gt;cat palavras.txt&lt;/code&gt; serão exibidas na tela as mais de trezentas e vinte mil palavras do arquivo. &lt;code&gt;cat&lt;/code&gt; lê o arquivo e joga seu conteúdo para &lt;em&gt;stdout&lt;/em&gt;, que neste caso é a própria tela.&lt;/p&gt;

&lt;p&gt;Vamos usar o pipe para exibir o arquivo em ordem alfabética invertida usando &lt;code&gt;sort&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;palavras.txt | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, com o caracter de &lt;em&gt;pipe&lt;/em&gt;, o &lt;code&gt;|&lt;/code&gt;, direcionamos o conteúdo da saída padrão de &lt;code&gt;cat&lt;/code&gt; para a entrada padrão de &lt;code&gt;sort&lt;/code&gt;, exibindo assim o arquivo em ordem alfabética invertida.&lt;/p&gt;

&lt;p&gt;Pode pode paginar a visualização do arquivo usando &lt;code&gt;less&lt;/code&gt; e outro pipe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;palavras.txt | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; | less
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pressione espaço para ir para a próxima página, ou Q para sair.&lt;/p&gt;

&lt;p&gt;Vamos exibir apenas as palavras do dicionário que contenham o texto &lt;em&gt;pli&lt;/em&gt;. Para isso usamos &lt;code&gt;grep&lt;/code&gt;, que retorna apenas as entradas que contenham o texto informado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;palavras.txt | &lt;span class="nb"&gt;grep &lt;/span&gt;pli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Sim, você pode usar &lt;code&gt;grep palavras.txt pli&lt;/code&gt; também, mas a ideia aqui é encadear vários &lt;em&gt;pipes&lt;/em&gt; para fins didáticos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E vamos usar &lt;code&gt;sed&lt;/code&gt; para deixar a primeira letra de cada palavra em maiúscula. &lt;code&gt;sed&lt;/code&gt; aplica uma expressão regular na entrada e retorna o resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;palavras.txt | &lt;span class="nb"&gt;grep &lt;/span&gt;pli | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/[a-z]/\U&amp;amp;/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para sabermos quantas palavras existem em nossa seleção, usamos &lt;code&gt;wc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;palavras.txt | &lt;span class="nb"&gt;grep &lt;/span&gt;pli | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 382
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, em outro exemplo, vamos listar os arquivos em um diretório qualquer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjye4qshy4idt0f495jp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjye4qshy4idt0f495jp.png" alt="ls -l" width="800" height="283"&gt;&lt;/a&gt;&lt;br&gt;
Perceba que os dados vieram exibidos em colunas. Para pegar o conteúdo de apenas uma das colunas, usamos &lt;code&gt;awk&lt;/code&gt;, que usa uma linguagem própria com o mesmo nome. Os nomes dos arquivos estão na nona coluna. Então, para selecioná-la, passamos essa informação para o &lt;code&gt;awk&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $9}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq4zsk3zr5j08wp9njyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq4zsk3zr5j08wp9njyh.png" alt="ls -l | awk '{print $9}'" width="331" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sim, você poderia ter usado &lt;code&gt;file&lt;/code&gt; para isso, mas estou claramente inventando situações para poder demonstrar as ferramentas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por fim, vamos usar &lt;code&gt;xargs&lt;/code&gt;, que pega os valores que chegam pelo &lt;em&gt;stdin&lt;/em&gt; e passam como parâmetros para o comando seguinte. Por exemplo, vamos listar os arquivos e os conteúdos dos diretórios usando &lt;code&gt;ls&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $9}'&lt;/span&gt; | xargs &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzj05wyexcc4wpx40cbl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzj05wyexcc4wpx40cbl1.png" alt="ls -l | awk '{print $9}' | xargs ls" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>shell</category>
      <category>intermediate</category>
      <category>ptbr</category>
      <category>quick</category>
    </item>
    <item>
      <title>[pt-BR] Como aprendi (e continuo aprendendo) Inglês</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Wed, 18 May 2022 16:35:26 +0000</pubDate>
      <link>https://dev.to/pbalduino/pt-br-como-aprendi-e-continuo-aprendendo-ingles-13j0</link>
      <guid>https://dev.to/pbalduino/pt-br-como-aprendi-e-continuo-aprendendo-ingles-13j0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Este texto foi publicado originalmente em 2017 no meu antigo site no Medium. Tenho uma vaga lembrança dele ter sido publicado em outro lugar antes disso, mas o importante aqui é de que se trata de um texto antigo e a evolução não parou de lá para cá.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Antes de mais nada, é válido deixar claro que estou compartilhando aqui minha experiência pessoal. O que funcionou comigo pode não funcionar com você, assim como minha realidade e minhas experiências podem parecer totalmente estranhas para você. Filtre o que você achar importante e relevante, ignore o resto e segue a vida.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Assim como emagrecer, acordar cedo ou começar a fazer exercícios, aprender Inglês é algo que, para a maioria das pessoas, acaba sempre ficando em segundo ou terceiro plano.&lt;/p&gt;

&lt;p&gt;No meu caso não foi nada diferente. Desde muito novo eu tive contato com materiais em Inglês, mas sempre tive para mim que eu sabia a linguagem. Eu estava no numeroso grupo que coloca “Inglês Intermediário” no currículo.&lt;/p&gt;

&lt;p&gt;Aos vinte eu comecei um curso numa escola que prometia ‘Inglês em 100 horas’. O método deles, ao menos para mim, funcionou muito bem.&lt;/p&gt;

&lt;p&gt;Era uma escola onde os professores não conversavam em Português com os alunos. Mesmo com todo o cuidado e toda a didática, era uma situação que te forçava a participar, entender e falar em Inglês. Infelizmente, se você é do tipo tímido ou introvertido, são grandes as chances de evitar interagir num curso desses. Nesse caso eu recomendo outra metodologia ou tentar lutar contra o próprio bloqueio. Não tenho a resposta.&lt;/p&gt;

&lt;p&gt;No meu caso, que era tímido e introvertido, ajudou demais ter feito o curso com um amigo que não parava de falar. Eu me sentia à vontade para conversar com ele em Inglês e a coisa fluiu bem.&lt;/p&gt;

&lt;p&gt;Por trabalhar com TI, as principais fontes de informação sempre estiveram em Inglês, o que me deixou habituado a ler, mas não a escrever ou conversar. Livros técnicos traduzidos costumam ser péssimos. Os melhores conseguem ser apenas horríveis.&lt;/p&gt;

&lt;p&gt;O fato foi que, ao menos por um tempo, esse curso conseguiu melhorar muito a minha conversação e minha compreensão de texto, mas eu ainda não era fluente no idioma.&lt;/p&gt;

&lt;p&gt;Eis que, após três meses de curso, sofri um acidente voltando para casa e deixei os estudos de lado por anos.&lt;/p&gt;

&lt;p&gt;Como eu disse no começo do texto, aprender um idioma é como emagrecer ou começar fazer exercícios. Para a maioria das pessoas esse hábito só vem depois que algo ruim acontece. Um infarto ou, no meu caso, uma vaga para ganhar quatro vezes mais.&lt;/p&gt;

&lt;p&gt;Eu trabalhava numa empresa pequena, realmente pequena, onde havia mais um programador além de mim. O faturamento era pouco, o salário era baixo e minha ambição era nula.&lt;/p&gt;

&lt;p&gt;Então me aparece essa oportunidade para trabalhar em uma multinacional suíça e ganhar quatro vezes mais do que eu ganhava:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Você sabe X?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sei&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"E Y?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sei&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"E o Inglês?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Precisa ser fluente?&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"Não existe outro. Ou você sabe, ou não sabe."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;E a pré-entrevista acabou ali mesmo.&lt;/p&gt;

&lt;p&gt;Fiquei olhando para o telefone. Minha incipiente carreira tinha acabado de sofrer um infarto.&lt;/p&gt;

&lt;p&gt;Eu tinha duas opções: reclamar de como a vida era injusta e de como empresas pediam Inglês avançado ou fluente sem a menor necessidade, ou eu poderia aproveitar o tranco para me mexer e sair do marasmo. Como já me disseram, &lt;em&gt;"até um pé na bunda te empurra para frente"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Pensando bem, essa oportunidade já tinha sido perdida mesmo. Uma próxima eu não deixaria escapar. Se for para cair, que seja para cima.&lt;/p&gt;

&lt;p&gt;Saí em busca de uma escola de idiomas para voltar a estudar. As melhores estavam bem além do meu orçamento. Sobravam poucas opções. Todas elas franquias de bairro com reputação bem ruim.&lt;/p&gt;

&lt;p&gt;Fiz uma entrevista com a coordenadora do curso. Eram sete módulos de seis meses cada, se não me falha a memória, e entrei no quarto. Bom, pelo menos eu estaria convivendo com pessoas que já estavam estudando continuamente há um ano e meio.&lt;/p&gt;

&lt;p&gt;No primeiro dia de aula chamei a professora de canto e expliquei o que tinha acontecido. Pedi a ela que, se possível, falasse comigo apenas em Inglês e eu que me virasse para entender e responder. Ela ficou surpresa e feliz com o pedido e já me respondeu em Inglês mesmo, concordando.&lt;/p&gt;

&lt;p&gt;Para minha surpresa, os demais alunos pareciam estar ali apenas para cumprir horário. Conversavam entre si em Português e tinham dificuldades de leitura. Me perguntei até que ponto o curso era realmente ruim ou se eram os alunos que nem ao menos se esforçavam.&lt;/p&gt;

&lt;p&gt;Um amigo me indicou podcasts para ouvir no ônibus, em Inglês. English as a Second Language, por exemplo, começava com um texto sendo lido bem devagar, em seguida havia uma explicação sobre as palavras chaves ou termos novos e então, o texto ou o diálogo ocorria em velocidade normal.&lt;/p&gt;

&lt;p&gt;Ao mesmo tempo, no curso, a professora só conversava comigo em Inglês e, logo, alguns alunos resolveram entrar na brincadeira.&lt;/p&gt;

&lt;p&gt;Nesse meio tempo, algo estranho começou a acontecer: eu saia do curso pensando em Inglês e ia assim até chegar em casa. Para mim era algo totalmente estranho pensar em Inglês, sem precisar antes formular a ideia em Português e, só então, traduzir. Era como se tivesse descoberto uma chavinha no cérebro que trocava o idioma. Uma tecla SAP.&lt;/p&gt;

&lt;p&gt;Esse amigo que recomendou os podcasts, que inclusive foi o mesmo que me barrou logo na pré-entrevista, comentou que uma forma de falar melhor era ficar bêbado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Comigo funcionou”&lt;/em&gt;, ele disse.&lt;/p&gt;

&lt;p&gt;Eu mal conseguia falar corretamente quando estava sóbrio e também não bebia. Não fazia o menor sentido.&lt;/p&gt;

&lt;p&gt;Meses após ter perdido aquela oportunidade, surgiu outra na mesma empresa. O salário seria menor, mas ainda assim era muito mais do que eu recebia na época. Eu era Roberto Baggio novamente na marca do pênalti.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Você sabe X?”&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sei&lt;/em&gt;&lt;br&gt;
&lt;em&gt;“E Y?”&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sei&lt;/em&gt;&lt;br&gt;
&lt;em&gt;“E o Inglês?”&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Fluente&lt;/em&gt;&lt;br&gt;
&lt;em&gt;“Tem certeza? Encara uma entrevista toda em Inglês?”&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Opa. Vamos lá.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Vamos ser honestos: eu não era fluente. Acho bem pouco provável que alguém passe do ponto do &lt;em&gt;"Inglês Intermediário"&lt;/em&gt;, do &lt;em&gt;"sei mais ou menos"&lt;/em&gt; para a fluência em pouco mais de seis meses. Mas o raio não cairia três vezes no mesmo lugar e eu estava me preparando justamente para uma situação assim. Tinha que dar certo. Se eu não acreditasse em mim, ninguém mais acreditaria.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Entenda que o objetivo desse texto não é ser motivacional nem vender uma solução milagrosa para pessoas desesperadas. Estou narrando de forma desnecessariamente honesta e sincera o que eu passei e como eu reagi para que você perceba que tudo é uma questão de tirar a bunda da cadeira e de mudar de postura. Seja por um infarto, seja por um tombo na carreira.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fiz um pequeno teste prático, recebi algum feedback do avaliador e fui chamado para a entrevista.&lt;/p&gt;

&lt;p&gt;Eis que eu estava na recepção da empresa, tremendo, pálido, mal conseguindo falar Português. Havia uma cultura de sigilo na empresa em que mesmo o principal negócio dela não tinha ficado claro para mim até então.&lt;/p&gt;

&lt;p&gt;Simplesmente não dava para ficar tranquilo. Tinha tudo para dar errado. O estádio em silêncio, a bola na marca do pênalti, o goleiro olhando para mim como se soubesse que eu ia errar.&lt;/p&gt;

&lt;p&gt;Entro na sala de reunião. Um gerente suíço que não falava Português e um engenheiro que falava Inglês tão depressa quanto um americano que tomou muito café.&lt;/p&gt;

&lt;p&gt;Começam a me contar sobre a empresa, sobre o projeto e sobre o que era esperado que eu fizesse lá. Em Inglês. Minha cabeça funcionando a cento e dez por cento com medo de perder uma só palavra e botar tudo a perder.&lt;/p&gt;

&lt;p&gt;Então preciso contar de forma resumida o que eu tinha feito até então, em que projetos já tinha trabalhado e qual era a minha experiência.&lt;/p&gt;

&lt;p&gt;Não teve nada de mágico: gaguejei, tropecei, troquei palavras. Minha pronúncia foi horrível e, em vários momentos, eu precisei repetir a frase de uma forma diferente para que todos entendessem.&lt;/p&gt;

&lt;p&gt;O gerente então fez uma pergunta sobre part numbers que fugiu totalmente do escopo da conversa. Olhei em volta, perdido. Vi um quadro branco.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Can I use the whiteboard?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sure, please.&lt;/em&gt;_&lt;/p&gt;

&lt;p&gt;Para minha sorte, eu já havia trabalhado com um sistema que controlava listas de partes de produtos industrializados. É, como o nome diz, uma lista contendo todas as peças, quantidades e códigos (os tais &lt;em&gt;part numbers&lt;/em&gt;) que formam um produto pronto.&lt;/p&gt;

&lt;p&gt;Então eu fui ao quadro branco, fiz diagramas, setas e rabiscos explicando, em Inglês, minha ideia sobre o que ele havia perguntado. Levantei cenários alternativos e situações que poderiam ter uma abordagem diferente. De repente, explicando algo que eu conhecia bem, eu não estava mais nervoso. O Inglês, mesmo tosco e manco, era apenas um detalhe. Uma ferramenta.&lt;/p&gt;

&lt;p&gt;O gerente gostou. O engenheiro balançou a cabeça aprovando.&lt;/p&gt;

&lt;p&gt;Passei.&lt;/p&gt;

&lt;p&gt;Gol.&lt;/p&gt;

&lt;p&gt;No primeiro mês de empresa fui enviado para um treinamento de um mês na Suíça.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz81t1f9bv2l9mishdb35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz81t1f9bv2l9mishdb35.png" alt="Pôr do Sol em Lausanne, Suíça. 2008." width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Me enrolei para falar com os comissários de bordo. Me enrolei na imigração. Me enrolei para comprar pão. Me enrolei para entender que diabos o engenheiro que estava dando o treinamento estava falando. Eu esqueci inclusive as palavras para comprar um barbeador e um sabonete.&lt;/p&gt;

&lt;p&gt;Na primeira semana lá fui chamado pelos outros colegas para conhecer uma casa noturna da cidade. "Tem música lá, é legal". Fomos.&lt;/p&gt;

&lt;p&gt;"E aí, você bebe o que?"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não bebo
"Nada?"&lt;/li&gt;
&lt;li&gt;Nada alcoolico.
"Certo."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E pediu vodka com Virgin Cola para o bartender. Tomei meio a contragosto, mas pensei comigo que já estava ali, que tinha conseguido. Por que não relaxar e comemorar um pouco?&lt;/p&gt;

&lt;p&gt;Não sei quantas eu tomei, lembro que conversamos a noite toda sobre a vida na Suíça, na França, no Brasil, sobre música e, em algum momento eu estava de volta ao hotel. Falando Inglês, pensando Inglês, alcoolizado demais para conseguir desligar a chavinha e voltar a pensar e falar em Português. A recepcionista me perguntou algo, eu respondi em Francês. Tosco, quebrado e errado, mas era Francês.&lt;/p&gt;

&lt;p&gt;Descobri. O que me fez falar mais e melhor não foi o álcool, mas a completa perda de inibição. Exatamente como quando fiz o curso de com um amigo na sala. Dane-se que estou falando errado. As pessoas estão entendendo. O errado eu corrijo com o tempo e com a prática.&lt;/p&gt;

&lt;p&gt;Aquele camarada sabia das coisas.&lt;/p&gt;

&lt;p&gt;De volta ao Brasil, alguém no escritório encontrou um professor particular nativo que aceitou dar aula para três alunos por um preço pagável.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vale lembrar que, também nessa época, descobri o Duolingo. Apesar das frases estranhas sobre tartarugas que falam e vacas, é gratuito e ajuda muito a melhorar o vocabulário.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para mim esta foi a forma mais efetiva de aprender Inglês sem precisar sair do país. Se você tiver dinheiro para investir, recomendo de verdade. Quatro aulas por mês custavam uma vez e meia a mensalidade de um curso franqueado de bairro.&lt;/p&gt;

&lt;p&gt;Dois anos atrás apareceu uma oportunidade de trabalhar fora. As coisas nessa empresa já não estavam boas, as chances de haver uma demissão em massa eram reais e eu já não estava mais fazendo as aulas particulares. Fiz o processo remotamente e a entrevista por Skype.&lt;/p&gt;

&lt;p&gt;Reprovado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Gostei da conversa, você tem experiência, conhece as ferramentas, mas não senti firmeza no seu Inglês. Estude mais, pratique mais e, se você ainda tiver interesse, voltaremos a nos novamente falar em um ano".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Mais um chute na bunda. Hora de me mexer.&lt;/p&gt;

&lt;p&gt;Voltamos a nos falar um ano depois. Dessa vez fui reprovado sem ao menos ir para a entrevista por Skype. Não tem problema, eu estava fazendo duas entrevistas por semana, toda semana, em Inglês, por Skype e telefone. Estava treinando durante o jogo. Era o que dava pra fazer.&lt;/p&gt;

&lt;p&gt;Atualmente eu consigo conversar tranquilamente em Inglês, viajei para o exterior algumas vezes e consegui me virar bem conversando. Sites como o Linguee me ajudam demais a escrever, podcasts e vídeos em Inglês me ajudam a manter o cérebro acostumado com o idioma. O Duolingo ainda me acompanha, mas tem servido bem para aprender Holandês, Alemão ou Sueco.&lt;/p&gt;

&lt;p&gt;Uma vez que você consegue fluência em um idioma, o esforço para conseguir fluência em outro é relativamente menor. Seu cérebro já passou por aquilo antes e consegue repetir o processo com menor esforço.&lt;/p&gt;

&lt;p&gt;Meus próximos passo são conseguir um trabalho no exterior, conseguir uma boa pontuação no IELTS e, quem sabe, estudar lá fora. Por isso eu treino, treino, estudo e estudo. Sem um objetivo, um foco, uma necessidade real, dificilmente eu teria conseguido me mexer e me esforçar.&lt;/p&gt;

&lt;p&gt;Assim como emagrecer, acordar cedo ou começar a fazer exercícios, a maioria das pessoas, incluindo eu, só se mexe quando a água bate forte na bunda.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update em 18/05/2022: Depois desse texto eu passei num processo seletivo para uma empresa sueca, e morei em Estocolmo por dois anos, me virando na maior parte do tempo em Inglês. Nesse meio tempo fui aprovado também para uma vaga de Líder Técnico no Booking, em Amsterdam, com um processo também totalmente em Inglês, mas acabei recusando.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ptbr</category>
      <category>career</category>
    </item>
    <item>
      <title>[pt-BR] Consumindo conteúdo HTTP no Terraform</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Mon, 16 May 2022 16:27:09 +0000</pubDate>
      <link>https://dev.to/pbalduino/consumindo-conteudo-http-no-terraform-196e</link>
      <guid>https://dev.to/pbalduino/consumindo-conteudo-http-no-terraform-196e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Parte de uma série de posts curtos com conhecimentos que podem ser úteis no dia a dia e quero compartilhar. Muitas vezes eles exigem um conhecimento prévio da ferramenta ou da linguagem.&lt;/p&gt;

&lt;p&gt;Esses textos curtos são publicados sob a tag #quick.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Existem situações em que você precisa armazenar o conteúdo de um endpoint ou de um arquivo que está online, e esse conteúdo não será modificado dentro daquele contexto.&lt;/p&gt;

&lt;p&gt;Por exemplo, trabalhei num projeto em que a geração de tokens JWT era feita pelo AWS Cognito. Para validar o token recebido pelo client e garantir que ele era legítimo, permitindo a liberação do acesso à API, é necessário verificar se o token foi gerado com a mesma chave do Cognito.&lt;/p&gt;

&lt;p&gt;Para isso, todo User Pool do Cognito gera um documento público que pode ser consumido pelo seu código. Esse documento fica em &lt;code&gt;https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Como o conteúdo desse documento nunca será alterado, é um desperdício fazer uma requisição HTTP para esse endereço toda vez que precisarmos validar um token. Como a validação precisa ser rápida e, no contexto de um recurso serverless, somos cobrados pelos tempo de uso, esse acesso extra causa um aumento desnecessário de custos.&lt;/p&gt;

&lt;p&gt;Para resolver isso, a requisição HTTP é feita uma única vez, durante o build da aplicação, e esse valor é passado para o código como uma variável de ambiente.&lt;/p&gt;

&lt;p&gt;Usando Terraform, bastou fazer assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Aqui criamos o User Pool onde serão armazenadas &lt;/span&gt;
&lt;span class="c1"&gt;# as credenciais dos usuários&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cognito_user_pool"&lt;/span&gt; &lt;span class="s2"&gt;"exemplo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"exemplo"&lt;/span&gt;

  &lt;span class="c1"&gt;# um monte de configurações&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Aqui armazenamos os dados da região AWS atual&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_region"&lt;/span&gt; &lt;span class="s2"&gt;"current"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c1"&gt;# E aqui fazemos a requisição HTTP, que terá os &lt;/span&gt;
&lt;span class="c1"&gt;# parâmetros automaticamente atualizados se você&lt;/span&gt;
&lt;span class="c1"&gt;# mudar de região ou recriar seu User Pool&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"http"&lt;/span&gt; &lt;span class="s2"&gt;"cognito_jwks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://cognito-idp.&lt;/span&gt;&lt;span class="k"&gt;${data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.amazonaws.com/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;aws_cognito_user_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exemplo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.well-known/jwks.json"&lt;/span&gt;

  &lt;span class="nx"&gt;request_headers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Accept&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Finalmente, exportamos o conteúdo da requisição &lt;/span&gt;
&lt;span class="c1"&gt;# para que seja usada em outros módulos do seu projeto&lt;/span&gt;
&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cognito_jwks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cognito_jwks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E, no módulo onde você definiu a Lambda, você faz assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# essa variável terá um valor atribuído&lt;/span&gt;
&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cognito_jwks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"exemplo"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;COGNITO_JWKS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cognito_jwks&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso funciona com qualquer outro recurso que você criar, não precisa ser necessariamente uma Lambda. COGNITO_JWKS contém um texto e você pode usá-lo da maneira que for melhor para o seu caso.&lt;/p&gt;

&lt;p&gt;Ao gerar a Lambda, o conteúdo do arquivo estará disponível como uma variável de ambiente, podendo ser acessado no código com &lt;code&gt;process.env.COGNITO_JWKS&lt;/code&gt;, caso você esteja usando JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixvngb1n3cjxf4datmg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fixvngb1n3cjxf4datmg5.png" alt="Variável de ambiente da AWS Lambda" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quick</category>
      <category>intermediate</category>
      <category>terraform</category>
      <category>ptbr</category>
    </item>
    <item>
      <title>[pt-BR] Convertendo callbacks em promises em JavaScript</title>
      <dc:creator>Plínio Balduino</dc:creator>
      <pubDate>Mon, 16 May 2022 15:39:33 +0000</pubDate>
      <link>https://dev.to/pbalduino/convertendo-callbacks-em-promises-em-javascript-1egi</link>
      <guid>https://dev.to/pbalduino/convertendo-callbacks-em-promises-em-javascript-1egi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Primeiro de uma série de posts curtos com conhecimentos que podem ser úteis no dia a dia e quero compartilhar. Muitas vezes eles exigem um conhecimento prévio da ferramenta ou da linguagem.&lt;/p&gt;

&lt;p&gt;Esses textos curtos serão publicados sob a tag &lt;a href="https://dev.to/t/quick"&gt;#quick&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Existem situações em que você precisa fazer com que um código que foi pensado para ser executado assincronamente seja executado de forma síncrona. Ao usar &lt;em&gt;promises&lt;/em&gt;, você faz isso com o uso da palavra chave &lt;code&gt;await&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;algoAssincrono&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succeeded&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Uhu!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deu ruim&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A execução do código vai aguardar até que a &lt;em&gt;promise&lt;/em&gt; seja finalizada para só então prosseguir.&lt;/p&gt;

&lt;p&gt;Quando você está escrevendo um código que exige um comportamento síncrono, como uma &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; ou o equivalente de qualquer outro fornecedor de &lt;em&gt;Cloud&lt;/em&gt;, você precisa garantir que todos os processos terminaram de ser executados antes do retorno da função:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processoAssincrono&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failure&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função &lt;code&gt;processoAssincrono&lt;/code&gt; trata o evento recebido pela Lambda e, caso esteja tudo certo, retorna um status HTTP 200 e um conteúdo que será consumido pelo client, ou um status HTTP 400 caso não esteja tudo certo, com o motivo pelo qual a requisição falhou.&lt;/p&gt;

&lt;p&gt;O nosso exemplo &lt;code&gt;processoAssincrono&lt;/code&gt; foi pensado para ser assíncrono. Talvez ele consulte um banco de dados, uma API, ou qualquer recurso que poderia causar o bloqueio do &lt;em&gt;event loop&lt;/em&gt;, então essa decisão faz todo o sentido, mas dentro de uma Lambda nós precisamos que o processo seja finalizado para só então retornarmos um valor. Com o uso de &lt;code&gt;await&lt;/code&gt;, só retornamos um valor depois que a &lt;em&gt;promise&lt;/em&gt; terminar sua execução, garantindo que a execução seja síncrona.&lt;/p&gt;

&lt;p&gt;Quando você usa um código feito com &lt;em&gt;callbacks&lt;/em&gt;, não existe essa possibilidade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;assincronoComCallbacks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succeeded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Funcionou&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; 
  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deu erro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para resolver isso, podemos criar uma &lt;em&gt;promise&lt;/em&gt; que só segue em frente quando os callbacks forem executados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fulfill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;assincronoComCallbacks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;succeeded&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fulfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succeeded&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;succeeded&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Uhu!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failed&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deu ruim&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função com &lt;em&gt;callbacks&lt;/em&gt; continua sendo assíncrona, mas estará encapsulada numa &lt;em&gt;promise&lt;/em&gt;, permitindo assim o uso de &lt;code&gt;await&lt;/code&gt;, tornando o processo seja executado como se fosse síncrono.&lt;/p&gt;

</description>
      <category>quick</category>
      <category>intermediate</category>
      <category>javascript</category>
      <category>ptbr</category>
    </item>
  </channel>
</rss>
