<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Javascript | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/javascript/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/javascript/index.xml" rel="self" type="application/rss+xml"/><item><title>[Akitando] #124 - Como Funciona Sockets, Cliente, Servidor e a Web? | Introdução a Redes Parte 4</title><link>https://akitaonrails.github.io/2022/08/04/akitando-124-como-funciona-sockets-cliente-servidor-e-a-web-introducao-a-redes-parte-4/</link><guid isPermaLink="true">https://akitaonrails.github.io/2022/08/04/akitando-124-como-funciona-sockets-cliente-servidor-e-a-web-introducao-a-redes-parte-4/</guid><pubDate>Thu, 04 Aug 2022 10:21:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/lc6U93P4Sxw"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Agora que todo mudno sabe como funciona o básico de rede, vamos ver como funciona o básico de aplicações de rede, o que são sockets, pra que eles servem, como disso chegamos em protocolos como HTTP ou FTP e os vários detalhezinhos que complicam a cabeça de um iniciante em programação Web.&lt;/p&gt;
&lt;h2&gt;Conteúdo&lt;span class="hx:absolute hx:-mt-20" id="conteúdo"&gt;&lt;/span&gt;
&lt;a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;00:00 - Intro&lt;/li&gt;
&lt;li&gt;01:36 - Noção de Sockets&lt;/li&gt;
&lt;li&gt;02:26 - Entendendo Comunicação Entre Processos&lt;/li&gt;
&lt;li&gt;03:18 - Memória Protegida/Isolada Impede Comunicação&lt;/li&gt;
&lt;li&gt;05:30 - Comunicação via Pipes&lt;/li&gt;
&lt;li&gt;07:18 - Comunicação via Arquivos&lt;/li&gt;
&lt;li&gt;09:56 - BSD Sockets&lt;/li&gt;
&lt;li&gt;12:43 - Fluxo de conexão&lt;/li&gt;
&lt;li&gt;16:54 - Portas&lt;/li&gt;
&lt;li&gt;19:55 - Recapitulando navegador/DNS&lt;/li&gt;
&lt;li&gt;21:15 - Exemplo de server web com Node&lt;/li&gt;
&lt;li&gt;22:17 - localhost é diferente de 0.0.0.0&lt;/li&gt;
&lt;li&gt;23:43 - Continuando Exemplo de Node&lt;/li&gt;
&lt;li&gt;24:19 - Portas Efêmeras&lt;/li&gt;
&lt;li&gt;25:47 - Continuando Exemplo de Node&lt;/li&gt;
&lt;li&gt;29:00 - Debugando com Telnet e Developer Tools&lt;/li&gt;
&lt;li&gt;31:57 - Camadas de Segurança&lt;/li&gt;
&lt;li&gt;34:07 - Big Loop&lt;/li&gt;
&lt;li&gt;37:24 - OSI, TCP, HTTP&lt;/li&gt;
&lt;li&gt;39:28 - Mostrando FTP&lt;/li&gt;
&lt;li&gt;42:25 - De redes distribuídas a &amp;ldquo;walled gardens&amp;rdquo;&lt;/li&gt;
&lt;li&gt;45:06 - Bloopers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SCRIPT&lt;span class="hx:absolute hx:-mt-20" id="script"&gt;&lt;/span&gt;
&lt;a href="#script" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Olá pessoal, Fabio Akita&lt;/p&gt;</description><content:encoded><![CDATA[

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

<p>Agora que todo mudno sabe como funciona o básico de rede, vamos ver como funciona o básico de aplicações de rede, o que são sockets, pra que eles servem, como disso chegamos em protocolos como HTTP ou FTP e os vários detalhezinhos que complicam a cabeça de um iniciante em programação Web.</p>
<h2>Conteúdo<span class="hx:absolute hx:-mt-20" id="conteúdo"></span>
    <a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00 - Intro</li>
<li>01:36 - Noção de Sockets</li>
<li>02:26 - Entendendo Comunicação Entre Processos</li>
<li>03:18 - Memória Protegida/Isolada Impede Comunicação</li>
<li>05:30 - Comunicação via Pipes</li>
<li>07:18 - Comunicação via Arquivos</li>
<li>09:56 - BSD Sockets</li>
<li>12:43 - Fluxo de conexão</li>
<li>16:54 - Portas</li>
<li>19:55 - Recapitulando navegador/DNS</li>
<li>21:15 - Exemplo de server web com Node</li>
<li>22:17 - localhost é diferente de 0.0.0.0</li>
<li>23:43 - Continuando Exemplo de Node</li>
<li>24:19 - Portas Efêmeras</li>
<li>25:47 - Continuando Exemplo de Node</li>
<li>29:00 - Debugando com Telnet e Developer Tools</li>
<li>31:57 - Camadas de Segurança</li>
<li>34:07 - Big Loop</li>
<li>37:24 - OSI, TCP, HTTP</li>
<li>39:28 - Mostrando FTP</li>
<li>42:25 - De redes distribuídas a &ldquo;walled gardens&rdquo;</li>
<li>45:06 - Bloopers</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>No começo dessa mini-série eu ia só até o episódio passado, mas depois que escrevi, resolvi estender mais três episódios. Estou pulando toda uma parte sobre rede física, MLPS, OLDM, Wimax, 802.11. Vale estudar o livro de redes do Tanenbaum pra esses detalhes, o objetivo é focar mais em assuntos que ajudem programadores e não quem está interessado em seguir na carreira de infraestrutura, por isso eu sei que pra quem é de telecom ou infra tem bastante coisa simplificada. Agora quero ir direto pra camada de transporte e aplicação e nos próximos episódios falar assuntos que o Tanenbaum não chega a explicar no livro.</p>
<p>Só antes de continuar, tem uma errata que esqueci de falar nos videos anteriores, sobre o primeiro video de redes. Lá eu tava tentando simplificar com metáforas pra falar que ondas como de rádio e internet wireless se parecem com ondas na água, mas do jeito que falei ficou parecendo que wireless precisa de um meio como ar pra se propagar, mas claro que não, ondas na água são diferentes de ondas eletromagnéticas, que se propagam no vácuo, diferente de som. Por isso que no espaço não tem barulho, mas satélites conseguem se comunicar. Já tá na errata do episódio mas achei melhor esclarecer.</p>
<p>Todo programador vai ter que lidar com coisas como endereços IP, que já expliquei, e também com as tais portas. Toda vez que você roda um <code>npm start</code> da vida, sobe uma aplicação web nas tais portas 3000 ou 4000. Todo tutorial só menciona isso: magicamente funciona. Mas não explica o que está acontecendo de verdade. É hora de entender a mágica. O episódio de hoje é sobre sockets.</p>
<p>(&hellip;)</p>
<p>Em resumo bem resumido, pense em sockets literalmente como tomada da sua casa. Diferentes portas tendo diferentes padrões de buracos, como o padrão brasileiro sendo uma porta, padrão europeu sendo outra, padrão americano outra e assim vai. E só plugues corretos encaixam em determinadas tomadas. Por isso seu notebook importado não encaixa na porcaria da tomada do Brasil. +</p>
<p>Na prática o conjunto de endereço IP e porta de saída, digamos, do seu navegador conectando num site, e o endereço IP e porta de entrada do tal site, essas quatro informações é o mínimo pra definir um socket. É o plug e a tomada conectada. Não se atenha tanto ao nome mas a esse conjunto de informações, é o que se precisa pra formar uma conexão de rede entre dois processos, que é o caminho que os pacotes que falamos antes vão trafegar.</p>
<p>Sockets, na verdade, é uma forma de comunicação entre processos. Todo sistema operacional existe pra gerenciar processos. Expliquei isso nos videos de Programação pra Iniciantes, em particular nos de concorrência e paralelismo e gerenciamento de memória. Processo é todo programa que tem rodando no seu computador, seja seu spotify ou banco de dados. No nível mais básico, um processo é representado por um número, um process ID ou PID que o sistema operacional dá pro seu programa. Quando do terminal de um Linux se digita <code>ps -ax</code> dá pra ver os processos e seus PIDs. O sistema operacional aloca uma certa quantidade de memória e internamente, seu processo acha que tem acesso a toda memória teórica de 64-bits, mas na realidade o sistema operacional é quem intermedia o acesso à RAM ou Swap de disco.</p>
<p>Isso é importante. Um processo é como uma criança rica mimada gastando cartão de crédito dos pais. Ele não tem noção que tem limite, e só vai gastando, e os pais, que é o sistema operacional, vai sempre só pagando, então essa criança tem a ilusão que tem dinheiro infinito. É mais ou menos assim. Seu PC tem só 8 giga de RAM real, mas seu processo acha que tem do endereço 0 até 2 elevado a 64 de memória, que seria o máximo teórico de 16 exabytes. Nenhum computador de verdade tem exabytes de RAM ainda. Isso é importante de entender então vou insistir com outra metáfora.</p>
<p>Cada processo rodando na máquina enxerga uma memória virtual, de 0 até 16 exabytes. Quando falamos que se consegue endereçar memória, na realidade pense assim: Imagine um livro com uma parte de índice no começo. O índice tem espaço pra 16 exabytes de linhas, mas o livro em si não tem 16 exabytes de páginas, saca? Todos os processos estão compartilhando a mesma memória física de 8 gigabytes reais, mas ele só enxerga o índice.</p>
<p>O sistema operacional intermedia e garante que um processo não consiga acessar a memória real inteira, as páginas do livro, de outro processo. Por isso falamos que rodam isolados, sem um sobrescrever a memória do outro. Eu explico sobre isso nos episódios sobre gerenciamento de memória. Mas a parte importante é entender que um processo não enxerga nunca a memória de outro processo. Ele acha que está sozinho na máquina.</p>
<p>Antigamente, nos primeiros computadores sem isolamento de memória, um processo poderia escrever num endereço de memoria real e um outro processo poderia ler essa informação diretamente desse endereço. Um livros sem índices. Na época dos computadores de 8 e 16 bits era mais ou menos assim. Até a Intel inventar memória protegida. Todo processo enxergava todas as páginas e poderia escrever em qualquer lugar. Endereçar memória diretamente era mais rápido mas levava a dezenas de bugs de um processo escrevendo em cima de endereços que outro processo tava usando, levando desde a comportamento não-determinístico até a crashes. Isso era menos ruim quando a gente só rodada um programa de cada vez, na era do MS-DOS. Mas nos primeiros Windows isso já era um problemão.</p>
<p>Desde que passamos a isolar os processos e demos endereços virtuais em vez de reais, pelo menos essa categoria de bugs foi extinta, já na época do Windows 3.1 e foi melhorando a cada nova versão. Também significa que se um processo quiser se comunicar com outro processo, não tem como, porque não tem como gravar algo na memória que outro processo possa ler diretamente. As únicas duas formas de dois processos se comunicarem ou é via pipes ou via arquivos. Vamos entender.</p>
<p>Pipes de Linux é simplesmente ligar a saída padrão de um programa na entrada padrão de outro programa, o stdout ligado ao stdin via um pipe, ou cano. Que nem quando fazemos <code>cat algum_arquivo</code> pipe <code>grep alguma coisa</code>. Expliquei um pouco disso no episódio de Ubuntu se quiser relembrar. Isso significa que um programa roda primeiro, cospe algum resultado no stdout, e esse resultado é passado pro stdin, pra entrada, do próximo programa. É uma forma de dois programas diferentes se comunicar, mas é uma forma serial: um programa precisa rodar primeiro até o fim, terminar, e só depois começa o outro.</p>
<p>Portanto é mais complicado se eu quero os dois programas rodando em paralelo, sem um esperar o outro terminar. A única outra solução é um programa ficar cuspindo coisas num arquivo e o outro programa ficar lendo desse arquivo. Esse arquivo serve de ponte, de stream de entrada e saída pra ambos, criando um tipo de conexão. Isso resolve o problema deles conseguirem rodar em paralelo, ao mesmo tempo. Como exemplo, pense num programa que vai gravando coisas num arquivo de log e pense outro programa como o Prometheus, que vai lendo esse log e organizando a informação. Arquivos é uma área compartilhada que dois processos podem usar pra se comunicar, já que memória é isolada.</p>
<p>Todo iniciante precisa se acostumar a lidar com arquivos. Sem entrar em detalhes, na maioria das linguagens, você manda abrir um arquivo a partir de um path ou caminho, que é a sequência de diretórios e sub-diretórios separados por uma barra e o nome do arquivo com extensão. Isso abre o que chamamos de um stream, pense como se fosse um cano de bits bidirecional, um rio onde flui bits. Agora podemos ou ler ou escrever nesse stream.</p>
<p>Podemos ler bit a bit, ou pedir pra ir enchendo tipo um balde antes, um buffer, um acumulador, pra pegar linha a linha de cada vez, por exemplo. Mesma coisa pra escrever, podemos jogar bit a bit nesse stream, ou preencher um buffer antes e mandar vários bits de uma só vez, como uma linha inteira. Podemos programar pra deixar encher esse balde, e quando tiver uma certa quantidade de bits ou quando vier algum caracter especial como uma quebra de linha, pedir pra notificar o programa pra fazer alguma coisa com o que veio. De novo, a maioria das bibliotecas de linguagens modernas já cuidam disso e você como programador só lida com coisas como linha a linha. Mas por baixo existem coisas como buffers.</p>
<p>Vale lembrar que se você programar numa linguagem um pouco mais baixo nível, tipo C, Rust ou até Java, vai lidar mais com esses conceitos de buffers. Java tem classes como Buffered Stream, por exemplo. Numa linguagem mais alto nível como Javascript, ele cuida disso pra gente por baixo dos panos, e você só fala &ldquo;vai lendo de linha a linha e vai me dando&rdquo;. Bibliotecas de linguagens de alto nível foram feitas pra oferecer produtividade ao custo de dar menos controle. Por outro lado é o velho 80/20, pra 80% das coisas que precisa, o 20% que oferece por padrão costuma ser suficiente. Pros outros 20%, aí precisa descer pra um C da vida.</p>
<p>Só pra ter de referência aqui, como que em Javascript com Node dá pra escrever e ler de um arquivo? Primeiro carrega a biblioteca &ldquo;fs&rdquo; de filesystem e ele tem várias funções como esse <code>writeFile</code> onde passo o nome do arquivo e o conteúdo como String. Se não der nenhum erro, podemos usar <code>readFile</code> pra ler o conteúdo que acabamos de escrever e mostrar na tela com o bom e velho <code>console.log</code>. Mas o principal é entender que a semântica são funções como essas, read alguma coisa, write alguma coisa.</p>
<p>`var fs = require(&ldquo;fs&rdquo;);
fs.writeFile(&lsquo;hello.txt&rsquo;, &lsquo;Hello World&rsquo;, function(err) {
if (err) {
return console.error(err);
}</p>
<p>fs.readFile(&lsquo;hello.txt&rsquo;, function (err, data) {
if (err) {
return console.error(err);
}
console.log(&ldquo;read: &quot; + data.toString());
});
});`</p>
<p>Enfim. Com pipes e arquivos, você tem o mínimo suficiente pra fazer dois processos comunicarem entre si mesmo sem compartilhar memória RAM. Esse tipo de técnica fica embaixo de um guarda chuva de assuntos que chamamos de IPC ou inter process communication. Existem outras formas de comunicação como sinais, mas só isso é suficiente pra hoje. Se você só tem um computador, isso é suficiente. Mas aí lá nos anos 60 inventaram um troço que fodeu esse esquema. Essa tal de rede.</p>
<p>Com redes, temos mais de um computador rodando em paralelo e seria bacana se um processo rodando em um computador pudesse falar com um processo rodando em outro computador. E seria mais legal ainda se pudéssemos usar uma semântica parecida com lidar com arquivos, sem de fato usar arquivos. Ter comandos parecidos como &ldquo;read&rdquo; ou &ldquo;write&rdquo;, ler ou escrever num stream de bits. Pensando assim que em 1983 surge a implementação de Berkeley Sockets no UNIX original BSD versão 4.2.</p>
<p>Por isso são chamados de BSD sockets, de Berkeley Software Distribution ou POSIX sockets. POSIX que é o conjunto de APIs e protocolos que define o que é um UNIX. Pra entender um pouco mais sobre UNIX e Linux e licenças de software livre, não deixe de assistir o episódio de Apple e GPL que fiz faz tempo. BSD Sockets se tornou meio que o padrão de como lidamos com comunicação entre processos de forma mais geral.</p>
<p>Já vimos nos episódios anteriores dessa mini-série de redes, como que informação é fragmentada em pacotes, e como esses pacotes são transferidos numa rede de um computador até outro, seja numa rede local ou seja na internet em geral. Vamos assumir que tudo isso funciona e que os sistemas operacionais sabem como produzir pacotes e enviar na rede e consumir pacotes que chegam da rede, seja via fibra ótica, cabo de cobre ou rede sem fio.</p>
<p>Não por acaso venho me repetindo bastante sobre sistemas de armazenamento: como HDs são dispositivos de blocos e não dispositivos de arquivos. No baixo nível do hardware, sistemas operacionais lidam com blocos de bits num HD ou blocos de bits em pacotes de rede. Tudo são blocos, toda informação é fragmentada e transferida num stream. Podemos fazer buffers de blocos. Se blocos de bits forem arquivos num HD, podemos pensar em blocos de bits que vem pela rede meio como arquivos também. As abstrações são parecidas embora no meio físico sejam diferentes. No fim do dia você está lendo bits de algum lugar e escrevendo bits em algum lugar, esse é o conceito principal.</p>
<p>Não é a definição exata mas a grosso modo poderíamos pensar em sockets como uma generalização das primitivas de arquivos. Um Linux entrega um file descriptor ou file handle pro seu programa, tanto se for um arquivo local no seu HD ou um socket de rede. Pense em um handle ou descriptor como uma caixa preta que representa um arquivo, um intermediário pra quem você pede pra receber bits ou enviar bits. E essa caixa preta poderia ser um arquivo em disco, mas poderia ser uma conexão remota em rede. Tem uma preparação extra que precisa fazer pra se comunicar na rede e em toda linguagem de programação vai ser parecido. O protocolo que os Berkeley Sockets definiram funciona mais ou menos assim.</p>
<p>`const http = require(&lsquo;http&rsquo;);</p>
<p>const hostname = &lsquo;127.0.0.1&rsquo;;
const port = 3000;</p>
<p>const prepareResponse = (req, res) =&gt; {
res.statusCode = 200;
res.setHeader(&lsquo;Content-Type&rsquo;, &rsquo;text/plain&rsquo;);
res.end(&lsquo;Hello World\n&rsquo;);
}</p>
<p>const server = http.createServer(prepareResponse);</p>
<p>server.listen(port, hostname, () =&gt; {
console.log(<code>Server running at http://${hostname}:${port}/</code>);
});`</p>
<p>Primeiro seu programa pede um bind pro sistema operacional. Bind é literalmente ligação, a ligação de um endereço IP com um outro número de 16 bits que chamamos de porta. Bind é um pedido de registro. Funciona assim. Todo processo quando inicia, o sistema operacional oferece um número de identificação, o tal PID. Só que esse PID muda o tempo todo. Hoje seu Spotify inicia com PID 10. Mas amanhã pode já ter outro programa com PID 10, então o sistema atribui PID 11 ou qualquer outro número. PIDs identificam programas rodando naquele momento, mas não servem pra identificar um programa individualmente a qualquer momento. Então precisamos de outro número que seja fixo que o programa possa pedir pra se registrar.</p>
<p>Digamos que seu programa peça pro sistema registrar ele com o número 3000. O sistema operacional mantém uma tabela em memória e poderia associar o PID atual do seu programa, digamos que seja 11, com esse número 3000, que ele chama de porta, ligados ou bound num endereço IP. Porta é um número que identifica um processo que o sistema operacional mantém numa tabela de controle na memória dele. Se ninguém antes pediu pra registrar essa porta, o sistema te associa nela e nenhum outro programa pode pedir pra se ligar na mesma porta. Porta é só isso, um identificador do programa rodando ligado ao endereço IP do computador.</p>
<p>Quando o sistema consegue te associar nessa porta 3000, devolve um ok pro programa e devolve o equivalente a um stream de bits, o cano aberto, como se tivesse acabado de conseguir abrir um arquivo. E agora seu programa pode entrar em modo de escuta, ou listen. Nesse momento ele fica bloqueado esperando o sistema te mandar alguma coisa por esse cano e não precisa fazer mais nada enquanto isso. Normalmente isso fica numa thread bloqueada ou é usado I/O assíncrono, que não é escopo explicar hoje. Só entenda que depois do bind, seu programa ficaria parado esperando e escutando o que vier através dessa porta 3000. O processo de bind e listen de sockets é similar ao processo de dar open e abrir um arquivo.</p>
<p>Daí alguém na rede resolve mandar alguma informação, pro endereço IP do computador onde ele tá rodando, e mandando junto que quer falar com seja lá quem está ligado nessa porta 3000. O sistema operacional recebe isso e vê, &ldquo;hum, quem tá escutando na porta 3000, vamos ver na tabela, ah é o processo de PID 11, vou mandar no cano aberto dele&rdquo;. Agora seu programa, que estava só escutando, começa a receber bits. Nesse momento ele pode escolher aceitar ou rejeitar, normalmente só se aceita, isso é o passo de accept.</p>
<p>E é no accept que fecha o que se chama de conexão entre este computador e o outro que pediu a conexão. O socket serve pra estabelecer essa conexão, esse stream de bits, entre dois programas rodando, mesmo se for em máquinas diferentes. E agora os dois programas precisam enviar comandos que ambos entendam. Se seu programa receber bits que formam um comando válido, pode começar ou a receber ou a enviar bits de volta pela mesma conexão. Aqui é a metáfora das tomadas de padrão diferente.</p>
<p>Pra comunicação acontecer, ambos precisam concordar que comandos aceitam trocar. Esse acordo entre as duas pontas é o tal de protocolo. Pense em protocolo como sendo os pinos nas posições corretas que encaixam certo nos buracos da tomada. Mesmo tendo um processo pendurado numa porta, se ele não for um servidor web, não adianta um navegador web tentar se comunicar nele, eles não vão se entender e só vai dar erro. Por exemplo, se um navegador web tentar se conectar com um servidor de banco de dados, só vai dar erro, porque o banco de dados não entende comandos de HTTP que o navegador manda.</p>
<p>Falando bem resumido, esse é o básico do básico do básico de programação distribuída em rede. Toda linguagem vai te dar bibliotecas e funções que tem nomes parecidos com esses passos, bind, listen, accept, send. Apesar da sintaxe de cada linguagem ser diferente, podem ver que em todas é o mesmo processo, porque as primitivas no sistema operacional são as mesmas e as tecnologias de rede são as mesmas. Independe da linguagem, o jeito de falar em rede é sempre a mesma. Eu sempre falo que é mais importante saber a fundação do que uma linguagem só, porque se você aprendeu isso em C, facilmente vai conseguir fazer a mesma coisa em Java ou Python.</p>
<p>Do lado do sistema operacional, entenda que portas é só uma tabelona com identificadores numéricos de 16-bits, onde é possível associar 2 elevado a 16 portas no total, de 0 até 65 mil 536. Por isso você nunca viu número de portas acima disso. Essa tabelona diz que se receber bits endereçados pra um IP e porta, ele sabe pra qual cano de qual processo rodando enviar. Agora vamos entender isso a partir do programa mais comum pra se comunicar em rede hoje, seu navegador web, como Chrome ou Firefox.</p>
<p>Seu navegador é um exemplo desse tal programa que pede uma conexão, um cliente. Ele não precisa fazer bind, porque não precisa que ninguém se conecte nele. Ele só quer se conectar na porta dos outros, de um servidor web. E é isso que diferencia um cliente de um servidor. Um servidor faz bind e listen numa porta e fica esperando, escutando. Um cliente envia pacotes pro endereço IP do servidor e pede pra se conectar num programa rodando lá que está escutando numa determinada porta. Pra isso funcionar, o cliente precisa saber não só o endereço IP como em qual porta o servidor está escutando. E por isso se estabeleceu que certas portas são exclusivas pra um determinado uso.</p>
<p>Mas não se enganem, portas são só números numa tabela que o sistema operacional gerencia. Os usos de cada número de porta são completamente arbitrários, determinados por consenso, e pro programa em si não faz nenhuma diferença se ligar numa porta 80 ou 3000 ou 8080. Não existe nenhum tratamento especial diferente. Portas são só números. E por isso você sobe uma aplicação web feita em Node numa porta 3000 e ela funciona igual quando subimos na porta 80 num servidor na Amazon.</p>
<p>Por convenção, estabeleceu-se que as primeiras 1024 portas, de 0 até 1023 são portas de sistema, e num Linux precisa ter permissão de root pra fazer um programa se registrar numa delas. Essa distinção existe porque vários usuários podem abrir sessões num mesmo servidor UNIX ou Windows Server, mas só o administrador pode subir processos em portas abaixo de 1024. Usuários nesse servidor podem subir processos em outras portas menos nessas. É nesse intervalo que se encontram as duas portas mais famosas de todas, a 80 de HTTP e 443 de HTTPS. Temos outras famosas, como porta 21 de FTP, porta 22 de SSH, porta 25 de SMTP pra envio de emails, porta 37 que usamos pra sincronia de horário via NTP, porta 53 que é DNS, porta 194 é de IRC, 993 pra IMAP de cliente de email e assim por diante.</p>
<p>Existe uma organização que registra o uso dessas portas baixas, a IANA ou Internet Assigned Number Authority. Dá pra ligar qualquer programa numa porta baixa, mas normalmente essas portas costumam ter serviços específicos como servidor web ou DNS. Por isso que num navegador quando digitamos endereço, podemos omitir a porta, porque o navegador preenche a porta pra gente usando essas convenções. Quando digitamos <a href="http://www.google.com"target="_blank" rel="noopener">http://www.google.com</a> primeiro ele precisa resolver esse nome de domínio, pra isso resolve esse nome num endereço IP e pra isso precisa de um name server ou DNS.</p>
<p>Já mostrei no episódio anterior como seu sistema operacional pergunta quem é esse nome pra um DNS, como o 1.1.1.1 da CloudFlare ou 8.8.8.8 do Google. O DNS vai te devolver um grupo de endereços IP e seu computador escolhe um deles. A partir desse ponto faz um cache disso localmente. Se no navegador pedir de novo o &lt;www.google.com&gt;, nem precisa pedir pro DNS, porque já tem gravado num cache local. Toda resposta de DNS tem uma coisa chamada TTL ou time to live, que é tipo uma expiração. Quando expirar, aí sim seu computador vai no DNS e pergunta de novo qual é o endereço do nome &lt;www.google.com&gt;. Em outro video vou explicar DNS com um pouco mais de detalhe mas se acostumem com esse conceito primeiro.</p>
<p>Enfim, graças ao DNS ou o cache local de DNS, seu navegador agora tem um endereço IP. Ele pode começar a se conectar. Mas como disse antes, precisa saber em que porta nesse endereço vai estar o programa que vai te devolver os HTMLs. Esse programa chamamos de servidor web, e como falei antes, por convenção, vai estar escutando nas portas 80 ou 443. Se no navegador você digitou http:// significa que quer conectar na porta 80. Se digitar https:// quer dizer que quer conectar na porta 443. O que vem antes dos dois pontos é com qual protocolo quer se comunicar com esse servidor, no caso HTTP ou HTTP com TLS.</p>
<p>Protocolos é quem definem os tais comandos e valores que ambos o navegador e o programa servidor web conseguem entender, os pinos certos pros buracos certos da tomada. No protocolo HTTP temos comandos em texto como GET ou POST pra pedir ou enviar coisas do navegador pro servidor. Vamos fazer um exemplo simples só pra consolidar o conceito. Vou fazer rapidinho um servidor web em Node.js estilo hello world, só pra ter um programa escutando numa porta. Isso você encontra quinhentos tutoriais na internet não vou detalhar muito.</p>
<p>Olha esse do tutorial do próprio site oficial do Node.js. Primeiro ele carrega a biblioteca &ldquo;http&rdquo;. Em seguida declara duas variaveis, uma pra guardar o endereco 127.0.0.1. Esse é o endereço que chamamos de loopback, ele representa o endereço local de rede do seu computador. Todo pacote enviado pra esse endereço não vai sair do seu computador, ele vai devolver pra ele mesmo. Por isso chamamos de loopback. Vale entender isso porque muita gente acha que 127.0.0.1 é a mesma coisa que outro endereço, o 0.0.0.0 e não sabe a diferença.</p>
<p>Normalmente um endereço IP é associado com uma placa de rede instalado na sua máquina, mas 127.0.0.1 é como se fosse uma placa de rede virtual, de mentira. Ele recebe pacotes e devolve pra ele mesmo. 127.0.0.1 é a mesma coisa que localhost. Quando damos bind de um processo nesse endereço, dá pra abrir o navegador e conectar por ele com <a href="http://localhost"target="_blank" rel="noopener">http://localhost</a>. Mas se alguém de fora tentar se conectar no mesmo serviço, na mesma porta, não vai conseguir, porque na placa de rede de verdade não tem bind nessa porta. Localhost só é acessível de dentro do próprio computador, não de fora.</p>
<p>Tem também o endereço 0.0.0.0 que significa “qualquer placa de rede do computador”. Quando queremos pendurar um servidor que vai receber bits independente de por qual placa de rede do seu computador vier, penduramos ele no 0.0.0.0. E no navegador podemos digitar localhost porque 127.0.0.1 é um desses “qualquer placa de rede”, mas também um navegador em outro computador na rede, vai conseguir se conectar no seu programa. Todo computador responde nesses endereços locais. Muita gente pensa que são a mesma coisa, mas só localhost e 127.0.0.1 são a mesma coisa. Pra desenvolvimento a gente usa localhost, porque normalmente não queremos outra pessoa na mesma rede acessando enquanto estamos no meio do desenvolvimento. Mas num servidor de verdade queremos dar bind em 0.0.0.0 pra deixar o programa acessível a qualquer pessoa.</p>
<p>A segunda variável define que quer se ligar na porta 3000. Eu expliquei que portas de 0 até 1023 são reservados e o sistema operacional exige permissão de administrador pra ligar um programa nessas portas baixas. Por isso que em máquina de desenvolvimento, preferimos usar portas de 1025 até 49 mil 151. Porque com suas permissões de usuário normal, pode pedir pro sistema ligar seu programa numa porta, sem privilégios especiais, sem precisar ficar usando o comando <code>sudo</code> toda hora. Por isso que pra subir uma aplicação de Node.js ou Django ou Laravel, numa porta como 3000 ou 4000, não precisa executar com <code>sudo</code>.</p>
<p>Pra complementar, de 49 mil 152 até 65 mil 535 são o que chamamos de portas dinâmicas ou privadas. Em particular 49 mil 152, que é um número difícil de decorar em decimal, mas é a mesma coisa que 2 elevado a 15 menos 2 elevado a 14, que é mais fácil de lembrar. Também são chamadas de portas efêmeras. Você até pode mas normalmente não se registra nenhum programa servidor que vai ficar rodando permanentemente nesse segmento. Essas são as portas usadas, por exemplo, por comunicadores como o Zoom ou Skype pra abrir conexão com outra pessoa na internet. Pode ser usado por games pra sessões multiplayer. São portas temporárias. Programas de comunicação tentam diversas dessas portas e usam a primeira livre que acharem. Não é regra, mas eu acho que programas que usam UDP em vez de TCP usam mais essas portas.</p>
<p>Por isso que nós programadores web, quando fazemos uma aplicação usando Node.js ou Spring ou Laravel ou qualquer coisa assim usamos portas como 3000, 4000, 8000, 8080 como era o Tomcat de Java e assim por diante. Qualquer uma depois de 1024 e antes daqueles 49 mil e tanto servem. Sem interferir com calls de Zoom e sem precisar de privilégios de administrador e ter que ficar digitando <code>sudo</code>. De novo, portas são só números. Se você achava que porta 8080 ou 3000 tinha algum significado, não tem, foram escolhidas arbitrariamente por alguém e todo mundo só usa a mesma porta por convenção.</p>
<p>Enfim, agora é específico de cada linguagem e framework, mas no caso do Node criamos uma instância do que ele chama de &ldquo;server&rdquo;. Eu modifiquei um pouco o exemplo do tutorial porque quando criamos o servidor já registramos como queremos que ele responda quando vier algum comando de HTTP. Já volto nisso. Na sequência, fazemos essa instância de server pausar e ficar escutando, esperando alguma coisa, que o sistema operacional vai mandar pra gente no cano dessa porta 3000. Se ninguém mais estava pendurado na porta 3000, e ele conseguir se ligar com sucesso, daí escreve essa mensagem de servidor rodando. E pronto, agora está escutando na porta 3000 desse computador.</p>
<p>Vamos voltar pro navegador. Lá no campo de endereço escrevo que quero usar o protocolo &ldquo;http&rdquo;, dois pontos, barra, barra, localhost que é outra forma de dizer &ldquo;127.0.0.1&rdquo;, dois pontos, porta 3000. Se eu não colocasse explicitamente esse dois pontos 3000, ele ia assumir que seria porta 80. Tenta aí, em qualquer site como google.com, digita no final dois pontos 80. Vai ver que dá no mesmo.</p>
<p>E pronto, veio uma resposta Hello World. Vamos voltar pro código do servidor. Lembra que quando criei a instância de server registrei uma função de resposta? O framework do Node esconde os detalhes. O Linux recebeu os pacotes de bits do navegador endereçados pra porta 3000, viu que tinha meu programa pendurado nele e começou a reenviar os pacotes pro cano da porta 3000.</p>
<p>O meu programa em Node começa a receber pacote e dá accept. E aí vê o que fazer com esses pacotes. Daí tinha essa minha função registrada no server. Ele encapsula esses pacotes numa estrutura chamada Request, ou HTTP Request. É isso que faz essa biblioteca &ldquo;http&rdquo; que estamos usando. Ele se encarrega de receber os bits e organizar tudo bonitinho nesse objeto de Request pra gente. A partir desse ponto eu posso fazer lógica de código pra fazer coisas diferentes dependendo do que vier nessa request, como carregar um arquivo HTML. No caso, como é um exemplo besta, eu só mando responder a mensagem de Hello.</p>
<p>Mas não é só a mensagem. Isso é um protocolo, tem algumas regrinhas. O mínimo do mínimo que se espera de resposta é montar uma segunda estrutura chamada HTTP Response. Nesse response registro um status code 200, que é o código do protocolo HTTP pra dizer que tá tudo ok, daí por boa etiqueta, registro também um cabeçalho com um mime type, no caso pra indicar que não vou responder um HTML e sim só um texto puro. É com esse mime type que o navegador sabe se é pra interpretar como HTML ou se é um binário e é pra fazer download, por exemplo. E finalmente, posso escrever minha mensagem de hello no response como um simples string.</p>
<p>O Node vai pegar esse pacote de response que preenchi e mandar pro sistema operacional devolver pela rede pro navegador pela mesma conexão. E o sistema operacional por baixo vai fazer tudo que já expliquei antes, vai quebrar esse response em datagrams, vai encontrar a rota pra enviar, etc. E no final o navegador vai receber o pacote de resposta e interpretar isso visualmente na tela, desenhando o hello na tela pro usuário. Esse é o fluxo mais básico de web. Se não entender nem isso, não vai entender nada mais complicado, então garanta que esse fluxo está super claro na sua cabeça.</p>
<p>Tem outra forma de ver como isso funciona. Antigamente todo sistema operacional vinha com um programa de internet bem simples chamado telnet. É um programa que se conecta em qualquer porta que tenha algum outro programa escutando e com ele posso manualmente digitar comandos pra enviar, caso eles aceitem comandos em texto em vez de binário. No caso do Arch Linux hoje ele fica no pacote opcional chamado de inetutils. Em nenhuma distro se instala mais por padrão porque acho que é considerado um risco de segurança. São ferramentas que precedem o conceito de encriptação. Em vez de telnet hoje se usa SSH pra abrir conexões encriptadas, mas como não quero ter que lidar com criptografia neste episódio, deixa eu mostrar o bom e velho telnet.</p>
<p>Aquele meu programa de hello de Node continua rodando. Ele tá pendurado na porta 3000 e mesmo quando processa a requisição de algum navegador, continua aceitando novas requisições de outros navegadores. Por isso que um servidor web consegue atender várias pessoas ao mesmo tempo. Vamos abrir um outro terminal e conectar direto nele usando telnet, passando o endereço e a porta.</p>
<p>Pronto, estou conectado. Agora posso enviar uma requisição HTTP manualmente. O protocolo HTTP diz que posso digitar o comando GET seguido de uma URI que é o barra alguma coisa e no final escrever HTTP/1.0 denotando a versão do protocolo que estou querendo usar. Isso é tudo texto. Nas linhas seguintes posso mandar outros detalhes desse comando, mas se der dois enters, duas quebras de linha, isso indica pro servidor que terminei minha requisição.</p>
<p>E olha só, quando dei dois enters, o Node entendeu que podia começar a responder, e essa é a resposta que ele envia. Olha só o que tinha mandado ele preencher na tal estrutura de resposta. O status code 200 veio na primeira linha, seguido do content type que é texto puro, mais uma data e horário que o framework preencheu pra mim e o fechamento da conexão seguido do corpo da resposta que é o string da mensagem hello.</p>
<p>Claro, hoje em dia não preciso de telnet pra ver isso. Todo navegador agora tem o tal Developer Tools, que se  acessa com o atalho control shift J no Windows ou control option J no Mac. Ele tem essa aba Network ou rede, onde podemos ver os pacotes de request e response e os cabeçalhos. Mesma coisa que fizemos no telnet, olha como no request ele mostra que o navegador fez um comando GET e embaixo temos a mesma resposta que recebemos via telnet, status code 200, content type text plain, a data e horário. Antes de existir Dev Tools a gente usava coisas como Telnet pra debugar.</p>
<p>Em linhas gerais é assim que um navegador, um cliente de APIs e tudo mais que fazemos na web funciona. Com o navegador conectando na porta 80 ou 443 ou numa porta de usuário como a 3000 do meu Node.js. O navegador monta uma estrutura em texto chamada request, um servidor feito em qualquer framework como Node da vida recebe, decide o que fazer baseado no que foi pedido, monta uma outra estrutura chamada response e devolve. Esse é o básico do básico de web.</p>
<p>A porta 443 e TLS é uma camada a parte. É um processo que acontece entre seu navegador e o servidor web, independente da aplicação por baixo. Esse meu hello em Node não precisa estar ciente que a conexão estava ou não criptografada. O navegador pede um handshake, um aperto de mão, com o servidor que, se estiver devidamente configurado com certificados SSL, vão abrir uma conexão segura usando chaves assimétrica, trocar uma chave simétrica, e a partir daí todo pacote que o servidor web envia vai criptografado e o navegador consegue descriptografar e vice versa. Eu explico isso na parte 2 dos meus videos sobre criptografia.</p>
<p>Mas eu digo que tanto faz porque o programa Node por baixo vai receber a request já descriptografado direitinho, como se nada tivesse acontecido. E em redes existe isso de cada camada na arquitetura trabalhar os pacotes trafegando e as camadas de cima, como minha aplicação, não precisar estar cientes e funcionar normalmente. Se não sabia o que é uma boa arquitetura, a arquitetura OSI de camadas de rede é uma boa inspiração, onde cada camada tem sua responsabiilidade, cada camada não precisa estar ciente se uma camada embaixo foi adicionada ou trocada, contanto que realizem as mesmas tarefas. Programação de software pra rede costuma ter essa metáfora de camadas de uma cebola. Quem já brincou de Tor e coisas assim já deve ter ouvido falar de Onion, por isso. Outro dia falo de coisas como Tor.</p>
<p>Um navegador web como Chrome é um dos softwares mais complexos que você tem instalado no seu computador depois do próprio sistema operacional, especialmente pra renderizar a parte gráfica corretamente. Mas pra se conectar num servidor web e mandar comandos simples de GET, um mero telnet como mostrei já serve. Vários outros programas simulam um navegador simples como os programas wget ou curl de Linux, que a gente usa mais pra fazer download, mas tecnicamente ele se comporta como um navegador web. Ou bibliotecas que usamos pra fazer clientes pra APIs como o Axios de Javascript, ou a classe HttpClient de Java ou C#, ou a classe http.client de Python e assim por diante. São todos mini navegadores, sem a parte gráfica.</p>
<p>Se nunca pensou assim, um servidor é todo programa que pede um bind de uma porta pro sistema operacional e fica em modo listen de escuta, esperando pra dar accept e abrir uma conexão com outro computador remoto. Aliás, vale outro conceito básico. Eu categorizo programas em dois tipos, short lived e long lived. Ou em bom português, programas de tiro curto e programas persistentes. Programa de tiro curto são muitos dos que você roda via linha de comando, comandos como o grep, sed, ou awk de Linux, programas que recebem um input, processam alguma coisa, cospem um resultado e saem fora. Servidores ou programas persistentes são loops.</p>
<p>Vamos desconsiderar por um segundo que existem threads, I/O assincrono, e que tudo seja como era antigamente, quando só dava pra rodar um comando bloqueante e síncrono por vez. Se eu fosse escrever numa pseudo-linguagem, ou seja, uma linguagem que não existe, a estrutura mais básica de um servidor de rede seria assim:</p>
<p>`while(true) {
listen(:3000)</p>
<p>stream = accept()
while(not stream.eof) {
request += stream.read_line
}
response = processa_alguma_coisa(request)
send(response)
}`</p>
<p>Todo servidor fica num loop infinito até receber sinal do sistema operacional pra morrer, o tal SIGTERM ou sinal de término, que se você já usou Linux, já enviou com o comando <code>kill</code>. Ou no Windows via powershell com o comando <code>taskkill</code>. Enfim, entenda que se executar um programa e ele tiver o comportamento de esperar um evento, reagir, e voltar a esperar, normalmente é um loop, equivalente a um while true.</p>
<p>Dentro desse while, ele manda comando pro sistema operacional, o <code>listen</code>, pra pedir pra ficar esperando o que vier numa porta, como 3000. Nesse ponto que eu falei pra ignorar que existe threads e concorrência. Faz de conta que quando ele dá listen, fica parado nessa linha até receber alguma coisa. Uma hora alguém conecta e começa a enviar bits. Daí sai dessa linha e cai no <code>accept</code> onde recebe o stream de bits, o tal cano de bits. Agora eu fiz um pseudo código arbitrário que é ficar lendo linha a linha até sinalizar <code>eof</code> que, se nunca viu, costuma ser sigla pra end of file, que terminou o envio ou acabou o arquivo.</p>
<p>Agora, o programa faz alguma coisa com esses bits que vieram, que chamei de request, e monta alguma resposta, que é a estrutura de response. No final envia de volta ou dá <code>send</code> desse response, pedindo pro sistema operacional devolver, pela mesma conexão fechada no accept, e o loop reinicia esperando outra requisição. Volta pro estado de listen, até aparecer mais bits. No mundo real existem threads e na realidade uma das coisas que pode acontecer dependendo da linguagem é o accept abrir uma nova thread pra processar o request e response enquanto o loop de listen continua ativo esperando mais conexões. Possibilitando lidar com dezenas ou centenas de conexões simultaneamente.</p>
<p>Aproveitando o conceito. Todo programa gráfico é um grande loop também. Ele fica esperando você digitar alguma coisa ou clicar alguma coisa com o mouse, é parecido com esse <code>listen</code>. E fica no loop infinito até receber um sinal pra fechar como o menu de Quit ou alt-f4 no Windows. Um game também é um grande loop, esperando seus comandos e reagindo. Essa é a fundação pro que muitos chamam de programação orientada a eventos original. O programa reage a eventos, como input de mouse e teclado ou algo assim. Não vou entrar em paradigmas, mas só pra lembrar que esse é um dos patterns mais comuns em programação, o que eu pessoalmemnte chamo de Big Loop.</p>
<p>Normalmente, em web, a gente fica muito preso ao protocolo HTTP, onde as duas peças principais são a tal estrutura texto de HTTP Request e HTTP Response e comandos básicos como GET, POST ou PUT. Todo tutorial de web começa direto neles. E por causa disso muita gente faz o que não devia, tentando embutir tudo que pode dentro dessas estruturas. Mas a internet não é feita só de HTTP, ela só é a mais popular. Muitos falam “internet” pensando em redes, roteadores, pontos de acesso. E chama o resto de Web. Mas Web, que é o nome mais curto pra World Wide Web, que se refere à capacidade de hipertexto de páginas HTML. A idéia que uma página pode ter links pra outras páginas formando uma teia, ou Web.</p>
<p>Mas internet na realidade é um conjunto de tecnologias, que envolve coisas como ethernet, wifi, fibra, o TCP/IP e todos os outros protocolos de aplicação, incluindo o HTTP de Web. E chamamos assim porque como expliquei antes, o modelo OSI de internet define sete camadas. A camada física que foi o episódio que expliquei sobre ondas, cabos de cobre e wireless. A camada de data link responsavel entre outras coisas como checar erros, como eu expliquei sobre Hamming Code e tudo mais. A terceira camada, de rede é que lida com coisas como roteamento, endereços IP e tudo mais.</p>
<p>Eu pulei as camadas seguintes, a camada 4 de transporte, a camada 5 de sessão, a camada 6 de apresentação e a camada 7 de aplicação. Isso porque em TCP/IP as funções da camadas acima da 5 acabam sendo acumuladas na camada de aplicação, que é onde mora protocolos como HTTP de Web.</p>
<p>Em OSI existe uma camada pra lidar com sessões, mas em Web controlamos sessão direto no HTTP usando cabeçalhos como de cookies. Sessões servem pra literalmente identificar uma sessão individual de cada usuário e no modelo OSI esse controle ficaria na camada 5, mas a gente acaba achando mais fácil acumular isso direto na camada de aplicação. Por isso em vez de ter um jeito único de lidar com sessões, protocolos como HTTP, FTP, IMAP e tudo mais, cada um controla sessões do seu jeito. Tem vantagens e desvantagens de se fazer isso.</p>
<p>Exemplo de outro protocolo era o antigo FTP ou File Transfer Protocol que hoje em dia ninguém mais usa pelo mesmo motivo que não se usa Telnet, ambos precedem conceitos mais modernos de segurança. Muitos antigos servidores de FTP estão expostos atrás de um servidor web, como o FTP da Unicamp que eu usava muito na faculdade e hoje hospeda espelhos de arquivos de Linux. Se digitar ftp.unicamp.br no seu navegador, vai ver que ele coloca http:// na frente, indicando que não está usando o protocolo FTP.</p>
<p>Num terminal Linux, se instalar o antigo pacote inetutils, além do telnet, vai ganhar o programa ftp. Basta digitar <code>ftp ftp.unicamp.br</code> no terminal. Ele vai pedir um usuário. Como antigamente, muitos servidores públicos aceitavam o usuário <code>anonymous</code>. E felizmente esse ainda aceita. A senha pode ser qualquer coisa ou vazia. E pronto, abriu uma conexão de FTP onde ele passa a esperar comandos que são parecidos com os comandos pra navegar no seu HD via terminal como <code>cd</code> pra mudar de diretórios ou <code>ls</code> pra listar o conteúdo do diretório. Se digitar <code>help</code> mostra os comandos que o protocolo FTP suporta. Lembra que HTTP suporta comandos como GET? Em FTP ele suporta comandos diferente. Get em FTP é pra fazer download de algum arquivo.</p>
<p>Eu até consigo mudar de diretório fazendo <code>cd /pub</code> pra ir pro diretório público, mas não sei porque, comandos como <code>ls</code> não devolvem nada e dão timeout. HTTP versão 1.0 era ótimo pra baixar páginas HTML e até mesmo fazer download de arquivos, como agora. Mas era chatinho enviar arquivos pro servidor. Hoje em dia é fácil, mas nos primórdios, a gente ainda não entendia tudo que dava pra fazer, nem lembro se HTML 1.0 tinha form multipart. Pra enviar arquivos pra um servidor, o certo era usar FTP.</p>
<p>Acumulamos um monte de funções em cima de HTTP que antes eram de outros protocolos. Hoje em dia é muito normal abrir um Gmail e anexar um arquivo. Ou abrir um Dropbox e subir um arquivo. E mesmo se quisermos transferir arquivos num equivalente FTP, não se usa FTP pelo mesmo motivo que hoje usamos HTTPS em vez de HTTP, por segurança. HTTPS é HTTP mais encriptação com certificado TLS. O equivalente seria FTPS. Assim como em vez de Telnet hoje usamos SSH. E SSH é mais versátil porque permite não só abrir um terminal remoto seguro, como também trafegar arquivos, via SFTP que é FTP sobre SSH. Vou falar mais de SSH no próximo episódio.</p>
<p>Outro protocolo que até existe ainda mas num nicho muito pequeno é o que falei 2 episódios atrás quando expliquei correção de erros e parchives. O protocolo NNTP de rede Usenet. A idéia era ter um servidor de artigos de texto, como fóruns e sincronizar diferentes servidores usando esse protocolo NNTP. De novo, acumulamos essas funções dentro de HTTP e o equivalente seria sites como StackOverflow, HackerNews, Reddit.</p>
<p>No começo da internet não usávamos navegador web pra tudo. Usávamos programas separados como FTP pra transferir arquivos. News pra ler notícias e discussões da Usenet, literalmente newsgroups. Telnet pra abrir sessões remotas de terminal. E Gopher, que eu quase nunca usei porque meio que tinha o mesmo propósito de HTTP e perdeu espaço quando a Web ficou mais popular. Mas todos são exemplos dos primeiros protocolos de aplicação no começo da internet comercial. Na prática, Usenet ainda é usado até hoje pra facilitar pirataria, algumas coisas que talvez seja mais difícil em BitTorrent ainda se acha na Usenet.</p>
<p>Todos foram substituídos. HTTPS se tornou o protocolo mais popular. SSH é a única boa alternativa tanto pra telnet quanto ftp. E protocolos específicos como NNTP, IRC de chat, Gopher e outros, tiveram suas funções acumuladas em HTTPS. E o S de segurança se tornou importante nos primórdios do comércio eletrônico, onde encriptação se tornou essencial pra permitir trafegar coisas como número de cartão de crédito. Sem isso seria impossível ter comércio online.</p>
<p>Tivemos primeiro o SSL da Netscape, e hoje é o TLS ou Transport Layer Security. Isso possibilitou escalar a economia na Web mas também dificultou pra hobistas e amadores que queriam só fuçar a rede com comandos simples no terminal, porque agora temos que lidar com uma camada de encriptação no meio.. Antigamente era só plugar telnet em qualquer porta que já dava pra fuçar, hoje já não é tão simples e como isso torna as coisas mais indiretas e abstratas, imagino que deve dificultar o aprendizado de muita gente.</p>
<p>Sem contar que se eu quisesse contribuir na rede e participar de sub-redes como servidores de chat IRC, era só montar meu próprio servidor IRC e plugar na internet. Ou se quisesse ter meu próprio servidor de newsgroups era só montar um servidor de NNTP e plugar na Usenet e assim a gente podia fazer parte do mesmo serviço distribuído na rede. No momento onde centralizamos tudo em HTTP, também perdemos a característica de serviços distribuídos e entramos na era de walled gardens ou jardins emparedados. Acho que os únicos exemplos de rede verdadeiramente distribuída onde qualquer um pode entrar e participar é BitTorrent e Bitcoin da vida. Sim, eu sei, como falei antes Usenet e IRC ainda existem, mas são nichos bem pequenos e desconhecidos. Tem muito mais gente usando Discord do que IRC.</p>
<p>E falando nisso, eu acho que preciso explicar um pouquinho sobre segurança de rede e vou deixar isso pro próximo episódio. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e compartilhem o video com seus amigos. A gente se vê, até mais!</p>
]]></content:encoded><category>redes</category><category>backend</category><category>javascript</category><category>akitando</category></item><item><title>[Akitando] #118 - Fiz um servidor de "SQL"?? | Entendendo Banco de Dados</title><link>https://akitaonrails.github.io/2022/05/09/akitando-118-fiz-um-servidor-de-sql-entendendo-banco-de-dados/</link><guid isPermaLink="true">https://akitaonrails.github.io/2022/05/09/akitando-118-fiz-um-servidor-de-sql-entendendo-banco-de-dados/</guid><pubDate>Mon, 09 May 2022 11:20:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/_7nISfpofec"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;O que tecnologias de compiladores e estruturas de dados tem a ver com banco de dados? Resolvi brincar de fazer um pequeno banco &amp;ldquo;stupid&amp;rdquo; pra vocês terem uma visão diferente sobre o que é um banco de dados por baixo dos panos. Disclaimer: isso não vai ser um tutorial de SQL, mas acho que pode mudar a visão de vocês sobre bancos.&lt;/p&gt;</description><content:encoded><![CDATA[

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

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O que tecnologias de compiladores e estruturas de dados tem a ver com banco de dados? Resolvi brincar de fazer um pequeno banco &ldquo;stupid&rdquo; pra vocês terem uma visão diferente sobre o que é um banco de dados por baixo dos panos. Disclaimer: isso não vai ser um tutorial de SQL, mas acho que pode mudar a visão de vocês sobre bancos.</p>
<h2>CONTEÚDO<span class="hx:absolute hx:-mt-20" id="conteúdo"></span>
    <a href="#conte%c3%bado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>00:00:00 Intro</li>
<li>00:00:35 Problema de Tutoriais/Cursos</li>
<li>00:02:51 Banco de Dados de Usuários</li>
<li>00:03:29 &ldquo;Simulando&rdquo; banco de dados</li>
<li>00:04:58 &ldquo;Fake&rdquo; SQL?</li>
<li>00:07:16 Construindo o Fake SQL</li>
<li>00:10:59 Experimente com Código!</li>
<li>00:15:39 Testando Fake SQL com Jest</li>
<li>00:19:38 Adicionando &ldquo;SQL&rdquo; no &ldquo;Fake SQL&rdquo;</li>
<li>00:22:01 Conhecendo Antlr4</li>
<li>00:24:39 Copiando do SQLite3</li>
<li>00:30:34 Criando meu Listener de Parse Tree</li>
<li>00:39:41 O que é um Índice?</li>
<li>00:49:10 Bancos de Dados tem Interpretadores!</li>
<li>00:49:51 Transaction Log!</li>
<li>00:55:33 Como &ldquo;grava&rdquo; um banco de dados em disco??</li>
<li>01:05:57 B-Trees</li>
<li>01:08:30 Fazendo Cliente-Servidor!</li>
<li>01:09:55 Conclusão</li>
<li>01:12:26 Bloopers!</li>
</ul>
<h2>Links<span class="hx:absolute hx:-mt-20" id="links"></span>
    <a href="#links" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>GitHub do Stupid Database - código do episódio (<a href="https://github.com/akitaonrails/akitando_episode_0118"target="_blank" rel="noopener">https://github.com/akitaonrails/akitando_episode_0118</a>)</li>
<li>GitHub do repositório de gramáticas do Antlr (<a href="https://github.com/antlr/grammars-v4"target="_blank" rel="noopener">https://github.com/antlr/grammars-v4</a>)</li>
<li>SQLite Amalgamation (<a href="https://www.sqlite.org/amalgamation.html"target="_blank" rel="noopener">https://www.sqlite.org/amalgamation.html</a>)</li>
<li>Visualização de AVL Tree (<a href="https://www.cs.usfca.edu/~galles/visualization/AVLtree.html"target="_blank" rel="noopener">https://www.cs.usfca.edu/~galles/visualization/AVLtree.html</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Finalmente resolvi falar um pouco sobre bancos de dados. Esse é provavelmente o primeiro grande desafio pra todo mundo que começa a carreira de programação e parece uma parede muito alta pra escalar, muitos acham intimidante, e muitos começam a usar, decoram alguns comandos SQL, mas não tem muita certeza do que diabos estão fazendo. O objetivo de hoje é tentar dar um modelo mental que vocês consigam enxergar servidores de bancos de dados de uma forma menos complicada.</p>
<p>(&hellip;)</p>
<p>Alguns avisos antes de começar. O episódio de hoje não vai explicar nenhum banco de verdade, seja Postgres ou Mongo. Quem está esperando um tutorial de SQL, não vai ser este video. O começo vai parecer estranho se estava esperando isso, mas tenha paciência e continue acompanhando, eu acho que vocês vão ficar surpresos. Até pra quem já entende de banco de dados, no mínimo vai ter material aqui pra ajudar vocês a explicarem pros seus colegas iniciantes.</p>
<p>Outra coisa, todos os exemplos de código que vou mostrar serão em Javascript. Eu pessoalmente teria feito tudo em Ruby ou Crystal que são linguagens que sou mais confortável, mas acho que a maioria das pessoas assistindo é mais Javascript, então vamos de Javascript. Quem for de outras linguagens deve conseguir acompanhar porque não vou usar nada exótico. Tudo que eu fizer aqui dá pra fazer em Python, PHP, C# ou o que quiserem. Desta vez todo o código está disponível num repositório no GitHub que vou deixar o link nas descrições abaixo. Inclusive fica de lição de casa refazer o que eu mostrar aqui na linguagem favorita de vocês. O código desse repositório é ingênuo de propósito porque foi um exercício que eu decidi fazer durante o feriado de Tiradentes e eu me coloquei um limite de 2 a 3 dias pra fazer tudo.</p>
<p>A motivação desse episódio é porque a menos que eu esteja muito enganado, a maioria dos tutoriais e cursos sobre banco de dados começa mais ou menos assim. Faça &ldquo;apt install mariadb&rdquo;, que é um fork do MySQL. Daí termina de instalar, inicia o serviço, abre o console que conecta no servidor e começa: agora vamos fazer &ldquo;create table users&rdquo; bla bla e depois &ldquo;insert into users&rdquo; bla bla e finalmente &ldquo;select name from users&rdquo; e já vai direto pra explicar SQL. Pior ainda se começa num tutorial de framework, que aí você já cai num Hibernate ou Sequelize e sequer sabe o que tá acontecendo por baixo.</p>
<p>Só que isso eu acho que é ir do zero a 100 muito rápido. Onde que os dados ficam gravados? Onde é esse tal de &ldquo;banco&rdquo;? Como que uma linguagem como SQL atua em cima desses dados? Pra que serve um índice? Qual a diferença disso pra eu simplesmente gravar um JSON num arquivo? Vamos dar uma pausa e começar do começo, bem do começo. E no começo tudo que vocês sabem é lidar com variáveis e collections como arrays ou sets ou, no caso de Javascript, objects.</p>
<p>Pois bem, pra começar resolvi escrever o banco de dados mais simples que dá pra fazer. Chamei ele de Stupid Database, porque não é pra ninguém achar que isso é um banco de verdade. Ele só se comporta como um. Tenho uma tabela de usuários, num array simples, onde cada linha é um objeto de Javascript, como podemos ver aqui. Na 1a linha, com ID 1 temos ninguém menos que nosso querido Peter Parker. Não esse, esse outro aqui. Com uns 25 anos, da cidade de Nova Iorque. Na 2a linha, com ID 2, temos o Clark Kent com 35 anos, de Metropolis, e assim por diante. Um total de 37 linhas nesse array, com várias pessoas desconhecidas, de nomes comuns.</p>
<p>O que é isso? É um array de objetos. Também podemos chamar isso de &ldquo;tabela&rdquo;. Olha só. Se eu abrir um console de Node.js, carregar esse arquivo com <code>db = await import('./lib/users-database.mjs')</code> e fizer <code>console.table(db.users)</code>, ele vai printar exatamente como qualquer um esperaria ver uma tabela, certo? Pra todos os efeitos e propósitos, essa é uma tabela mínima.</p>
<p>Ok, mas se é uma tabela, é possível inserir novas linhas, certo? Claro. Podemos criar um novo usuário, vamos dar o nome de outra pessoa desconhecida de nome comum, Levi Ackerman, uns 37 anos, de Paradis. E pra inserir num array de Javascript usamos a função <code>.push</code>. E no nosso caso, inventei que o id de cada linha é um número crescente que começa em 1, então essa nova linha vai ser o tamanho da tabela mais um. E pronto, esse seria o equivalente em SQL a fazer um <code>insert into users</code> da vida.</p>
<p>Beleza, mas então qual é o equivalente a um <code>select</code> de SQL? Simples, uma das formas é a função <code>filter</code>. Eu passo pra função outra função que ele vai executar em cada objeto, um por um em cada linha desse array, no caso, procurando o objeto que tem o nome &ldquo;Levi Ackerman&rdquo;. O resultado disso é outro array só com os objetos encontrados. Podemos passar de novo pelo comando <code>console.table</code> e voilá, esse é o resultado correto, que seria o equivalente em SQL a fazer <code>select * from users where name = 'Levi Ackerman'</code>.</p>
<p>Aí nesse ponto você deve estar cético, pensando aí. Porra, Akita tá de sacanagem. Isso aí é só uma porcaria de um array, não é um banco de dados. Eu quero ver comando de SQL, porra! Ok, talvez você tenha razão. Então deixa eu ir pro terminal e executar um programinha que eu escrevi, um REPL. Lembram o que é um REPL? O comando <code>node</code> onde eu estou é um REPL, um console que interpreta os comandos que eu digito imediatamente e já me dá o resultado. O REPL <code>node</code> interpreta javascript e executa. Pra quem é de Python, se digitar <code>python</code> vai abrir o REPL de Python, que executa imediatamente os comandos em Python que digitar, e assim por diante. Várias linguagens tem REPLs que já vem na instalação ou que você pode instalar separadamente, mas só lembrar que REPL é um console interativo da linguagem. É uma ferramenta comum em linguagens dinâmicas.</p>
<p>Enfim, vou executar o REPL que eu escrevi e chamei de <code>repl.mjs</code>. Olha só, abriu uma linha de comando. Vocês queriam ver SQL? Tá bom, vamos começar digitando <code>insert into users (name, age, city) values ('Levi Ackerman', 37, 'Paradis')</code>. Opa, retornou o número 38. Agora vamos ver se inseriu mesmo, vou digitar a query <code>select * from users where users.city = 'Paradis'</code>. E, olha só, achou esse senhor desconhecido de nome Levi, como deveria.</p>
<p>Pronto, não era SQL que vocês queriam ver? Tá aqui. Mas isso não é MySQL, não é Postgres, nada nessa manga, nada nessa outra, é só Javascript puro. Vamos fazer outra query, quero todos os indivíduos nessa tabela com idades entre 60 e 2000 anos, porque alguns indivíduos tem expectativa de vida bem alta ultimamente. Como que faz? <code>select * from users where users.age between 60 and 2000</code>, é assim que vocês aprenderam né? E olha só, obviamente, achou certinho. Olha lá o Steve Rogers com 100 anos, acho que é 100 né? Ou nosso amigo Thor com 1500 anos. Só não comer açúcar, fazer dieta intermitente, e vive saudável muitos anos.</p>
<p>Eu espero que eu tenha conseguido deixar vocês confusos. O que diabos tá acontecendo aqui? Eu abri uma linha de comando bizarra e comecei a digitar SQL como se fosse um Postgres da vida, e ele claramente tá pesquisando em cima daquele array de objetos em Javascript. Como isso é possível? E esse é o real objetivo desse episódio, eu quero mostrar como eu fiz isso e em paralelo vocês entenderem mais ou menos como um banco de dados de verdade é feito. Então vamos lá.</p>
<p>Primeiro de tudo vamos deixar super claro: isto é meramente um exercício educacional, um código que eu me limitei em uns 2 a 3 dias pra fazer. Todo código que vou mostrar a partir de agora não tem condições de ser usado em produção de verdade. Pra isso ele precisaria ser bem mais complicado pra levar em consideração coisas como autenticação e autorização, locks e concorrência, otimizações de performance, otimizações de redundância, etc e tudo isso só ia dificultar a explicação. Por isso eu fiz só o mínimo do mínimo necessário pra ficar fácil de explicar, que é o objetivo de todo código educacional.</p>
<p>O segredo de tudo começa na biblioteca que eu chamei de <code>lib/fake-sql.mjs</code>. Essa é uma coleção de funções que eu escrevi com nomes estratégicos. Deixa eu mostrar. A primeira é a função <code>from</code> que recebe como argumentos as variáveis <code>table</code> e <code>conditions</code>. Lá na frente eu vou carregar o array <code>users</code> e outro array chamado <code>heroes</code>, tudo dentro de um hash chamado <code>database</code>, daí se fizer <code>database['users']</code> eu acesso o mesmo array que tava mostrando até agora.</p>
<p>E aqui uma das vantagens de usar uma linguagens dinâmica interpretada como Javascript. Já que performance e segurança não são preocupações pra hoje, eu posso fazer um protótipo simplesmente montando aquele comando de <code>filter</code> como fiz antes concatenado com a variável <code>conditions.where</code>. Se não ficou claro, deixa eu mostrar o que essa função faz. Vamos abrir o console do Node e deixa eu dar uns copy e paste só pra importar esse arquivo &lsquo;fake-sql.mjs&rsquo; e o mesmo &lsquo;users-database.mjs&rsquo; de antes. Não se preocupem com essa parte que é só carga.</p>
<p>Pronto, agora vamos fazer a mesma pesquisa de antes onde eu quero todo mundo com idades entre 60 e 2000 anos. É só fazer <code>from('users', { where: 'users.age &gt;= 60 &amp;&amp; users.age &lt;= 2000'})</code> que é a mesma coisa que o <code>between 60 and 2000</code> que fiz em SQL. De propósito chamei essa função de <code>from</code> e fiz um hash com uma chave <code>where</code> pra ficar meio parecido com SQL. E olha só, voltou o mesmo resultado de antes. Tô vendo o Steve Rogers, o Thor, a Diana e o Hank Pym. Essa função é o grosso do meu simulador de SQL, todo o resto agora é perfumaria.</p>
<p>Pra parecer mesmo SQL falta começar com <code>select</code> né? Pra que serve o select? Serve pra eu pegar só as colunas, ou chaves, que eu quiser, em vez de todas. Vamos criar a função <code>select</code> lá na biblioteca então. E olha só, parece mais complicadinho. Essa função recebe como argumentos uma lista de colunas e o resultado do <code>from</code>, ou seja, aquele array de resultados.</p>
<p>A primeira metade é outra trapaça. Se eu pedir &ldquo;*&rdquo; ele vai substituir por uma lista com todas as chaves dos objetos. Aqui estou assumindo que todos os objetos do resultado sempre tem as mesmas chaves. Não estou checando nada e não vou introduzir o conceito de Schemas, por isso falei que tô trapaceando. Enfim, daí ele vê se o argumento foi a palavra &ldquo;count&rdquo;, daí devolve direto só o total de objetos no array de resultados. E caso contrário, pega a string que passei e dá split por vírgula, pra transformar num array.</p>
<p>O resultado dessa função é um <code>map</code>. Lembra o que faz um map? Ele pega uma coleção, transforma cada elemento e devolve tudo em outra coleção, convertendo cada objeto da coleção original usando essa função que passo de parâmetro. Em resumo, vai transformar meu objeto original num outro objeto só com as chaves que pedi pra selecionar. Vamos ver na prática lá no mesmo console de Node.</p>
<p>Estou de novo no console e faço <code>select('name,age')</code>. Aqui é uma escolha de design, eu poderia passar como parâmetro um array com os strings &rsquo;name&rsquo; e &lsquo;age&rsquo; mas só pra ficar mais &ldquo;limpo&rdquo; nessa sintaxe que tenta imitar SQL, decidi passar tudo grudado num único string. Por isso, do lado de dentro, preciso fazer um split. Obviamente esse é o jeito menos otimizado de passar parâmetros, mas como eu disse antes, é só um exercício.</p>
<p>Aproveitando a deixa, é isso que eu falo em vários videos: experimente com código. Faça experimentos como esse na sua máquina, código que não é de nenhum projeto do trabalho, é só um treino sem compromisso. E aí experimente designs que normalmente ninguém deixaria você fazer no trabalho. Só quando se experimenta coisas que ninguém faria é que às vezes pode dar inspiração pra coisas que podem ser úteis.</p>
<p>Pra quem curte anime, isso me lembra o Food Wars, já viram, Shokugegi no Souma? É uma história de competição numa escola culinária onde o protagonista, por acaso, adora fazer comidas bizarras que nunca dão certo. Esse é o motivo. Se você nunca tentou fazer os códigos mais impensáveis, nunca vai chegar num design inovador de verdade. Abra um diretório vazio, começa a escrever, apaga, joga fora, vai treinando. Ninguém precisa nem saber.</p>
<p>Enfim, voltando ao console, depois de passar a lista de colunas que queremos, como segundo parâmetro colocamos a mesma função <code>from</code> de antes. Olha o resultado: uma lista filtrada só com as colunas que queremos, sem a coluna de cidade ou id, no caso. E veja de novo a implementação. Eu pego o resultado e faço um map. A função de transformação faz um array só com as colunas que eu escolhi. E no final faço um <code>reduce</code> pra recriar objetos com o nome das colunas como chave.</p>
<p>Parece um pouco complicado se você nunca usou &ldquo;map&rdquo; e &ldquo;reduce&rdquo;, que existem em todas as linguagens e servem pra transformar listas e reduzir o resultado num acumulador. Teste só esse trecho num script com vários tipos de listas pra entender o que isso tá fazendo. É bem básico e você precisa saber. De novo, exercite até conseguir enxergar esse trecho e saber exatamente o que está acontecendo. Tem outras formas de escrever a mesma coisa pra ter o mesmo resultado, eu poderia não ter usado map e reduce e feito só com <code>for</code>.</p>
<p>Enfim. Olha o que estou fazendo. Só de escrever duas funções, esse &ldquo;select&rdquo; e &ldquo;from&rdquo; que recebe um hash de condições com uma chave &ldquo;where&rdquo;, já consigo simular o básico do básico de um select de SQL. Só pra ver mais um exemplo, num SQL você sabe que poderia fazer <code>select name from users where bla bla order by name desc</code> pra ordenar o resultado em ordem decrescente de nome. Como daria pra fazer nesse meu fake SQL? Vamos criar uma nova função chamada <code>orderBy</code> que recebe como parâmetro o nome da coluna por onde queremos ordenar, daí um segundo parâmetro pra dizer se é ordem ascendente ou descendente e como terceiro parâmetro, de novo o resultado da função <code>from</code>.</p>
<p>Essa implementação é simples, é basicamente o que qualquer iniciante de Javascript que já estudou algoritmos simples de ordenação já exercitou: implementar a função de comparação que se passa pra função <code>sort</code> que todo array tem. Novamente, se nunca tentou ordenar um array procure no google &ldquo;como ordena um array em javascript&rdquo; e vai achar a explicação dessa função. Não tem nada de especial aqui.</p>
<p>Vamos voltar pro console de Node. Como que fica pra usar isso? Aqui é que vai ficar um pouco diferente de um SQL normal porque o &ldquo;ORDER BY&rdquo; costuma ir no final do comando, mas na minha versão em Javascript, vai antes. E fica assim <code>select('name', orderBy('name', 'desc', from('users', bla bla bla)))</code>. E olha só, funcionou direitinho, retornou ordenado em ordem decrescente, Lois Lane na frente, Barbara Gordon no final. Pára e pensa, com a função <code>from</code> filtramos a tabela inteira pra pegar só quem é de Gotham ou Metropolis. Agora ordenamos o resultado, e finalmente selecionamos só as colunas que queremos. E por que essa ordem? Porque poderíamos escolher ordenar por idade mas no final só selecionar a coluna de nome. Por isso a ordenação vai antes de selecionar as colunas pro resultado final.</p>
<p>Só pra terminar essa parte, vamos ver rapidamente só mais duas funções. Como faz o equivalente a um &ldquo;insert&rdquo; de SQL? Essa é fácil. é só usar a função <code>push</code> que todo array tem como já mostrei antes. No caso, eu estabeleci que todo objeto vai ter um ID que é numérico e cresce incrementalmente, como muita primary key padrão que todo mundo cria, só pra ficar mais fácil. Vamos no console do Node e testar isso. Mesma coisa do primeiro exemplo <code>insert('users', { name: 'Levi Ackerman', age: 37, city: 'Paradis' })</code>. E devolve 38 que é o ID que ele calculou pra esse objeto.</p>
<p>Agora pra simular delete como no SQL é a mesma coisa que o filter da função <code>from</code> pra encontrar os objetos que queremos, daí só usamos a função <code>pop</code> que todo array de Javascript tem, e isso vai arrancar os objetos da lista. Nesse código-fonte eu implemento outras funções como o equivalente a &ldquo;update&rdquo; e tem uma versão inacabada de como seria um &lsquo;inner join&rsquo; e &lsquo;outer join&rsquo; se tiverem curiosidade de tentar terminar da forma correta. E é assim que vou fazendo um fake-sql pra simular os diversos aspectos que tem num banco de dados SQL comum.</p>
<p>Mas claro, mesmo sendo um exercício, já tem código suficiente aqui pra confundir a gente. Então esse é um bom momento pra fazer alguns testes unitários pelo menos né? Lembram como faz? Primeiro é só fazer um <code>npm install --save-dev jest</code> pra instalar o framework de testes Jest. Agora abrimos o arquivo <code>package.json</code> e colocamos esse comando grandão em scripts, test. Eu precisei usar essa flag experimental pra conseguir carregar os módulos ES certinho. Não sei se é o melhor jeito, mas foi como funcionou aqui.</p>
<p>Agora é só rodar <code>npm test</code> no terminal e ele vai executar os testes que eu já tinha feito no arquivo <code>stupid.test.js</code>. O comando do Jest vai vasculhar por arquivos terminados em &ldquo;.test.js&rdquo; e rodar os testes que tem lá dentro. E como é esse arquivo? Vamos abrir rapidinho só pra ver alguns exemplos. As primeiras linhas são pra carregar as funções do fake-sql e as tabelas de users e heroes.</p>
<p>Criamos um bloco de describe pra função &ldquo;select&rdquo; que é de longe quem tem mais casos de testes. Sabe todos aqueles testes que fizemos manualmente no console do Node? Pois é, é o que queremos automatizar em forma de testes unitários. Por exemplo, o primeiro teste é que deve achar o nome, então executa aquela mesma linha de select name from users where users.name igual Peter Parker. Pega o array de resultados, escolhe o primeiro objeto e espera que a propriedade “name” desse objeto seja Peter Parker, “to be” Peter Parker, se for, esse teste passa. E vai fazendo isso pra outros exemplos.</p>
<p>Vocês podem olhar esse arquivo com calma depois que tá no repositório. Link na descrição abaixo como falei, mas veja o último que é mais um teste integrado. Eu começo fazendo dois novos inserts, um pra tabela users com o objeto do Katar Hol, e outro insert na tabela heroes dizendo que na verdade ele é o Hawkman! Quem diria? E ligando com o que seria equivalente a uma chave estrangeira numa tabela de SQL, fazemos a propriedade user_id desse objeto ser igual ao valor que voltou no insert anterior. E é assim que seria um sisteminha CRUD da Liga da Justiça, pensa o estag do Bruce Wayne fazendo isso.</p>
<p>Só pra comparar depois, pedimos a contagem das duas tabelas e guardamos nessas duas variáveis de total. Agora fazemos um select com o innerJoin que eu não mostrei o código, mas se você já aprendeu SQL, inner join é uma forma de fazer a intersecção de duas tabelas de resultado. Ele vai ligar o resultado desse <code>from</code> feito na tabela users com a tabela heroes via a chave <code>user_id</code>. E esperamos receber uma tabela de resultado com as colunas name e alterego. Alter ego só tem na tabela heroes.</p>
<p>Então esperamos que na primeira linha do resultado, a propriedade name seja Katar Hol e o alterego seja Hawkman. Continuando, digamos que eu errei a idade do Katar, não era 35 e sim 37. Então eu posso usar essa outra função <code>updateFrom</code> que eu não mostrei o código. Quero que o age, a idade, mude pra 37, e isso nos objetos que voltar da mesma função <code>from</code> onde a cidade é Thanagar.</p>
<p>Eu faço de novo um select pela mesma condição e checo que a idade que voltou mudou pra 37 mesmo. E estamos quase no fim. Agora quero testar a função <code>deleteId</code> que também não mostrei o código. Vou apagar os objetos com os ids user_id e hero_id que tinha guardado lá em cima. E pra saber se apagou mesmo, peço um select count pra trazer a contagem das duas tabelas e tem que ter um objeto a menos do que tinha antes de quando eu gravei os totais depois do insert lá em cima. Vamos pro terminal, se rodar <code>npm test</code>, olha só, tudo passa corretamente. E agora eu tenho um mínimo de testes caso eu queira brincar de mexer mais nesse código.</p>
<p>Testes é outro assunto super longo, mas mesmo num exercício de fim de semana como esse, ter testes me ajudou muito. Se não tivesse eu teria levado o dobro do tempo pra fazer as coisas. Mas eu não segui nenhum tipo de TDD, eu escrevia um pedaço e testava depois, mudava o design, mudava o teste, e fui fazendo assim. Não pensa tanto em procedimento, só faz a porra do teste.</p>
<p>Até esse ponto implementei um monte de funções de javascript com nomes como select, insert, updateFrom, from, innerJoin, orderBy e assim por diante pra imitar os nomes dos comandos mais comuns que todo banco de dados SQL tem. E como exercício, eu poderia parar por aqui. Entenderam mais ou menos como é possível simular um fake SQL em cima de arrays de javascript? Mas claro, não é isso que você queria ver. Por mais parecido que seja, isso ainda não é SQL. Funções de Javascript tem um monte de parênteses, o orderBy tá na ordem errada, tá parecido mas tá longe de estar igual a SQL.</p>
<p>O que eu quero é poder ter um script como eu fiz nesse arquivo <code>test.sql</code> que também tá no repositório. Olha só, vários comandos SQL igualzinho o que você conseguiria executar no MySQL, SQL Server. Pra executar esses SQL eu fiz outro script chamado <code>stupid.mjs</code>. Vamos ver o finalzinho dele. Olha só, ele abre o arquivo <code>test.sql</code>, passa o script nessa função esquisita <code>parseScriptWithSplitQueries</code> e pra cada linha devolvida dá um eval. O que acontece se executar isso? Vamos voltar pro terminal e executar.</p>
<p>E voilá, ele executa todos os comandos SQL! Eu dei <code>console.log</code> do que tá rodando, e são minhas funções Javascript e não o SQL. Como que faz isso? Vamos voltar praquele script e o segredo começa naquela função esquisita <code>parseScriptWithSplitQueries</code>. Ela passa o conteúdo do arquivo <code>test.sql</code>, que são aqueles montes de comandos SQL, pra essa classe SplitQueries. Se olhamos lá em cima, ela é importada desse outro arquivo <code>parser/SplitQueries.mjs</code>. Vamos abrir ela.</p>
<p>Pronto, a primeira coisa que ele faz é importar essa biblioteca chamada Antlr4. E vamos pausar aqui pra eu explicar. Como expliquei no começo, no feriado de Tiradentes eu tava pensando em como ia explicar banco de dados pra vocês, aí tive a idéia de fazer um do zero. Se eu terminasse o episódio aqui, acho que já dava pra ter o primeiro gostinho de como um banco funciona por baixo. Esse código que mostrei até agora é super trivial de fazer, não foi mais que algumas poucas horas brincando. Mas a cereja do bolo seria mostrar como que comandos SQL de verdade funcionam e apesar das funções javascript que fiz terem nomes parecidos com SQL, ainda não é SQL. E aí fiquei coçando a cabeça, porque eu queria mostrar SQL, mas eu não queria gastar muito mais que um dia pra isso.</p>
<p>O episódio que lancei antes desse justamente explica o que é uma linguagem compilada e interpretada, e mencionei que tanto um compilador quanto um interpretador começam com um parser. E uma das formas de se fazer um parser é usar um software chamado Antlr4, que é feito em Java. Naquele episódio eu disse que não ia explicar ele. Pois bem, vou explicar rapidinho agora. O antl4 é um gerador de parsers. Lembram o que é um parser? É quando pegamos uma gramática, passamos o código fonte por um lexer pra conseguir uma coleção de tokens e passamos esses tokens pra um parser pra conseguir uma ParseTree.</p>
<p>Num interpretador ou compilador, essa ParseTree é transformada numa Abstract Syntax Tree ou AST, que daí passa por uma série de otimizadores pra reescrever o código da forma mais eficiente possível, e aí finalmente gerar o código de máquina tanto pra executar na hora, caso seja um Just in Time Compiler ou gerar um binário num arquivo, caso seja um Ahead of Time Compiler ou AOT. No meu caso, eu não preciso fazer tudo isso, só preciso ir até o ponto onde gera uma Parse Tree, pra a partir dela, fazer um transpiler, que vai converter SQL em Javascript. Entenderam onde eu quero chegar?</p>
<p>Escrever uma gramática do zero é extremamente tedioso e trabalhoso. Mas minha vantagem é que não estou inventando uma nova linguagem, pelo contrário, eu quero um SQL que seja o mais compatível possível com o SQL de verdade. E aqui vem outra vantagem do Antlr4. Ele tem uma comunidade muito esforçada que já se deu ao trabalho de escrever a gramática de praticamente todas as linguagens que você já ouviu falar e um monte que vocês nem sabiam que existiam. Vou deixar o link do repositório nas descrições abaixo, mas olha essa página do GitHub que coisa linda.</p>
<p>Lembram que eu falei da linguagem BCPL? Quer saber como é a gramática? Basta entrar aqui nessa pasta e abrir o arquivo <code>bcpl.g4</code> que é a extensão de gramática do antlr4. Olha o que eu expliquei no episódio anterior. Começa definindo o que ele entende por &ldquo;letras&rdquo;, são todas as maiúsculas e minúsculas. E essa distinção é importante porque tinha linguagens antigas que só entendiam comandos em maiúsculo. Continua definindo, o que é um dígito em octal, um dígito em hexadecimal, o que são dígitos numéricos.</p>
<p>E qual é o tamanho da gramática pra entender BCPL inteiro? Que é a linguagem que inspirou o C? Nada mais que 131 linhas, contando linhas em branco. E se a gente voltar pra primeira página, olha lá embaixo, uma pasta chamada &ldquo;python&rdquo;, dentro tem python2, e no python3 temos de novo arquivos .g4 que ele separou pro lexer e pra gramática do parser. E mesmo esse arquivo tem menos de 200 linhas.</p>
<p>Mas de volta à primeira página, o que nos interessa mesmo é essa pasta sql lá embaixo. Tem as gramáticas do mysql, postgres mas o que eu queria, e ainda bem que tinha, é do sqlite3, que é o banco de dados sql mais simples e provavelmente o mais usado do mundo. Isso porque enquanto um postgres da vida é usado em servidores, todo dispositivo IoT, internet das coisas, que é qualquer dispositivo com um mínimo de processamento com acesso a internet, precisa de um banco de dados local. Pense um roteador de wifi da sua casa. 99% de certeza que dentro usa um sqlite3. Pensa vários apps no seu celular Android, vários sqlite3. Pensa uma geladeira inteligente, certamente tem sqlite3 dentro.</p>
<p>Aliás, o que estou construindo neste episódio estou chamando de stupid database, porque é o banco mais besta e ao mesmo tempo mais simples com objetivo educacional, mas se quiser ver o menor banco de dados SQL realmente completo e funcional, tem que estudar o código C do Sqlite3. Existe um subprojeto chamado Sqlite Amalgamation que concatena os mais de 100 arquivos de código fonte num único arquivo &ldquo;sqlite3.c&rdquo; e por isso se chama amalgamation.</p>
<p>O sqlite3 inteiro consiste de 75% de código C e o resto é arquivos .h de cabeçalhos. Esse arquivão dá um total de quase 240 mil linhas ou 145 mil se tirar linhas em branco, totalizando 8.4 megabytes de código fonte. Se um dia realmente quiser saber em detalhes como um banco de verdade funciona, precisa entender como o sqlite3 funciona, O código fonte tá disponível pra ler e ir testando pedaço a pedaço. Bom trabalho de iniciação científica ou TCC pra quem tá na faculdade de ciências da computação.</p>
<p>Mas, explicar 145 mil linhas de código em um único episódio seria impossível então espero que se contentem com essa minha versão de stupid database. Enfim, falei tudo isso pra dizer que foi nesse respositório de gramáticas do Antlr4 que peguei emprestado os arquivos &ldquo;SqliteLexer.g4&rdquo; e &ldquo;SqliteParser.g4&rdquo;. E como eu não ia ter comandos como &ldquo;create table&rdquo;, &ldquo;alter table&rdquo; e coisas assim, saí apagando da gramática tudo que não ia suportar até ficar com uma versão mais reduzida. Ainda sobrou muita coisa que eu não implemento, mas apaguei o suficiente pra facilitar meu trabalho.</p>
<p>Daí eu precisei instalar o antl4, e pra isso é só ir no site deles e ver como instala, não vou detalhar aqui. Assumindo que já tá instalado, no terminal é só rodar o comando <code>antl4 -Djavascript</code> pros dois arquivos SqliteLexer e SqliteParser.g4. Esse flag &ldquo;-D&rdquo; diz em que linguagem ele vai gerar o lexer e parser. E dá pra gerar em praticamente todas as linguagens que quiser, seja python, java e no nosso caso, javascript. Isso gera esses arquivos &ldquo;.interp&rdquo; e olha só SqliteLexer.js e SqliteParser.js. Esses arquivos a gente não precisa mexer. Nem vou abrir porque pode assustar os mais fracos de coração.</p>
<p>O mais importante é que ele gerou esse SqliteParserListener.js. Esse podemos abrir e vamos descobrir um monte de funções vazias. Que diabos que são essas funções? E eles estão em pares, veja só aqui no começo temos uma função chamada &ldquo;enterParse&rdquo; e depois &ldquo;exitParse&rdquo;. Se abrirmos aquele arquivo que pegamos emprestado, o SqliteParser.g4 podemos ver aqui no começo que &ldquo;parse&rdquo; tem esse &ldquo;sql statement list&rdquo; e EOF que é End of File ou final do arquivo. Daí vemos que sql statement list tem vários sql statements e sql statement pode ser vários tipos como delete statement, insert statement, select ou update. Entenderam? É assim que ele começa definindo as regras do que esse parser consegue entender, e são justamente as operações que queremos. Então já sabemos que o ponto de entrada no parser vai ser por essa regra “parse” que engloba o arquivo inteiro de comandos SQL que passarmos pra ele.</p>
<p>A gente não mexe nesse arquivo de Listener também, porque se amanhã eu mexer no arquivo .g4 e mandar regerar com o comando <code>antl4</code>, daí vai sobrescrever nesses arquivos todos. Por isso criei esse outro chamado CustomListener.js. Ele é basicamente uma classe que extende da classe SqliteParserListener e lá embaixo eu copio todas aquelas funções vazias pra sobrescrever elas. Agora sim posso começar a brincar.</p>
<p>Eu não vou mostrar tudo em detalhes, depois vocês podem olhar o código fonte no meu repositório. Mas só pra entender vamos voltar pro arquivo principal desse diretório, o SplitQueries.mjs que é pra onde eu tava mandando os comandos SQL do arquivo <code>test.sql</code> lembram? Agora que expliquei o que são os principais arquivos, veja que nesse script eu importo todos eles, o Lexer, o Parser e o meu CustomListener. Ele começa recebendo um input, que pode ser uma linha de SQL ou várias linhas de SQL como o conteúdo do arquivo <code>test.sql</code>.</p>
<p>Uso a função InputStream da biblioteca antlr4 pra quebrar num stream de caracteres. Lembra o que são streams? Lembro que já expliquei isso em algum episódio, mas pra quem não sabe, iniciantes estão acostumados a carregar o conteúdo de um arquivo tudo de uma vez em memória, mas e se o arquivo não couber na memória? O jeito mais eficiente é ir lendo pedaços do arquivo de cada vez e ir processando aos poucos, pra isso abrimos um stream. Enfim, passamos esse stream pro Lexer, que criar uma lista de tokens a partir desse stream. Ou seja, ele recebe a linguiçona de strings e vai quebrando numa lista de tokens.</p>
<p>Agora passamos esses tokens pro Parser e em seguida pedimos pra construir a Parse Tree, a árvore, como expliquei no episódio anterior. Pra você que é de front-end, é como quando o navegador carrega uma página HTML, que é um stream de caracteres, e gera o DOM, a árvore que representa aquele HTML. Agora criamos uma instância do nosso CustomListener passando a referência pra esse array “result” que é onde vamos escrever o javascript final. Pra gerar essa parse tree, começamos da primeira regra que tem no nosso arquivo .g4 do parser, que é a regra chamada &ldquo;parse&rdquo;, por isso chamamos <code>parser.parse</code>.</p>
<p>Finalmente, fazemos o antl4 passear pela parse tree, nó a nó, por isso essa função chama <code>ParseTreeWalker</code> e damos como parâmetro pra ele o Listener, que tem as regras de conversão, e a árvore propriamente dita. E é aqui que entra meu CustomListener. Vamos entrar lá de novo. Aqui eu vou dar uma trapaceada porque quero gerar o javascript baseado no meu fake sql, lembra? As funções em javascript que eu criei chamada &ldquo;select&rdquo;, &ldquo;from&rdquo;, &ldquo;orderBy&rdquo;. Pra isso eu vou pegar os pedaços que a ParseTree vai me dando e vou preenchendo nesse objeto construído pela função <code>buildSqlStruct</code> que eu inventei. Ela tem os pedaços que formam um comando SQL. Olha só como tem um array pra colunas, outro array pra condições, e flags pra saber se tem &ldquo;order by&rdquo; e coisas assim.</p>
<p>Logo embaixo tem a função <code>enterParse</code>, mas nesse momento eu não preciso fazer nada. Deixa ele ir navegando pela árvore até achar um comando como &ldquo;insert&rdquo; ou &ldquo;select&rdquo;. Digamos que eu tenha um comando como <code>insert into users (name, age, city) value ('Katar Hol', 37, 'Thanagar')</code> como mostrei lá no começo. Um comando sql normal de insert. Olha o nosso arquivo de parser .g4, a regra do insert se chama <code>insert_stmt</code> de statement. Então provavelmente quando o parser achar o insert, vai chamar a função <code>enterInsert_stmt</code> passando um contexto nessa variável <code>ctx</code> que é a sub-árvore do comando de insert.</p>
<p>Essa parte foi a mais trabalhosa que é decifrar o que vem nesse contexto. E já aviso que a documentação que achei online não foi muito útil não. Na prática, o que eu aprendi a fazer foi executar o parser com um comando SQL de teste e vasculhar o que vem no contexto usando o bom e velho <code>console.log</code> e eu entendi que o que importa é saber quem são os nós filhos, ou seja <code>ctx.children</code>. Então, vamos lá na função de entrada do insert e deixa eu colocar esse <code>console.log</code> aqui. Se eu printar o ctx inteiro vai ser super longo, então só imprimo o nome da classe a o <code>getText()</code> que é representação em texto desse nó. Vamos abrir o REPL e mandar o comando insert de teste.</p>
<p>Olha só o que ele imprime: os nós, que são instâncias de TerminalNode costumam ser tokens como o comando &ldquo;insert&rdquo; e as outras partes do comando como &ldquo;into&rdquo;. Daí quando tem um nome de tabela, com outra super classe, no caso Table_nameContext, daí vem outro TerminalNode que é a abertura de parênteses. Daí temos um Column_nameContext que é o campo &ldquo;name&rdquo; e assim por diante. Foi isso que o Lexer fez, ele quebrou o comando e o Parser organizou nesse sub-árvore de nós que podemos navegar. Vamos voltar pro código no Listener.</p>
<p>Já sabemos que é só navegar por cada nó dos filhos do contexto, então pra cada <code>child</code> de <code>ctx.children</code> eu faço um switch case. Se a super classe for Table_nameContext eu preencho o nome da tabela naquele objeto sqlStruct. Próximo nó, se for um TerminalNode, não faço nada. Próximo nó, se for um Column_nameContext vou acumulando numa lista de colunas no objeto sqlStruct e mesma coisa se forem ExprContext, são os valores, então vou acumulando na lista <code>values</code> no sqlStruct. Quando acabar a lista de nós filhos, sai dessa função. Daí o Walker vai chamar a função de saída que, por convenção, vai se chamar <code>exitInsert_stmt</code>, por acaso é a função logo embaixo nesse Listener.</p>
<p>Pronto, quando entra nessa função sabemos que navegamos por todo o comando insert. Agora é só pegar o que cadastramos no objeto sqlStruct e literalmente montar uma string com a versão do comando em javascript. Primeiro eu monto uma string combinando o nome de cada coluna como chave, dois pontos, o valor, que é a sintaxe de javascript pra montar um objeto. Depois eu começo a montar a função &ldquo;insert&rdquo;, concateno o nome da tabela e depois junto os valores com vírgula entre chaves. Isso vai gerar esse comando em javascript que eu mostro no REPL antes de executar.</p>
<p>Expliquei meio rápido mas deu pra entender a idéia? Todo comando que eu passar praquela função SplitQueries vai passar pelo Lexer e Parser, e vai gerar uma árvore, a Parse Tree. Daí eu ando nessa árvore, nó a nó, usando as funções do Listener. Toda vez que quero implementar um comando SQL, pego a função de entrada, como a <code>enterInsert_stmt</code>, pego o contexto que é a sub-árvore e vou dividindo os pedaços que preciso e acumulando na minha estrutura sqlStruct. E na função de saída monto a string com a versão em Javascript, que é o que a função SplitQueries vai retornar, no caso pro REPL.</p>
<p>Vamos abrir o script do tal REPL, a linha de comando que vim mostrando até agora. Eu uso uma biblioteca chamada &ldquo;prompt-sync&rdquo; que faz exatamente o que o nome diz: abre um prompt que fica esperando eu escrever algum comando. Tá vendo ele escrevendo &ldquo;stupid query&rdquo;? Daí eu digito o comando insert e ele captura nessa variável <code>query</code>, que vai passar pra função <code>parseScriptWithSplitQueries</code> que tá definido lá em cima. Igual eu tava fazendo no script <code>stupid.mjs</code> que lia comandos do arquivo <code>test.sql</code>.</p>
<p>Essa função passa o script pro SplitQueries, que é o parser, que vai navegar e transformar a árvore e cuspir um string com o comando javascript do nosso fake-sql. Pra cada linha que ele cuspir dou um <code>eval</code> e executo, imprimo o resultado na tela com o <code>console.table</code> e no final abro o prompt de novo, e fica nesse loop, que é o que um repl tem que fazer mesmo. E pronto, é assim que se constrói um interpretador simples de SQL em javascript.</p>
<p>O que eu fiz no Listener pra converter o insert em javascript agora preciso fazer a mesma coisa pros comandos delete, update, e select, que é o mais complicado de todos. Vamos só bater o olho no select. Começa pela função <code>enterSelect_stmt</code>. Diferente do insert que forcei olhar pros nós filhos direto, aqui só crio o objeto sqlStruct que vou precisar preencher e deixo o Walker passear pelos próximos nós pra ir coletando o que eu preciso. Por isso falei que é mais complicadinho, porque precisa implementar várias regras diferentes do Listener que não vou mostrar em detalhes aqui.</p>
<p>Em particular um select é complicado porque nas condições que começa depois do Where eu posso ter uma série de expressões, e expressões dentro de expressões. Começo a capturar lá em cima na função <code>enterExpr</code>ession. E aqui eu chamo uma função que vai ser recursiva, justamente porque pode ter expressões dentro de expressões. Falei que ia ser complicado. Não tenta entender linha a linha num primeiro momento, começa tentando entender só o conceito.</p>
<p>Não vou nem tentar ir passo a passo, de novo, fica de lição de casa, mas só pra mostrar rapidinho, essa função <code>recursiveChildren</code> vai tentando interpretar uma expressão de cada vez. Por exemplo, em SQL podemos fazer algo como &ldquo;age between 60 and 2000&rdquo; e em javascript isso tem que virar &ldquo;age &gt;= 60 &amp;&amp; age &lt;= 2000&rdquo; e esse tratamento começa nesse if que checa se esbarrou num &ldquo;between&rdquo; e cria uma estrutura pra isso.</p>
<p>Ou pior, em SQL podemos ter algo como &ldquo;city in (&lsquo;Gotham&rsquo;, &lsquo;Metropolis&rsquo;)&rdquo; e em javascript isso tem que virar &ldquo;[&lsquo;Gotham&rsquo;, &lsquo;Metropolis&rsquo;].includes(city)&rdquo; e de novo olha aqui no código o if que ativa se esbarrar no token &ldquo;IN&rdquo; pra criar uma estrutura de <code>range</code>. Continuando, em SQL o &ldquo;NOT&rdquo; vem antes da expressão, então quando falo &ldquo;NOT age &gt; 40&rdquo; tem que virar &ldquo;age &lt;= 40&rdquo; que é o inverso. Lá em cima eu fiz uma função chamada <code>invertOp</code> pra inverter todos os operadores. Se for igual vira diferente, se for maior, vira menor ou igual e assim por diante.</p>
<p>Enfim, pra conseguir pegar a maioria dos casos mais comuns de select, eu tive um bom trabalhinho. Por isso que agora consigo ir no meu repl e digitar vários tipos de SELECT e ele vai conseguir montar. Quando terminar de transformar todos os nós que preciso da sub-árvore do SELECT, vai cair na função de saída, o <code>exitSelect_stmt</code>. Só deem uma olhada. No final vai ter preenchido estruturas como sqlStruct.orderby, sqlStruct.table, sqlStruct.conditions e assim por diante. Daí é só montar a string com minha sintaxe de javascript do fake sql e retornar.</p>
<p>Eu sei que parece complicado mas realmente não é. Se você já teve que usar jQuery pra manipular nós de HTML do DOM num navegadow, é basicamente o mesmo conceito. Quando a gente tem um HTML como &ldquo;<ul><li>1</li><li>2</li></ul>&rdquo; que é uma lista, o contexto começa com o nó &ldquo;ul&rdquo;, ele vai ter 2 children que são nós &ldquo;li&rdquo;, o primeiro &ldquo;li&rdquo; vai ter valor 1, o segundo &ldquo;li&rdquo; vai ter valor 2. E se tivermos isso aberto no DOM que podemos manipular com javascript, podemos transformar isso em dois parágrafos, por exemplo. E é algo semelhante que fui fazendo nesse Listener, convertendo nós de SQL em string Javascript, pra todos os comandos que eu quis suportar no banco stupid.</p>
<p>Esse projetinho ainda tá incompleto, como falei antes, coisas como inner join, outer join, sub-selects e coisas assim eu não implementei. Fica de exercício pra vocês se quiserem. Mas vamos recapitular: até aqui fiz um banco de dados em memória bem stupid, que são só arrays de objetos. Fiz funções javascript com nomes que se assemelham aos comandos SQL e chamei isso de Fake SQL. E de bônus usei o Antlr4 pra pegar a gramática do Sqlite3, gerar lexer e parser em javascript e preencher o listener com código pra transpilar SQL de volta em javascript que chama minhas funções de Fake SQL.</p>
<p>Mas até aqui só expliquei como que de comandos SQL dá pra executar alguma coisa por baixo. Mas pra ser um banco de dados de verdade, ainda faltam funcionalidades que vou explicar só em conceito. O mais importante é vocês entenderem índices. Todo iniciante esquece que existem índices porque não entendem a importância. Alguns sabem que é pra aumentar a performance, mas como em máquina de desenvolvimento, que você dá insert em poucas linhas na tabela, não faz quase nenhuma diferença, todo mundo esquece de usar. Então deixa eu explicar o problema.</p>
<p>Pra ilustrar criei esse script de benchmark chamado <code>bench_index.mjs</code>. Agora, esquece o parser de SQL, vamos usar só o fake sql. Notem que lá em cima eu carrego uma nova biblioteca chamada <code>fake-sql-index.mjs</code>. Pula por um segundo. A primeira função aqui é um timer genérico, passo um comando e ele grava a hora logo antes, a hora logo depois, subtrai os dois pra saber quantos milissegundos levou pra processar. Depois faço uma rotina de criação de índices. Vou explicar o que isso significa já já, mas na prática estou criando um índice pra cada coluna da nossa tabelinha.</p>
<p>Em seguida crio uma nova função de insert decorada em cima do insert anterior. Ignorem por enquanto, já explico. Agora vem a parte da carga, vou duplicar aquela tabela de 37 usuários 18 vezes. Só que é acumulativo, então da primeira vez, 37 vira 74. Daí duplica de novo e vira 148, daí duplica de novo e vira 296 e faz isso 18 vezes, aumentando a quantidade de objetos exponencialmente até dar quase 10 milhões de objetos em memória.</p>
<p>Agora olhem o primeiro teste do benchmark, é usando minha função <code>from</code> lembra? Que vai fazer um eval chamando a função <code>.filter</code> desse nosso array de quase 10 milhões de objetos e checando um a um se a propriedade <code>city</code> é igual a &ldquo;Wakanda&rdquo;. Ele vai checar isso quase 10 milhões de vezes, objeto a objeto. Porque não tem outra forma nessa versão simples e no nosso teste vai levar algo na faixa de 150 milissegundos, o que é bem rápido porque já tá tudo na memória e fuçar RAM é muito rápido. Se fosse pesquisar num HD seria 100 ou 200 vezes mais devagar que isso, levando vários segundos inteiros pra fazer a mesma pesquisa.</p>
<p>O segundo teste é diferente, ele usa outras funções que ainda não mostrei e que está naquele arquivo &ldquo;fake-sql-index.mjs&rdquo;. Logo no começo chamei a função <code>createIndex</code> dessa biblioteca. Vamos ver o que ela faz. Olha só, já tinha uma lista chamada <code>databases</code> pra representar o banco de dados e agora criei outra estrutura global chamada <code>indexes</code> pra representar índices. Daí crio um índice pra cada chave da tabela. Então a chave pra idade da tabela users seria <code>indexes['users']['age']</code> e cada uma delas vai ter uma instância desse tal de <code>AVLTree</code>.</p>
<p>AVLTree é parecida com uma Red-Black Tree. Expliquei isso no vídeo de Árvores, lembra? Deixa recapitular o conceito rapidinho aqui. Eu tenho aquela lista de usuários com nome, idade e cidade, certo? Se eu quiser achar todo mundo da cidade de Wakanda como faz? Do jeito que tá agora preciso olhar o 1o elemento e vai ser o Peter Parker em Nova Iorque, não é. Pula pro próximo, vai ser Clark Kent, em Metropolis. Só quando chegar na linha 12 que vamos achar o T&rsquo;Challa em Wakanda. Mas eu não sei se é só ele, vamos checando um a um de novo até chegar na linha 25 e achamos a Okoye. Mas ainda não sabemos se acabou, então tem que ir até a última linha 37 que é a Jubilee em Los Angeles e agora sabemos que só tem 2 usuários de Wakanda, mas pra saber isso tivemos que checar 37 vezes. Tem como melhorar isso? Tem.</p>
<p>O jeito mais ingênuo é jogar numa árvore de procura binária. O processo é simples. Primeiro de tudo ordemos a lista de cidades. Vou simular aqui. Depois, não começamos do começo, da linha 0. Começamos do meio. Metade de 36 é 18. E na linha 18 temos New York. Agora, Wakanda é maior ou menor que New York? Por ordem alfabética é maior, então ignoramos tudo abaixo da linha 18 e vamos pra metade entre 18 e 36, que é a linha 27. E 27 continua sendo outro New York. Wakanda ainda é maior, então pegamos o meio entre 27 e 36 que é 31. De novo Wakanta é maior. O meio entre 31 e 36 é 33. E nessa linha temos San Francisco. Ainda Wakanda é maior. Meio de 33 e 36 é 34. Agora é Themyscira. Wakanda ainda é maior. E finalmente, entre 34 e 36 temos 35, onde encontramos o primeiro Wakanda.</p>
<p>Esse foi por acaso, o pior caso, onde procurei Wakanda que fica no final da lista. Mas olhem só, no pior caso anterior tinha que vascular 37 vezes. Mas desse jeito binário de ir jogando metade fora a cada checagem, tivemos que fazer só 6 comparações. Ou seja, 6 vezes menos comparações no pior caso. Se em vez de eu procurar na tabela principal, procurar no índice ordenado de cidade, vou descobrir as duas últimas linhas depois de só 7 comparações e isso me resulta nos ids 12 e 25. Agora pego esses ids na tabela principal e acho o T&rsquo;Challa e a Okoye, totalizando 7 comparações e 2 operações pra pegar os objetos na tabela de usuários. 9 operações, que é quase 4 vezes menos operações.</p>
<p>Vamos ver o benchmark das 10 milhões de linhas. Vasculhando, que em mundo de banco de dados é o que chamamos de fazer um &ldquo;table scan&rdquo; porque estamos escaneando linha a linha da tabela inteira, 10 milhões de vezes, levou na casa de 150 milissegundos. Mas agora buscando no índice, que é o que faz essa função getFromIndex, vai custar na faixa de 10 milissegundos. 15 vezes mais rápido. Mas aí vai levar uns 35 milissegundos pra pegar os ids e buscar os objetos na tabela, que é o que faz essa função <code>getFromIds</code>, um total de uns 40 milissegundos, que continua sendo pelo menos 3 vezes mais rápido do que um table scan. Lembrando que esses tempos só são em millisegundos porque estamos em RAM, se fosse em disco seria muito mais lento.</p>
<p>No caso, por causa do javascript, essa função <code>getFromIds</code> tá prejudicando nosso benchmark. Mas se fosse em C estaríamos falando de uma diferença ainda maior, na casa de tudo 10 vezes mais rápido mais ou menos. Antes que alguém comece a chiar nos comentários, Javascript não é sempre X vezes mais lento que C, mas nesse trecho específico sim. Enfim, uma AVLTree e uma Red-Black Tree, diferente de uma árvore de procura binária simples, são árvores balanceadas. Eu mostro no outro video a diferença de forma animada, mas em resumo, significa que o processo de ordenar e colocar na árvore exige uma operação de rotação pra fazer o balanceamento, então a inserção na árvore é um pouquinho mais lenta do que uma árvore binária simples, mas na hora de procurar vai exigir menos comparações então a pesquisa é mais rápida.</p>
<p>Pra todas as pesquisas serem mais rápidas, o certo é ter índices pra cada expressão que queira procurar. Se quisesse fazer uma pesquisa por idade e cidade ao mesmo tempo, eu deveria ter um índice que contenha esses dois valores na mesma árvore. Se quiser procurar também separado por idade e em outras pesquisas procurar por cidade, daí preciso ter outro indice separado pra cidade e outro pra idade. Mas aí você pensa, porque diabos tenho que ficar criando índices manualmente, se tudo fica mais rápido com índices, o banco já não cria índices pra todas as colunas automaticamente como eu fiz no meu banco estúpido aqui nesse trecho?</p>
<p>Agora é hora de falar daquela função nova de insert decorada. Eu usei um decorator só pra não ter que mexer na função de insert original e só plugar a funcionalidade de índice. Vamos ver o que faz esse <code>decorateInsert</code>. Abrindo a biblioteca &ldquo;fake-sql-index&rdquo;, vemos que ela recebe a função <code>insert</code> antiga e devolve outra função. Dentro ela chama o insert original, mas na sequência insere também os valores nos índices de cada coluna. Ou seja, se estivermos inserindo um novo objeto com os campos name, age, city e id, são 4 novos inserts. O que antes era só 1 operação de insert no array de users, pra atualizar todos os índices, virou um total de 5 inserts. A operação de insert ficou pelo menos 5 vezes mais lenta.</p>
<p>Imagina uma tabela com 50 colunas. Se todas tiverem índices, cada insert vai exigir 51 operações de insert. Um pra linha na tabela principal e 50 inserts pros índices de cada coluna. Então o insert ficaria 50 vezes mais lento. E não é só isso. Concorda que toda vez que fizer update também precisa atualizar todos os índices? E se fizer delete também tem que deletar de todos os índices? Portanto insert, update e delete todos ficam lentos. E é por isso que não se faz índices pra todas as colunas.</p>
<p>Índices é um trade-off de deixar operações de pesquisa muito mais rápidas ao custo de deixar operações de escrita muito mais lentos. E nós programadores é que temos que avaliar, testar e achar formas de criar o mínimo de índices possível pra ter a maioria das pesquisas rápidas sem prejudicar demais as operações de escrita. Da mesma forma, não ter índice nenhum significa que as pesquisas podem ser 10 vezes mais lentas, porque vai cair num table-scan. Na prática, todo select complexo vai ser uma combinação de pesquisa em índices e table-scan pras coisas que não tem índice. E é por isso que existe o comando EXPLAIN na maioria dos bancos de dados pra explicar qual estratégia que o banco vai usar pra executar sua pesquisa.</p>
<p>Se quiser ficar bom em fazer queries que tiram o máximo dos seus índices, estudem como funciona o comando EXPLAIN. Internamente um banco de dados como Postgres pode pegar seu SELECT com condições WHERE complicadas e dividir o trabalho, por exemplo, pra rodar em paralelo em múltiplos núcleos do CPU. Ele vai tentar sempre otimizar a query pra rodar no menor tempo possível, usando a menor quantidade recursos que puder. É bem mais complicado do que eu dar um &ldquo;filter&rdquo; num array, obviamente. Mas já deve dar pra dar uma idéia.</p>
<p>De curiosidade, além dos comandos básicos de SQL como select, insert, ainda podemos programar stored procedures, que são programinhas em SQL, com condicionais como IF, variáveis e tudo mais. No caso de Postgres, a linguagem mais comum é o PL/pgSQL, num Oracle é o PL/SQL, num SQL Server é o T-SQL. Um postgres vai passar o código por um parser mais complicado do que eu mostrei e vai usar LLVM pra fazer o just in time compile desses programinhas, incluindo a fase de transformation passes pra otimizar o código antes de tentar executar. Então existe um JIT até no seu banco de dados hoje em dia. Todo banco de dados tem um interpretador embutido.</p>
<p>Seguindo no nosso banco estúpido ainda temos um probleminha. Notem que estamos usando o console do Repl do banco stupid pra inserir, apagar linhas, mas quando saímos e entramos de novo, os dados que mudamos não estão mais lá porque sempre carregamos do zero, do mesmo arquivo &lsquo;users-database.mjs&rsquo;, mas nunca salvamos em cima desse arquivo. Portanto os dados são fixos. E se a gente quisesse gravar as mudanças em disco pra persistir? Ah, isso é fácil, alguns poderiam dizer. Basta fazer o que todo tutorial de javascript já explicou: transformar a lista de objetos num arquivo JSON e gravar. Certo?</p>
<p>Totalmente errado. E nem meu banco é stupid o suficiente pra fazer isso. Na realidade vou quebrar o problema em dois. Um banco de dados de verdade tem no mínimo dois mecanismos, pra tanto persistir dados, quanto garantir a integridade desses dados, em particular num banco SQL. Se você estudou o básico de SQL já deve ter ouvido falar que bancos relacionais tem a característica de ser ACID, certo? Atomicidade, Consistência, Isolamento e Durabilidade. Se nunca ouviram falar, é obrigatório estudar isso. Hoje vou falar só de um pequeno aspecto de consistência e durabilidade.</p>
<p>Em particular, tudo que um banco responde &ldquo;gravei&rdquo; depois que você mandou inserir, tem que estar garantidamente gravado de verdade quando pesquisar. Todo conjunto de operações que eu mandar numa transação, ou todas executam ou nenhuma executa. Não pode ter operações feitas pela metade. Tudo isso porque uma característica importante é integridade. Tudo que o banco me confirmar eu preciso acreditar que fez realmente tudo certo, sem exceções. Essa é a característica de todo banco de dados relacional. O mesmo não se aplica a bancos NoSQL como Redis ou Dynamo, eles fazem trade-offs diferentes, mas outro dia falo disso.</p>
<p>Um dos mecanismos pra ter algumas dessas garantias é o transaction log ou journal. Um sistema de arquivos modernos como NTFS, ext4 ou APFS também tem esse mecanismo, como já expliquei no video de sistemas de arquivos. Como o nome diz é basicamente um arquivo de log, cuja característica principal é ser um arquivo append-only, ou seja, que nunca muda o que já foi escrito e só dá pra ir apendando, só adicionando na frente. O conceito é que antes de executar uma operação você primeiro grava que operação vai fazer nesse log e depois executa. Caso dê alguma catástrofe, tipo acabar a luz e o computador desligar, da próxima vez que reiniciar ele consegue dar replay nesse log e refazer as operações pra trazer os dados de volta num estado consistente.</p>
<p>Quero simular isso rapidinho pra vocês verem. Pra isso criei um outro módulo chamado &ldquo;fake-sql-transact&rdquo;. Abrindo o código, as duas primeiras funções são pra abrir o arquivo de log em modo append  - pra isso que serve esse “a” aqui -, e a segunda é pra apendar alguma coisa nesse arquivo. Em seguida, tenho decorators pras três operações principais que modificam os dados, um pra insert, outro pra delete e outro pra update. Repetindo, um decorator recebe como argumento o nome da função original e devolve outra função como retorno. Dentro dessa nova função vou salvar o comando no log de transações e só depois executo de fato o insert, delete ou update.</p>
<p>Pra testar dupliquei o script de repl que estava usando até agora e fiz um <code>replTransact.mjs</code> pra ter essa funcionalidade. Olha o que faço. Primeiro importo as funções insert, deleteFrom e updateFrom do módulo de fake-sql com outros nomes. Daí o resto importa igual. Agora chega nesse trecho onde começo abrindo o arquivo de log de transações que chamei de <code>transact.log</code>. A primeira coisa que faço é checar se tem algum coisa nesse arquivo e, se tiver, essa função de replay vai repetir todas as operações lá dentro. Como toda vez eu carrego sempre os mesmos dados do arquivo de <code>users-database</code>, eu sempre perdia tudo que fazia nela. Agora isso vai recuperar o que fiz baseado no log.</p>
<p>Em seguida abro o arquivo em modo append e recrio as funções de insert, deleteFrom e updateFrom com versões decoradas que recebem o objeto do arquivo de log aberto. A partir de agora quando chamar um insert, por exemplo, ele vai salvar a operação no log e depois fazer as alterações no array de objetos. O resto do script é igualzinho, então vamos sair, ir pro terminal, e carregar esse novo repl. A primeira coisa que vou fazer é dar insert em mais dois usuários. Vamos inserir os desconhecidos de Paradis. Insert do Levi Ackerman, 37 anos, depois deixa eu inserir uma parente distante dele, Mikasa Ackerman, 20 anos.</p>
<p>Pronto, agora posso fazer <code>select name from users where users.city = 'Paradis'</code> e estão lá direitinho. Vamos dar Ctrl+C pra sair e abrir o Repl de novo. E olha só, ele executa a função de replay e reinsere os dois. Se eu fizer o mesmo select, eles estão lá direitinho. E com isso eu implementei um tipo estúpido de persistência desses dados. Imagina que isso fosse um servidor de banco normal, como um Posgres, e bem na hora que tá salvando essas linhas em disco, dá uma pane, acaba a energia ou o sistema crasheia. O banco ia ficar num estado inconsistente, mas como antes de tentar gravar na tabela ele salvou as operações num transaction log, no próximo restart, vai conseguir fazer um replay, como o que simulei nessa versão simples.</p>
<p>Todo banco de dados e todo sistema de arquivos moderno tem um transaction log ou o outro nome que se usa pra isso, que é um journal, que é inglês pra diário. Óbvio que diferente da minha versão estúpida, ele não vai dar replay de todo o arquivo de transactions toda vez que restarta, isso seria estúpido. Ele só dá replay nas últimas transações que não concluíram até o fim. E isso leva à última característica de um banco de dados que quero discutir hoje, que é: como se salva esses dados numa tabela de verdade num HD?</p>
<p>Bom, já mostrei que meu banco estúpido sempre carrega os dados de um arquivo como o &ldquo;users-database&rdquo;. E nesse caso estou persistindo os dados em formato texto, em javascript. Acho que todo mundo aqui já salvou dados assim de outra forma, como um arquivo JSON. Bastaria chamar a função <code>JSON.stringify</code> e salvar a string num arquivo, certo? Por que a gente não faz só isso? Toda vez que insere ou modifica uma linha naquele array de usuários, basta chamar o <code>JSON.stringify</code> e salvar tudo no arquivo. Fácil, não?</p>
<p>E isso estaria errado. Vamos entender o raciocínio pra vocês nunca cometerem esse erro. O que faz uma função como <code>JSON.stringify</code>? Ele executa uma operação que chamamos de serialização ou marshalling. Daí quando lemos de um JSON e recriamos o array de objetos em memória, chamamos de desserialização ou unmarshalling. Esse é o tipo de operação que tem literalmente em toda biblioteca de APIs que você já tenha usado, como APIs pra integrar com meios de pagamento, ou APIs pra fazer bots de instagram ou twitter. Toda API te devolve um XML ou um JSON e você converte pra objetos da sua linguagem pra poder manipular os dados. Daí prepara um payload qualquer e serializa de volta em XML ou JSON pra mandar pra API.</p>
<p>Essa operação necessariamente duplica os dados em memória, pra começar. Você já tem o array de objetos em memória, e gera uma versão em JSON, em texto, que também tá em memória. Ambos vão ocupar o dobro ou mais de espaço. Os dados no array estão em binário e toda vez que transforma binário numa representação legível em texto, isso ocupa mais memória. Vamos ver quanto. Eu fiz um scriptzinho besta que usa a biblioteca &ldquo;object-sizeof&rdquo; que instalei via npm. E lá embaixo faço uma versão serializada do array de users usando o <code>JSON.stringify</code>.</p>
<p>Olha só. A string com a conversão em JSON do array tá ocupando 4.3 kilobytes na memória. Já a versão original binária em memória do array de objetos de users ocupa uns 3 kilobytes. Portanto a versão JSON é mais de 40% maior. Imagina se fosse um array gigante, com 1 gigabyte. Significa que o JSON ocuparia algo na ordem de 1.4 gigabytes. 400 Mega a mais por causa da conversão em texto e do formato JSON. Representações em texto de estruturas de dados fazem o trade-off de ocupar mais espaço pra gerar um arquivo que é mais fácil de um ser humano como nós, programadores, conseguirmos manipular num editor de textos. Por isso é um bom formato pra arquivos curtos, que não vão crescer o tempo todo. Mas em termos puramente de performance, trafegar JSON é um desperdício de espaço, banda e processamento.</p>
<p>Exatamente por isso que empresas como o Google preferem usar outro protocolo pra fazer comunicação entre serviços, como o ProtoBuf, que é um protocolo binário de formato de dados. Nenhum game que você joga online trafega JSON pra atualizar a posição do seu personagem no jogo, sempre é um protocolo binário. Mas pra APIs de coisas como mandar mensagens automatizadas no Whatsapp ou Twitter, eles oferecem um protocolo baseado em JSON, porque a maioria das pessoas nunca ia conseguir montar um pacote binário. E também porque costuma ser poucos dados trafegados. Num jogo precisa estar trafegando dezenas ou centenas de pacotes de dados por segundo, por isso todo byte conta. Numa API de mensagens ou pagamentos, você manda poucos pacotes de dados, por isso, mesmo que seja 40% mais pesado, não vai fazer tanta diferença assim pra você.</p>
<p>Da mesma forma, num banco de dados, a gente primeiro não quer perder 40% de espaço gravando num formato ineficiente como JSON ou XML ou qualquer outro protocolo baseado em texto. Mesmo desconsiderando isso, ainda tem outro problema. Uma função como JSON.stringify, converte a estrutura de dados do array inteira de uma só vez pra texto. Depois não tem como inserir ou modificar só uma linha. Como que adiciona um novo elemento no JSON? Não tem como de maneira rápida. E um banco de dados vai o tempo todo aumentando de tamanho e não dá pra ficar convertendo de binário pra texto, tabelas inteiras toda vez. É inviável. Tem que ter um jeito de ir adicionando só um insert ou update de cada vez, sem mexer no que já tava gravado, sem criar outro arquivo e sobrescrever por cima.</p>
<p>Pra gravar em disco queremos gravar em formato binário, algo próximo da tal árvore ordenada que mencionei antes e que simulei com índices usando uma árvore AVL. Você poderia pensar, ok, todo Nó de uma árvore contém a referência ou ponteiro na memória pra outros Nós. Basta gravar o nó em disco e mudar de ponteiro em memória pra endereço no disco, daí consigo navegar pelos nós no disco e consigo inserir novos nós fácil, certo?</p>
<p>Nos videos sobre sistemas de arquivos eu explico como que funciona um sistema de partição, endereçamento em sistemas de arquivos e tudo mais. Recomendo que dêem uma olhada. Mas pros nossos propósitos basta saber que na prática o sistema operacional enxerga um disco como se fosse um array gigante de dados, começando com a posição zero e incrementando pra 1, 2, 3 etc até acabar o espaço de 64-bits, que é endereços pra caramba, terabytes e terabytes. Então beleza, é parecido como memória funciona, que pra uma linguagem é como se fosse um arrayzão gigante que começa em 0 e vai endereçando até acabar a RAM, também com endereços de 64-bits. Então tá fácil, dá pra gravar um binário em RAM pra um binário em disco só convertendo as posições de cada nó quando passa de um arrayzão em memória pro arrayzão em disco.</p>
<p>Mas discos de HD tem uma diferença importante. Vamos pensar a árvore AVL. Deixa eu mostrar uma representação gráfica de como seria a árvore de índice de idades. Vou inserir aqui todas as idades de todo mundo que tá no array de usuários. Ela vai ficar assim. Conseguem enxergar que essa árvore é uma lista ordenada? Começa lendo da esquerda pra direita. Olha só. 22, 25, 27, 30, 30, 30, 30, 32, 33, 33, 35, 35, 35, 35 etc.</p>
<p>E se eu quiser achar todo mundo com idade maior que 40? Começa descendo tudo pra esquerda. 22 é menor que 40, vai pra direita, 27 é menor que 40, sobe, 25 ainda é menor, 30 é menor, sobe, 30 ainda é menor, 33 é menor, sobe 30 é menor, 35 é menor, sobe, 35 é menor. sobe, 40 é menor. Desce tudo até 40, é menor, opa 41. sobe, 42. opa. Daqui pra direita é tudo maior que 40. Então eu tenho no final 10 endereços pras posições na memória onde estão esses nós.</p>
<p>Essas posições em memória não são necessariamente consecutivas. Eu peço um espaço pro gerenciador de memória, tipo malloc, e ele me dá algum endereço que eu não me preocupo. Expliquei isso no episódio de gerenciamento de memória, dêem uma olhada depois. Mas enfim, saiba que toda vez que você inicia uma nova variável na sua linguagem, por baixo a variável é só um nome pra alguma posição na memória, um endereço, que você não sabe. Uma das utilidades de uma linguagem de programação é esconder esses endereços de você pra não ficar complicado. Em Assembly você teria que lidar direto com o endereço. Em disco é a mesma coisa, só que em disco vai ser a localização em coordenadas tridimensionais de qual dos discos, em qual trilha e em qual posição da trilha.</p>
<p>Tão vendo esse CD aqui, um HD é como se fossem vários CDs um em cima do outro. Em cima e embaixo de cada disco desse tem um cabeçote com um leitor, que vai navegar nos diversos cilindros ou trilhas desse disco. Agora imagina que aqueles 10 endereços que retornou pras idades maior que 40 seja cada um num disco diferente, em trilhas diferentes, em posições aleatórias. Concorda que pra ler tudo, o HD vai ter um trabalhão? Especialmente porque os discos não estão parados, eles ficam girando sem parar dentro do HD e o cabeçote tem que ir lendo até bater no endereço que foi pedido, daí ele muda de cilindro, e procura outro endereço. É muito trabalhoso pegar endereços aleatórios num disco, é muito lento. HDs funcionam melhor quando queremos pegar pedaços mais longos de dados de uma só vez numa única passada do cabeçote na trilha.</p>
<p>E essa nossa árvore AVL é super curtinha. Imagina um banco de dados de milhares ou milhões de nós. Seu HD ia fritar pra ficar procurando nós individualmente e aleatoriamente. Mas tem jeito melhor? Tem sim, na verdade tem dois jeitos, as árvores B-Tree e B+Tree que eu cheguei a mencionar no episódio de árvores e agora espero que faça mais sentido pra que eles servem. Deixa eu mostrar como ficam as mesmas idades ordenadas organizadas numa árvore B-tree.</p>
<p>Nem vou inserir todo mundo, só as idades dos 10 primeiros usuários. Olha o formato que essa árvore tá ficando. Entenderam? Cada nó pode ter mais de um valor. Em particular se eu pesquisar só quem tem mais de 40 anos, aí vou ter só esses dois grandes nós aqui na direita. E eles vão ser lidos do disco em no máximo 2 operações, em vez de ter que pesquisar e ler de 10 endereços aleatórios como no exemplo da árvore AVL. A grande sacada é justamente isso de acumular vários valores um atrás do outro num único nó grandão, num bloco ou cluster. Isso porque um HD não lê byte a byte, ele lê em setores ou blocos de uma só vez. Todo HD vai sempre ler pelo menos um bloco de 512 bytes ou até 4 kilobytes de uma só vez e colocar num buffer.</p>
<p>Se não ficou claro, lembra quando se formata um HD novo? Na tela de formatação ele pergunta sobre tamanho da unidade de alocação. Por padrão costuma ser 4 kilobytes que é o tamanho do setor. É a menor unidade que ele lê ou grava de uma só vez. Quanto maior for, melhor pra ler depois, mas desperdiça mais espaço, porque quando precisar gravar menos de 4 kilobytes, o que faltar, não pode reusar mais. Mas enfim, em um único setor do disco cabe nossa estrutura de usuários inteira, que a gente viu que ocupava menos de 4 kilobytes lembra? Então num HD nossa tabelinha de usuários cabe inteiro num único setor e consegue ser lido do HD de uma só vez.</p>
<p>O trabalho pra ler um único byte não compensa pro HD, como o disco tá girando sem parar, na hora que a cabeça começa a ler, ele já lê de uma só vez vários bytes. Ler um byte ou ler 4 kilobytes, é quase o mesmo trabalho. Então se eu organizar a árvore pra já conseguir organizar em clusters, fica mais fácil de ler depois. Na hora que o HD for ler esse valor 41 do exemplo, já vai ler de uma vez o 42, 43 e 47. Como já organizei na árvore pra serem valores consecutivos, ou seja, um atrás do outro sem intervalo, ele vai ler os 4 valores corretos numa única passagem.</p>
<p>Nesse exemplo eu fiz nós que vão ter no máximo uns 7 valores, mas numa árvore B-tree de verdade vai ter dezenas ou centenas de valores um atrás do outro em cada nó. E é assim que o HD vai gravar e vai ler de uma só vez. A diferença de uma árvore B-tree e B+tree é que no B+tree só os últimos nós da árvore que vão conter dados, os nós acima só vão conter metados, os ponteiros pros nós de baixo.</p>
<p>Atualizar a árvore é significativamente mais complicado do que a rotação que já mostrei de uma árvore simples Red Black ou AVL, mas o layout pro HD é muito mais amigável. Recomendo depois procurar num livro de algoritmos, como o do Cormen, os detalhes sobre uma B+Tree. No Cormen inclusive ele explica exatamente sobre essa vantagem e no meu repositório no GitHub desse episódio adicionei outro repositório como sub módulo que encontrei alguém que implementou em C a B+Tree do Cormen pra gravar a árvore em disco, pra quem tiver curiosidade.</p>
<p>E de fato, se eu procurar por &ldquo;btree&rdquo; no repositório do código fonte do banco sqlite3, vamos encontrar várias menções a árvore B-tree que ele usa pra gravar as tabelas, os índices, e tudo mais. E se sair procurando em outros bancos como MySQL, Postgres, até Redis e outros, você vai encontrar uma variação dessa árvore sendo usada.</p>
<p>Em resumo o importante é entender que um bom banco de dados precisa levar em consideração a estratégia e custos de ler e gravar dados em disco, em blocos, vários bytes de uma só vez. Um programador iniciante que só lida com variáveis em memória, costuma pensar só um byte de cada vez, mas é bom saber que dependendo do que tá fazendo, é mais eficiente pegar mais dados do que precisa e descartar o que não precisa. Não é intuitivo mas é justamente por isso que ninguém deve sair fazendo um banco de dados do zero sem ter conhecimento pra isso. Existem vários papers e anos de pesquisa pra cada aspecto de um banco de dados modernos. Lembrem-se que a gente vem fazendo isso faz mais de 60 anos.</p>
<p>A intenção do episódio de hoje não foi incentivar ninguém a escrever o próprio banco, mas sim entender alguns dos principais componentes que um banco de dados de verdade precisa ter. Muita gente tenta racionalizar um banco com variáveis e arrays em memória, e espero que tenha ficado mais claro como é bem mais do que isso. E também porque chamei o episódio onde explico árvores de &ldquo;O Começo de Tudo&rdquo;. Compiladores precisam de árvores. Bancos de dados precisam de árvores. Tudo precisa de árvores, e se você não consegue enxergar listas ordenadas como árvores, está perdendo o entendimento de como tudo funciona em computação.</p>
<p>Aliás, como último exercício de tudo que fiz até agora no meu banco estúpido, faltou mostrar mais uma coisa. Como transformar esse meu console de linha de comando de SQL em um sistema cliente/servidor, como um banco de verdade. E esse nem vou explicar o código, porque é um servidor simples de TCP. Pra quem aprendeu redes na faculdade isso aqui é o primeiro dia de aula. Mas olha só. Num terminal vou executar o servidor com <code>./stupid-server.mjs</code> e pronto, isso vai pendurar o meu servidor na porta 4000 da minha máquina.</p>
<p>Em outro terminal, vou executar <code>./stupid-client.mjs</code> que vai tentar se conectar na porta 4000. E no terminal do servidor, mostra que alguém se conectou. Esse cliente não tem nenhuma lógica do banco, não importa nenhum código do interpretador de SQL nem o array de users, mas eu posso mandar comandos em SQL. Esses comandos vão trafegar pela rede e chegar no servidor. O código do servidor é parecido com o REPL, e no fim devolve o resultado de volta pro cliente.</p>
<p>E pra provar que é um servidor mesmo, posso abrir outro Terminal separado e abrir mais um &ldquo;stupid-client&rdquo;. O servidor mostra que mais alguém se conectou. Posso mandar mais SQL por aqui, e ele vai responder. E esse é o esqueleto básico de como um servidor de banco de dados funciona. Depois estudem o código no repositório do GitHub pra ver como eu fiz isso, mas se entenderam até aqui, essa foi a parte mais fácil, eu literalmente fiz esse cliente e servidor em uns 15 minutos.</p>
<p>Fazer um banco de dados de verdade exige conhecimento bem mais avançado do que isso em ciências da computação e vai exigir centenas, milhares de horas homem de desenvolvimento, testes e ajustes. Essa minha versão estúpida eu justamente chamo de estúpido porque fiz só as coisas mais fáceis, o suficiente pra fazer esse episódio. Eu basicamente peguei o feriado e pensei &ldquo;hum, que tipo de banco SQL será que consigo fazer em uns 2 ou 3 dias de trabalho&rdquo;, e foi isso aqui que mostrei pra vocês. Em particular, o interpretador de SQL, eu nunca tinha usado Antlr4 antes, então foi a parte que gastei mais tempo pra fazer, devo ter gasto pouco mais de 1 dia pra fazer o parser e interpretador. Portanto, tendo conhecimentos básicos de algoritmos e as coisas que já vinha explicando no canal, dá pra fazer esse exercício do zero em uns 3 dias.</p>
<p>Eu me coloquei um limite de tempo porque não dava pra ficar eternamento mexendo no código, uma hora eu precisava gravar este episódio. Mas se alguém se interessar puramente pelo exercício, o próximo passo que não fiz foi justamente mover o array de objetos do &ldquo;users-database&rdquo; pra uma árvore B+tree e gravar em disco, incluindo os índices. Só que aí precisaria também implementar um cache, pra não precisar ir toda hora no disco, e precisaria implementar um sisteminha simples de lock, caso na versão cliente e servidor, vários clientes tentem modificar os dados ao mesmo tempo.</p>
<p>Além disso era bom fazer um limite de conexões. Javascript não tem multi-thread real, então teriamos um limite do que é possível fazer. E nesse caso sintam-se a vontade de reimplementar tudo numa linguagem diferente como Java ou C# ou qualquer outra coisa assim. Só que se fizerem numa linguagem que não é dinâmica, aí vão ter mais trabalho por não terem a trapaça que eu fiz usando &ldquo;eval&rdquo; pra executar as condições de where. Enfim, dá pra ficar brincando bastante em cima disso ainda.</p>
<p>Pra só usar um banco de dados precisa saber em detalhes como ele foi feito? Claro que não. Justamente o que mostrei aqui já é um modelo mínimo suficiente pra ter na cabeça pra não parecer que é uma caixa preta mágica. Usem isso pra ajudar a explicar os principais conceitos técnicos de como um banco de dados funciona pra colegas e amigos iniciantes. Quero saber se isso ajudou a mudar um pouco o que vocês imaginavam que era um banco de dados. Num outro episódio vou falar mais especificamente de bancos de verdade como um Postgres, Redis ou Dynamo. Mas por hoje acho que já ficou comprido o suficiente. Se ficaram com dúvidas mandem nos comentários abaixo, se curtiram o video deixem um joinha, assinem o canal e compartilhem o video pros seus amigos. A gente se vê, até mais.</p>
]]></content:encoded><category>bancos-de-dados</category><category>algoritmos-e-estruturas-de-dados</category><category>javascript</category><category>akitando</category></item><item><title>[Akitando] #39 - A História do Front-End para Iniciantes em Programação | Série "Começando aos 40"</title><link>https://akitaonrails.github.io/2019/02/13/akitando-39-a-historia-do-front-end-para-iniciantes-em-programacao-serie-comecando-aos-40/</link><guid isPermaLink="true">https://akitaonrails.github.io/2019/02/13/akitando-39-a-historia-do-front-end-para-iniciantes-em-programacao-serie-comecando-aos-40/</guid><pubDate>Wed, 13 Feb 2019 17:00:00 -0200</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/VKmPGmFY7H4"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Este episódio vai testar a paciência de vocês. Desta vez quero explorar um pouco os diversos assuntos que são associados com a tal carreira de &amp;ldquo;Front-End&amp;rdquo; no mundo de desenvolvimento Web.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


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

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Este episódio vai testar a paciência de vocês. Desta vez quero explorar um pouco os diversos assuntos que são associados com a tal carreira de &ldquo;Front-End&rdquo; no mundo de desenvolvimento Web.</p>
<p>Se já começaram a estudar o assunto devem ter visto que existe uma infinidade de sopas de letrinhas, coisas como SASS, CSS, React, Vue, e muito mais. Por que existem tantas letrinhas assim? Quais escolher?</p>
<p>Obs: eu fico falando &ldquo;Webpacker&rdquo; o tempo todo mas na verdade é &ldquo;Webpack&rdquo; sorry :-)</p>
<p>Links:</p>
<ul>
<li>
<p>History of Web Fonts: (<a href="https://thehistoryoftheweb.com/web-fonts/"target="_blank" rel="noopener">https://thehistoryoftheweb.com/web-fonts/</a>)</p>
</li>
<li>
<p>A brief history of CSS until 2016 (<a href="https://www.w3.org/Style/CSS20/history.html"target="_blank" rel="noopener">https://www.w3.org/Style/CSS20/history.html</a>)</p>
</li>
<li>
<p>Responsive Web Design: Media Queries (<a href="http://blog.chrismaxwell.com/responsive-web-design-media-queries"target="_blank" rel="noopener">http://blog.chrismaxwell.com/responsive-web-design-media-queries</a>)</p>
</li>
<li>
<p>Front-End Developer Handbook 2018 (<a href="https://frontendmasters.com/books/front-end-handbook/2018/"target="_blank" rel="noopener">https://frontendmasters.com/books/front-end-handbook/2018/</a>)</p>
</li>
<li>
<p>Eloquent JavaScript (<a href="https://eloquentjavascript.net/"target="_blank" rel="noopener">https://eloquentjavascript.net/</a>)</p>
</li>
<li>
<p>Mastering Regular Expressions (<a href="http://shop.oreilly.com/product/9780596528126.do"target="_blank" rel="noopener">http://shop.oreilly.com/product/9780596528126.do</a>)</p>
</li>
<li>
<p>Juliana Negreiros (<a href="https://github.com/juunegreiros/utilities"target="_blank" rel="noopener">https://github.com/juunegreiros/utilities</a>) - página cheia de boas referências.</p>
</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Estamos no quarto episódio desta série, semana passada começamos com algumas coisas básicas do Developer Roadmap onde eu discuti porque saber Git e aprender Linux de verdade são as duas coisas mais importantes pra começar. Mas eu me lembrei no caso de Linux que eu disse que tinha duas formas, você aprender do jeito difícil que é instalar e configurar uma distro como Arch Linux num ambiente virtualizado como Virtualbox. Ou aprender do jeito ultra difícil, que eu esqueci de mencionar no final do episódio, e que é instalando direto como sistema operacional principal da sua máquina! Sim, vai ser bem difícil se for sua única máquina e você só tiver acesso ao site do Arch Wiki pelo celular. Mas vai por mim, hoje tá bem fácil porque a gente fazia essas coisas nos anos 90 só confiando que tinha tudo certo nos disquetes e sem internet pra baixar alguma coisa caso tivesse esquecido, e Wikis sequer haviam sido inventados, aliás, Google não tinha sido inventado. Então considere que hoje tá muito fácil e instale Arch Linux como seu sistema operacional principal. Se conseguir fazer isso sozinho, você está no caminho certo.</p>
<p>No episódio de HOJE vamos falar sobre um dos assuntos mais desnecessariamente complicados da carreira de programador Web, o guarda-chuva que chamamos de Front-end. Porém, em vez de seguir o Roadmap, neste episódio vou fazer uma longa tangente hoje. Aliás, vai ser um dos meus episódios mais longos, então não deixem de dizer nos comentários se preferiam que eu tivesse quebrado esse episódio em duas partes ou se nesses casos está ok ser longo mesmo.</p>
<p>Se você está entrando hoje no mercado de front-ends vai esbarrar em dezenas de letrinhas, coisas como Sass, Vue, React, Angular, Ember, Bootstrap, Npm, Yarn, Webpacker, Flow, TypeScript, Dart, BEM, SMACSS, PWAs, SPAs, RAIL, e por aí vai. Eu entendo porque alguém que está iniciando os estudos agora vai ficar extremamente confuso sobre por onde começar. E como sempre o melhor jeito de entender como começar é do começo.</p>
<p>(&hellip;)</p>
<p>A tangente que eu me referi é que eu vou fazer o contrário da maioria dos tutoriais ou guias que falam de front-end. Em vez de dizer logo de cara o que eu acho que você devia estudar, eu pessoalmente acho mais fácil explicar porque aquelas sopas de letrinhas existem e daí vocês mesmos podem começar a chegar em algumas conclusões. A história do front-end é a própria história da Web e algumas coisas que você tem hoje só fazem sentido no contexto dos anos 90 ou dos anos 2000, sem saber disso você meio que tem que engolir como as coisas são sem entender porque. No fim do episódio eu espero que vocês tenham muito mais perguntas do que neste momento.</p>
<p>A estrutura mais simples que você precisa ter na cabeça é a seguinte: quando você abre um navegador e digita um endereço tipo https : // meusite.com.br ele vai fazer dezenas de operações mas no mínimo ele precisa primeiro traduzir o domínio num endereço IP, e quem faz esse trabalho inicial é o tal servidor de DNS ou Domain Name Server que você já deve ter ouvido pelo menos o nome, pra onde a configuração de rede do seu computador está apontando. DNS é como se fosse uma lista telefônica, traduzindo nomes pra números.</p>
<p>Agora é tarefa da tal rede, roteadores, provedores, conectar seu navegador a um servidor. A internet funciona porque todas as pontas falam o mesmo formato de mensagens e trafegam de uma determinada maneira, que é o que chamamos de protocolo, e o padrão que nos interessa é o famoso TCP/IP. Por agora só entenda que com o endereço ele encontra o servidor certo no mundo. Bem em resumo estamos falando de um programa ou aplicação que é um cliente de TCP ligando a um servidor TCP, que fica escutando no que chamamos de uma porta. Todo servidor web que serve páginas HTML é um programa que quando você carrega ele se liga a uma porta, que é representado por um número que vai de 1 a mais de 65 mil.</p>
<p>A convenção é que um servidor Web ouve conexões na porta 80. Um servidor SSH ouve na porta 22. Um servidor Web também escuta na na porta 443 quando recebe requisição de conexão segura via HTTPS, e muitos servidores de desenvolvimento como Node.js, Rails ou Java ouvem em portas como 3000 ou 5000 ou 8080, respectivamente. Não há nada de mágico nesses números, são arbitrários e foram escolhidos anos atrás e por isso é só uma convenção, mas na prática, qualquer número de porta serve, contanto que exista alguma coisa “escutando” nessa porta.</p>
<p>Nesse minuto de explicação eu simplifiquei bastante. Na faculdade você faria exercícios simples de escrever um programinha que escuta numa porta e outro que conecta nessa porta. É assim que começa a nascer a semente de um servidor web e de um navegador. Agora o que é o servidor Web mais simples de todos? Ele simplesmente lê um arquivo da máquina e serve esse arquivo. O endereço completo que você digita no navegador se chama URL ou Universal Resource Locator que é composto pelo protocolo, pelo domínio e pelo caminho de um arquivo, no caso mais simples. Então antigamente você veria endereços como esse <a href="http://sitedafaculdade.edu/~jose/arquivo.html"target="_blank" rel="noopener">http://sitedafaculdade.edu/~jose/arquivo.html</a></p>
<p>E esse til jose, se você estudou Linux como eu disse no episódio anterior, vai saber que é um atalho pro diretório /home/jose. E é assim que você faz o servidor web mais simples de todos e, como hoje em dia sabemos, o mais bugado em termos de segurança porque se ele traduz direto da URL pra um caminho de arquivos no seu sistema operacional, sem nenhuma checagem, você poderia ficar tentando achar maneiras de vasculhar todos os arquivos do usuário, mesmo os que ele achou que não seriam servidos publicamente. E fazíamos isso mesmo antigamente pra achar brechas.</p>
<p>E quando o navegador, que é um exemplo de um programa que é cliente de TCP, recebe esse arquivo.html agora ele traduz as marcações pra elementos visuais. E como existe o elemento que chamamos de LINK que é o <a href=”http://….> onde “A” significa anchor ou âncora e href é hypertext reference, nasce o conceito de hipertexto onde um texto possui links pra outros textos. No começo ninguém estava interessado em visual, simplesmente em disponibilizar textos linkando com outros textos. E assim nasce a tal World Wide Web ou WWW. É um conceito que nasceria naturalmente dados esses elementos que eu mencionei até agora, era inevitável.</p>
<p>No próximo passo alguém pensou, e se em vez de digitar o nome de um arquivo eu digitar o nome de um programa executável? Um binário que é um programa, que no caso do Windows são aqueles arquivos que terminam o nome com .exe, tipo um Word.exe ou Excel.exe em vez de um hipertexto cujo nome termina com a extensão .html?</p>
<p>Num navegador bem antigo não ia acontecer nada. Provavelmente poderia dar erro porque o servidor não saberia interpretar algo que não é texto. Mas aí alguém fez um dos primeiros servidores web reconhecer quando alguém pede um executável e em vez de só ler o arquivo e cuspir o conteúdo pro navegador, ele primeiro tenta rodar esse executável no servidor e cospe pro navegador o resultado dessa execução, que esperamos que seja um texto em HTML.</p>
<p>Ou seja, pro navegador não faz diferença se pedimos um executável ou um arquivo texto ao servidor, contanto que o que volte pra ele como resposta seja um conteúdo texto em HTML. E se considerarmos que pedir arquivos texto, que nunca mudam é algo estático, assim nasce a primeira geração de sites dinâmicos, ou seja, que dinamicamente podem mudar o resultado dependendo do que o executável faz. Isso começa com programas binários feitos em C mesmo, e o padrão foi nomeado como CGI ou Common Gateway Interface. Mas fazer C ficar cuspindo HTML é como usar um canhão pra matar uma mosca, mas felizmente havia outra linguagem mais simples em ambientes UNIX e Linux e melhor adaptada pra manipular cadeias de texto, ou strings, e foi assim que Perl se tornou a principal linguagem para fazer CGIs e foi assim que o mundo começou a conhecer mais sobre essa sub-linguagem que o Perl trazia chamada Regular Expressions ou REGEX pra manipular strings. Se você ainda não sabe o que é REGEX coloque na sua lista de coisas obrigatórias pra estudar.</p>
<p>E depois do surgimento de alguns servidores web como o da NCSA, ou da Netscape, dentre outros, um começou a despontar pela sua facilidade de uso e por ser open source, ou seja de código aberto, o famoso Apache, cujo nome eu sempre ouvi a história de que foi inspirado em “A Patch”, que traduz em português como “remendo” já que ele não deixa de ser um puxadinho de remendos de código que foram sendo adicionados, um patch de cada vez. Pra quem não sabe, você pode comparar duas versões do mesmo arquivo de código, um mais antigo e outro mais novo usando uma ferramenta de linha de comando que vem na maioria das distribuições Linux chamada “diff” pra tirar a “diferença” entre eles e colocar num arquivo de remendo ou “patch”, e usar outra ferramenta, a linha de comando “patch” pra aplicar essa diferença.</p>
<p>E falando em remendos de arquivos, uma das coisas mais irritantes da Web no começo dos anos 90 era que se eu quisesse fazer um site com 10 páginas e algum layout ou estilo visual, eu precisava copiar e colar o HTML inteiro de uma página pra outra, dez vezes e daí editar o conteúdo diferente entre cada uma. Se depois eu quisesse mudar o layout pra outro formato, eu precisava abrir as 10 páginas e mudar uma a uma. Originalmente a idéia não era que o HTML ditasse como o conteúdo seria visualmente estilizado, a idéia era que cada navegador estilizasse as páginas do jeito que quisesse. O motivo disso foi porque HTML foi inspirado em outras linguagens de marcação de conteúdo como SGML, voltados estruturar documentos governamentais que pudessem ser lidos por um computador. A função do HTML era marcar o que era um cabeçalho, um parágrafo, uma lista, e os perfis de impressão decidiam fonte, espaçamentos e tudo mais pra comportar esse conteúdo numa página de papel, e os navegadores é decidiriam como apresentar esse conteúdo num monitor, inclusive o usuário do navegador poderia customizar escolhendo que não queria o padrão de fontes Times New Roman e sim Arial e todas as páginas mostrariam Arial. Por isso se você viu exemplos de páginas do começo da web, ela eram todas bem sem sal, com fundo cinza, fontes pretas e links azuis, tudo meio igual.</p>
<p>Você já podia embutir um jeito rudimentar de forçar o controle de estilo direto no HTML com o atributo chamado style, mas foi com CSS que separamos o estilo do conteúdo e ganhamos mais controle sobre como o navegador pinta o visual na tela, coisas como escolher fontes, tamanhos, espaçamentos, alinhamentos, e muito mais. Isso foi no começo dos anos 90, até lá por 95 ou 96 quando CSS apareceu pela primeira vez. Nessa época você já tinha Netscape superando o antigo Mosaic, mas o Internet Explorer sairia na frente porque implementava melhor o primeiro CSS, ao contrário da Netscape. Foi quando surgiram páginas de teste como o famoso ACID pra checar a compatibilidade de CSS entre navegadores. Tem uma página com a história completa da novela em cima do CSS que estou deixando nos links na descrição abaixo.</p>
<p>Essa briga deu início à Guerra dos Navegadores, as ferozes batalhas entre a Microsoft e a Netscape pela hegemonia da Web com cada versão de um navegador tentando ser melhor, principalmente em termos visuais e de interatividade do que o anterior. Recomendo muito que você procure pelo documentário da Discovery, The True Story of the Internet onde o primeiro episódio narra em mais detalhes como foi essa guerra. Eu falei sobre isso num dos primeiros episódios desse canal quando dei dicas de séries e filmes pra programadores.</p>
<p>No fim dos anos 90, a Netscape estava perdendo a guerra e resolveu mudar seu modelo de negócio que envolvia vender o navegador, e abriu seu código fonte, criando a fundação Mozilla. O Opera apareceu também mostrando como redimensionar conteúdo pros dispositivos móveis da época como os Palms, Pocket PC e os primeiros dumb-fones de marcas famosas na época como Nokia ou Siemens, a primeira geração de pseudo-“smartphones” vamos assim dizer, isso antes ainda do surgimento da Blackberry e foi quando vimos o primeiro uso de media types, que evoluiriam pra media queries e viriam a se tornar oficiais só no CSS3 em 2012, mas os primeiros rascunhos datam desde pelo menos 1997. Se você não sabe o que são media types, lembre-se que layout de conteúdo era mais especializado para impressão em papel, pra editorar revistas, jornais ou livros. E tínhamos agora que adaptar para monitores de computador, mas além disso ainda havia outras formas de mostrar conteúdo. Imagine dispositivos tácteis como braille para cegos ou que geram som para surdos. Cada um deles é um “tipo de mídia” ou media types. E o Opera começou a popularizar o uso do atributo @media que evoluiria para as media queries que usamos hoje onde o CSS pergunta ao navegador que tipo de mídia estamos lidando, se é uma tela de celular, tela de tablet ou tela de computador.</p>
<p>Com o boom do Internet Explorer foi quando a Microsoft começou a embutir o máximo possível da Web no Windows, e com o Windows 98 vimos pela primeira vez a integração dessas tecnologias direto no sistema operacional, como a utilização de MIME-types, uma tecnologia que surgiu primeiro em e-mails para possibilitar embutir arquivos binários em e-mails que eram somente texto puro. MIME que significa Multipurpose Internet Email Extensions e que você conhece como pares que determinam o tipo de arquivo como text/html ou image/png ou video/mpeg. É uma forma mais avançada do que no Windows são as extensões de arquivo como .html ou .png ou .mpg.</p>
<p>O File Explorer foi mesclado ao Internet Explorer que possibilitava explorar os arquivos da máquina ou explorar os arquivos na Web. Hoje em dia todos os navegadores de arquivos usam MIME types. E isso foi um dos estopins para caracterizar prática monopolista da Microsoft em forçar as pessoas a usar Internet Explorer. A comissão européia na época forçou a Microsoft a deixar os fabricantes de computador escolher se deixariam pré-instalado o Netscape ou Opera. Mas o argumento da Microsoft era que era impossível separar o Internet Explorer do Windows porque ele era parte fundamental de como você navegava no sistema. Foi uma controvérsia enorme na época do Windows 98.</p>
<p>Voltando ao assunto dos servidores web, quando servidores como Apache se tornaram capazes de coisas como executar um script que manipulava o HTML antes de mandar para os navegadores eu poderia escrever o HTML do layout como se fosse um template, um modelo, e fazer só o conteúdo diferente daquelas 10 páginas separadas, e se precisasse mudar o layout, bastava mudar nesse template e todas as 10 automaticamente seriam modificadas.</p>
<p>Com esse conceito começamos a evoluir o mundo de escrever páginas de texto com hiperlink pra algo mais dinâmico e visualmente mais agradável do que textos em fontes Times New Roman ou Courier New com fundo cinza. A diferenciação passou a ser a customização gráfica e de design dos sites e começava a nascer a profissão de web designers que começou com designers gráficos de revista tentando entender como traduzir a linguagem visual de revistas e livros no formato digital da Web. A gente via muito design muito bizarro nessa época, eu diria que foi a época da esplendor exuberante barroco do design Web.</p>
<p>E não é só isso, dado que linguagens no servidor, seja em C ou Perl poderiam ter acesso a recursos como bancos de dados, de repente uma nova possibilidade se abre: aplicações Web em vez de só sites Web. E se eu pudesse fazer um formulário onde o usuário pudesse digitar seu cartão de crédito e enviar para esse script Perl no servidor e gravar no banco de dados? É como se inicia a semente para coisas como e-commerces. A Microsoft novamente não deixou passar a oportunidade e criou seu próprio servidor web, o IIS ou Internet Information Services que adicionou tecnologias proprietárias como o Frontpage Server Extensions que, junto com o programa Frontpage, permitir criar páginas dinâmicas, com validações complicadas de formulário, de maneira simples. Porém páginas feitas com essas extensões só podiam rodar em IIS e serem interpretados por Internet Explorer, aumentando ainda mais a pressão em cima de Apache ou Netscape. Você encontra resquícios disso em produtos atuais da Microsoft como o servidor Sharepoint.</p>
<p>Em paralelo ao Perl e os CGIs, nasceu outra forma de criar páginas dinâmicas com extensões embutidas diretamente dentro do núcleo do Apache, e seu principal proponente foi o PHP. Agora, em vez do servidor web chamar um programa externo pra gerar os HTMLs, o próprio servidor web ganhou a capacidade de interpretar lógica de programação pra cuspir HTML. A Microsoft seguiu lado a lado adicionando em 1996 a extensão de ASP no IIS. E então nasceu a guerra server-side entre PHP e ASP pela hegemonia do mundo servidor. Na sequência ainda ganhamos aberrações como Coldfusion, representando o pico do mau uso do então inovador XML não só como forma de representar dados em formato de tags, mas usar tags como linguagem de programação, inspirado pelo famigerado JSP no mundo J2EE.</p>
<p>Isso coincidiu com a evolução do Java no lado do servidor, e outra categoria de servidores Web, os application servers ou servidores de aplicação. Entenda que um servidor de aplicação é um servidor web, mas nem todo servidor Web como Apache ou NGINX de hoje é um servidor de aplicação. Servidores Web tem como principal função servir páginas HTML e servidores de aplicação tem como principal função executar programas que cospem HTML. Essa época também coincidiu com a abertura inicial de capital ou IPOs da Netscape e Yahoo que marcam o início da famosa Bolha da Internet do meio pro fim dos anos 90. Com a entrada de programadores mais experientes do que meros designers fazendo HTML, tecnologias que permitiam o tráfego de informações seguras como o SSL da Netscape, nasceram as primeiras aplicações Web como content management systems ou CMS como o histórico FileNet, o monstruoso Vignette que todo portal de conteúdo usava, versões open source como PHP Nuke, Mambo que viriam a inspirar a próxima geração como Drupal, Joomla, ou Zope em Python, que daria origem ao Plone, e finalmente o nascimento do Wordpress no começo dos anos 2000 que ajudaria a iniciar a era dos blogs.</p>
<p>Uma vez que começou a ficar claro que era possível programar aplicações interativas, controlar o visual se tornou mais e mais importante. A evolução do CSS1 pro CSS2 que inaugurou também a época das Web Fonts, e moveu os layouts ou estruturas de páginas de usar tabelas e células para a era Tableless e design fluido também viu o nascimento de outras 2 tecnologias fundamentais para a Web de hoje: Dynamic HTML ou DHTML com o HTML versão 4 e uma tecnologia inaugurada pela Mozilla na forma de Asynchronous Javascript ou AJAX. E seu principal garoto propaganda, o GMAIL que começou a ser desenvolvido em 2001 e foi lançado só no dia primeiro de abril de 2004, também inaugurando a era dos memes do dia da mentira.</p>
<p>O GMAIL foi a personificação de tudo que Bill Gates temia nos anos 90: que os navegadores Web se tornassem substitutos dos sistemas operacionais, no caso do Windows, na função de executar programas. Ele previu corretamente que sem padrões proprietários você não teria como segurar os usuários no Windows, porque eles poderiam rodar o mesmo programa num navegador como Netscape em qualquer sistema como MacOS ou distribuições Linux. O GMAIL foi provavelmente a primeira aplicação Web que substitui com sucesso um dos programas nativos mais importantes num sistema operacional: o cliente de e-mails como o Outlook da Microsoft. E isso ameaçava tudo, incluindo o monopólio sobre programas como o Office.</p>
<p>Neste ponto da história, estamos entrando em 2004. Em termos de tecnologias de front-end avançamos o HTML até a versão 4 que comporta coisas como Dynamic HTML e AJAX. Derivado do SGML tivemos o HTML mas também surgiria o XML para estruturar qualquer tipo de dados e como uma estrutura mais geral onde HTML, ou mais especificamente, XHTML seria um caso especial. HTML é especializado em estruturar conteúdo de texto. XML é especializado em estruturar dados, como cadastros. CSS versão 2.1 é o cascading style sheet, que passou a suportar web fonts, internacionalização, posicionamento relativo e absoluto que permite que os elementos na tela de ajustem dinamicamente de acordo com o tamanho total da tela, ao contrário do que fazíamos no meio dos anos 90 onde considerávamos um comprimento fixo de tela pra encaixar os elementos, especialmente dentro de tabelas e usando muito recorte de imagens porque CSS não era poderoso o suficiente para alguns designs gráficos. Além disso, é importante entender que CSS é uma linguagem declarativa, onde declaramos regras visuais que são aplicadas no HTML e essas regras são cascateadas onde uma regra herda as características da regra pai, numa hierarquia de regras. Aliás, tenham sempre em mente a estrutura de uma árvore ou hierarquia. Quase tudo na Web é baseado nessa estrutura. HTML são árvores de elementos. CSS são árvores de atributos de estilo. Sites são árvores de páginas uma linkando na outra. E agora que evoluímos de simples sites de conteúdo hipertexto, pra gerenciadores de conteúdo CMS, pra e-commerces e com o início da era de aplicativos Web como Gmail e redes sociais como Orkut, MySpace e Friendster, abriu-se uma nova fase de desenvolvimento.</p>
<p>Em paralelo, na era Java do começo dos anos 2000 popularizou-se o conceito de Frameworks, que mais do que linguagens fornecem uma estrutura pré-definida para ajudar a desenvolver aplicativos, fornecendo coisas como segurança, validação de dados, autenticação e autorização granular, templates visuais, e que determinavam meio que um “guia” de lugares onde você deveria colocar cada tipo diferente de código. Antes disso cada aplicativo como Joomla ou Drupal fazia tudo do zero. No mundo PHP começaram a surgir frameworks inspirados em J2EE ou Struts, como o Zend Framework. E finalmente abrimos a era do Ruby on Rails pro fim de 2004 e o agora lendário demo do blog em 15 minutos que David Hansson gravou no evento FISL de 2005 no Brasil, inaurando a era dos frameworks que herdam os conceitos de Agilidade inaugurado pelo Manifesto Ágil de 2001.</p>
<p>Por causa de Ruby on Rails começou a surgir a primeira geração de sub-frameworks Javascript e CSS. Até então escrever HTML ou CSS ou mesmo Javascript era algo trabalhoso, que não funcionava exatamente da mesma forma em todos os navegadores. Lembrando que estamos na época do famigerado Internet Explorer 6 do também famigerado Windows XP e do Netscape 7. Com isso em mente, alguém pensou: porque não unificar essas coisas? Por que não fazer um framework via Javascript pra homogeneizar e evitar que o programador tenha que fazer código específico para Internet Explorer ou Netscape? Daí surge a primeira geração de micro-frameworks especializados em visual do lado do navegador como Mootools, Dojo, o próprio JQuery, e os que o Ruby on Rails tornou popular na época, no caso o Prototype e o Scriptaculous. Scriptaculous que popularizou novas formas de elementos de interação como drag and drop de elementos no HTML, onde podíamos arrastar as coisas como podemos arrastar e-mails no inbox do GMAIL.</p>
<p>Pouco tempo depois, em 2007 surge uma nova revolução na área de design visual e usabilidade. Vemos o nascimento dos smartphones a partir do primeiro iPhone lançado em julho de 2007. Com ele temos o navegador Safari, que é uma evolução do navegador chamado Konqueror do KDE no Linux, que usava o núcleo KHTML que viria a se tornar o que conhecemos hoje como WebKit. Só que telas de celular tinham resolução muito menor do que um desktop. Em 2007 o mais comum eram monitores com resolução de 1024 pixels por 768, mas o iPhone tinha meros 320 por 480 pixels.</p>
<p>Uma coisa que se tornou popular nos anos 90 e que eu não falei ainda, foi uma forma de simplesmente não usar nada de HTML nem CSS nem Javascript. Pra tentar tomar a dianteira, empresas como a Microsoft não fizeram só componentes proprietários pro servidor como o Frontpage Server Extensions ou ASP. A Sun criou o Java e queria dar um jeito de colocar Java em tudo. O Java servia pra muitas coisas incluindo fazer aplicativos pra Desktop, como os malditos aplicativos de Imposto de Renda que você usa até hoje. Mas eles queriam dar um jeito de colocar Java nos navegadores, mas sendo uma linguagem geral ela virar um problema de segurança se de repente você rodasse Java no navegador e ele pudesse acessar seus arquivos. Por isso criou-se o conceito de sandboxing, um container que permite executar código Java com baixos privilégios ou seja, sem privilégios pra acessar arquivos ou a própria rede, ele devia rodar dentro desse container e assim nascem os aplets.</p>
<p>Quem dessa época não lembra do famigerado applet de demonstração que mostrava água se mexendo num tipo de animação que era impossível de fazer só com CSS ou mesmo com GIF animado. E seguindo nessa tendência a Microsoft criou o padrão ActiveX que era o mesmo que applets mas em vez de usar Java você programava em C++ ou mesmo Visual Basic 6. Felizmente Applets Java e ActiveX já não existem mais, mas a Macromedia também fez seu sandbox na forma do famigerado plugin Flash que trazia tecnologias realmente legais pra época como ilustrações vetoriais com curvas de Bezier que já era usado em programas como CorelDraw ou Adobe Illustrator para conseguir embutir ilustrações de melhor qualidade e tamanho muito menor do que imagens bitmap como JPEG ou GIF. E mais do que isso, adicionar o conceito de linha do tempo para animar essas ilustrações. Adicionando uma linguagem bem tosca e simples chamada ActionScript e você podia fazer coisas interativas como joguinhos. Todo mundo jogou alguma coisa em Flash no começo dos anos 2000.</p>
<p>Em 2019 o processador de um iPhone, o famoso A12 Bionic nos novos iPhone XS é quase tão potente quanto um processador Intel Core em um Macbook Pro. Um processador em um iPhone original de 2007 era um processador ARM11 de meros 412Mhz e tinha só meros 128 MEGAbytes de RAM. E a bateria tinha não mais que 1400 miliamperes, hoje celulares tem até 4000 miliamperes. Entre pouco processamento e pouca bateria, sem teclado, sem mouse, só com touch, rodar Flash era um exercício de futilidade. Os primeiros Androids queriam se destacar deixando rodar Flash mas rapidamente foi provado que isso só deixava celulares Android extremamente lentos e a bateria acabava num piscar de olhos. Flash já não tinha boa reputação por causa do tanto de bugs e principalmente buracos graves de segurança em sua programação porca. A gente dava um jeito de aguentar com CPUs mais potentes e muita RAM em desktops, mas em smartphones não tinha pra onde correr. A Apple se recusou a rodar Flash e não só isso demonizou o Flash publicamente na famosa carta aberta de Steve Jobs que selou o destino do fim do Flash.</p>
<p>Só que a partir de 2005 a única forma decente de ver videos do YouTube ou outros sites era via o plugin de Flash ou via o plugin de Silverlight que era tipo uma evolução do ActiveX da Microsoft, mas também não durou muito. Sem esses plugins não havia video. A Apple ajudou a evoluir o HTML para suportar playback de vídeo acelerado por hardware, e popularizou o envelope MP4 de vídeo com compressão H.264 e com isso nascia novas tags de vídeo pra HTML. Somado ao fim do Flash também aumentou a pressão por adicionar funcionalidades de animação também acelerado pela nova classe de GPUs e assim surgem coisas como o atual canvas controlado por CSS e WebGL.</p>
<p>A revolução dos smartphones, a queda da Sun que foi adquirida pela Oracle pondo também um ponto final em applets, as ingerências da Microsoft pós julgamento anti-truste nos anos 2000 desacelerando os desenvolvimentos do Internet Explorer e tecnologias como Silverlight. Tudo isso forçou a W3C e seu consórcio de empresas a acelerar uma coisa que já estava muitos anos atrasado: a evolução pro HTML5 e CSS3 que só aconteceu em 2014 onde alguns anos antes disso todos os navegadores, começando com o surgimento do Google Chrome em 2008 começaram a implementar uma funcionalidade de cada vez.</p>
<p>Ficamos de 2008 a 2015 num período muito chato de transição. Tínhamos que desenvolver Web em meio a HTML, CSS, Javascript estando no meio do caminho e mudando o tempo todo em cada nova versão de cada navegador. Era impossível fazer um site que funcionasse em todos os navegadores e em todos os dispositivos ao mesmo tempo com os padrões ainda não oficializados e cada navegador implementando partes da especificação. E por conta disso surgiram meta-linguagens pra nos blindar essa bagunça. Foi quando JQuery deixou de ser opcional e passou a ser uma necessidade pra lidar com Javascript e CSS. Com o fim do Flash, Javascript voltou a ser a única alternativa viável pra animação e interação, uma linguagem extremamente ruim que não via uma evolução significativa desde o começo dos anos 2000. Então começou a surgir uma gambiarra na forma de transpilers, linguagens que não são compiladas em instruções nativa de uma máquina real ou uma máquina virtual, mas que traduzem de uma linguagem para outra linguagem.</p>
<p>Novamente, o mundo Ruby on Rails veio tentar ajudar. O rubista Hamptom Caitlin escreveu o SASS ou Syntathically Awesome Stylesheets, usando Ruby. SASS é tipo um dialeto de CSS que permite estruturar melhor o CSS, dando funcionalidade de reusar código, e esconder detalhes específicos de navegadores. O Twitter resolveu criar sua própria versão e daí surgiu o LESS. SASS e LESS ficaram concorrendo por anos mas SASS é superior hoje em dia.</p>
<p>Também do mundo Ruby, em 2009 Jeremy Ashkenas escreveu um compilador em Ruby chamado Coffeescript. Uma nova linguagem cujo resultado da compilação era Javascript. Ele adicionou dezenas de conceitos de linguagens como Ruby e Python para criar uma nova linguagem muito mais agradável de trabalhar e que geraria a porcaria do Javascript por baixo. Isso ajudou muito a evitar termos que usar algo como JQuery ou ficar nós mesmos nos preocupando em adicionar código específico pra cada navegador. Hoje em dia todo mundo demoniza Coffeescript porque a sintaxe dele é um pouco agressivo e pouco ortodoxo, mas foi dele que saíram diversos conceitos como interpolação de strings, melhor controle sobre enumerators e iteradores, a agora famosa sintaxe de fat arrow pra funções anônimas e muito mais que foi incorporado ao Javascript versão ES6 que só foi sair em 2015, tornando o Coffescript obsoleto.</p>
<p>Mais do que só matar o Flash, o surgimento de smartphones com telas verticais e resoluções diferentes de um monitor de computador, também surgiu a necessidade de criar estilos que se adequassem automaticamente ao formato da tela e com o movimento de tableless, ou seja, parar de usar tabelas pra estruturar layout em HTML, e a consolidação de elementos flutuantes com espaçamento relativo do CSS2 transicionamos pro tal design responsivo que tanto se fala em hoje em dia. Layouts que automaticamente se adequam ao dispositivo e com o advento da interação via touch uma nova classe de pesquisa foi iniciada, o que hoje chamamos de UX ou usabilidade. Pense que até então o normal eram teclado e mouse, como criar telas interativas que só usam o dedo? Hoje em dia isso é um problema resolvido, mas principalmente entre 2009 e 2015 isso foi assunto de muita discussão.</p>
<p>E como o primeiro smartphone de verdade do mundo foi o iPhone da Apple, além das tecnologias ela trouxe outra coisa do seu DNA: seu estilo de design e linguagem de usabilidade. Se o fim dos anos 90 foi a época barroca do design Web, a Apple trouxe a linguagem de Bauhaus: o que hoje chamamos de design minimalista, que valoriza os espaços em branco entre elementos, linhas simples sem o escândalo de cores bregas e tudo desalinhado que se via em páginas de redes sociais como MySpace. E em cima dessa linguagem as empresas pararam de reinventar a roda em cada site e passaram a criar bibliotecas de estilo reusáveis e daí nascem os frameworks de CSS, escritos nas linguagens SASS e LESS que falei acima. O mais famoso deles sendo o Twitter Bootstrap. Por isso muitos sites parecem que foram feitos pelo mesmo designer, porque todo mundo usa o Bootstrap em vez de partir do zero e ficar reinventando a roda redesenhando o visual de botões e outros elementos. Daí criamos elementos novos com o hamburguinho pra menus, os Jumbotrons e Scrollspy que toda landing page usa.</p>
<p>Com tantos novos elementos de Javascript e CSS surgiu outra necessidade. Agora não era mais só escrever um arquivo de CSS, linkar no HTML e pronto. Passamos a reusar dezenas de bibliotecas como um JQuery da vida, código pra Google Analytics, frameworks de CSS gigantes, enfim muitos e muitos assets. Primeiro, precisávamos dar um jeito de baixar todos esses assets e bibliotecas nos nossos projetos sem ficar indo de site em site, clicando no link de download e descomprimindo zips manualmente nos diretórios. No mundo Perl já tinhamos coisas como o CPAN que permitia baixar bibliotecas de um servidor central. No mundo Ruby, depois de várias tentativas finalmente consolidamos no Bundler pra não só baixar as bibliotecas mas gerenciar corretamente as versões corretas que nossos projetos precisariam. E no mundo Javascript as coisas começaram meio devagar com o advento do NPM que só ficaria realmente usável quando concorrentes como YARN tentaram tomar seu lugar. Mas no mundo Javascript o NPM pelo menos se tornou o padrão de fato para gerenciar os assets no lado da máquina do desenvolvedor.</p>
<p>Mas só isso não é suficiente. Como eu expliquei no começo do episódio, um servidor web cospe HTML e todos esses assets pro navegador. E como agora colocarmos dezenas deles nos nossos projetos você devia imaginar que quanto mais arquivos e quanto maior eles forem, mais lento vai ser pro navegador baixar e renderizar tudo. E isso se tornou ainda mais óbvio nos primeiros smartphones. Hoje em dia temos alta velocidade em conexões 4G e já estamos próximos de ir pra 5G, mas em 2009 o normal ainda era 2G e poucos com 3G. Como otimizar esses assets pra ficarem menor? Alguém parou pra pensar: esses assets de Javascript e CSS são tudo texto. Nós programadores sabemos fazer texto ficar menor. Por exemplo, nós escrevemos código com tabulação, espaços, usamos nomes grandes e descritivos pra ficar mais fácil outro programador conseguir editar esse código. Mas um navegador não se importa com espaços em branco ou nomes descritivos, computadores sabem ler dados sem formatação. E espaços em branco ou nomes grandes ocupam espaço desnecessário. Mais do que isso, quanto mais arquivos separados tivermos, mas lento vai ser. Então porque não juntar vários arquivos num único arquivo e porque não filtrarmos e tirarmos fora espaços em branco e reduzir nomes de variáveis e funções ao menor tamanho possível, dentre outros truques? Esse é o conceito que chamamos de minificação, minificar textos humanamente legíveis em textos menores horrorosos mas que navegadores conseguem ler. E com tantas atividades agora pra chegar nos arquivos de HTML, CSS e Javascript finais otimizados, temos que transpilar de SASS pra CSS, de Coffeescript ou ES6 pra Javascript ES5 que na época era mais usado. É o que chamamos de um canos de processamento de assets ou Asset Pipeline como chamamos no Ruby on Rails onde o conceito nasceu. E no mundo Javascript surgiram coisas similares como Grunt, Gulp e hoje em dia Webpacker somado a ferramentas como Babel que fazem exatamente esse tipo de coisa. Por causa disso, todo novo framework que se preza tem algum tipo de integração com coisas como Webpacker pra ter esse pipeline de processamento. Isso ficou um pouco menos necessário desde que evoluímos pro padrão HTTP/2, mas isso é assunto pra outro dia.</p>
<p>Evoluindo em cima da herança do GMAIL, só AJAX não era mais suficiente e passamos a experimentar em tirar lógica dos servidores de aplicação e transferir o controle do estado da aplicação pra mais próximo da tela gráfica, e assim surgem os frameworks Javascript. Em vez de ficar controlando cada elemento da tela individualmente via Javascript e ficar controlando os estilos globais com CSS, por que organizar uma tela de uma aplicação direto só em seus menores elementos? Por exemplo, num Spotify em vez de falarmos em botões ou listas, podemos separar em coisas maiores como Playlist, Menu de Usuário, dashboard de playback, lista de resultados de pesquisa de música. São todos grandes “componentes” que interagem entre si. E cada um deles tem uma representação gráfica que depende de um estado. Por exemplo, no dashboard de playback, temos estados como tocando, pausado, shuffle ativado ou Não. E pra criar esses componentes e gerenciar os estados no lado do cliente, aproveitando tecnologias do HTML5 como web storage que permite guardar esse estado no navegador, surgem frameworks como Ember, Angular, React + Redux ou Vue.js. E assim também surge o conceito de uma única página que carrega toda essa aplicação que é composta de javascript e assets como CSS e imagens, sem precisar mudar de página pra atualizar entre cada estado. Pra fazer isso usamos Ajax por baixo e rodamos tudo numa única página e por isso temos o conceito que vocês já devem ter ouvido de SPAs ou Single Page Apps.</p>
<p>Isso aconteceu a partir do nascimento de aplicações mais complexas em interação e estado como o próprio Google Docs, Slack, Spotify e outros. E é por isso que hoje você tem esses frameworks. Na época que a Apple estava na dianteira desse tipo de aplicativos por conta do iCloud ela tinha um framework próprio chamado Sproutcore. Dali veio a semente que viria a se tornar Ember, que também saiu da comunidade Ruby on Rails e por isso Ember se parece um pouco em estrutura com o Rails. O Google tinha o antigo GWT que foi muito usado no mundo Java pra fazer aplicativos parecidos com o Gmail, mas depois criou o Angular e depois o Polymer que não deu muito certo em adoção. E com o crescimento do Facebook e necessidade de criar aplicativos como o Facebook Messenger, surgiu o React que torna mais veloz o desenho de partes da tela cujo estado foi modificado com seu Virtual DOM. Ou seja, em vez de ficarmos redesenhando explicitamente um elemento na tela, tipo mudar a cor de um botão pra vermelho, só mudamos o estado do botão e deixamos esse Virtual DOM redesenhar o que precisar na tela, de forma que podemos evitar redesenhar o que não se precisa e ao mesmo tempo otimizar a velocidade total do redesenho. E na tentativa de fazer concorrência e evoluir em cima da experiência do Angular e React, no mundo open source surgiu o Vue.js que começou a ganhar algum momento graças à sua inclusão como padrão no framework Laravel no mundo PHP.</p>
<p>E nos dias de hoje, com a evolução do Javascript ES6, a dominância do Chrome como navegador mais usado e a decadência do Internet Explorer, e também o surgimento de processadores multi-core mais rápidos e mais eficientes nos smartphones, com RAM mais barata que permite que desktops e dispositivos consigam ter 6GB ou 8GB ou mais de RAM, começou a surgir uma nova classe de aplicativos: os híbridos. Aplicativos de desktop ou de mobile que tecnicamente tem uma estrutura nativa que liga com o hardware como camera, touch, audio e muito mais mas são controlados por uma fina camada de Javascript e outras tecnologias Web como HTML5 e CSS3. Então podemos usar a mesma estrutura que descrevi acima pra fazer aplicativos desktop ou mobile como é o caso de coisas que usamos todo dia como o próprio Spotify ou Slack ou editores de código como Atom ou Visual Studio Code. E assim surgem também frameworks híbridos como o Electron que é uma forma de encapsular tecnologias do Chrome e abrir como se fosse um aplicativo nativo ou então React Native que torna possível você desenvolver um aplicativo simples pra iOS ou Android como se estivesse desenvolvendo um site web em React.</p>
<p>Caraca!! Eu sei que eu pincelei bem por cima de dezenas de assuntos e mais de 25 anos de história. Já disse em outros episódios que eu sinto que nasci na hora certa porque eu pude ver cada evento que eu narrei aqui acontecendo em tempo real. Isso me ajudou muito porque eu pude ir aprendendo cada nova tecnologia à medida que elas foram aparecendo. Algumas delas morreram já, como ASP clássico, Flash, Silverlight, Active X, Applets Java, Coffeescript, GWT, e ao mesmo tempo muitas novidades apareceram na forma dos atuais padrões HTML 5, CSS 3 e Javascript ES6 e as ferramentas por cima delas como React, SASS e assim por diante. Mas eu espero que ao ouvir sobre essa linha do tempo você consiga ter uma noção melhor de onde cada coisa se encaixa. E eu recomendo que você assista este episódio mais vezes, não agora, mas de tempos em tempos pra ver se o que eu estou falando vai fazendo mais sentido à medida que você vai estudando e treinando.</p>
<p>Sempre que tiver dúvidas sobre uma tecnologia comece do começo: pesquise sua história. A história vai te dizer, porque essa tecnologia existe? Que problemas ela foi desenhada pra resolver? Ela ainda resolve esse problema da melhor forma ou já surgiram substitutos? Ainda vale a pena aprender ou já tem coisa melhor na frente? Por onde anda o autor original da tecnologia? Ou a empresa que patrocinou essa tecnologia? São perguntas como essas que vão te dar o norte sobre o que estudar e como estudar.</p>
<p>Se eu fiz meu trabalho direito, você começou este episódio com dúvidas sobre o que estudar. E deve ter terminado este episódio com mais dúvidas ainda! E esse é o objetivo. Se você tem poucas perguntas, não está se esforçando o suficiente. Faça a pergunta errada e vai receber a resposta errada. Reveja seus conceitos, veja a lista de coisas que tem pra estudar, coloque na linha do tempo, veja quais problemas você vai resolver com quais ferramentas. Encontre problemas pra resolver e vá aprendendo dessa forma: na tentativa e erro. Quais problemas? Eu não disse no episódio anterior que você precisa aprender a fuçar os projetos open source que estão no Github? É por ali mesmo, você vai achar o tal clone do Instagram que alguém fez. Ele vai estar feito em Angular, que eu falei aqui. Você já entendeu pra que ele serve, procure um tutorial online sobre Angular. Daí vai ver que tem arquivos com extensão .scss que é SASS e agora você sabe o que é SASS e que deve ter algum pipeline, como Webpacker, então procure um tutorial de SASS e outro tutorial de Webpacker. E quando for rodar, você já sabe pelo menos em conceito a diferença de um servidor web e um servidor de aplicações, e se levou a sério meu episódio anterior você está estudando distribuições Linux, agora procure um tutorial de como instalar, configurar e subir um NGINX por exemplo.</p>
<p>Cada um desses assuntos não é pra levar anos pra aprender. Se você for devagar, gaste 1 mês em cada item. Aprenda os 20% que eu vivo falando. E aprenda treinando. Teoria e prática. A parte avançada vai aparecendo à medida que você realmente coloca a mão no código e faz rodar na sua máquina. Qualquer coisa antes disso é perda de tempo. E apesar de eu não gostar de recomendar diretamente sites de tutoriais ou cursos, vou deixar linkado alguns que conhecidos meus recomendaram, então não deixe de ver esses links na descrição do vídeo abaixo.</p>
<p>E por hoje é isso aí, o objetivo de hoje foi colocar as tecnologias de front-end dentro da história. Semana que vem quero tentar fazer a mesma coisa com tecnologias back-end e na seguinte finalmente um pouco sobre devops. Eu sei que vocês ficaram com dúvidas, e eu mesmo não sou o melhor programador de front-end, então mandem suas dúvidas nos comentários abaixo pra todo mundo poder ajudar a responder. Se curtiram mandem um joinha, compartilhem com seus amigos, assinem o canal e cliquem no sininho pra não perder os próximos episódios. A gente se vê, até mais pessoal!</p>
<p>Este episódio vai testar a paciência de vocês. Desta vez quero explorar um pouco os diversos assuntos que são associados com a tal carreira de &ldquo;Front-End&rdquo; no mundo de desenvolvimento Web.</p>
<p>Se já começaram a estudar o assunto devem ter visto que existe uma infinidade de sopas de letrinhas, coisas como SASS, CSS, React, Vue, e muito mais. Por que existem tantas letrinhas assim? Quais escolher?</p>
]]></content:encoded><category>frontend</category><category>desenvolvimento-web</category><category>javascript</category><category>akitando</category></item><item><title>[Akitando] #7 - A Controvérsia da Lerna vs ICE</title><link>https://akitaonrails.github.io/2018/09/04/akitando-7-a-controversia-da-lerna-vs-ice/</link><guid isPermaLink="true">https://akitaonrails.github.io/2018/09/04/akitando-7-a-controversia-da-lerna-vs-ice/</guid><pubDate>Tue, 04 Sep 2018 11:00:00 -0300</pubDate><description>&lt;p&gt;Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal &lt;a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener"&gt;Akitando&lt;/a&gt;. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.&lt;/p&gt;
&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/WObC_2e0kZk"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;Descrição no YouTube&lt;span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Semana passada aconteceu uma pequena controvérsia no mundo Javascript quando um colaborador do Core Team da Lerna decidiu mudar a licença de uso do projeto para proibir colaboradores de empresas como Palantir, Microsoft de usar o projeto.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Disclaimer: esta série de posts são transcripts diretos dos scripts usados em cada video do canal <a href="https://www.youtube.com/channel/UCib793mnUOhWymCh2VJKplQ"target="_blank" rel="noopener">Akitando</a>. O texto tem erros de português mas é porque estou apenas publicando exatamente como foi usado pra gravar o video, perdoem os errinhos.</p>


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

<h3>Descrição no YouTube<span class="hx:absolute hx:-mt-20" id="descrição-no-youtube"></span>
    <a href="#descri%c3%a7%c3%a3o-no-youtube" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Semana passada aconteceu uma pequena controvérsia no mundo Javascript quando um colaborador do Core Team da Lerna decidiu mudar a licença de uso do projeto para proibir colaboradores de empresas como Palantir, Microsoft de usar o projeto.</p>
<p>Vamos entender exatamente o que significa isso.</p>
<p>Seguem os links para este episódio:</p>
<ul>
<li>
<p>Lerna project (<a href="https://lernajs.io/"target="_blank" rel="noopener">https://lernajs.io/</a>)</p>
</li>
<li>
<p>Pull Request 1616: (REVERTED): Add Text to MIT License banning ICE collaborators (<a href="https://github.com/lerna/lerna/pull/1616"target="_blank" rel="noopener">https://github.com/lerna/lerna/pull/1616</a>)</p>
</li>
<li>
<p>Pull Request 1633: chore: Restore unmodified MIT license (<a href="https://github.com/lerna/lerna/pull/1633"target="_blank" rel="noopener">https://github.com/lerna/lerna/pull/1633</a>)</p>
</li>
<li>
<p>Eric Raymond: Non-discrimination is a core value of open source (<a href="http://esr.ibiblio.org/?p=8106"target="_blank" rel="noopener">http://esr.ibiblio.org/?p=8106</a>)</p>
</li>
<li>
<p>The Cathedral and the Bazaar (<a href="http://www.catb.org/esr/writings/cathedral-bazaar/"target="_blank" rel="noopener">http://www.catb.org/esr/writings/cathedral-bazaar/</a>)</p>
</li>
<li>
<p>The Open Source Definition (<a href="https://opensource.org/osd-annotated"target="_blank" rel="noopener">https://opensource.org/osd-annotated</a>)</p>
</li>
<li>
<p>Free Software Foundation (<a href="https://www.fsf.org/"target="_blank" rel="noopener">https://www.fsf.org/</a>)</p>
</li>
<li>
<p>Choose an open source license (<a href="https://choosealicense.com/"target="_blank" rel="noopener">https://choosealicense.com/</a>)</p>
</li>
<li>
<p>AkitaOnRails: [Off-Topic] Software Livre: Exercício de CAPITALISMO (<a href="http://www.akitaonrails.com/2016/04/22/off-topic-software-livre-exercicio-de-capitalismo"target="_blank" rel="noopener">http://www.akitaonrails.com/2016/04/22/off-topic-software-livre-exercicio-de-capitalismo</a>)</p>
</li>
<li>
<p>Eclipse CPL to EPL Transition (<a href="https://www.eclipse.org/legal/cpl2epl/cpl2eplfaq.php"target="_blank" rel="noopener">https://www.eclipse.org/legal/cpl2epl/cpl2eplfaq.php</a>)</p>
</li>
</ul>
<h2>Script<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Mudando completamente de assunto de blockchains e Coréia, vamos falar um pouco de software, mais precisamente, sobre licenças de software e algumas coisas que talvez vocês ainda não saibam.</p>
<p>Me deu vontade de falar um pouco sobre isso por causa da recente controvérsia do projeto Lerna, que se descreve como uma ferramenta para gerenciar projetos javascript num repositório com múltiplos pacotes, um monorepo.</p>
<p>E o assunto em questão foi a recente tentativa de radicalmente mudar a licença do software pra restringir o uso de empresas como Palantir ou Microsoft, que de alguma forma estão ligados com a controvérsia da ICE, a US Immigration and Customs Enforcement. Eu sempre fui favorável a não existir políticas restritivas e punitivas de fronteiras, especialmente a que está em discussão agora nos Estados Unidos.</p>
<p>(&hellip;)</p>
<p>Eu não quero entrar no assunto de política internacional. Deixo isso para quem tem experiência no assunto, eu certamente não tenho.</p>
<p>Mas eu certamente tenho experiência com software e licenças e quero ajudar os desenvolvedores a entender o que significa esse episódio.</p>
<p>O ponto em questão foi a abrupta decisão do contribuidor do core team do Lerna, Jamie Kyle em fazer um pull request que edita a licença MIT que a Lerna usa e adicionar cláusulas restritivas e retroativas, literalmente excluindo o uso pelas empresas Palantir, Microsoft, Amazon, Ernst &amp; Yount, Thomson Reuters, Deloitte, Johns Hopkins University, Dell, Xerox, Canon, Linkedin e algumas outras.</p>
<p>Esse assunto apareceu no canal de chat da minha empresa. A gente discute assuntos assim de vez em quando, o que é bem legal. Nem precisei saber a motivação (se é ICE ou o que for), na hora eu já respondi que isso não rolar. Não precisa ser gênio pra saber isso.</p>
<p>E de fato, no dia seguinte, o pull request foi revertido por outro líder do projeto, Daniel Stockman, e o Jamie Kyle foi banido do projeto, citando episódios anteriores que ele fere o código de conduta do projeto. Ironicamente código de conduta que o próprio Jamie adicionou ao projeto.</p>
<p>E porque eu imediatamente já sabia que isso ia acontecer? Vamos entender.</p>
<p>Se você cria código e libera esse código num repositório público, ele ainda é SEU código. Não só código. Quando você faz um trabalho criativo, o trabalho está automaticamente sob seu copyright. A menos que você inclua uma licença, NINGUÉM pode copiar, distribuir, ou modificar seu trabalho sob o risco de tomar um processo.</p>
<p>Agora, à medida que o trabalho tem outros colaboradores esse NINGUÉM inclui você.</p>
<p>Na prática, se você colocar o seu projeto no GITHUB você já concordou com termos de uso dele, dizendo que seu projeto é automaticamente liberado para visualização por qualquer um e portanto passível de sofrer FORK. Qualquer um no GITHUB pode fazer FORK do seu projeto e modificá-lo a partir desse ponto dependendo da licença.</p>
<p>Copyright é um direito legal que, por um certo período de tempo, lhe dá a autonomia de decidir o que fazer com seu próprio trabalho. Aliás, você é responsável por enforçar esse copyright. Independente do que você quer, você, criador, detém esse direito.</p>
<p>Na prática, se você um dia ver um software sem nenhuma licença, passa longe dele! Você está assumindo um risco desnecessário se usar um software sem licença, especialmente se adicionar seu próprio código em cima disso. Se escolher usar mesmo assim, você foi avisado.</p>
<p>Agora, você pode fazer o que quiser com esse direito, incluindo jogar totalmente fora. Se é isso que você quer, você pode usar um Unlicense, que é basicamente abrir mão do direito e torná-lo public domain. A partir daqui é terra de ninguém, qualquer um pode fazer qualquer coisa.</p>
<p>Normalmente o que se faz é: você retém o direito do copyright, mas adiciona uma licença que permite o uso. A licença define o que se pode fazer com esse software e dá garantias aos usuários sobre o uso, cópia, modificação e distribuição.</p>
<p>Agora, você pode escolher uma licença permissiva, ou seja, que dá total liberdade aos usuários ou uma licença restritiva, ou seja, que restringe as liberdades do usuário.</p>
<p>Licenças como MIT ou BSD são permissivas, e é por isso que muitos usam. Dentre as liberdades, a mais importante é que você pode lançar como um produto comercial sem liberar o código fonte modificado.</p>
<p>Licenças como GPL e AGPL são bem restritivas, e essas as empresas precisam passar longe se não souberem com o que estão lidando. Muitos chamam esse tipo de licença de um vírus porque ele se propaga a toda modificação que você fizer e você é obrigado a liberar o código fonte modificado e não pode distribuí-lo comercialmente sem soltar esse código junto. GPL v3 e AGPL são particularmente nefários nesse aspecto. AGPL é feito para quebrar o truque dos Software as a Service.</p>
<p>Num SaaS você pode usar um software GPL v2 (versão 2) mas não precisa liberar o código fonte porque você não está distribuindo o software. Você está liberando acesso à execução do código modificado através de APIs. Então os seus usuários não usam diretamente o código. Pois bem, o AGPL diz que mesmo nesse caso se alguém usa o seu software GPL modificado através da rede, você precisa liberar o código fonte.</p>
<p>Outra forma de burlar o GPL, no caso o GPL v2 é o que ficou conhecido como Tivoização. Tivo é o avô de hardwares como Apple TV ou Google Chromecast. A Tivo usa Linux e outros softwares que são licenciados com GPL v2. Eles liberam o software conforme a licença, mas o hardware é bloqueado e não deixa rodar outro binário que possa ser verificado via assinatura digital, então na prática você tem o código mas não pode rodar no hardware. O povo do Richard Stallman ficou bravo com isso e foi o que levou ao GPL v3 que permite uso de assinatura digital para propósitos de segurança mas evita cenários como a Tivoização.</p>
<p>Uma das consequências disso é a eterna rixa entre o povo do BSD, mais especificamente o FreeBSD que, apesar de não usar a kernel do Linux, usa outros componentes como o compilador GCC. A filosofia do BSD é ser o mais livre possível e eles nunca gostaram muito do GPL v2 por restringir a liberdade dos usuários. A kernel do Linux permaneceu em GPL v2 mas quando componentes como GCC foram migrados para v3 o povo do FreeBSD resolveu levar a sério sair do gcc e foi quando começaram a usar CLang/LLVM no lugar.</p>
<p>BSD, como vocês sabem é a base do Darwin que é a fundação do MacOS e iOS. É uma das razões de porque a Apple investiu tanto em LLVM. Hoje em dia eles também usam somente Clang/LLVM em vez de GCC, e isso acabou gerando frutos possibilitando uma arquitetura flexível e mais moderna e facilitou a invenção da linguagem Swift. Mas isso é tema pra outro episódio.</p>
<p>Como vocês podem ver, licenças é um assunto bem cabeludo. Mas no coração de tudo isso está a história de Richard Stallman e a Free Software Foundation (FS) e a história da Open Source Initiative (OSI) de Eric Raymond, autor do famoso livro The Cathedral and the Bazaar. Esse é o livro que torna famoso a Lei de Linus que diz “dados olhos suficientes, todos os bugs são superficiais”.</p>
<p>Parece a mesma coisa, mas Free Software não é Open Source Software. Open Source é naturalmente mais difundido hoje porque ele é ironicamente mais Free do que o Free Software Foundation, já que é mais amigável a empresas. A Free Software tem a visão mais &ldquo;pura&rdquo; da liberdade do software mas restringindo as liberdades das pessoas. O Free da FSF é manter o software Free, o Free da OSI é garantir as liberdade do uso do software - que incluir a liberdade de fechar o software. Ambos estão certos no abstrato. Eu sempre compartilhei da filosofia da FSF mas eu sei como ela não é tão prática no mundo real comparada à OSI.</p>
<p>Muita gente usa free e open source software. Vocês precisam no mínimo ler os textos que explicam a filosofia GNU no site gnu.org e ler os textos de Eric Raymond.</p>
<p>Free e Open source não deve ter nenhuma conotação política. Política necessariamente define e discrimina grupos. Eric Raymond inclusive criticou sobre o episódio da Lerna dizendo que a Lerna deserdou da comunidade open source e deveria ser evitado por qualquer um que valorize a saúde da comunidade. Ele continua dizendo que a escolha do projeto Lerna destrói uma das normas mais profunda que mantém a comunidade open source funcional: manter política separado do trabalho. Leia o blog post do Eric no link que deixei na descrição do vídeo abaixo.</p>
<p>Na página que define Open Source no site da OSI existe a 5a cláusula: Não discriminação contra pessoas ou grupos. Você jamais pode dizer que é pró-diversidade se você age ativamente para discriminar grupos. E aqui vem o problema: não importa quais grupos, quer você concorde com eles ou não.</p>
<p>Uma frase erroneamente atribuida a Voltaire mas que na verdade foi da escritora inglesa Evely Beatrice Hall que eu uso no cabeçalho do meu perfil do Facebook diz: “Eu discordo do que você diz, mas eu vou defender com minha vida o seu DIREITO de dizer isso.”</p>
<p>É muito fácil dizer &ldquo;somos inclusivos&rdquo;. Ser inclusivo só com seus amigos ou grupo próximo é fácil. Você só sabe se é realmente inclusivo se você tolera alguém que você odeia. Se não conseguir isso, você é, por definição, discriminatório. É muito fácil se auto intitular altruísta, o verdadeiro altruísta primeiro não busca reconhecimento e está disposto a ajudar até mesmo aquele que ele sabe que não o ajudaria. Fora disso você não é nem inclusivo e nem altruísta, está apenas trocando uma boa ação por auto promoção.</p>
<p>E tudo bem, não existe nenhuma lei dizendo que você precisa fazer isso. Você tem o direito de se auto promover. E sabendo disso, para trabalhar em grupos numa comunidade ou na sociedade, você precisa aprender a separar sua ideologia fast-food ou política da moda e o seu trabalho. E pior: tentar fazer ativismo em torno de uma causa que parece justa, fazendo uma ação que é injusta, discriminatória e sequer legalmente válida - ou potenticialmente ilegal é ERRADO. Não se corrige um mal fazendo outro mal, NÃO IMPORTA a intenção. Ou você respeita a lei, ou você não é diferente de quem está criticando, é assim simples. Não existe “ah mas ele fez pior”. Um mal grande ou um mal pequeno, ambos são maus.</p>
<p>Free e Open Source NÃO é um movimento político. Ele não foi feito pra ser usado pra ativismo. Ele não foi feito pra ser usado como instrumento político. Ele não tem conotações sociais. Os desenvolvedores, fora do código, fora do projeto, deveriam ter total liberdade para fazerem o que quiserem, se quiserem ser pró-Trump ou anti-Trump, pró-ICE, ou anti-ICE, não é da conta de ninguém. Por isso eu não gosto da forma como códigos de conduta tem sido usados para ligar a vida pessoal de alguém com sua colaboração.</p>
<p>Colaboração no mundo open source é voluntário. É uma troca justa. Você investe seu tempo e conhecimento construindo partes de um software. Quanto mais o software se torna famoso, mais seu investimento tem um retorno. As empresas podem usar o software com menos custos de manutenção do que se eles tivessem que fazer tudo do zero dentro de casa, então investir em open source também tem retorno de investimento. Open source é um exemplo real de livre-mercado em funcionamento. Só porque um projeto se torna open source, isso não garante seu sucesso, tanto quanto abrir uma empresa não garante que você vai ficar rico. É um ambiente de seleção natural e sobrevivência do mais adaptável.</p>
<p>O mundo open source, ao contrário do que a maioria pensa, é um dos melhores exemplos de livre mercado capitalista pra lidar com softwares que são commodities. Acredite: todo software que não é commodity, não tá aberto ao público.</p>
<p>As licenças de software garantem o uso, modificação e distribuição. A propriedade do projeto, é dos colaboradores.</p>
<p>Você pode mudar uma licença. Mas pra isso precisa colher a autorização de todas as pessoas que já colaboraram com seu projeto. E não se trata de conseguir 51%, precisa de 100%, não importa se a pessoa fez só um commit mudando uma única linha. Ou você valoriza a contribuição de todo mundo ou você não valoriza ninguém. Não existe &ldquo;a maioria decide e a minoria cala a boca&rdquo;. Se fosse assim, open source não existiria como é hoje.</p>
<p>Quando o projeto Eclipse mudou sua licença do CPL para EPL ele levaram mais de um ano pra conseguir todas as aprovações e isso tendo sido bem organizados nesse trabalho.</p>
<p>Achar todas as pessoas pode ser difícil. Conseguir consenso é mais difícil ainda. Talvez você precise remover o código daqueles que não concordaram.</p>
<p>E isso é pra realizar a mudança da licença. Mas mesmo assim, mudanças de licença não são retroativas. Se você deu a licença de uso, você Não pode removê-la no passado. Só pra novos usuários, e só pra novas versões. Senão eu estou retirando direitos que eu dei aos primeiros usuários, se eu fizer isso, qual o propósito de se ter uma licença em primeiro lugar? E que tipo de mal caráter eu estou me tornando se acho que isso é certo? Ah mas a intenção era boa. Não importa. Não é relevante. Você deu uma licença ao usuário que confiou e colaborou no seu software, agora você quer tirar isso dele para comprar a sua consciência frente a um assunto que importância pra você mas pode não ter pra todo mundo. Isso se chama egoísmo. E o assunto em questão eu só vejo de uma forma: criancice e desperdício de talento. Uma pena pois parece que o Jamie costumava ser um bom contribuidor.</p>
<p>Isso tudo que eu acabei de falar é óbvio. Deveria ser óbvio. Deveria ser ainda mais óbvio se você um contribuidor de um Core Team de algum projeto. Um adulto não pode dizer &ldquo;eu era ignorante da lei&rdquo;.  Você não pode assaltar um banco e dizer &ldquo;puts, eu não sabia que não podia assaltar um banco&rdquo;. Ignorância da lei não o torna isento da lei. É SEU direito não se interessar em saber da lei, mas a lei existe independente do que você acha e ela se aplica IGUAL pra todos, independente das suas convicções.
De qualquer forma, o episódio deu uma repercussão mais porque a mídia está toda alvoraçada em torno esse negócio da ICE. O dano foi revertido, mas no frigir dos ovos o projeto e a comunidade ao redor dela foi muito prejudicada por causa de uma ação imatura e impensada. Fica o exemplo.</p>
<p>O assunto de licença, ética, leis direitos é super longo e daria pra fazer uma série inteira, então vou parar por aqui. Espero que este episódio tenha aberto um pouco mais a cabeça de vocês se ainda não sabiam dos conceitos que eu disse aqui. O principal: de boas intenções o inferno tá cheio. Crianças, fiquem longe de confusão! Não vale a pena!</p>
<p>Coloquei links na descrição do vídeo. Contribuam com feedback na seção de comentários abaixo, se gostaram dêem um joinha, não deixem de assinar o canal e clicar no sininho para não perderem os próximos episódios! A gente se vê na próxima! Até mais!</p>
]]></content:encoded><category>open-source</category><category>leis-e-regulacao</category><category>javascript</category><category>akitando</category></item><item><title>Iniciante Experimentando o Rails 5.1.x</title><link>https://akitaonrails.github.io/2017/10/24/iniciante-experimentando-o-rails-5-1-x/</link><guid isPermaLink="true">https://akitaonrails.github.io/2017/10/24/iniciante-experimentando-o-rails-5-1-x/</guid><pubDate>Tue, 24 Oct 2017 16:29:00 -0200</pubDate><description>&lt;p&gt;Uma coisa chata de lidar com projetos de clientes é que a maioria deles demora para fazer um upgrade completo de framework. E não dá para culpá-los, já que boa parte das dependências do ecossistema também leva um tempão para atualizar.&lt;/p&gt;
&lt;p&gt;O &lt;a href="http://weblog.rubyonrails.org/2017/9/29/this-week-in-rails-getting-closer-to-rails-5-2-beta/"target="_blank" rel="noopener"&gt;Rails 5.2 Beta&lt;/a&gt; está chegando, e eu apostaria que a maioria dos projetos Rails lá fora ainda está na versão 4.2, ainda cogitando o salto para o 5.0 (que até não é um upgrade tão complicado).&lt;/p&gt;</description><content:encoded><![CDATA[<p>Uma coisa chata de lidar com projetos de clientes é que a maioria deles demora para fazer um upgrade completo de framework. E não dá para culpá-los, já que boa parte das dependências do ecossistema também leva um tempão para atualizar.</p>
<p>O <a href="http://weblog.rubyonrails.org/2017/9/29/this-week-in-rails-getting-closer-to-rails-5-2-beta/"target="_blank" rel="noopener">Rails 5.2 Beta</a> está chegando, e eu apostaria que a maioria dos projetos Rails lá fora ainda está na versão 4.2, ainda cogitando o salto para o 5.0 (que até não é um upgrade tão complicado).</p>
<p>A propósito, caso você não saiba, o site oficial do Rails Guides tem uma seção dedicada a upgrades. É o <a href="http://guides.rubyonrails.org/upgrading_ruby_on_rails.html"target="_blank" rel="noopener">A Guide for Upgrading Ruby on Rails</a>. O processo de upgrade não é tão difícil <strong>se, e somente se</strong>:</p>
<ul>
<li>
<p>Você tiver uma cobertura de testes razoável. No mínimo, feature specs para as partes mais críticas do sistema.</p>
</li>
<li>
<p>Você subir apenas uma versão de cada vez, nunca pular direto para a mais recente. Por exemplo: se está no Rails 4.1, primeiro sobe para o 4.2, confirma que tudo funciona. Depois vai para o 5.0. E só então vai para o 5.1. Cada versão tem <strong>muitas</strong> deprecations, mudanças de comportamento, alterações na configuração padrão e recursos novos. Cada ponto merece atenção cuidadosa.</p>
</li>
</ul>
<p>Então, o que você está perdendo se ainda está no Rails 4.2?</p>
<p>De novo, caso não saiba, o site oficial do Rails Guides também compila Release Notes detalhadas e fáceis de ler para cada nova versão. As mais recentes são as <a href="http://guides.rubyonrails.org/5_1_release_notes.html"target="_blank" rel="noopener">Ruby on Rails 5.1 Release Notes</a>.</p>
<h2>Começando um novo projeto<span class="hx:absolute hx:-mt-20" id="começando-um-novo-projeto"></span>
    <a href="#come%c3%a7ando-um-novo-projeto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O comando <code>rails new</code> ganhou várias flags novas. Acho que as que a maioria vai usar são:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>rails new --skip-action-mailer --skip-coffee --webpack=react my_fancy_new_project</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Você pode desabilitar recursos que não precisa, como o ActionMailer. Pode desabilitar o CoffeeScript. Foi legal por um tempo, mas agora que temos ES6 é melhor usar direto.</p>
<p>O Rails 5.1 vem com suporte a webpack. Mas até o Rails 5.2 chegar, precisamos rodar o <code>webpack-dev-server</code> manualmente em modo de desenvolvimento para ter hot reload dos assets. Para isso, recomendo instalar o bom e velho <a href="https://github.com/ddollar/foreman"target="_blank" rel="noopener">Foreman</a>. Instale assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>gem install foreman</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E adicione um arquivo <code>Procfile.dev</code> no seu projeto com o seguinte conteúdo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>web: ./bin/rails s -b 0.0.0.0 -p 3000
webpack: ./bin/webpack-dev-server</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora você pode subir seu servidor de desenvolvimento assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>foreman start -f Procfile.dev</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em produção, não precisa do <code>webpack-dev-server</code>, pois a task <code>bin/rails assets:precompile</code> consegue compilar todos os assets como arquivos estáticos com timestamps em <code>public/assets</code>.</p>
<h2>Mudanças no Front-end<span class="hx:absolute hx:-mt-20" id="mudanças-no-front-end"></span>
    <a href="#mudan%c3%a7as-no-front-end" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora você pode comemorar: Yarn, Webpack, e sem mais jQuery pré-instalado. Samuel Muller tem um <a href="http://samuelmullen.com/articles/embracing-change-rails51-adopts-yarn-webpack-and-the-js-ecosystem/"target="_blank" rel="noopener">artigo bem bacana</a> que resume a maioria dessas mudanças em mais detalhes.</p>
<p>O Ruby on Rails agora suporta oficialmente tudo o que o ecossistema Javascript tem a oferecer. Não falta mais nada.</p>
<p>Acabou a era de fazer vendor manual de assets JS no diretório <code>vendor/assets/javascripts</code>. Não precisa mais do <a href="https://rails-assets.org/"target="_blank" rel="noopener">Rails Assets</a>, que era uma fonte secundária do RubyGems específica para empacotar bibliotecas JS como gems.</p>
<p>Digamos que, por algum motivo, você quer o jQuery de volta. Agora é só fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yarn add jquery</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E, como de costume, adicionar no seu manifest <code>app/assets/javascripts/application.js</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>// app/assets/javascripts/application.js
...
//= require jquery
...
//= require_tree .</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O tal <a href="https://github.com/rails/rails/pull/26836"target="_blank" rel="noopener">&ldquo;suporte ao Yarn no Rails 5.1&rdquo;</a> se resume a alguns wrappers e boilerplate. Você pode rodar <code>rails yarn:install</code> para instalar as dependências, mas pode igualmente digitar <code>yarn</code> que ele instala tudo o que está declarado no <code>package.json</code>, como em qualquer projeto puramente Javascript.</p>
<p>Toda a mágica da integração vem com a inclusão da gem <a href="https://github.com/rails/webpacker"target="_blank" rel="noopener">Webpacker</a>. Ela adiciona um monte de configuração de boilerplate para o webpack. E, <strong>dado bônus</strong>: você pode incluí-la hoje mesmo nos seus projetos Rails 4.2+. Comece adicionando a gem ao <code>Gemfile</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># Gemfile
gem &#39;webpacker&#39;, &#39;~&gt; 3.0&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Depois <code>bundle install</code> normalmente e rode:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>bundle exec rake webpacker:install</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se não usou a flag <code>--webpack=react</code> no <code>rails new</code>, pode adicionar depois. Ou adicionar Angular também:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>bundle exec rake webpacker:install:angular
bundle exec rake webpacker:install:react </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Se estiver no Rails 5.1, substitua <code>bundle exec rake</code> por <code>bin/rails</code>.</p>
<p>Adicionar componentes React de verdade exige um pouco mais do que os comandos acima, mas os detalhes fogem ao escopo deste post.</p>
<p>Andy Barnov tem um <a href="https://x-team.com/blog/get-in-full-stack-shape-with-rails-5-1-webpacker-and-reactjs/"target="_blank" rel="noopener">bom post</a> sobre como seguir a convenção de packs do Rails 5.1 para adicionar seus componentes React no pipeline. Como ele recomenda: não briga com as convenções e você fica tranquilo.</p>
<p>Curiosamente, mesmo tendo usado a flag <code>--webpack-react</code> no <code>rails new</code>, ainda precisei rodar o seguinte comando para inicializar o suporte a webpack e react:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>./bin/rails webpacker:install:react</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Mas uma vez feito isso, você tem um novo lugar para adicionar componentes React: o diretório <code>app/javascripts/packs</code>. E nas views, em vez do habitual <code>javascript_include_tag</code>, você usa o novíssimo <code>javascript_pack_tag</code>. O resto você consegue descobrir a partir do componente de exemplo <code>hello_react.jsx</code> que é gerado automaticamente.</p>
<h2>Considerações Finais<span class="hx:absolute hx:-mt-20" id="considerações-finais"></span>
    <a href="#considera%c3%a7%c3%b5es-finais" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agora você tem muito mais opções para Javascript, já que o Rails 5.1 abraça de vez os padrões atuais.</p>
<p>Houve uma época em que ninguém sabia direito como agilizar um <a href="http://guides.rubyonrails.org/asset_pipeline.html"target="_blank" rel="noopener">Asset Pipeline</a>. Era uma bagunça compilar todos os assets num único arquivo com timestamps para cache busting — mas a gem <strong>Sprockets</strong> resolveu isso.</p>
<p>Houve uma época em que o Javascript 5 era uma bagunça monumental. Bibliotecas como o jQuery &ldquo;consertaram&rdquo; de fato a situação do DOM nos browsers, e o CoffeeScript normalizou a linguagem de um jeito que a tornava prazerosa. O ES6 veio tomar as rédeas, mas é muito injusto criticar o jQuery e o CoffeeScript: nem o ES6 nem o HTML5 existiam para resolver o problema quase 10 anos atrás. O jQuery e o CoffeeScript estavam lá, e resolveram.</p>
<p>Quando Angular, Ember e React começaram a surgir, já tínhamos uma solução boa o suficiente para sites pesados em Javascript com o <a href="https://github.com/turbolinks/turbolinks"target="_blank" rel="noopener">Turbolinks</a>. Ainda é uma ótima solução que você deveria considerar antes de adicionar uma solução React/Redux completa (e às vezes desnecessária) de uma tacada só.</p>
<p>CSS é outro assunto. A comunidade Rails também criou o Sass (que o Twitter depois invejou e copiou como Less para o framework Bootstrap).</p>
<p>É fácil olhar para o cenário atual e simplesmente repetir que CoffeeScript é ruim ou que Sprockets é ruim. Mas nos últimos 10 anos essas ferramentas eram o estado da arte — numa época em que as pessoas não tinham Yarn, Webpack, React e tudo o que surgiu nos últimos 3 anos ou assim.</p>
<p>O Rails 5.1 é um release muito bom para casar o melhor do Rails com o melhor que se estabilizou no cenário caótico do Javascript. Recomendo fortemente que qualquer projeto novo, em campo aberto, comece com o Rails 5.1 em mente.</p>
<p>O que me motivou a escrever este post foi destacar que muita gente faz perguntas que já estão respondidas no <a href="http://guides.rubyonrails.org/"target="_blank" rel="noopener">Rails Guides</a> oficial. Não só sobre como instalar e usar os vários componentes do framework, mas também como fazer upgrade e quais são as novidades de cada release. Vale a pena dar uma olhada mais cuidadosa por lá.</p>
]]></content:encoded><category>rails</category><category>javascript</category><category>frontend</category></item><item><title>A Obrigatória "Flame War": Phoenix vs Node.js</title><link>https://akitaonrails.github.io/2015/12/03/a-obrigatoria-flame-war-phoenix-vs-nodejs/</link><guid isPermaLink="true">https://akitaonrails.github.io/2015/12/03/a-obrigatoria-flame-war-phoenix-vs-nodejs/</guid><pubDate>Thu, 03 Dec 2015 12:01:00 -0200</pubDate><description>&lt;p&gt;Já vou avisando logo de cara: este post vai ser muito injusto. Não só sou suspeito por não gostar de Javascript e Node.js, como neste momento estou animadíssimo e fascinado com Elixir e Erlang.&lt;/p&gt;
&lt;p&gt;Comparações são sempre injustas. Não existe isso de benchmark sintético &amp;ldquo;justo&amp;rdquo;, o autor está &lt;strong&gt;sempre&lt;/strong&gt; enviesado para chegar em algum resultado pré-determinado. É o velho caso da pseudociência onde você já tem a conclusão na cabeça e sai catando dados que confirmam essa conclusão. As variáveis são muitas demais. As pessoas acham que fica justo quando você roda na mesma máquina contra dois tipos &amp;ldquo;parecidos&amp;rdquo; de aplicação, mas não fica. E também não confie em mim, faça seus próprios testes.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Já vou avisando logo de cara: este post vai ser muito injusto. Não só sou suspeito por não gostar de Javascript e Node.js, como neste momento estou animadíssimo e fascinado com Elixir e Erlang.</p>
<p>Comparações são sempre injustas. Não existe isso de benchmark sintético &ldquo;justo&rdquo;, o autor está <strong>sempre</strong> enviesado para chegar em algum resultado pré-determinado. É o velho caso da pseudociência onde você já tem a conclusão na cabeça e sai catando dados que confirmam essa conclusão. As variáveis são muitas demais. As pessoas acham que fica justo quando você roda na mesma máquina contra dois tipos &ldquo;parecidos&rdquo; de aplicação, mas não fica. E também não confie em mim, faça seus próprios testes.</p>
<p>Dito tudo isso, vamos nos divertir um pouco, certo?</p>
<h3>O Obrigatório Aquecimento &ldquo;Hello World&rdquo;<span class="hx:absolute hx:-mt-20" id="o-obrigatório-aquecimento-hello-world"></span>
    <a href="#o-obrigat%c3%b3rio-aquecimento-hello-world" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Para este post bem curto, criei só um &ldquo;hello world&rdquo; com Node.js + Express, vou apontar para o endpoint raiz, o Express renderizando um template HTML supersimples com um título e um parágrafo.</p>
<p>Para Elixir, fiz o bootstrap de um projeto Phoenix básico e adicionei um endpoint extra chamado &ldquo;/teste&rdquo; no Router. Esse endpoint chama o PageController, depois a função &ldquo;teste&rdquo;, e renderiza um template EEX com o mesmo título e parágrafo do exemplo em Express.</p>
<p>Bem simples. O Phoenix faz mais coisa que o Express, mas isso aqui de qualquer forma não é para ser um julgamento justo. Escolhi o <a href="https://www.joedog.org/siege-home/"target="_blank" rel="noopener">Siege</a> como ferramenta de teste sem nenhum motivo especial. Você pode escolher a ferramenta que mais gostar. Estou rodando isso no meu Macbook Pro 2013 com 8 cores e 16GB de RAM, então esse benchmark nunca vai estourar a minha máquina.</p>
<p>O primeiro teste é uma rodada simples de 200 conexões concorrentes (o número de CPUs que tenho) disparando 8 requisições cada, totalizando 1.600. Primeiro, os resultados do Node.js + Express:</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Node+8+x+200.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Node+8+x+200.mp4)
</source></video>
<p>A primeira rodada já quebrou algumas conexões, mas a segunda rodada se recuperou e terminou as 1.600 requisições. E estes são os resultados do Phoenix:</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Phoenix+8+x+200.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Phoenix+8+x+200.mp4)
</source></video>
<p>Como dá para ver, o Node.js leva vantagem em tempo total gasto. Um único processo Node.js só consegue rodar uma única thread real do SO. Por isso ele teve que usar apenas um core de CPU (apesar de eu ter outros 7 cores sobrando). Por outro lado, o Elixir consegue alcançar todos os 8 cores da minha máquina, cada um rodando um Scheduler em uma thread real do SO. Então, se esse teste fosse CPU bound, deveria ter rodado 8 vezes mais rápido que a versão Node.js. Como o teste é majoritariamente um caso de operações I/O bound, a construção async esperta do Node.js dá conta do recado.</p>
<p>Esse não é um teste impressionante nem de longe. Mas estamos só esquentando.</p>
<p>Ah, e aproveitando, repare como os logs do Phoenix mostram os tempos de processamento das requisições em MICROssegundos em vez de milissegundos!</p>
<h3>A Diversão de Verdade<span class="hx:absolute hx:-mt-20" id="a-diversão-de-verdade"></span>
    <a href="#a-divers%c3%a3o-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Agora vem a diversão de verdade. Nesta segunda rodada, adicionei uma chamada bloqueante de &ldquo;sleep&rdquo; nos dois projetos, então cada requisição vai dormir por um segundo inteiro, e isso não é absurdo. Muitos programadores escrevem código ruim que bloqueia por esse tempo, processam dados demais do banco, renderizam templates complexos demais, e por aí vai. Nunca confie que um programador vai fazer as melhores práticas o tempo todo.</p>
<p>Daí, disparo o Siege com dez conexões concorrentes e só uma requisição cada, para começar.</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Node+1+x+10+Sleep.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Node+1+x+10+Sleep.mp4)
</source></video>
<p>É por isso que no meu artigo anterior &ldquo;Why Elixir?&rdquo; (<a href="http://www.akitaonrails.com/2015/12/01/o-obrigatorio-por-que-elixir-visao-pessoal%29"target="_blank" rel="noopener">http://www.akitaonrails.com/2015/12/01/o-obrigatorio-por-que-elixir-visao-pessoal)</a>, repeti várias vezes o quão <strong>&ldquo;rudimentar&rdquo;</strong> é uma solução baseada no padrão Reactor. É facílimo bloquear um event loop single-threaded.</p>
<p>Se você ainda não sabia, como o Node.js funciona? Em resumo, é um simples loop infinito. Quando uma função Javascript roda, ela bloqueia esse event loop. A função tem que explicitamente devolver o controle para o loop para que outra função tenha a chance de rodar. Chamadas de I/O demoram e ficam paradas esperando uma resposta, então ela pode devolver o controle e esperar um callback para continuar rodando, e é por isso que você acaba na temida <em>&ldquo;pirâmide do callback hell&rdquo;</em>.</p>
<p>Agora, com tudo o que expliquei nos artigos anteriores, você já deve imaginar como Elixir + Phoenix vai se sair:</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Phoenix+2+x+400+-+Sleep.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/Phoenix+2+x+400+-+Sleep.mp4)
</source></video>
<p>Como esperado, isso é um passeio no parque para o Phoenix. Ele não tem um loop single-thread rudimentar esperando que as funções em execução devolvam o controle por boa vontade. Os Schedulers conseguem suspender à força corrotinas/processos rodando se acharem que estão demorando demais (a contagem de 2.000 reductions e configurações de prioridade), então cada processo em execução tem uma fatia justa de recursos para rodar.</p>
<p>Por causa disso, posso ir aumentando o número de requisições e conexões concorrentes, e continua <strong>rápido</strong>.</p>
<p>No Node.js, se uma função demora 1 segundo para rodar, ela bloqueia o loop. Quando finalmente retorna, a próxima função de 1 segundo pode rodar. É por isso que se eu tenho dez requisições demorando 1 segundo cada para rodar, o processo inteiro vai linearmente levar 10 segundos!</p>
<p>O que obviamente não escala! Se você &ldquo;fizer do jeito certo&rdquo;, consegue escalar. Mas para que se dar ao trabalho?</p>
<h3>&ldquo;Node&rdquo; feito direito<span class="hx:absolute hx:-mt-20" id="node-feito-direito"></span>
    <a href="#node-feito-direito" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Como nota lateral, acho irônico que &ldquo;Node&rdquo; se chame &ldquo;Node&rdquo;. Eu suporia que conectar múltiplos Nodes que se comunicam entre si fosse fácil. E na prática, <a href="http://www.sitepoint.com/how-to-create-a-node-js-cluster-for-speeding-up-your-apps/"target="_blank" rel="noopener">não é</a>.</p>
<p>Se eu tivesse subido 5 processos Node, em vez de 10 segundos, tudo demoraria 2 segundos, já que cinco requisições bloqueariam os 5 processos Node por 1 segundo, e quando retornassem, as próximas cinco requisições bloqueariam de novo. Isso é parecido com o que precisamos fazer com Ruby ou Python, que têm os temidos Global Interpreter Locks (GIL) que, na realidade, só conseguem rodar uma computação bloqueante por vez. (Ruby com Eventmachine e Python com Tornado ou Twisted são parecidos com a implementação de event loop reactor do Node.js).</p>
<p>O Elixir consegue fazer muito melhor para coordenar de fato nodes diferentes, e são as bases de Erlang que permitem que sistemas altamente distribuídos como <a href="https://www.ejabberd.im/"target="_blank" rel="noopener">ejabberd</a> ou <a href="https://www.rabbitmq.com/"target="_blank" rel="noopener">RabbitMQ</a> façam o que fazem com toda eficiência.</p>
<p>Olha como é simples para um Elixir Node detectar a presença de outros nodes Elixir e fazer com que mandem e recebam mensagens entre si:</p>
<video controls>
<source src="https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/7+-+Nodes.mp4">
Your browser does not support the video tag. [Direct Link](https://s3.us-east-2.amazonaws.com/blip.tv/Elixir/7+-+Nodes.mp4)
</source></video>
<p>Isso, é simples assim. A gente usa Remote Procedure Calls (RPC) há décadas; isso não é novidade. Erlang implementou isso há anos, e está embutido e disponível para uso fácil out-of-the-box.</p>
<p>Nos sites deles, o ejabberd se autointitula um &ldquo;Robust, Scalable, and Extensible XMPP Server&rdquo;, e o RabbitMQ se autointitula &ldquo;Robust messaging for applications&rdquo;. Agora sabemos que eles merecem os rótulos &ldquo;Robust&rdquo; e &ldquo;Scalable&rdquo;.</p>
<p>Então, estamos nos matando para fazer coisas que estão polidas e prontas há anos. O Elixir é a chave para destravar toda essa bondade do Erlang agora mesmo. Vamos só usar e parar de dar de ombros.</p>
]]></content:encoded><category>performance</category><category>elixir-e-erlang</category><category>javascript</category></item><item><title>[Small-Bites] Em defesa do Asset Pipeline: tudo que você precisa</title><link>https://akitaonrails.github.io/2014/12/02/small-bites-em-defesa-do-asset-pipeline-tudo-que-voce-precisa/</link><guid isPermaLink="true">https://akitaonrails.github.io/2014/12/02/small-bites-em-defesa-do-asset-pipeline-tudo-que-voce-precisa/</guid><pubDate>Tue, 02 Dec 2014 17:26:00 -0200</pubDate><description>&lt;p&gt;No atual caos que são as opções no mundo Javascript para gerenciamento de dependências (CommonJS, AMD, ES6-modules), sistemas de build (Grunt, Gulp, Broccoli), pacotes (NPM, Bower) é fácil sermos contaminados com o velho &amp;ldquo;F.U.D.&amp;rdquo; (Fear, Uncertainty, Doubt).&lt;/p&gt;
&lt;p&gt;Asset Management é um problema praticamente todo resolvido no mundo Rails desde Fevereiro de 2009 (nós basicamente criamos o conceito). Mesmo assim, ainda temos que ouvir afirmações sem sentido como &amp;ldquo;precisamos consertar ou substituir o Asset Pipeline&amp;rdquo; e então nascem coisas como &amp;ldquo;requirejs-rails&amp;rdquo; ou receitas de como desabilitar o Sprockets e usar outras coisas. Em resumo: não faça isso.&lt;/p&gt;</description><content:encoded><![CDATA[<p>No atual caos que são as opções no mundo Javascript para gerenciamento de dependências (CommonJS, AMD, ES6-modules), sistemas de build (Grunt, Gulp, Broccoli), pacotes (NPM, Bower) é fácil sermos contaminados com o velho &ldquo;F.U.D.&rdquo; (Fear, Uncertainty, Doubt).</p>
<p>Asset Management é um problema praticamente todo resolvido no mundo Rails desde Fevereiro de 2009 (nós basicamente criamos o conceito). Mesmo assim, ainda temos que ouvir afirmações sem sentido como &ldquo;precisamos consertar ou substituir o Asset Pipeline&rdquo; e então nascem coisas como &ldquo;requirejs-rails&rdquo; ou receitas de como desabilitar o Sprockets e usar outras coisas. Em resumo: não faça isso.</p>
<p>Até eu fico sem paciência para participar dessas discussões porque, no final do dia, o que precisamos é da solução mais simples que funciona e podemos confiar. E sem mais delongas eu elejo a combinação ModuleJS e Rails-Assets como as melhores opções.</p>
<p>Antes de continuar vou assumir que você pelo menos leu (ou já conhece) os seguintes assuntos:</p>
<ul>
<li><a href="http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes"target="_blank" rel="noopener">Asset Pipeline para Iniciantes</a></li>
<li><a href="http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes-parte-2"target="_blank" rel="noopener">Asset Pipeline para Iniciantes - Parte 2</a></li>
<li><a href="http://www.akitaonrails.com/2013/12/13/rails-assets"target="_blank" rel="noopener">Rails Assets</a></li>
</ul>
<p>Para ilustrar a solução vamos direto a um pequeno exemplo. Se for algo pequeno, podemos ficar tentados a colocar tudo no <tt>app/assets/application.js</tt>, como por exemplo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">Foo</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">hello</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;Hello&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nx">world</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;World&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">Bar</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">helloWorld</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">Foo</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&#34; &#34;</span> <span class="o">+</span> <span class="nx">Foo</span><span class="p">.</span><span class="nx">world</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;body&#39;</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;&lt;p&gt;&#39;</span> <span class="o">+</span> <span class="nx">Bar</span><span class="p">.</span><span class="nx">helloWorld</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;&lt;/p&gt;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso vai simplesmente adicionar um parágrafo escrito &ldquo;Hello World&rdquo; na página. A idéia é um exemplo bem trivial para que a técnica fique clara, mas obviamente imagine isso em algo mais complicado.</p>
<p>A primeira coisa que gostaríamos de fazer é separar esse código. Talvez quebrar em arquivos como <tt>app/assets/javascripts/foo.js</tt> e <tt>app/assets/javascripts/bar.js</tt>. Então vamos direto ao assunto e adicionar o <a href="http://larsjung.de/modulejs/"target="_blank" rel="noopener">ModuleJS</a> diretamenta à nossa <tt>Gemfile</tt>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># Gemfile</span>
</span></span><span class="line"><span class="cl"><span class="n">source</span> <span class="s1">&#39;https://rails-assets.org&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ...</span>
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rails-assets-modulejs&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Depois de instalar com o bom e velho <tt>bundle install</tt>. Modificamos o <tt>app/assets/javascripts/application.js</tt> para carregar a dependência:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">//= require jquery
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require jquery_ujs
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require modulejs
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require_tree .
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Isso foi o que eu já expliquei no meu post mais antigo sobre <a href="http://www.akitaonrails.com/2013/12/13/rails-assets"target="_blank" rel="noopener">Rails Assets</a>. Se a biblioteca que você quer tem um pacote Bower, ele pode ser automaticamente encapsulado numa gem de Rails Engine como uma gem feita manualmente. E se não tiver como pacote Bower aí não tem jeito: baixe os arquivos e jogue num diretório em <tt>vendor/assets</tt> para mantê-la estática dentro do projeto, mas o ideal é que você <strong>não</strong> deixe bibliotecas javascript vendorizados.</p>
<p>Para começar a refatoração do javascript acima, vamos começar quebrando os objetos &lsquo;Foo&rsquo; e &lsquo;Bar&rsquo; em dois arquivos:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// app/assets/javascripts/foo.js
</span></span></span><span class="line"><span class="cl"><span class="nx">modulejs</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span> <span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">hello</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="s2">&#34;Hello&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nx">world</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="s2">&#34;World&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// app/assets/javascripts/bar.js
</span></span></span><span class="line"><span class="cl"><span class="nx">modulejs</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span> <span class="s1">&#39;bar&#39;</span><span class="p">,</span> <span class="p">[</span> <span class="s1">&#39;foo&#39;</span> <span class="p">],</span> <span class="kd">function</span><span class="p">(</span><span class="nx">Foo</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">helloWorld</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="nx">Foo</span><span class="p">.</span><span class="nx">hello</span><span class="p">()</span> <span class="o">+</span> <span class="s2">&#34; &#34;</span> <span class="o">+</span> <span class="nx">Foo</span><span class="p">.</span><span class="nx">world</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja que não precisamos mais das constantes &lsquo;Foo&rsquo; e &lsquo;Bar&rsquo;, apenas devolver o corpo do hash com as funções. No módulo &lsquo;bar&rsquo;, declaramos que precisamos do módulo &lsquo;foo&rsquo; (em um array) e passamos como parâmetro do construtor com o nome antigo da constante &lsquo;Foo&rsquo;, daí internamente o código se mantém exatamente o mesmo. E já que estamos modularizando, vamos adicionar um módulo que encapsula a chamada principal:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// app/assets/javascripts/main.js
</span></span></span><span class="line"><span class="cl"><span class="nx">modulejs</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span> <span class="s1">&#39;main&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;bar&#39;</span><span class="p">,</span> <span class="s1">&#39;jquery&#39;</span><span class="p">],</span> <span class="kd">function</span><span class="p">(</span><span class="nx">Bar</span><span class="p">,</span> <span class="nx">$</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">start</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;body&#39;</span><span class="p">).</span><span class="nx">append</span><span class="p">(</span><span class="s1">&#39;&lt;p&gt;&#39;</span> <span class="o">+</span> <span class="nx">Bar</span><span class="p">.</span><span class="nx">helloWorld</span><span class="p">()</span> <span class="o">+</span> <span class="s1">&#39;&lt;/p&gt;&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Como pode ver acima, o módulo &lsquo;main&rsquo; vai depender do &lsquo;bar&rsquo; (definido em &lsquo;bar.js&rsquo;) e também de um &lsquo;jquery&rsquo; que ainda não existe, então vamos criar um genérico <tt>modules.js</tt> para encapsular o jQuery assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">// app/assets/javascripts/modules.js
</span></span></span><span class="line"><span class="cl"><span class="nx">modulejs</span><span class="p">.</span><span class="nx">define</span><span class="p">(</span> <span class="s1">&#39;jquery&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">jQuery</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Veja que podemos fazer a mesma coisa para qualquer outra biblioteca. Damos um nome em string, no caso &lsquo;jquery&rsquo;, que o ModuleJS vai conseguir encontrar depois e retornamos a classe principal, só isso.</p>
<p>Para finalizar no arquivo original <tt>application.js</tt> chamamos esse novo &lsquo;main&rsquo; assim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">modulejs</span><span class="p">.</span><span class="nx">require</span><span class="p">(</span><span class="s1">&#39;main&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">app</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Pronto! Tudo isolado e com as dependências todas controladas. A grande vantagem de fazer desta forma é que no cabeçalho do <tt>application.js</tt> podemos continuar declarando as dependências com o <tt>require_tree .</tt> pois não importa a ordem dos arquivos, apenas a chamada principal do módulo &lsquo;main&rsquo;.</p>
<p>Pronto, não precisamos de RequireJS, podemos continuar usando o Asset Pipeline que vai gerar os arquivos minificados como o Rails sempre fez e com o mínimo de dependências que podem causar conflitos difíceis de rastrear depois. Vá adicionando seus pacotes preferidos de Bower diretamente na <tt>Gemfile</tt> e continue usando apenas um sistema de gerenciamento de dependência que sabemos que funciona: Bundler.</p>
]]></content:encoded><category>rails</category><category>javascript</category><category>frontend</category></item><item><title>Web Components é uma Revolução?</title><link>https://akitaonrails.github.io/2014/07/06/web-components-e-uma-revolucao/</link><guid isPermaLink="true">https://akitaonrails.github.io/2014/07/06/web-components-e-uma-revolucao/</guid><pubDate>Sun, 06 Jul 2014 01:09:00 -0300</pubDate><description>&lt;p&gt;Existe uma nova celebridade na cidade, e seu nome é &lt;a href="http://webcomponents.org/"target="_blank" rel="noopener"&gt;&amp;ldquo;Web Components&amp;rdquo;&lt;/a&gt;. Ultimamente muitos apresentam esta nova tecnologia como o &amp;lsquo;Santo Graal&amp;rsquo; que vai resolver todos os problemas da Web. Este artigo não é um apoio incondicional, não é uma crítica negativa irrefutável, mas meramente uma apresentação de perspectivas com o objetivo de dar clareza. Nenhuma discussão pode funcionar onde os gritos mais altos são simplesmente &lt;em&gt;&amp;ldquo;Isso vai revolucionar a Web!&amp;rdquo;&lt;/em&gt; (sem explicar porque) ou &lt;em&gt;&amp;ldquo;O Google e a Mozilla estão por trás então é foda!&amp;rdquo;&lt;/em&gt; (sem comentários).&lt;/p&gt;</description><content:encoded><![CDATA[<p>Existe uma nova celebridade na cidade, e seu nome é <a href="http://webcomponents.org/"target="_blank" rel="noopener">&ldquo;Web Components&rdquo;</a>. Ultimamente muitos apresentam esta nova tecnologia como o &lsquo;Santo Graal&rsquo; que vai resolver todos os problemas da Web. Este artigo não é um apoio incondicional, não é uma crítica negativa irrefutável, mas meramente uma apresentação de perspectivas com o objetivo de dar clareza. Nenhuma discussão pode funcionar onde os gritos mais altos são simplesmente <em>&ldquo;Isso vai revolucionar a Web!&rdquo;</em> (sem explicar porque) ou <em>&ldquo;O Google e a Mozilla estão por trás então é foda!&rdquo;</em> (sem comentários).</p>
<p>Do ponto de vista puramente técnico é muito simples entender o que é um &ldquo;Web Component&rdquo;. Ele é o conjunto de 4 tecnologias de navegadores web.</p>
<ul>
<li>Custom Elements</li>
<li>HTML Imports</li>
<li>Templates</li>
<li>Shadow DOM</li>
</ul>
<p>Colocando em ordem de importância, eu resumiria da seguinte forma:</p>
<ul>
<li>Custom Elements - permite criar tags diferente dos canônicos como &ldquo;body&rdquo;, &ldquo;input&rdquo; e evitar o classes-hell ou div-hell onde tudo é um punhado de divs dentro de divs criando os horrendos macarrões de tags. A idéia é encapsular tudo dentro de tags simples e mais fáceis de manusear.</li>
<li>Shadow DOM - para o fator encapsulamento, precisamos primeiro conseguir eliminar o sangramento de estilos e comportamentos por tudo que existe numa página. Shadow DOM permite criar trechos de nós de elementos de DOM que são independentes e isolados entre si, onde o estilo de um trecho não interfere com outro. Somente o Chrome e Firefox mais novos suportam isso. WebKit/Safari deixou de suportar a implementação incompleta que tinham (mas talvez voltem) e o IE, para variar, nunca nem tentou implementar isso. Para funcionar na maioria dos navegadores existem projetos como o Polymer/Platform e X-Tag para servir como &ldquo;polyfill&rdquo; para navegadores legados.</li>
<li>Templates - como o nome diz, para criar componentes dinâmicos, é importante ter trechos de DOM inertes, diferentes de somente uma string, para conseguir manipular e instanciar conforme necessário. Por exemplo, linhas de uma tabela dinâmica. Existem várias bibliotecas de templates, como Mustache, mas para Web Components funcionar, era importante ter um padrão.</li>
<li>HTML Imports - e uma vez tendo um trecho de DOM isolado, com estilos e comportamentos independentes de outros componentes, agora precisamos empacotar isso. E para isso servem esses imports que basicamente é um arquivo HTML que declara os arquivos CSS e Javascript que ele depende, e o HTML Import sabe como carregar tudo de uma vez. Aqui fica uma das minhas maiores preocupações - que vou tentar explicar mais para o fim.</li>
</ul>
<p>Existem já dezenas de artigos e documentação de como é um Web Component, como construir um do zero e onde encontrar componentes. Não é foco deste artigo explicar os detalhes técnicos de um Web Component.</p>
<p>Por si só, devo dizer que são tecnologias interessantes que todo bom nerd gosta de brincar. Porém não deveria ser novidade que só porque alguma coisa é tecnicamente interessante, por si só, não garante absolutamente nada. A principal pergunta é: <em>&ldquo;o que eu ganho com isso?&rdquo;</em> Antes de responder a essa pergunta, toda tecnologia é somente uma solução procurando um problema.</p>
<p>Infelizmente nem eu, nem ninguém, temos como prever o futuro, então neste artigo quero avaliar qualquer proposta baseado no que temos no presente, relembrar o passado e o que isso pode representar no curto prazo. O longo prazo deixo para os profetas e quem gosta de apostar em loteria. Então vou tentar quebrar alguns dos grandes problemas do desenvolvimento Web que temos hoje.</p>
<h2>O Problema do HTML/CSS macarrônicos<span class="hx:absolute hx:-mt-20" id="o-problema-do-htmlcss-macarrônicos"></span>
    <a href="#o-problema-do-htmlcss-macarr%c3%b4nicos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A forma de desenhar uma página Web mudou bastante nos últimos 20 anos. As tecnologias básicas ainda são as mesmas: HTML 5 para estruturar um documento. CSS 3 para estilizar os elementos nesse documento. Javascript para adicionar comportamento. Acho que a esta altura todos já sabemos que devemos separar estilização/apresentação da estrutura e conteúdo. Também sabemos que não devemos nem usar tabelas para tudo e nem usar divs com float para tudo.</p>
<p>Passamos pela era da <a href="http://semanticweb.org/wiki/Main_Page"target="_blank" rel="noopener">Web Semântica</a> e <a href="http://www.smashingmagazine.com/2011/01/12/guidelines-for-responsive-web-design/"target="_blank" rel="noopener">Web Responsiva</a>. Quando os navegadores implementaram tables no <a href="http://www.barrypearson.co.uk/articles/layout_tables/history.htm"target="_blank" rel="noopener">Netscape Navigator 1.1 e IE 2.0 em 1995 e 1996</a> ainda não se falava em acessibilidade e semântica apareceriam a partir de 1997 com o HTML 3.2. Estávamos criando a Web e usando ao mesmo tempo, como hoje as implementações apareciam antes de se ter uma especificação mais geral. A W3C é lenta não é de hoje.</p>
<p>Acho que a evangelização de Responsive Web também merece um &ldquo;rant&rdquo; mas fica para outro artigo.</p>
<p>Mesmo assim ainda somos reféns de códigos como deste exemplo de tabs do framework <a href="http://getbootstrap.com/components/#input-groups"target="_blank" rel="noopener">Bootstrap</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav nav-tabs&#34;</span> <span class="na">role</span><span class="o">=</span><span class="s">&#34;tablist&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;active&#34;</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Profile<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Messages<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E vejamos um trecho para tabs mas usando um web component do novíssimo <a href="http://www.polymer-project.org/components/paper-elements/demo.html#paper-tabs"target="_blank" rel="noopener">Polymer/Paper</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">paper-tabs</span> <span class="na">selected</span><span class="o">=</span><span class="s">&#34;0&#34;</span> <span class="na">selectedindex</span><span class="o">=</span><span class="s">&#34;0&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;paper_tabs&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">paper-tab</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tab_home&#34;</span> <span class="na">active</span><span class="p">&gt;</span>Home<span class="p">&lt;/</span><span class="nt">paper-tab</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">paper-tab</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tab_profile&#34;</span><span class="p">&gt;</span>Profile<span class="p">&lt;/</span><span class="nt">paper-tab</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">paper-tab</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;tab_messages&#34;</span><span class="p">&gt;</span>Messages<span class="p">&lt;/</span><span class="nt">paper-tab</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">paper-tabs</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse é o resultado da primeira tecnologia de Web Components: <a href="http://www.html5rocks.com/en/tutorials/webcomponents/customelements/"target="_blank" rel="noopener">Custom Elements</a>. De fato isso acrescenta uma clareza enorme. No primeiro exemplo o que temos é:</p>
<blockquote>"Uma lista não ordenada com classes nav e nav-tags e dentro delas itens de lista."</blockquote>
<p>Se você souber o que são as classes &ldquo;nav&rdquo; e &ldquo;nav-tabs&rdquo; vamos saber que se trata de uma lista de tabs. No caso do exemplo do Paper podemos ler claramente:</p>
<blockquote>"Um conjunto de tabs, implementado com Paper."</blockquote>
<p>Isto é um exemplo pequeno mas imaginando como páginas Web são complexas, tirar a ambiguidade de para que servem cada conjunto de tags numa árvore infinita de tags é muito importante. Perdemos muito tempo em tentativa e erro de retirar pedaços e tentando inserir outros pedaços no meio da árvore de HTML e decifrando nomes de classes CSS.</p>
<p>Na prática, sem ter Custom Elements para tornar as tags mais amigáveis, outra forma é encapsular a inicialização usando um marcador simples numa tag HTML (como uma classe CSS ou ID) e ativar o resto via Javascript. É como todo plugin JQuery funciona. Um exemplo simples é como encapsulamos o Google Maps com o plugin <a href="http://gmap3.net/en/catalog/9-map/map-32"target="_blank" rel="noopener">Gmap3</a> do JQuery:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;my-map&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nx">$</span><span class="p">(</span><span class="s2">&#34;#my-map&#34;</span><span class="p">).</span><span class="nx">gmap3</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">map</span><span class="o">:</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">address</span><span class="o">:</span><span class="s2">&#34;Cupertino, CA&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">options</span><span class="o">:</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">zoom</span><span class="o">:</span><span class="mi">4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mapTypeId</span><span class="o">:</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">MapTypeId</span><span class="p">.</span><span class="nx">SATELLITE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mapTypeControl</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mapTypeControlOptions</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">style</span><span class="o">:</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">MapTypeControlStyle</span><span class="p">.</span><span class="nx">DROPDOWN_MENU</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">navigationControl</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">scrollwheel</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">streetViewControl</span><span class="o">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E outro exemplo com a alternativa com o <a href="http://polymerlabs.github.io/google-map/components/google-map/"target="_blank" rel="noopener">Web Component Google-Map</a> (lembrando que esta versão é mais simples do que o plugin Gmap3):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">google-map</span> <span class="na">latitude</span><span class="o">=</span><span class="s">&#34;37.77493&#34;</span> <span class="na">longitude</span><span class="o">=</span><span class="s">&#34;-122.41942&#34;</span> <span class="na">fitToMarkers</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">google-map-marker</span> <span class="na">latitude</span><span class="o">=</span><span class="s">&#34;37.779&#34;</span> <span class="na">longitude</span><span class="o">=</span><span class="s">&#34;-122.3892&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="na">draggable</span><span class="o">=</span><span class="s">&#34;true&#34;</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;Go Giants!&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">google-map-marker</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">google-map-marker</span> <span class="na">latitude</span><span class="o">=</span><span class="s">&#34;37.777&#34;</span> <span class="na">longitude</span><span class="o">=</span><span class="s">&#34;-122.38911&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">google-map-marker</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">google-map</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Estamos movendo parte do que faríamos via Javascript de volta ao HTML. Mas somente isso não é suficiente e já sabemos disso. A tecnologia de &ldquo;Cascading Style Sheet versão 3&rdquo;, comumente conhecida como CSS 3 até hoje permanece arcaica. Felizmente inventamos uma forma de tornar os malditos macarrões de CSS gerenciáveis. Agradecimentos são devidos à <a href="http://www.hamptoncatlin.com"target="_blank" rel="noopener">Hampton Catlin</a>, um grande rubista que - em <strong>2007</strong> - inventou a <a href="http://sass-lang.com/"target="_blank" rel="noopener">linguagem de script SASS</a>, que é um &ldquo;super-set&rdquo; de CSS e gera CSS 3, adicionando variáveis, nesting, partials, import, mixins, extensão/herança, operadores.</p>
<p>SASS foi a primeira linguagem de pré-processamento que acelerou a idéia da possibilidade de novas formas de gerenciar assets Web como CSS. Depois dele vieram LESS e toda uma gama de frameworks e bibliotecas como <a href="http://singularity.gs/"target="_blank" rel="noopener">Singularity</a>, <a href="http://neat.bourbon.io/"target="_blank" rel="noopener">Bourbon Neat</a>, <a href="http://susy.oddbird.net/"target="_blank" rel="noopener">Susy</a>, <a href="http://foundation.zurb.com/"target="_blank" rel="noopener">Zurb Foundation</a>, <a href="http://compass-style.org/"target="_blank" rel="noopener">Compass</a>. Foi uma pena terem escrito o Twitter Bootstrap original em <a href="http://wordsbyf.at/2012/03/08/why-less/"target="_blank" rel="noopener">LESS em vez de SASS</a>, mas acho que o projeto <a href="http://libsass.org/"target="_blank" rel="noopener">LibSass</a> (SASS escrito em C) ainda não existia. Mas pelo próprio exemplo acima fica claro porque você deveria escolher outro framework em vez de Bootstrap.</p>
<p>Porém SASS não foi a primeira vez que alguém criou um pré-processador para a Web. Provavelmente a primeira foi a <a href="http://en.wikipedia.org/wiki/Wiki_markup"target="_blank" rel="noopener">Wiki Markup</a> implementada junto com o primeiro Wiki, o <a href="http://en.wikipedia.org/wiki/WikiWikiWeb"target="_blank" rel="noopener">WikiWikiWeb</a> de Ward Cunningham em 1995. Depois disso ainda tivemos o MediaWiki da Wikipedia até chegarmos atualmente a pré-processadores de HTML como Markdown, que praticamente usamos sem pensar em comentários de Github.</p>
<p>No mundo Rails já tentamos melhorar o HTML também, com pré-processadores como o HAML (do próprio Catlin) ou outros mais recentes como <a href="http://slim-lang.com/"target="_blank" rel="noopener">Slim</a>. Mas nesse caso ainda não estamos melhorando o HTML tão drasticamente como SASS faz com CSS, por isso ainda não há uma boa alternativa e Custom Elements é o mais próximo de uma boa alternativa neste momento.</p>
<p>Estou trazendo estes pontos porque Web Components não declara nenhum pré-processador de CSS como padrão, por convenção. Assumimos CSS 3 puro. Não é um problema, mas se estamos falando de reuso, atualmente a melhor forma é usando mixins de SASS encapsuladas em bibliotecas como Compass ou Bourbon.</p>
<h2>O Problema do Sangramento de Estilos e Comportamentos<span class="hx:absolute hx:-mt-20" id="o-problema-do-sangramento-de-estilos-e-comportamentos"></span>
    <a href="#o-problema-do-sangramento-de-estilos-e-comportamentos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Este é um dos aspectos mais irritantes de desenvolvimento front-end depois da compatibilidade de navegadores: como organizar as milhares de linhas de CSS? (seja ele puro, escrito em SASS ou LESS).</p>
<p>Antes de continuar, se nunca ouviu falar de <a href="http://markdaggett.com/blog/2011/12/04/css-anti-patterns/"target="_blank" rel="noopener">CSS Anti-patterns</a>, leia a respeito antes. E também que todos já pelo menos ouviram falar nas diversas metodologias para organizar CSS (<a href="http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/"target="_blank" rel="noopener">OOCss</a> , <a href="http://www.smashingmagazine.com/2012/04/20/decoupling-html-from-css/"target="_blank" rel="noopener">SMACSS</a>, <a href="http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/"target="_blank" rel="noopener">BEM</a>). Eu honestamente não usaria ACSS e me foram dados bons argumentos para preferir BEM.</p>
<p>Essa introdução foi somente porque também não sou ainda um bom desenvolvedor front-end mas até aqui é o mínimo para começar. Vamos assumir que já passamos desses pontos também. Meu raciocínio começa pelo seguinte caso de uso: <em>&ldquo;quero criar CSS para um elemento visual, composto de diversos tags, e que não deve se deformar aleatoriamente por estilo de fora e nem deformar outros elementos ao redor.&rdquo;</em> Seria o caso de um Widget ou o que poderia ser um &ldquo;Web Component&rdquo;, ao pé-da-letra.</p>
<p>Passamos anos fazendo <a href="http://codeutopia.net/blog/2012/05/26/best-practices-for-building-embeddable-widgets/"target="_blank" rel="noopener">Widgets</a>. As duas grandes formas são usando um iframe com <a href="http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage"target="_blank" rel="noopener">postMessage()</a> ou zerar os estilos de um trecho do DOM com <a href="https://github.com/premasagar/cleanslate"target="_blank" rel="noopener">Cleanslate</a> e garantir que você está isolando seu CSS e Javascript usando namespaces e torcendo pra acidentalmente não sobrar nada global no meio do caminho ou outro desenvolvedor sobrescrever o que você fez.</p>
<p>Isso mudou em 2012 quando surgiu a implementação de <a href="http://blog.teamtreehouse.com/working-with-shadow-dom"target="_blank" rel="noopener">Shadow DOM</a>. Os novos elementos do HTML 5 como &ldquo;audio&rdquo; ou &ldquo;video&rdquo; ou &ldquo;range&rdquo; foram criados dessa forma em muitos navegadores. Em resumo mencionamos que uma página Web é uma árvore de tags, essa árvore que chamamos de Document Object Model ou &ldquo;DOM&rdquo;. Imagine se pudéssemos isolar um trecho de nós, uma sub-árvore, que não fosse influenciada pelos estilos externos e cujos estilos internos não &ldquo;vazassem&rdquo; para fora. Para isso criamos um novo elemento, um &ldquo;ShadowRoot&rdquo; que delimita uma sub-árvore isolada e independente e que, para todos os propósitos, não aparece no DOM principal, mas tem sua própria raíz de DOM isolada. Esse é o conceito.</p>
<p>No <a href="http://caniuse.com/shadowdom"target="_blank" rel="noopener">momento deste artigo</a>, somente o Chrome a partir da versão 25 (hoje no 35), o Firefox a partir da versão 31 (hoje no 30) e Ópera versão 15 (hoje no 22) suportam Shadow DOM. A Apple <a href="http://trac.webkit.org/changeset/164131"target="_blank" rel="noopener">retirou o suporte do WebKit</a> em fevereiro. A Microsoft sequer <a href="http://connect.microsoft.com/IE/feedback/details/793965/ie11-feature-request-support-for-shadow-dom"target="_blank" rel="noopener">considerou começar a implementar</a> ainda.</p>
<p><a href="http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/"target="_blank" rel="noopener">Shadow DOM</a> não é obrigatório para criar Custom Elements, mas é um recurso interessante e importante para atingir o objetivo de componentes Web independentes e isolados que não precisem recorrer a recursos como reiniciar o CSS de uma sub-árvore com artifícios como Cleanslate. De qualquer forma, seja via as convenções listadas acima e outras, ou seja via Shadow DOM, hoje temos como criar um nível razoável de isolamento e facilidade de manutenção. O problema é que isso não é inerente a HTML 5 e CSS 3, mas uma camada acima que não tem um consenso geral ainda.</p>
<h2>O Problema de Reusar Elementos<span class="hx:absolute hx:-mt-20" id="o-problema-de-reusar-elementos"></span>
    <a href="#o-problema-de-reusar-elementos" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Num mundo onde fazíamos praticamente tudo via server-side, esse era um problema praticamente resolvido. Seja com Rails e ERB/HAML/Slim, seja com templates de Django, seja com Blade em Laravel, seja com Razor em Asp.Net. Porém hoje temos aplicações mistas, onde deferimos muita lógica para a camada do navegador usando mais Javascript. Em vez de devolver pedaços prontos de HTML, agora devolvemos dados semi-estruturados em JSON e deixamos o Javascript criar os elementos no DOM.</p>
<p>Significa que no navegador temos um conjunto de dados e precisamos de uma forma de declarar os elementos de DOM onde vamos aplicar esses dados antes de instanciar o trecho no DOM. Do mundo Ruby surgiu uma das formas mais populares, <a href="http://mustache.github.io/"target="_blank" rel="noopener">Mustache</a>, criado pelo co-fundador do Github, <a href="https://github.com/defunkt"target="_blank" rel="noopener">Chris Wanstrath</a>. Depois outro rubista, <a href="https://github.com/wycats"target="_blank" rel="noopener">Yehuda Katz</a>, trouxe outra alternativa com o <a href="http://handlebarsjs.com/"target="_blank" rel="noopener">Handlebars</a>. A idéia geral é criar um elemento &ldquo;script&rdquo; e dentro dela colocar templates usando a notação do Mustache. Então um Javascript pode pegar o conteúdo string dessa tag script e criar o elemento no DOM depois de mesclar com os dados que quiser.</p>
<p>Está claro que estamos fazendo uma &ldquo;gambiarra&rdquo; elegante. A parte não tão elegante é ter que injetar HTML usando &ldquo;innerHTML&rdquo;, mas funciona muito bem. O outro problema é controlar manualmente coisas como imagens e javascripts que um elemento pode precisar mas antes dele ser usado, ou seja, talvez sem necessidade. Para isso precisamos controlar via Javascript.</p>
<p>Na definição de Web Components foi criado um novo elemento para resolver alguns desses problemas, o <a href="http://www.html5rocks.com/en/tutorials/webcomponents/template/"target="_blank" rel="noopener">&ldquo;template&rdquo;</a>. Sua definição é bem recente, de fevereiro de 2014. Serve basicamente o mesmo propósito de colocar um template dentro de uma tag &ldquo;script&rdquo; mas em vez de ser somente um string injetável ele realmente é uma sub-árvore de DOM &ldquo;inerte&rdquo;, que podemos manipular os nós via Javascript antes de ativá-lo ao inserir no DOM principal.</p>
<p>Por não ser mais um trecho de texto, perdemos a função do Mustache e do Handlebar de facilmente mesclar dados e inclusive ter alguma lógica como condicionais e loops. Em vez disso precisamos manipular os nós via javascript, fazendo coisas como:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="nx">t</span><span class="p">.</span><span class="nx">content</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;img&#39;</span><span class="p">).</span><span class="nx">src</span> <span class="o">=</span> <span class="s1">&#39;logo.png&#39;</span><span class="p">;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Em vez de ter:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;{{minha-imagem}}&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;great image&#34;</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Neste caso de templates eu diria que demos 2 passos pra trás e 1 para frente. Provavelmente dentro de um &ldquo;HTML template&rdquo; vamos precisar ter um Mustache para completar o processo? Admito que não acompanho a especificação mas pelo pouco que vi até agora não me parece que a especificação W3C de HTML template resolve o problema que bibliotecas como Mustache, Handlebars ou <a href="https://github.com/tildeio/htmlbars"target="_blank" rel="noopener">HTMLBars</a> resolvem hoje.</p>
<p>E não estou nem mencionando sobre Binding. Pelo que entendi isso não está na especificação, mas implementado em projetos como o <a href="http://mdv.googlecode.com/svn/trunk/docs/design_intro.html"target="_blank" rel="noopener">Google MDV</a> que agora está integrado ao <a href="http://www.polymer-project.org/docs/polymer/databinding.html"target="_blank" rel="noopener">Data Binding e Event Mapping do Polymer</a> como <a href="https://github.com/Polymer/TemplateBinding"target="_blank" rel="noopener">TemplateBinding</a>.</p>
<h2>O Problema de Reusar &ldquo;Componentes&rdquo;<span class="hx:absolute hx:-mt-20" id="o-problema-de-reusar-componentes"></span>
    <a href="#o-problema-de-reusar-componentes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Definindo &ldquo;Web Components&rdquo; como, um conjunto de HTML, CSS, Javascript que funciona em independência e isolamento, finalmente sobra o problema de &ldquo;empacotar&rdquo; esse conjunto. E agora entra a <a href="http://w3c.github.io/webcomponents/spec/imports/"target="_blank" rel="noopener">nova especificação de HTML Imports</a> de Julho de 2014.</p>
<p>Na prática, um HTML Import é nada mais do que um arquivo HTML &ldquo;normal&rdquo; com links para outros arquivos como stylesheets, imagens, javascripts e outros assets. Novamente, não vou descrever todos os detalhes e para aprender mais leia o artigo <a href="http://www.html5rocks.com/en/tutorials/webcomponents/imports/"target="_blank" rel="noopener">Why imports?</a>.</p>
<p>Atualmente, se precisamos usar algum conjunto desses, como um componente de Bootstrap, por exemplo, precisamos manualmente linkar para os stylesheets na ordem correta e fazer algo como:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;bootstrap.css&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;fonts.css&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  ...
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;jquery.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;bootstrap.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;bootstrap-tooltip.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;bootstrap-dropdown.js&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Com HTML Imports podemos fazer simplesmente:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-HTML" data-lang="HTML"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;import&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;bootstrap.html&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O problema imediato de algo como Web Components é que qualquer pequena página pode ter rapidamente dezenas de Imports, cada import requerendo outros arquivos e potencialmente triplicando ou mais a quantidade de chamadas pela rede. Quando tivermos algo melhor como HTTP 2.0 ou outro processo de <a href="http://stackoverflow.com/questions/10480122/difference-between-http-pipeling-and-http-multiplexing-with-spdy"target="_blank" rel="noopener">pipelining e multiplexing como com o protocolo SPDY</a> talvez não tenhamos que nos preocupar com isso, mas com o HTTP 1.1 que temos hoje precisamos ainda pensar em como economizar ao máximo chamadas de rede para pedir assets.</p>
<p>O mundo Rails trouxe pela primeira vez uma implementação de um processo completo e automatizado para concatenar e minificar stylesheets, javascript e sprites com o <a href="https://github.com/sstephenson/sprockets"target="_blank" rel="noopener">Sprockets</a> que <a href="https://github.com/sstephenson"target="_blank" rel="noopener">Sam Stephenson</a> - também criador do Prototype - iniciou em fevereiro de 2009 (obviamente os componentes que podem ser usados pelo Sprockets, como compressor, já existiam). Finalmente o Sprockets foi adicionado ao Rails 3.1 lançado em Agosto de 2011 como <a href="http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes"target="_blank" rel="noopener">&ldquo;Asset Pipeline&rdquo;</a>.</p>
<p>Hoje em dia o Sprockets continua sendo uma das opções mais completas e outros frameworks correram para criar suas próprias versões, como o <a href="https://github.com/d-i/half-pipe"target="_blank" rel="noopener">&ldquo;connect-assets&rdquo;</a> para Node.js, diversas receitas para Grunt e <a href="http://blog.carbonfive.com/2014/05/05/roll-your-own-asset-pipeline-with-gulp/"target="_blank" rel="noopener">Gulp</a>) e opções para <a href="http://grails.org/plugin/asset-pipeline"target="_blank" rel="noopener">Grails</a>, <a href="http://getcassette.net/"target="_blank" rel="noopener">Cassette/ASP.NET MVC</a>, <a href="https://github.com/cyberdelia/django-pipeline"target="_blank" rel="noopener">Pipeline Django</a>.</p>
<p>No mundo de Web Components foi imediatamente criado o projeto <a href="http://www.polymer-project.org/articles/concatenating-web-components.html"target="_blank" rel="noopener">Vulcanize</a> ou no caso do mundo Rails podemos adicionar o processo ao próprio Sprockets com o projeto <a href="http://www.akitaonrails.com/2014/06/29/usando-polymer-com-rails"target="_blank" rel="noopener">Emcee</a>, que foi o tema do meu post anterior. A idéia é pegar os HTML imports e concatená-los num único arquivo, incluindo tornar os links para stylesheets e javascripts externos como trechos inline num único HTML. Nem o Vulcanize e nem o Emcee atualmente minificam seus conteúdos, no entanto.</p>
<p>Note que imports é apenas uma parte do problema. Nem vamos entrar no problema de gerenciamento de versões (problema que projetos como Bower, NPM, Bundler no Ruby, PHP Composer, NuGet, Gradle, Pip, etc foram criados para resolver). O que acontece com componentes que dependem de versões específicas de outro componente? E bibliotecas internas como JQuery que um componente pode precisar? Ainda não sei o que acontece nesses casos.</p>
<h2>Web Components é uma &ldquo;Revolução&rdquo;?<span class="hx:absolute hx:-mt-20" id="web-components-é-uma-revolução"></span>
    <a href="#web-components-%c3%a9-uma-revolu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tudo isso dito, vamos revisar:</p>
<ul>
<li>Podemos criar conjuntos de tags isolados com Shadow DOM, com seus próprios estilos e comportamentos que não vazam e não automaticamente herdam estilos e comportamentos do DOM principal, a técnica é usar Shadow DOM (ou uma das formas antigas com Cleanslate, criação de elementos com Javascript, IFrame)</li>
<li>Podemos definir trechos inertes de HTML que podem ser instanciados via Javascript para dentro do DOM. Com projetos como TemplateBinding recuperamos algo como HTMLBars e podemos mesclar dados com o template. A técnica é usar HTML template e Polymer (ou uma das formas antigas com Mustache, Handlebars, HTMLBars).</li>
<li>Uma vez definido nosso &ldquo;widget&rdquo; ou &ldquo;componente&rdquo;, podemos encapsulá-lo dentro de uma embalagem mais amigável usando Custom Elements (ou uma das formas antigas como plugins de JQuery fazem com Javascript para encapsular).</li>
<li>E uma vez montado o Widget/Componente podemos empacotar tudo num único HTML Import para podermos resusar facilmente dentro de outros HTML (em vez da forma antiga de declarar manualmente os arquivos de dependência)</li>
</ul>
<p>Vocês devem ter notado que do ponto de vista de um desenvolvedor que apenas consome tais componentes/widgets, o processo em si é uma melhoria mas não é tão diferente quanto utilizar plugins de JQuery. De fato é uma passo adiante, oficializando o que antes era &ldquo;gambiarra&rdquo; em alguma coisa um pouco melhor (Custom Elements em vez de Javascript, Shadow DOM em vez de IFrame, HTML Template em vez de string em tag Script).</p>
<p>E aqui vem o maior desafio ao conjunto de tecnologias de Web Components: ele é definitivamente melhor. Só que não é disruptivo. Ao usuário final, o que ele &ldquo;vê&rdquo; e &ldquo;interage&rdquo; numa página web no navegador será exatamente idêntico. Significa que o usuário final tem muito pouco a se beneficiar da tecnologia. Portanto ele não é o público-alvo.</p>
<p>O público-alvo é o desenvolvedor front-end que, em vez de buscar um plugin JQuery - por exemplo - vai buscar um Web Component e a forma de utilizá-los não será muito diferente. Como ele não tem a motivação de melhorar muita coisa a seu público-alvo, ele tem muito pouco incentivo para mudar sua forma de trabalho.</p>
<p>O raciocínio é simples: quero colocar um Carrossel na minha página. Existem centenas, <a href="http://www.jssor.com/"target="_blank" rel="noopener">Jssor Slider</a>, <a href="http://sorgalla.com/jcarousel/"target="_blank" rel="noopener">jCarousel</a>, <a href="http://kenwheeler.github.io/slick/"target="_blank" rel="noopener">Slick - the last carousel you&rsquo;ll ever need</a>. E para Web Components? Pelo menos no momento deste artigo só encontrei o <a href="https://github.com/addyosmani/polymer-ui-carousel"target="_blank" rel="noopener">Polymer-ui-carousel</a>, que não chega aos pés dos antecessores. Qual você acha que o desenvolvedor front-end vai escolher?</p>
<p>Existem dois repositórios de componentes públicos (aliás, não entendi porque existem dois, um projeto como esse não ganha nada nascendo já fragmentado): o <a href="http://component.kitchen/"target="_blank" rel="noopener">Component Kitchen</a> com cerca de 276 componentes e o <a href="http://customelements.io/"target="_blank" rel="noopener">Custom Elements</a> com 327 componentes. Como todo repositório inicial, a maioria deles não é de grande serventia. São mais demonstrações e provas de conceito. Sinceramente, alguém se dar ao trabalho para fazer um componente de Pokémon tem que ser só um tech-demo. É inútil. E você pode contar com coisas redundantes e/ou desnecessárias como botões de Facebook, gravatar, botão de Github, coisas que um <a href="http://www.addthis.com/"target="_blank" rel="noopener">AddThis</a> já tem resolvido. Claro, não quero ser injusto e dizer que Web Components não tem utilidade só porque a primeira geração de componentes não é interessante. Essas coisas levam tempo para amadurecer, como qualquer tecnologia.</p>
<p>Para que a estratégia funcione ou a tecnologia em si é <string>disruptiva</string> - o que acabamos de ver que não é, é apenas <strong>evolutiva</strong> -, ou é necessário um pacote completo para ser candidato a <a href="http://en.wikipedia.org/wiki/Killer_application"target="_blank" rel="noopener">&ldquo;killer-app&rdquo;</a>. Voltamos ao que disse antes sobre uma solução procurando um problema. Sem um verdadeiro killer-app-blockbuster é muito difícil conseguir tração e coesão de um ecossistema. No caso do Ruby isso foi o Rails. No caso do Go parece que é o Docker. No caso do Node foi o halo-effect do Google Chrome evoluindo o V8.</p>
<p>Para isso o Google criou o <a href="http://www.polymer-project.org/components/paper-elements/demo.html#core-toolbar"target="_blank" rel="noopener">Polymer/Paper</a> que define um conjunto coeso e visualmente integrado (via filosofia gráfica e interativa do <a href="http://www.google.com/design/"target="_blank" rel="noopener">Material Design</a> que, assumindo que &ldquo;pegue&rdquo;, também tem a vantagem de dar ao usuário final um &ldquo;eye-candy&rdquo; que justifique sua adoção). É uma proposição &ldquo;tudo ou nada&rdquo;, embora você possa pegar pedaços dela, a intenção é fazer aplicações/sites usando inteiramente o Polymer.</p>
<p>O projeto <a href="http://www.polymer-project.org/"target="_blank" rel="noopener">Polymer</a> é ambicioso e somente uma corporação como o Google poderia fazer algo assim tão rápido (dado que metade das especificações de tecnologia de Web Components como HTML Imports e HTML template são deste ano de 2014). Ao contrário do que deveria parecer, a arquitetura não é simples e com o pouco suporte de navegadores a única estratégia é criar Polyfills, implementações (&ldquo;quasi&rdquo;-completas) para tudo que navegadores &ldquo;legados&rdquo; mas que muita gente usa como IE abaixo de 10, Safari e Mobile Safari. Para isso serve o <a href="http://www.polymer-project.org/docs/start/platform.html"target="_blank" rel="noopener">Polymer/Platform</a>.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/413/polymer-architecture.png" alt="Arquitetura do Polymer"  loading="lazy" /></p>
<p>Só que já passamos do ponto de somente usar plugins JQuery, agora migramos para a era dos one-page-apps via Javascript que consome endpoints REST que retornam JSON. Estamos falando somente do ponto de vista de componentes, mas uma aplicação é maior do que isso. Para quem vem do mundo ASP.NET MVC, Rails, Django, falamos muito sobre o conceito &ldquo;Web MVC&rdquo; (Model-View-Controller) ou mais corretamente, <a href="http://en.wikipedia.org/wiki/Model_2"target="_blank" rel="noopener">MVC Model-2</a> da Sun, definido para J2EE.</p>
<p>Muitos nem sabem que usam outro modelo, o <a href="http://en.wikipedia.org/wiki/Model%e2%80%93view%e2%80%93presenter"target="_blank" rel="noopener">MVP</a> (Model-View-Presenter) presente em ASP.NET (antigo), Window.Forms, <a href="http://www.gwtproject.org/?csw=1"target="_blank" rel="noopener">GWT</a> (Google Web Toolkit, lembram? Também do Google!). E, finalmente, também da Microsoft chegamos ao <a href="http://en.wikipedia.org/wiki/Model_View_ViewModel"target="_blank" rel="noopener">MVVM</a> (Model View View Model), uma evolução de MVP com MVC2, mais conhecido pelos seus conceitos de Data Binding 2-way de elementos do DOM com models puxados via Javascript. Agora temos a categoria que vocês já devem ter conhecido com <a href="http://knockoutjs.com/"target="_blank" rel="noopener">Knockout.js</a>, <a href="https://angularjs.org/"target="_blank" rel="noopener">Angular.js</a>, <a href="http://emberjs.com/"target="_blank" rel="noopener">Ember</a>. Estamos falando de mais do que o jeito MVP de arrastar componentes a um canvas e adicionar eventos de callback, mas um framework completo que lida com Models, Views, Rotas.</p>
<p>O Yehuda Katz escreveu sobre <a href="https://gist.github.com/wycats/9144666b0c606d1838be"target="_blank" rel="noopener">integrar o Ember com Web Components</a> em Maio e ele explicita muitos detalhes que vale a pena ler a respeito. Segundo esta <a href="https://groups.google.com/forum/#!msg/polymer-dev/4RSYaKmbtEk/uYnY3900wpIJ"target="_blank" rel="noopener">thread no Google Groups</a>, parece que o projeto Angular 2.0 deve também se integrar com Web Components e Polymer. Quando estes projetos e outros frameworks se unirem ao esforço Polymer provavelmente vamos ver o real valor dos Web Components.</p>
<p>Polymer é o projeto principal. Web Components é o conjunto de mecanismos, o meio para atingir esse objetivo. E é um problema clássico de ovo e galinha: os navegadores diferentes de Chrome precisam se equiparar e seguir a vontade do Google. Os polyfills, via Polymer/Platform e <a href="http://www.x-tags.org/blog"target="_blank" rel="noopener">Mozilla X-Tag</a> vão suprir o que falta (Mutation Observers, Shadow DOM, etc) como o JQuery fez no passado. Mas para os navegadores tracionarem nessa direção os desenvolvedores precisam entrar no barco, e para isso somente um pacote completo como Polymer/Paper e, se possível, aliado a frameworks como Ember e Angular podem fazer isso acontecer, e não pequenos componentes-demonstração.</p>
<h2>A História se Repete<span class="hx:absolute hx:-mt-20" id="a-história-se-repete"></span>
    <a href="#a-hist%c3%b3ria-se-repete" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Já vimos essa história acontecer antes. Durante o <a href="http://en.wikipedia.org/wiki/Browser_wars"target="_blank" rel="noopener">Browser Wars</a> muitos apenas vão se lembrar que a Microsoft conspirou ativamente para destruir a Netscape, culminando no processo que quase quebrou a Microsoft em 3 no ano 2000 e a consequência final que foi a sobra do amaldiçoado Internet Explorer 6 que, apesar de ter sido um excelente navegador em sua era, ele não deveria nunca ter durado mais de uma década em uso.</p>
<p>Muitos talvez não lembrem que isso também gerou muitas novas tecnologias, para listar algumas:</p>
<ul>
<li>O Internet Explorer 3.0 foi o primeiro navegador a implementar o CSS 1.</li>
<li>O Internet Explorer 4.0 foi quem expôs o DOM e criou o DHTML, Dynamic HTML, com Dynamic Styling e manipulação de elementos do DOM via Javascript</li>
<li>O Internet Explorer 5.0 foi quem trouxe a semente do Ajax com o componente proprietário XMLHTTP e a técnica de buscar conteúdo de forma assíncrona com iframes usada no Outlook Web Access, dando origem ao XMLHttpRequest</li>
</ul>
<p>O período negro pós-2000 da Microsoft culminou no fracasso do Windows Vista e consequente sobrevida à la The Walking Dead tanto do Windows XP quanto do IE 6. O Google pegou o bastão de onde a Microsoft largou. O Core Business do Google é o AdWords. Controlar as plataformas Web faz parte da estratégia e o navegador continua sendo importante, porque ele é o novo sistema operacional desta geração, seja desktop ou mobile. Esqueçam Windows vs OS X vs GNU/Linux.</p>
<p>Outra tecnologia Microsoft que foi esquecida foi a primeira verdadeira tentativa de componentizar a Web. Foi com <a href="http://www.w3.org/TR/NOTE-HTMLComponents"target="_blank" rel="noopener">HTML Components</a> do fim de 1998. Nessa época ainda estávamos tentando dominar drag-and-drop de elementos com DHTML e começando a brincar com as possibilidades de fazer requisições sem precisar recarregar a página.</p>
<p>Se olhar esta página de <a href="http://bit.ly/1jV3VpJ"target="_blank" rel="noopener">APIs Legadas</a> da Microsoft teremos:</p>
<ul>
<li>Legacy DOM - substituída, claro, pelo DOM mais moderno</li>
<li>IE Architecture/Active X - substituído por Silverlight, Flash, ainda Applets e widgets</li>
<li>Browser Extensions - ainda temos extensions mas nenhum padrão</li>
<li>DHTML Behaviors e DHTML Data Binding - são os novos Web Components</li>
<li>Filters and Transitions - que até hoje temos browser-specific com modificadores como -moz ou -webkit, CSS 3</li>
<li>Vector Markup Language (VML) - que é o atual SVG e HTML 5 Canvas</li>
</ul>
<p>Não estou querendo dizer que é tudo mérito da Microsoft. A intenção é apenas explicar - para quem começou a usar a Internet na era pós-Browser Wars e pós-<a href="http://en.wikipedia.org/wiki/Dot-com_bubble"target="_blank" rel="noopener">Crash das Dot-coms</a> que Web Components não surgiu do nada, ela é o próximo passo lógico da evolução dos browsers e arquitetura Web.</p>
<p>Para o próprio Google essa não é a primeira vez. A primeira vez foi com <a href="http://en.wikipedia.org/wiki/Google_Web_Toolkit"target="_blank" rel="noopener">GWT</a> (Google Web Toolkit), que nasceu em 2006. Esse foi o auge dos frameworks MVC back-end que facilitavam desenvolvimento de aplicações Web usando Ajax. Foi a era pós-J2EE onde surgiram Rails, Django e outros Rails/Django-like como CakePHP, Grails.</p>
<p>Depois veio a era back-end assíncrono, desenterrando o problema <a href="http://www.kegel.com/c10k.html"target="_blank" rel="noopener">C10K de 1999 de Dan Kegel</a>, use case de Web Sockets (chat, APIs) que começa com Scala, vai para Node.js, chega em GoLang, Elixir. Novamente, não veio do nada, foi o próximo passo evolutivo depois do próprio Erlang, Twisted, Tornado, Java NIO/Netty, etc.</p>
<p>Em paralelo o Google investiu no Chrome e para isso precisou investir em Javascript e tornar o V8 algo realmente usável. Milhares de homens-hora e milhões de dólares depois, temos uma engine realmente performática. Com isso o mundo Javascript cresceu exponencialmente. Uma tecnologia que já se imaginava dominada na década de 90 ganhou nova roupagem e uma segunda chance. Com isso a arquitetura MVC2 evoluiu para um híbrido, com frameworks MVVM no client-side.</p>
<p>Portanto é natural evoluir do mindset GWT para Angular.js e eventualmente para Web Components/Polymer. E é onde estamos agora. Note que estamos sempre circulando os conceitos de MVC-clássico, MVC Model-2, MVP e agora MVVM, todos patterns originados do lendário MVC de <a href="http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html"target="_blank" rel="noopener">Trygve Reenskaug</a> do Smalltalk-80. Lembrando que já experimentamos programação orientada a componentes antes: foi a década de 90, que imaginou uma revolução ao usar componentes reusáveis para tornar o processo de programação meramente um jogo de arrastar blocos. Isso ficou conhecido como <a href="http://en.wikipedia.org/wiki/Rapid_application_development"target="_blank" rel="noopener">RAD</a> (Rapid Application Development), que deu origem a toolkits e IDEs. Foi o conceito que deu origem a PowerBuilder, Visual Basic, Delphi, Swing. E a evolução na direção de ferramentas CASE (Computer Aided Software Engineering). Achávamos que poderíamos criar diagramas (UML) e as ferramentas gerariam o código-fonte para nós. Já ouviu falar disso? Pois é, não deu muito certo. O Visual Studio de hoje <a href="http://msdn.microsoft.com/en-us/library/ff657795.aspx"target="_blank" rel="noopener">ainda tem suporte</a> a isso (yikes).</p>
<p>A diferença são as ondas da moda: na década de 90 ainda estávamos definindo o que era possível e, pelo bem ou pelo mal, o que a Microsoft inventou realmente foi revolucionário porque não havia precedente. A era pré-Bolha trouxe o MVC2 para o desenvolvimento Web com Web Objects e J2EE. O advento do Ajax e aplicações dinâmicas trouxe de GWT a Rails. E agora a era da Renascença do Javascript trouxe o MVVM e Web Components.</p>
<p>Não sei o que vem depois daqui, mas depois de organizar a informação histórica espero que mais alguém tenha insights do que vem pela frente. O que acham que Web Components realmente pode trazer que já não vimos com GWT e anteriores?</p>
]]></content:encoded><category>frontend</category><category>javascript</category><category>desenvolvimento-web</category></item><item><title>Rails Assets</title><link>https://akitaonrails.github.io/2013/12/13/rails-assets/</link><guid isPermaLink="true">https://akitaonrails.github.io/2013/12/13/rails-assets/</guid><pubDate>Fri, 13 Dec 2013 19:49:00 -0200</pubDate><description>&lt;p&gt;Ontem o &lt;a href="https://twitter.com/fgrehm"target="_blank" rel="noopener"&gt;@Fgrehm&lt;/a&gt; mandou no nosso Campfire sobre o projeto &lt;a href="https://rails-assets.org"target="_blank" rel="noopener"&gt;rails-assets.org&lt;/a&gt;. Ele acabou de ser lançado, portanto não pode ser considerado mais que um &amp;ldquo;beta&amp;rdquo;. Ela pode ser tanto a salvação da lavoura para front-ends em projetos Rails ou não, na prática ainda não sabemos.&lt;/p&gt;
&lt;p&gt;O &lt;a href="https://twitter.com/jcemer"target="_blank" rel="noopener"&gt;@jcemer&lt;/a&gt; publicou hoje um &lt;a href="http://jcemer.com/asset-pipeline-rails-assets-or-let-die.html"target="_blank" rel="noopener"&gt;ótimo post&lt;/a&gt; explicando isso do ponto de vista de um front-end full-time, colocando em perspectiva.&lt;/p&gt;
&lt;p&gt;Em resumo, o Rails trás um mecanismo fantástico chamado Asset Pipeline. Ele tem diversas funções, em particular otimizar os assets dos projetos Rails, compilando fontes de Sass ou Less para CSS. Depois concatenando todos os CSS, JS em um único arquivo. Depois minificando (com Uglify) para diminuir seu tamanho. Em particular com Sass ele ainda pode concatenar sprites em uma única imagem também. Enfim, o pacote completo para otimizar assets ao máximo.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Ontem o <a href="https://twitter.com/fgrehm"target="_blank" rel="noopener">@Fgrehm</a> mandou no nosso Campfire sobre o projeto <a href="https://rails-assets.org"target="_blank" rel="noopener">rails-assets.org</a>. Ele acabou de ser lançado, portanto não pode ser considerado mais que um &ldquo;beta&rdquo;. Ela pode ser tanto a salvação da lavoura para front-ends em projetos Rails ou não, na prática ainda não sabemos.</p>
<p>O <a href="https://twitter.com/jcemer"target="_blank" rel="noopener">@jcemer</a> publicou hoje um <a href="http://jcemer.com/asset-pipeline-rails-assets-or-let-die.html"target="_blank" rel="noopener">ótimo post</a> explicando isso do ponto de vista de um front-end full-time, colocando em perspectiva.</p>
<p>Em resumo, o Rails trás um mecanismo fantástico chamado Asset Pipeline. Ele tem diversas funções, em particular otimizar os assets dos projetos Rails, compilando fontes de Sass ou Less para CSS. Depois concatenando todos os CSS, JS em um único arquivo. Depois minificando (com Uglify) para diminuir seu tamanho. Em particular com Sass ele ainda pode concatenar sprites em uma única imagem também. Enfim, o pacote completo para otimizar assets ao máximo.</p>
<p>Se você ainda não conhece sobre esse recurso, não deixe de ler meu <a href="http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes"target="_blank" rel="noopener">tutorial</a>.</p>
<p>Só que à medida que um projeto precisa ter várias bibliotecas CSS, JS, etc o processo pode ficar chato. Principalmente porque em alguns casos precisa manualmente modificar os paths dentro de seus fontes.</p>
<p>Um dos problemas é que o Asset Pipeline vai juntar todos os arquivos em um único, colocando timestamp no nome. E aí os paths não vão funcionar a menos que usem o helper <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetUrlHelper.html#method-i-asset_path"target="_blank" rel="noopener">asset_path</a> ou <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetUrlHelper.html#method-i-asset_url"target="_blank" rel="noopener">asset_url</a>. Por isso acabamos usando rubygems feitas manualmente como o <a href="https://github.com/anjlab/bootstrap-rails"target="_blank" rel="noopener">bootstrap-rails</a>.</p>
<p>E isso leva a outro problema: atualizações. Primeiro, os autores originais lançam uma determinada biblioteca Javascript. Podemos manualmente fazer o download dos fontes e &ldquo;vendorizá-los&rdquo; no projeto. Ou, se você utilizar o Bower podemos esperar sair esse novo pacote e atualizar com o Bower. Ou, se estivermos usando uma Rubygem, podemos esperar sair a nova gem e atualizar com Bundler.</p>
<p>Então, vamos separar tudo e usar Bower pra gerenciar bibliotecas de front-end e usar Bundler para gerenciar gems de back-end e todo mundo fica feliz? Não é tão fácil assim já que muitas gems - ActiveAdmin como um bom exemplo - já dependem de bibliotecas de front-end encapsuladas em rubygems como temos neste trecho da gemspec:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="o">...</span>
</span></span><span class="line"><span class="cl"><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span> <span class="s2">&#34;bourbon&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span> <span class="s2">&#34;jquery-rails&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span> <span class="s2">&#34;jquery-ui-rails&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">...</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Já que temos duas comunidades tendo exatamente o mesmo trabalho: no Bower alguém vai atualizar pacotes de jquery; na Rubygems alguém vai ter que atualizar também. Então, porque não otimizar isso e apenas um deles atualizar. Nesse caso vamos aproveitar - e colaborar - para deixar as do Bower sempre atualizadas.</p>
<p>Será que existe uma forma, então, de converter um pacote Bower para um pacote Rubygems? E este é o problema que o Rails Assets se propõe a tentar resolver. Seguindo exatamente o mesmo exemplo do site deles, colocaremos na Gemfile de nossos projetos Rails desta forma:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">source</span> <span class="s1">&#39;https://rubygems.org&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">source</span> <span class="s1">&#39;https://rails-assets.org&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">gem</span> <span class="s1">&#39;rails&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">group</span> <span class="ss">:assets</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;sass-rails&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;uglifier&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;coffee-rails&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rails-assets-bootstrap&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rails-assets-angular&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">gem</span> <span class="s1">&#39;rails-assets-leaflet&#39;</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira diferença é um novo source. E isso é importante pois não vai poluir o repositório de Rubygems com gems que são meros &lsquo;stubs&rsquo;.</p>
<p>A segunda diferença são as gems prefixadas seguindo o padrão &ldquo;rails-assets-[nome do pacote Bower]&rdquo; que, obviamente, foram feitas desta forma para não conflitarem com as que já existem no Rubygems.org. Se isso funcionar significa que a antiga gem &ldquo;bootstrap-rails&rdquo; poderá ser descontinuada e passamos a usar a &ldquo;rails-assets-bootstrap&rdquo;, e assim por diante.</p>
<p>Se uma determinada gem ainda não existir, o processo vai demorar um pouco porque o Rails Assets vai baixar o pacote do Bower, modificá-la, encapsulá-la como uma Rubygem e publicar no seu repositório. Mas quanto mais gente usar com mais bibliotecas, mais rubygems já estarão prontas para baixar imediatamente.</p>
<p>Para o Asset Pipeline continua a mesma coisa. No mesmo arquivo <tt>app/assets/javascripts/application.js</tt> teríamos igual:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="c1">//= require_self
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require bootstrap
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require angular
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require leaflet
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require_tree .
</span></span></span><span class="line"><span class="cl"><span class="c1">//= require_tree shared
</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E no <tt>app/assets/stylesheets/application.css</tt> teríamos também igual:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="c">/*
</span></span></span><span class="line"><span class="cl"><span class="c"> *= require_self
</span></span></span><span class="line"><span class="cl"><span class="c"> *= require bootstrap
</span></span></span><span class="line"><span class="cl"><span class="c"> *= require leaflet
</span></span></span><span class="line"><span class="cl"><span class="c"> *= require_tree .
</span></span></span><span class="line"><span class="cl"><span class="c"> *= require_tree shared
</span></span></span><span class="line"><span class="cl"><span class="c"> */</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>As rubygems que encapsulam bibliotecas front-end não são apenas por causa do Asset Pipeline, além disso elas também podem conter generators para facilitar a criação de alguma estrutura de diretórios ou arquivos de configuração específicos. Mas mesmo nesse caso podemos separar em duas coisas: uma sendo só os fontes originais e uma segunda gem que depende da primeira com ferramentas ou outros extras como generators.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Para Rubistas a primeira vantagem mais óbvia é o seguinte: não precisamos misturar dois workflows de dependência, uma com Bower (ou manualmente) e outra com Bundler. Podemos continuar apenas com Bundler. Lembrando que se pacotes Bower não forem vendorizados no projeto Rails ainda teríamos que manter esse processo com Bower na integração contínua - adicionando o comando no .travis.yml, por exemplo; e também teríamos que ter no deployment. Idealmente, não deveríamos ter que vendorizar bibliotecas. Isso sem contar que se usar Bower num projeto Rails e usar Heroku, precisa de um outro <a href="http://xseignard.github.io/2013/02/18/use-bower-with-heroku/"target="_blank" rel="noopener">buildpack</a> para funcionar. Ou seja, o Bower adiciona muito mais complexidade do que somente ter que rodar mais um comando &ldquo;install&rdquo; em desenvolvimento. Ambientes de teste, produção, tudo fica um pouco mais complicado, e desnecessariamente.</p>
<p>Além disso, quem colaborava mantendo a rubygems de um &ldquo;bootstrap-rails&rdquo;, por exemplo, pode continuar a dedicar seu tempo atualizando diretamente o pacote equivalente do Bower e deixar essa fonte única sempre atualizada, o que pode ser um reforço ao Bower e aos não-rubistas que a utilizam.</p>
<p>E com isso também não precisamos ter gems de stubs poluindo o Rubygems.org. Ou seja, &ldquo;se&rdquo; funcionar será uma situação ganha-ganha para todo mundo. Porém nem tudo são flores. Como uma das idéias do Rails Assets é modificar o fonte para adicionar os asset-paths corretos, quer dizer que podem existir situações onde patterns automáticos não peguem, ou existam ambiguidades que precisem ser resolvidos manualmente. Então, das duas uma: ou colaboramos com o Rails Assets para adicionar os patterns que faltam, se for possível; ou criamos um passo no workflow do Rails Assets que permitam modificações manuais. Ainda não sei, precisamos ver quais são esses cenários e como corrigí-los. Mas isso não elimina os pontos positivos descritos anteriormente.</p>
<p>O melhor a fazer: testar e experimentar. O projeto é open source, você pode <a href="https://github.com/rails-assets/rails-assets/"target="_blank" rel="noopener">colaborar</a> mandando Pull Requests ou mesmo reportando <a href="https://github.com/rails-assets/rails-assets/issues"target="_blank" rel="noopener">Issues</a> e ajudando a evoluir. Se a idéia for furada - o que não me parece - vamos saber rapidamente - e voltamos ao mesmo problema de antes, mas pelo menos esta é uma proposta de solução muito interessante que vale a pena ser explorada mais a fundo.</p>
]]></content:encoded><category>rails</category><category>frontend</category><category>javascript</category></item><item><title>A Controvérsia CoffeeScript</title><link>https://akitaonrails.github.io/2011/04/16/a-controversia-coffeescript/</link><guid isPermaLink="true">https://akitaonrails.github.io/2011/04/16/a-controversia-coffeescript/</guid><pubDate>Sat, 16 Apr 2011 18:31:00 -0300</pubDate><description>&lt;p&gt;Para quem não está acompanhando, esta semana rolou uma pequena controvérsia acerca de uma nova decisão na linha de desenvolvimento para o futuro Rails 3.1 (atualmente estamos na 3.0.6). A partir dessa versão, o framework trará como dependência as bibliotecas CoffeeScript, SASS e Sprockets, além da mudança que já havia sido anunciada antes de trocar a instalação padrão do framework Javascript, Prototype + Scriptaculous, por &lt;a href="http://twitter.com/#!/dhh/statuses/45923430608023552"target="_blank" rel="noopener"&gt;jQuery&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A maioria dessas mudanças foram bem recebidas e até em alguns casos, aplaudida, no estilo &lt;em&gt;“já não era sem tempo!”&lt;/em&gt; (caso do jQuery).&lt;/p&gt;</description><content:encoded><![CDATA[<p>Para quem não está acompanhando, esta semana rolou uma pequena controvérsia acerca de uma nova decisão na linha de desenvolvimento para o futuro Rails 3.1 (atualmente estamos na 3.0.6). A partir dessa versão, o framework trará como dependência as bibliotecas CoffeeScript, SASS e Sprockets, além da mudança que já havia sido anunciada antes de trocar a instalação padrão do framework Javascript, Prototype + Scriptaculous, por <a href="http://twitter.com/#!/dhh/statuses/45923430608023552"target="_blank" rel="noopener">jQuery</a>.</p>
<p>A maioria dessas mudanças foram bem recebidas e até em alguns casos, aplaudida, no estilo <em>“já não era sem tempo!”</em> (caso do jQuery).</p>
<p>Porém, a <a href="http://twitter.com/#!/dhh/status/58207700672200704"target="_blank" rel="noopener">escolha</a> de colocar o CoffeeScript como padrão causou um grande <a href="http://twitter.com/#!/dhh/status/58288725247012864"target="_blank" rel="noopener">furor</a>, diversas trocas de hostilidades, piadas de humor negro, <a href="http://doihavetousecoffeescriptinrails.com/"target="_blank" rel="noopener">sarcasmo</a> e também muita gente que simplesmente gosta de fazer barulho sem motivo algum (tem tempo sobrando, eu diria).</p>
<p>O pessoal do Rails Core Team acha que é a melhor decisão. Uma parcela barulhenta da comunidade acha que foi uma grande bobagem. E agora, o que isso significa?</p>
<h2>Introdução: Pré-processadores<span class="hx:absolute hx:-mt-20" id="introdução-pré-processadores"></span>
    <a href="#introdu%c3%a7%c3%a3o-pr%c3%a9-processadores" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Existem muitas coisas que são difíceis mudar. Quem lida com montagem de interfaces HTML/CSS multi-browser sabe a dor de cabeça. Especificar algo como HTML e CSS é muito difícil. Como eu sempre digo, leia as <a href="http://www.w3.org/Style/CSS/current-work.en.html"target="_blank" rel="noopener">especificações</a>. À primeira vista parece bem completo. Mas não é! Cada navegador tem muitas diferenças de implementação.</p>
<p>Frameworks como jQuery para Javascript ajudam a aliviar muitas dessas diferenças, abstraindo as implementações em algo menos complicado. No caso do Javascript é possível criar frameworks assim porque ele é uma real linguagem de programação genérica – e uma bastante completa, diga-se de passagem.</p>
<p>Já um HTML e CSS <strong>não</strong> são linguagens de programação (quem ainda chama HTML e CSS de <em>“linguagem de programação”</em> merece apanhar, sério. E quando eu pergunto, <em>“em que linguagens sabe programar?”</em> e o cidadão responde <em>“ah, sei HTML”</em>, esse merece ser jogado da janela do prédio!). HTML e CSS são <em>“linguagens de marcação”</em>. Tem gente que não sabe nem o que significa HTML: “HyperText <strong>Markup</strong> Language”. Está no próprio nome!</p>
<p>O quero dizer é que é impossível programar um framework HTML ou CSS escrito em HTML ou CSS, algo parecido com o efeito de um jQuery. Ou seja, podemos refatorar e reescrever quanto quisermos, mas nunca conseguiremos extrair uma “biblioteca” parametrizável e reusável escrito em CSS que seja capaz de gerar mais CSS.</p>
<p>Sabemos o benefício que existe em usar frameworks que abstraem muitas das repetições e coisas específicas de cada navegador numa linguagem mais genérica. Por exemplo, no caso do Javascript, em vez de fazer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">elm</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// browser implements part of W3C DOM HTML  
</span></span></span><span class="line"><span class="cl"> <span class="c1">// Gecko, Internet Explorer 5+, Opera 5+  
</span></span></span><span class="line"><span class="cl"> <span class="nx">elm</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">id</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">all</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// Internet Explorer 4 or Opera with IE user agent  
</span></span></span><span class="line"><span class="cl"> <span class="nx">elm</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">all</span><span class="p">[</span><span class="nx">id</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">layers</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="c1">// Navigator 4  
</span></span></span><span class="line"><span class="cl"> <span class="nx">elm</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">layers</span><span class="p">[</span><span class="nx">id</span><span class="p">];</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Hoje podemos simplesmente fazer, com jQuery:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">elm</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s2">&#34;#&#34;</span> <span class="o">+</span> <span class="nx">id</span><span class="p">);</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Outra alternativa seria mudar a especificação do HTML e CSS para serem mais enxutas e mais flexíveis. Mas isso seria praticamente impossível pois todos os navegadores do planeta precisaram ser atualizados para a mesma versão para que valesse a pena. É o dilema do HTML 5 vs Internet Explorer 6. Enquanto existir um cidadão usando o famigerado IE 6, vamos ter que criar código que trata versões e dá “fallback”, ou seja, escolhe uma versão não HTML 5.</p>
<p>Agora, nós conhecemos técnicas que podem facilitar a vida do desenvolvedor. Quem programa em C conhece <a href="http://en.wikipedia.org/wiki/C_preprocessor"target="_blank" rel="noopener">pré-processadores</a>. Ele permite escrever macros, que podem ser reusados por todo seu código. Daí antes de compilar em código nativo de máquina, o compilador do C vai fazer o equivalente a um grande “procurar e substituir”, trocando as macros por código, por exemplo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp"># define MYCASE  
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">case</span> <span class="nl">id</span><span class="p">:</span>   
</span></span><span class="line"><span class="cl"> <span class="n">item</span><span class="err">##</span><span class="n">_</span><span class="err">##</span><span class="n">id</span> <span class="o">=</span> <span class="n">id</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="k">break</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">switch</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"><span class="n">MYCASE</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Quando o pré-processador do C passar por esse código, ele será “reescrito” como:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">switch</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="mi">23</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="n">widget_23</span> <span class="o">=</span> <span class="mi">23</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Com esse recurso podemos praticamente criar uma sintaxe completamente nova que você nem perceberia mais que está lidanco com C. Não é exatamente recomendável fazer isso, mas as macros estão ali para justamente tentar abstrair mais do código e torná-la mais fácil de ler e dar manutenção. No final o código binário gerado seria o mesmo, mas para o desenvolvedor a vida pode ser mais fácil.</p>
<p>Pois bem, no mundo Ruby, sabendo que HTML e CSS não podem ser modificados e não podem gerar a si mesmos, recaímos em Ruby mesmo para criar o equivalente a pré-processadores. São formas de escrever HTML e CSS em uma sintaxe mais simples e com mais abstrações, de maneira a tentar evitar escrever tantas duplicações e a tornar a manutenção futura até mais simples.</p>
<p>CSS em particular é um monstro complicado porque diferente de HTML ela não define estrutura, define estilo a ser aplicado à estrutura. O HTML é razoavelmente “simples” e linear. Não há valores, não há reusos triviais, ela é uma hierarquia simples. Já CSS tem valores, tem reuso desses valores, tem conceitos de herança e prioridade dos estilos, tem valores derivados de outros valores. Mas ela não dá nenhum recurso para tornar isso fácil, então você é obrigado a repetir e repetir sem parar. E quando tem uma mudança drástica, é obrigado a reescrever muita coisa.</p>
<p>Entra SASS. Ele é como um pré-processador de CSS, que adiciona diversas funcionalidades que muitos acreditam que já deveriam ter sido criadas desde o começo. Por exemplo, veja o seguinte código em SASS:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">/* style.scss */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="nt">main-color</span><span class="o">:</span> <span class="p">#</span><span class="nn">ce4dd6</span><span class="o">;</span>  
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="nt">style</span><span class="o">:</span> <span class="nt">solid</span><span class="o">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">#</span> <span class="nt">navbar</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">border-bottom</span><span class="p">:</span> <span class="err">{</span>  
</span></span><span class="line"><span class="cl"> <span class="kc">color</span><span class="o">:</span> <span class="err">$</span><span class="n">main-color</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="n">style</span><span class="p">:</span> <span class="err">$</span><span class="kc">style</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="err">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">a</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">color</span><span class="p">:</span> <span class="err">$</span><span class="n">main-color</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="err">&amp;:hover</span> <span class="err">{</span> <span class="k">border-bottom</span><span class="p">:</span> <span class="err">$</span><span class="kc">style</span> <span class="mi">1</span><span class="kt">px</span><span class="p">;</span> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="err">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>É transformado no seguinte CSS:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">/*</span> <span class="nt">style</span><span class="p">.</span><span class="nc">css</span> <span class="o">*</span><span class="err">\</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">#</span> <span class="nt">navbar</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">border-bottom-color</span><span class="p">:</span> <span class="mh">#ce4dd6</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">border-bottom-style</span><span class="p">:</span> <span class="kc">solid</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nt">a</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">color</span><span class="p">:</span> <span class="mh">#ce4dd6</span><span class="p">;</span> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="nt">a</span><span class="p">:</span><span class="nd">hover</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">border-bottom</span><span class="p">:</span> <span class="kc">solid</span> <span class="mi">1</span><span class="kt">px</span><span class="p">;</span> <span class="p">}</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Notem que aqui o objetivo sequer é escrever “menos linhas de código”. Se o objetivo fosse apenas esse, o SASS seria inútil. Mas o principal é a forma de escrever estilos como blocos dentro de blocos, usar variáveis e muito mais. No exemplo, digamos que você tivesse que mudar a cor principal (main-color). Teria que fazer um processo manual de “procurar e trocar” por todo seu código e ainda assim não teria nenhuma certeza se trocou tudo certo. Aqui basta trocar uma variável. Esse é apenas um dos benefícios. SASS tem muitos outros recursos que permitem organizar seu CSS de maneira nunca antes possíveis.</p>
<p>O autor do SASS é o grande Hampton Caitlin, que é contribuidor na comunidade Ruby há muitos anos. Antes do SASS, porém, ele havia criado outro tipo de pré-processador, mas para HTML chamado <a href="haml-lang.com/">HAML</a>. Vejamos o exemplo que ele mostra no site. Primeiro o código escrito em HAML:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># profile  

.left.column  
 #date= print_date  
 #address= current_user.address  
 .right.column  
 #email= current_user.email  
 #bio= current_user.bio  </code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Esse HAML será transformado no seguinte HTML:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">\<span class="err">&lt;</span>%= print_date %\&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">\<span class="err">&lt;</span>%= current_user.address %\&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">\<span class="err">&lt;</span>%= current_user.email %\&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">\<span class="err">&lt;</span>%= current_user.bio %\&gt;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<hr>
<p>A idéia principal do HAML é estética. Não funcionalidades. Segundo o próprio website, eis a definição de porque HAML existe:</p>
<blockquote>
  <p>“Haml é baseado em um princípio primário. Marcação deve ser muito bonita.”</p>

</blockquote>
<p>E eis o que eu acredito ser o principal problema do HAML: “ser bonito” ou “ser feio” é completamente uma questão não-absoluta de gosto pessoal. Quem acha HAML bonito vai criticar totalmente HTML. Mas quem acha HTML bonito o suficiente, vai achar HAML muito feio. E contra isso não há nenhum tipo de argumento.</p>
<p>No caso, a maioria do Rails Core Team, não viu valor na mudança estética de HTML para HAML. Eu pessoalmente também não vejo. Por outro lado não desgosto de HAML, se eu pegar um código que usa HAML provavelmente vou usá-lo sem problemas, mas se começar um projeto do zero, não sei se eu usaria. Provavelmente seria relutante.</p>
<p>O problema é o objetivo do HAML: se ele me acrescentasse funcionalidades que me permitissem simplificar a organização das views, criar estruturas reusáveis ou algo assim, seria muito interessante. Mas um arquivo HAML é um para um equivalente a um arquivo HTML (diferente do SASS que oferece mixins e imports). Um bloco HAML é um para um equivalente a um bloco de HTML (diferente do SASS que introduz nesting). E assim por diante.</p>
<p>Ou seja, estou literamente trocando seis por meia dúzia em troca de “estética”. Sendo que essa estética não tem explicação lógica, apenas gosto pessoal. Ou seja, qual é mais “bonito” aos seus olhos, este HAML:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-css" data-lang="css"><span class="line"><span class="cl"><span class="o">%</span><span class="nt">strong</span><span class="p">.</span><span class="nc">code</span><span class="p">#</span><span class="nn">message</span> <span class="nt">Hello</span><span class="o">,</span> <span class="nt">World</span><span class="o">!</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ou este HTML:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">**Hello, World!**</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Pois é, eu pessoalmente prefiro o HTML. O que não invalida quem prefere HAML. Portanto, dado que a escolha é puramente estética, entendo perfeitamente porque o Rails Core Team preferiu deixar o HAML de fora e só trazer o SASS. O SASS traz benefícios reais de produtividade e mantenabilidade do código. O HAML é puramente estético e é difícil de defender alguma coisa simplesmente por “parecer” esteticamente melhor.</p>
<h2>CoffeeScript – melhor ou apenas mais estética?<span class="hx:absolute hx:-mt-20" id="coffeescript--melhor-ou-apenas-mais-estética"></span>
    <a href="#coffeescript--melhor-ou-apenas-mais-est%c3%a9tica" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>E aí caímos na controvérsia do <a href="http://jashkenas.github.com/coffee-script/"target="_blank" rel="noopener">CoffeeScript</a>. Há um ano eu <a href="http://akitaonrails.com/2010/03/27/brincando-com-coffee-script"target="_blank" rel="noopener">já havia escrito</a> uma introdução a ele, portanto recomendo que leiam meu antigo artigo primeiro antes de continuar.</p>
<p>E como no caso do HAML, eu critico seu objetivo de existir. Do próprio website oficial, eu destaco este trecho:</p>
<blockquote>
  <p>Javascript sempre teve um excelente modelo de objetos em seu interior. CoffeeScript é uma tentativa de expôr as boas partes do Javascript de maneira simples.</p>
<p>A regra de outro do CoffeeScript é: “É somente Javascript”. O código compila um-para-um no JS equivalente, e não há nenhuma interpretação em tempo de execução.</p>

</blockquote>
<p>Assim como HAML, CoffeeScript tem exatamente o mesmo objetivo: ser um-para-um mais “esteticamente” bonito do que o original. E essa é a razão da discussão, porque quem acha CoffeeScript esteticamente mais bonito vai defendê-lo (caso do Rails Core Team) e quem não acha essa estética tão bonita assim vai questionar, criticar.</p>
<p>Repito: é uma questão <strong>puramente estética</strong>! Não há nenhum argumento técnico, lógico e objetivo para declarar que CoffeeScript é melhor ou pior. E não se trata simplesmente de escrever menos código (em muitos casos no SASS você pode acabar com mais linhas de código, só que com maior mantenabilidade), portanto ser mais “curto” pra escrever é interessante mas dificilmente é um argumento definitivo.</p>
<p>Além disso, uma linguagem de marcação como HTML é bem mais fácil de entender se você mantiver a estrutura mas só mudar a forma de escrever. Já uma linguagem de programação completa e complexa como Javascript, se você mudar a sintaxe, para quem nunca viu CoffeeScript, a curva de aprendizado será considerável não é zero e pode ser grande dependendo de quem vai pegar esse código para dar manutenção depois. Quem já sabe obviamente dirá <em>“mas é muito simples”</em> mas para quem não conhece e não está vendo nenhum valor extra sendo adicionado, naturalmente irá questionar: <em>“e o que eu ganho com isso?”</em> E ele também está certo, porque se para ele a estética é irrelevante, de fato ele não está levando absolutamente nenhum benefício em termos de programação ou organização.</p>
<p>Também usamos o argumento que Ruby é mais elegante ou esteticamente mais bonito do que outras. Mas Ruby efetivamente traz técnicas e paradigmas de programação novos como closures, classes abertas, metaprogramação, mixin de módulos, e muito mais. Não é apenas estética.</p>
<p>Mas não pensem que CoffeeScript é ruim por causa disso. De jeito nenhum, de fato Javascript tem uma sintaxe que está ficando velha muito rápido. O Coffee tem diversas ajudas de sintaxe que tornam mesmo muitas coisas menos complicado. Vejam alguns exemplos, primeiro em Coffee:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="n">switch</span> <span class="n">day</span>  
</span></span><span class="line"><span class="cl"> <span class="k">when</span> <span class="s2">&#34;Mon&#34;</span> <span class="k">then</span> <span class="n">go</span> <span class="n">work</span>  
</span></span><span class="line"><span class="cl"> <span class="k">when</span> <span class="s2">&#34;Tue&#34;</span> <span class="k">then</span> <span class="n">go</span> <span class="n">relax</span>  
</span></span><span class="line"><span class="cl"> <span class="k">when</span> <span class="s2">&#34;Thu&#34;</span> <span class="k">then</span> <span class="n">go</span> <span class="n">iceFishing</span>  
</span></span><span class="line"><span class="cl"> <span class="k">when</span> <span class="s2">&#34;Fri&#34;</span><span class="p">,</span> <span class="s2">&#34;Sat&#34;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">day</span> <span class="n">is</span> <span class="n">bingoDay</span>  
</span></span><span class="line"><span class="cl"> <span class="n">go</span> <span class="n">bingo</span>  
</span></span><span class="line"><span class="cl"> <span class="n">go</span> <span class="n">dancing</span>  
</span></span><span class="line"><span class="cl"> <span class="k">when</span> <span class="s2">&#34;Sun&#34;</span> <span class="k">then</span> <span class="n">go</span> <span class="n">church</span>  
</span></span><span class="line"><span class="cl"> <span class="k">else</span> <span class="n">go</span> <span class="n">work</span>  </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Agora em Javascript:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">switch</span> <span class="p">(</span><span class="nx">day</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Mon&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">work</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Tue&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">relax</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Thu&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">iceFishing</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Fri&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Sat&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">day</span> <span class="o">===</span> <span class="nx">bingoDay</span><span class="p">)</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">bingo</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">dancing</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="p">}</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="s2">&#34;Sun&#34;</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">church</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"> <span class="k">break</span><span class="p">;</span>  
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="o">:</span>  
</span></span><span class="line"><span class="cl"> <span class="nx">go</span><span class="p">(</span><span class="nx">work</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="p">}</span>  
</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>E no final nem é tão complicado assim aprender Coffee. Basicamente entre no <a href="http://jashkenas.github.com/coffee-script/"target="_blank" rel="noopener">site oficial</a> deles e leia essa primeira página. Ela tem tudo que você precisa saber para começar. Eu diria que você precisa, em média de 1 a 2 horas para saber como ler e escrever em Coffee. Mais do que isso e significa que você tem pouca prática com programação, o que não é ruim, mas só para constatar que é só isso que um bom programador deveria levar.</p>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Isso tudo dito, eu consigo entende o valor estético do CoffeeScript e não acho ruim usá-lo. Não sinto ele tão valioso quanto um SASS. Também entendo manter o HAML fora do Rails por enquanto, até que seja mais fácil convencer os outros do seu valor.</p>
<p>O problema maior é que o Rails está começando a ficar mais complexo. É natural e até que ele conseguiu se manter bem nos últimos 5 anos sem virar um novo J2EE. Está longe disso. Mas agora temos um passo de pré-processamento que os programadores precisam ter consciência. Os arquivos <tt>.scss</tt> ou <tt>.coffee</tt> primeiro precisam passar por um processo de pré-processamento/compilação para se tornarem <tt>.css</tt> e <tt>.js</tt>. Pior ainda, se usar o <a href="https://github.com/sstephenson/sprockets"target="_blank" rel="noopener">Sprockets</a> (ou equivalente <a href="https://github.com/sbecker/asset_packager"target="_blank" rel="noopener">Asset Packager</a>), múltiplos arquivos CSS e JS serão compilados em um único minificado para melhorar velocidade de transferência.</p>
<p>Vários problemas podem acontecer: alguém editar o CSS final em vez do SCSS que o gerou, sem perceber. Esquecer de executar o passo que transforma o SCSS em CSS antes de atualizar uma versão em produção. Dar erro no navegador do cliente e a partir daí ficar difícil de determinar qual era o arquivo original em SCSS que gerou aquele CSS, e assim por diante. Nenhum desses problema é crítico ou incontornável uma vez que você sabe o que fazer. Mas é um passo extra na curva de aprendizado para quem está começando.</p>
<p>Todos esses pacotes são opcionais. Basta entrar na <tt>Gemfile</tt> que o Rails 3.1 irá gerar e retirar as dependências que não lhe interessam e adicionar as escolhas que prefere. Nesse sentido o Rails permanecerá modular, de forma a facilitar novas escolhas, por isso ninguém deveria estar preocupado.</p>
<p>No geral acredito que todas as mudanças mencionadas são positivas e aumenta o valor agregado do Ruby on Rails. E se você realmente gosta da prática de programação, aprender HAML, SASS, CoffeeScript, Sprockets, etc não deveria ser um sacrifício e sim um prazer. Se alguém está considerando aprender coisas novas um “sacrifício”, deveria rever sua carreira de programação.</p>
]]></content:encoded><category>javascript</category><category>engenharia-de-software</category></item></channel></rss>