The blog of Bruno Lara Tavares2023-10-09T15:00:04-03:00https://blog.bltavares.com/Bruno Lara Tavarescontato@bltavares.comCluster em casa – Sistema operacional2019-05-21T00:00:00-03:00https://blog.bltavares.com/2019/05/21/cluster_em_casa_sistemas_operacionais<p>Depois de <a href="https://blog.bltavares.com/2019/05/12/cluster_em_casa_hardware/">escolhido o hardware</a> para montar o cluster em casa, precisamos dar o primeiro passo para ligá-los, ou seja, precisamos de um sistema operacional.</p>
<h2 id="sistemas-operacionais-para-sbcs">Sistemas operacionais para SBCs</h2>
<p>O ideal seria começar com o hardware mais limitado: os Raspberry Pis ARMv6. A grande vantagem de ter escolhido Raspberry Pi ao invés de outros <a href="https://en.wikipedia.org/wiki/Single-board_computer">Single Board Computers</a> (SBC) está na quantidade de sistemas e suporte oferecido para o hardware.</p>
<p>Precisamos confirmar o suporte a ARMv6 de sistemas operacionais como RancherOS e CoreOS, voltados para criação de clusters, dado que o ARMv6 é uma arquitetura mais antiga e mais lenta, voltado para IoT e hobbistas.</p>
<p>Existem provedores de servidores ARM no mercado, como a <a href="https://www.scaleway.com/en/">Scaleway</a> e <a href="https://www.packet.com/">Packet</a>, que oferecem computadores ARMv8 64 e isso vem aumentando a demanda de suporte a ARMs, mas ainda é comum não encontrar suporte em sistemas operacionais voltados a contêineres para as versões mais antigas da arquitetura.</p>
<h3 id="coreos">CoreOS</h3>
<p><a href="https://coreos.com/">CoreOS</a> possui alguns componentes que suportam ARM no seu canal alpha/beta de distribuição, mas todos estão bem longes da estabilidade.</p>
<p>O <a href="https://coreos.com/etcd/docs/latest/op-guide/supported-platform.html">suporte de plataformas documentado</a> aponta que ARM64 é experimental e ARM é instável.</p>
<h3 id="rancher-os">Rancher OS</h3>
<p>Rancher OS possui <a href="https://rancher.com/docs/os/v1.2/en/running-rancheros/server/raspberry-pi/">suporte oficial ao Raspberry Pi</a> desde a versão v0.5.0, mas menciona ter sido testado apenas em Raspberry Pi 3.</p>
<p>Uma das vantagens ofertadas pelo Rancher OS pode ser também um dos nossos problemas. O sistema operacional possui todo os serviços base rodando como contêineres Docker. Como eu precisaria configurar o ClusterHat em um dos PIs, essa característica do OS teria uma grande chance de se tornar um grande problema.</p>
<p>A instalação da placa requer acesso os plugues GPIO, e mesmo sabendo que seria possível repassar o acesso para dentro de um container usando volumes, parece ser uma complexidade desnecessária. Nós já temos complexidade o suficiente no nosso setup, e eu preferiria evitar mais uma delas durante a escolha do OS.</p>
<h3 id="k3os">k3OS</h3>
<p>A equipe da Rancher Inc. anunciou recentemente o <a href="https://k3os.io/">k3OS</a>, logo depois de anunciar o <a href="https://k3s.io/">k3s</a>. Eu já havia montado o cluster quando o anúncio foi feito, mas vamos analisar ainda assim.</p>
<p>A proposta do k3s é reduzir a complexidade de componentes de um nó rodando kubernetes, e o k3OS oferece um sistema operacional que se configura automaticamente e se associa ao cluster.</p>
<p>A promessa é de rodar um nó de kubernetes usando apenas 512mb de memória, mas alguns dos SBCs do nosso cluster são os pequenos Raspberry Pis Zero W, que possuem apenas os 512mb de memória requeridos.</p>
<p>Isso sozinho já torna improvável escolher o k3s, dado que toda a memória iria para manter o sistema do kubernetes. O segundo motivo para evitar esse sistema no nosso caso é o uso de kubernetes, que <a href="https://github.com/kubernetes/kubeadm/issues/253#issuecomment-296738890">não suporta ARMv6 desde 2017</a>.</p>
<p>A proposta de um sistema que configura sozinho um novo nó para o cluster, e usa poucos recursos, é extremamente interessante para pequenos computadores, mas ainda não para computadores tão pequenos quanto os que escolhi.</p>
<p>Vou acompanhar <a href="https://github.com/rancher/k3os/issues/65">o issue pendido suporte a ARM</a> para uma possível mudança de OS no futuro.</p>
<h3 id="balenaos">BalenaOS</h3>
<p>Anteriormente chamada <a href="https://www.balena.io/blog/resin-io-changes-name-to-balena-releases-open-source-edition/">Resin.io</a>, o <a href="https://www.balena.io/os/">BalenaOS</a> oferece uma maneira simples de distribuir e executar software em diversos SBCs.</p>
<p>O sistema operacional se integra com o sistema de build e empacotamento chamado <a href="https://www.balena.io/cloud/">BalenaCloud</a>, que permite que você escreva seu software, associe seu SBC, gere uma imagem Linux já preparada com um sistema de distribuição de pacotes e configurações, tudo configurável por um dashboard.
O serviço é bem completo, oferecendo processo de build do código para a arquitetura do SBC, VPN para garantir a acessibilidade independentemente de onde o computador estiver, sistema de atualização e configuração.</p>
<p>A empresa possui uma engine para containers otimizada para rodar em SBCs chamado <a href="https://www.balena.io/engine">BalenaEngine</a>, otimizada para evitar o uso do disco, dado que na maior parte das vezes estamos rodando o sistema a partir de cartões microSD, que possuem uma taxa de desgaste maior que SSDs e HDDs.</p>
<p>Como o objetivo do projeto é entender quais os componentes necessários para criar o nosso cluster p2p, preferi seguir buscando outros sistemas operacionais. A oferta é bem interessante, principalmente se eu estivesse procurando apenas uma maneira de executar programas que eu mesmo escrevi em vários SBCs.</p>
<p>Apesar de não usar o sistema, recomendo ver a <a href="https://www.youtube.com/watch?v=cvah8oTNir4">apresenta sobre as otimizações</a> incluídas na engine, que poderia ser utilizada sem todos os outros componentes. Ainda está na minha lista experimentar mudar a engine que roda nos Raspberry Pies e testar quão fácil seria trocar apenas um dos componentes do sistema.</p>
<h3 id="armbian-e-raspbian">armbian e raspbian</h3>
<p>Os dois sistemas são ótimos pontos de partida para construir o que quisermos, com ambos baseados no Debian. O <a href="https://www.armbian.com/">armbian</a> oferece suporte para várias SBCs, menos o Raspberry Pi, enquanto o <a href="https://raspbian.org/">raspbian</a> é focado apenas em Raspberry Pis.<br />
O criador do ClusterHat oferece imagens pré-configuradas para a inicialização da placa e compartilhamento da interface de rede através do conector GPIO e USB, baseadas no <a href="https://raspbian.org/">raspbian</a>.</p>
<p>A grande vantagem de começar com um Debian como base nesse caso é permitir a escolha aberta do nosso orquestrado. A pesquisa do orquestrador fica para o próximo post.
Faltaria apenas configurar Docker para cada um dos computadores usando os scripts de instalação para Debian.</p>
<h3 id="hypriotos">HypriotOS</h3>
<p><a href="https://github.com/hypriot/image-builder-rpi/releases">HypriotOS</a> é outro sistema operacional focado para SBCs, principalmente para o Raspberry Pi, que tem como objetivo entregar um sistema já pronto para utilizar Docker. Não só apenas o sistema já possui Docker Engine instalado, mas também possui <a href="https://cloud-init.io/">cloud-init</a> para configuração inicial, similar a servidores na nuvem.</p>
<p>Essa proposta encaixa muito bem com o que estava procurando:</p>
<ul>
<li>Instalação fácil, com otimizações para rodar Docker já configuradas</li>
<li><code class="language-plaintext highlighter-rouge">cloud-init</code> permite que eu declare o setup em um arquivo para ser executado durante o primeiro boot, configurando rede e hostname, primeiros pacotes necessários, chaves de acesso e serviços iniciais, sem precisar de conectar um teclado e monitor, ou investigar os IPs de cada placa na rede.</li>
<li>Baseado em Debian, que permitirá trazer as configurações necessárias para instalar o ClusterHat no sistema sem muito mais esforço que em um sistema onde tudo vive dentro do Docker, e escolher o orquestrador.</li>
</ul>
<h2 id="sistemas-para-os-x86">Sistemas para os x86</h2>
<p>Seguindo com a pesquisa, agora precisamos escolher o sistema operacional para os x86. Para manter uniformidade nos sistemas operacionais, escolhi algo baseado em Debian.</p>
<p>Começando com o processo de boot, me lembrei de diversos posts e links que apareceram na minha linha do tempo, e me pareceu uma boa oportunidade para investigá-los.</p>
<ul>
<li>https://twitter.com/jessfraz/status/1019745690887557127</li>
<li>https://twitter.com/majorhayden/status/934957592228585472</li>
<li>https://blog.jessfraz.com/post/home-lab-is-the-dopest-lab/</li>
<li>https://carolynvanslyck.com/blog/2017/10/my-little-cluster/</li>
<li>https://twitter.com/netbootxyz</li>
<li>https://blog.sophaskins.net/blog/setting-up-a-home-hypervisor/</li>
<li>https://github.com/bradfitz/homelab</li>
</ul>
<h3 id="pxe-boot--iniciando-o-sistema-pela-rede">PXE Boot – iniciando o sistema pela rede</h3>
<p>Duas ferramentas me chamaram a atenção: <a href="https://github.com/danderson/netboot/tree/master/pixiecore">pixiecore</a> e <a href="https://netboot.xyz">netboot.xyz</a>. Ambas permitem que um computador faça bootstrap a partir de uma imagem na rede.
<a href="https://github.com/danderson/netboot/tree/master/pixiecore">pixiecore</a> permite configurar um servidor com uma imagem local, enquanto o <a href="https://netboot.xyz">netboot.xyz</a> já traz uma lista pré-configurada para carregar um sistema e roda na internet.</p>
<p>Várias das placas mães com UEFI já possuem o a opção para carregar uma imagem pela rede, utilizando <a href="https://en.wikipedia.org/wiki/Preboot_Execution_Environment">PXE</a>, mas cada firmware pode ter problemas na implementação. Para nossa sorte, existe uma imagem mais moderna e com suporte a IPv6 e HTTPS, chamada <a href="https://ipxe.org/">iPXE</a>, que pode evitar os problemas do PXE embutido na placa mãe.</p>
<p>O <a href="https://netboot.xyz">netboot.xyz</a> nos oferece uma imagem baseada em <a href="https://ipxe.org/">iPXE</a>, já configurada para acessar uma lista de servidores pela internet. O processo de escolha de um novo sistema foi bem fácil e requer apenas gravar um ISO ou pendrive para a inicialização.</p>
<p>Pude escolher entre CoreOS, RancherOS e Debian apenas utilizando um menu durante o boot.</p>
<h3 id="mais-nós-no-cluster--hipervisores-e-vms">Mais nós no cluster – Hipervisores e VMs</h3>
<p>Depois do primeiro sistema x86 pronto, podemos testar a viabilidade de adotar o <code class="language-plaintext highlighter-rouge">pixiecore</code> para utilizar imagens locais. Podemos usar o <a href="https://www.linux-kvm.org/page/Main_Page">KVM</a> para virtualizar pequenos servidores e e aumentar a quantidade de nós que temos no nosso cluster.</p>
<p>Alguns colegas já haviam recomendado usar o <a href="https://www.unraid.net/">UnraidOS</a>, e no trabalho eu já havia utilizado vSphere algumas vezes. Esss são escolhas comuns na <a href="https://www.reddit.com/r/homelab/">comunidade de homelab</a>, mas várias outras recomendações me levaram ao <a href="https://www.proxmox.com/en/proxmox-ve/features">Proxmox VE</a>.</p>
<p><a href="https://www.proxmox.com/en/proxmox-ve/features">Proxmox VE</a> é construído em cima do Debian, e pode ser instalado por cima de uma instalação básica de Debian. O sistema oferece uma interface web para gerenciar VMs KVM e contêineres LXC. Alem disso, dado que estamos rodando um Debian, também posso utilizar Docker diretamente no hipervisor, apesar de não recomendado.</p>
<p>Optei por instalar do zero, ao invés de migrar de um sistema com Debian já instalado. Depois de configurar o IP fixo e responder algumas perguntas durante a instalação guiada, pude subir uma VM usando a interface web.</p>
<p>Agora podemos testar um boot com <a href="https://github.com/danderson/netboot/tree/master/pixiecore">pixiecore</a>. O processo de subir o servidor de boot requer apenas inicializar um container Docker, compartilhando o namespace de rede para que as VMs recebam pacotes de rede por broadcast. . Os passos estão documentados no README do projeto.
Depois de brigar um pouco com as opções de boot da VM, testando UEFI e BIOS, consegui iniciar VMs tanto com CoreOS quanto RancherOS.</p>
<p>As duas imagens suportam configurações durante o boot, similar ao <a href="https://cloud-init.io/">cloud-init</a>, e é possível prover um arquivo de configuração para ser enviado como user-data junto da imagem do OS.
Infelizmente essa estratégia não funciona bem para criar VMs Debian. As imagens distribuídas oficialmente não têm <a href="https://cloud-init.io/">cloud-init</a> configuradas, diferente do que acontece nas imagens Debian utilizadas em nuvens.</p>
<p>O HypriotOS nos permite utilizar <a href="https://cloud-init.io/">cloud-init</a>, e seria muito legal poder reaproveitar isso para todos os nós Debian, mas criar uma imagem Debian com tudo configurado para boot pela rede ficou pra depois.</p>
<h2 id="escolhas">Escolhas</h2>
<p>No primeiro momento cheguei a utilizar o sistema pré-configurado com o ClusterHat, para aprender melhor como funciona o processo de boot, inicialização e configuração da placa adicional.</p>
<p>Depois de estudar <a href="https://github.com/burtyb/clusterhat-image">o script de geração da imagem</a> base, criei um <a href="https://cloud-init.io/">cloud-init</a> para o HypriotOS. Agora tenho um sistema otimizado para Docker rodando no Raspberry Pi, com o setup inicial descritivo.</p>
<p>No laptop reformado, escolhi utilizar o <a href="https://www.proxmox.com/en/proxmox-ve/features">Proxmox VE</a> para ganhar acesso a VMs, e configurei Docker mesmo que contraindicado.</p>
<p>Ainda temos uma quantidade em que é viável escolher Debian sem boot pela rede ou <a href="https://cloud-init.io/">cloud-init</a>, e escolhi utilizar o <a href="https://netboot.xyz">netboot.xyz</a> por enquanto.</p>
<p>Toda a minifrota de computadores roda Debian. As configurações estão <a href="https://github.com/bltavares/homelab">documentadas no GitHub</a>, caso alguém tenha interesse.
Com os computadores ligados e funcionando, o próximo post agora é sobre configuração e conexão.</p>
Cluster em casa - Hardware2019-05-12T00:00:00-03:00https://blog.bltavares.com/2019/05/12/cluster_em_casa_hardware<p>Nos últimos meses eu estive estudando sobre ferramentas de orquestração de contêineres, tentando entender como diferentes requerimentos mudam as escolhas de software e plataforma.</p>
<p>Apesar do movimento de adoção da nuvem, eu sempre fui fã dos Raspberry Pis como computadores para estudos. Eles são fantásticos computadores de baixo custo para construir um cluster com vários nós.</p>
<p>Descobri uma placa chamada <a href="https://clusterhat.com/">ClusterHat</a>, que permite que eu configure 5 Raspberry Pis (4 + 1) em um pequeno cluster. Eu já possuía Raspberry Pis comprados a alguns anos e um laptop com problemas de gerenciamento de energia no armário, e poderia aproveitar esses aparelhos para começar o cluster.</p>
<p>Depois, a expansão poderia vir aos poucos.</p>
<p><img src="/assets/cluster_em_casa/conjunto_pi_hardware.jpg" alt="Conjunto de Raspberry Pis de diversas gerações" /></p>
<blockquote>
<p>Tudo pronto para começar a configurar um cluster.</p>
</blockquote>
<p>Um detalhe interessante do hardware disponível é a mistura de arquiteturas. Temos alguns ARMv6, ARMv7, ARMv8_64 e x86_64 conectados, criando um requerimento não usual para nosso orquestrador.
Processadores ARM estão ficando cada vez mais popular, mas nem todos os projetos estão preparados para essa arquitetura, o que nos limita quais orquestradores podemos executar.</p>
<p>A quantidade de recursos também é limitada, e o que escolhermos deve caber nos nossos pequenos computadores, e ainda sobrar espaço para rodar os contêineres.</p>
<p>Ter esses computadores pequenos também traz algo novo para explorar: poderíamos ter um cluster móvel, que é mais fácil de expandir a partir de vários locais.
Eu sempre me interessei com conectividade P2P, e agora que temos endereços IPv6 distribuídos per ISPs no Brasil, isso se torna ainda mais viável criar a conexão a partir de vários lugares.</p>
<p>Nos próximos posts vou descrever as opções de componentes para construir o cluster e quais foram as ferramentas escolhidas dado nossos requerimentos de hardware.</p>
Updates sobre o ecossistema de Rust (Maio/Junho 2017)2017-06-13T00:00:00-03:00https://blog.bltavares.com/2017/06/13/updates_sobre_o_ecossistema_do_rust<p>(Note: This post should be Google Translate friendly. I’ve refrained from using slangs to help with that.)</p>
<p>Algumas pessoas que me acompanham no dia a dia já perceberam o quanto Rust me fascina.</p>
<p>Eu venho acompanhando a linguagem tem algum tempo, e sempre me perguntam o motivo desse interesse. Um dos motivos é ver como a comunidade vem evoluindo e tornando possível usar Rust em vários lugares.</p>
<p>Resolvi fazer um post, com atualizações sobre o ecossistema, para ajudar quem não tem acompanhando tanto as mudanças.</p>
<h1 id="mas-o-que-é-rust">Mas o que é Rust?</h1>
<p>Tirando do <a href="https://www.rust-lang.org/en-US/">site do Rust</a>, em uma tradução livre:</p>
<blockquote>
<p>Rust é uma linguagem de programação para sistemas de baixo nível, com enfoque a velocidade, prevenção de erros de memória e segurança entre threads.</p>
</blockquote>
<blockquote>
<p>Desenvolvida pela Mozilla, a linguagem permite que você programe como se estivesse programando JavaScript ou Ruby (com algumas ressalvas), mas entregando performance em C</p>
</blockquote>
<p>Em resumo, é uma linguagem que parece uma mistura de JavaScript e Ruby, com umas pitadas de Java. Rust tem um fluxo de atualização onde há uma versão nova a cada 6 semanas, trazendo todas as novidades continuamente.</p>
<p>Pra quem quer saber mais, vou separar uma <a href="#como-começar">seção</a> de texto com links de como começar na linguagem.</p>
<h1 id="updates-do-ecossistema-maiojunho-2017">Updates do ecossistema (Maio/Junho 2017)</h1>
<h2 id="implementing-weld-in-rust"><a href="http://dawn.cs.stanford.edu/2017/04/25/weld/">Implementing Weld in Rust</a></h2>
<p>O pessoal de Stanford publicou sobre a experiência deles desenvolvendo o projeto <a href="https://weld-project.github.io/">Weld</a>, um sistema de processamento de dados muito rápido.</p>
<p>Esse tipo de infraestrutura funciona muito bem em Rust por alguns pontos:</p>
<ul>
<li>Poucas camadas de abstração no programa final, tornando ele bem rápido</li>
<li>Possível de integrar com outras linguagens. O projeto tem um demo de integração com os dados processados rapidamente pelo Weld e sendo visualizados por um programa Python com Pandas.</li>
</ul>
<p>Ou seja, dá pra escrever a parte que precisa ser muito rápido em Rust no meio de um projeto Python. Legal né?</p>
<h2 id="pesquisa-de-opinião-sobre-rust"><a href="https://blog.rust-lang.org/2017/05/03/survey.html">Pesquisa de opinião sobre Rust</a></h2>
<p><a href="https://docs.google.com/forms/d/e/1FAIpQLScw5xyQCGireVaHLeb_8dQOhwvaqDZ5mF9utc0i75Z0pndhXg/viewform?c=0&w=1">Link direto pra pesquisa</a></p>
<p>Esse é o segundo ano que a comunidade está realizando umas pesquisa para entender melhor sobre as motivações de usar Rust (ou de não usar).</p>
<p>Esse tipo de informação ajuda a identificar problemas na documentação, pontos de dificuldade de introduzir os conceitos novos da linguagem, problemas de didática, falta de material, problemas no ecossistema e tudo mais.</p>
<p>Inclusive, a comunidade tem pedido para pessoas que não usam, ou desistiram de usar Rust, responderem também. Existe uma série de perguntas exatamente para endereçar pessoas que não usam a linguagem e ajudar a entender onde a comunidade tem falhado em cobrir a ferramenta.</p>
<p>Agora já fecharam as submissões, mas estou esperando pelos resultados.</p>
<h2 id="upgrade-do-llvm-na-linguagem"><a href="https://www.reddit.com/r/rust/comments/67din2/the_merge_of_llvm_40_into_rust_has_finally/dgpnjxb/">Upgrade do LLVM na linguagem</a></h2>
<p>Rust utiliza uma série de ferramentas já testadas por anos por outros sistemas para gerar códigos otimizados e rápidos. Uma delas é o LLVM, utilizado também pela Apple no XCode, Haskell e Mono.</p>
<p>Essa parte do projeto é fundamental para permitir que Rust execute em Arduinos!</p>
<p>Faz pouco tempo que o LLVM adiciona suporte oficial a projetos em AVR e melhoraram o suporte a ARM, o que significa que agora códigos que utilizam LLVM podem acabar executados por Arduinos, Androids e Raspberry PIs. Isso foi anunciado no LLVM 4 e agora a linguagem atualizou a infraestrutura para utilizar a nova versão.</p>
<p>Isso permite que novos projetos surjam para facilitar o desenvolvimento de dispositivos embarcados, o que deve acontecer por <a href="https://github.com/rust-embedded">um grupo bem interessado em ver Rust no Arduino</a> virar realidade.</p>
<p>Ainda será preciso algum trabalho para deixar essa experiencia de maneira fantástica para iniciar, mas agora esse trabalho está desbloqueado.</p>
<h2 id="divulgada-a-estratégia-para-a-comunidade-ajudar-a-melhorar-as-bibliotecas---rust-libz-blitz">Divulgada a estratégia para a comunidade ajudar a melhorar as bibliotecas - <a href="https://blog.rust-lang.org/2017/05/05/libz-blitz.html">Rust Libz Blitz</a></h2>
<p>Falando em boa experiência, uma das coisas frustrantes e complicadas de investir em uma linguagem nova é a quantidade de boas bibliotecas disponíveis. As primeiras pessoas sempre chegaram a um ecossistema sem bom desenvolvimento.</p>
<p>Com a evolução da linguagem, teremos boas bibliotecas, mas ainda não temos um bom ecossistema para desenvolver aplicações Web.</p>
<p>Alguns dos problemas já possuem ferramentas que estão evoluindo bem rápido como:</p>
<ul>
<li>Diesel: ORM que executa na versão estável da linguagem - <a href="http://diesel.rs/">http://diesel.rs/</a></li>
<li>Rocket: Framework web que ainda requer uma versão instável da linguagem - <a href="https://rocket.rs/">https://rocket.rs/</a></li>
<li>Tokio: Plataforma para escrever código assíncrono - <a href="https://tokio.rs/">https://tokio.rs/</a></li>
</ul>
<p>Essas bibliotecas maiores são compostas de bibliotecas menores, como parsers de URL, Buffer de escrita, e tantas outras.</p>
<p>Como temos um ecossistema novo, essas bibliotecas às vezes não são tão estáveis quanto gostaríamos, apesar de ter um domínio bem definido para atacar.</p>
<p>A comunidade anunciou em um post bem legal de ler qual a estratégia que eles utilizaram para tornar esse ecossistema cheio de ferramentas fáceis de adotar no seu projeto:</p>
<ul>
<li>De tempo em tempo, uma equipe da linguagem vai escolher uma biblioteca candidata para estabilização</li>
<li>Eles seguem uma série de convenções definidas e claras para analisar a biblioteca
<ul>
<li>O objetivo está em normalizar as interfaces, chamadas, estrutura, e claro, documentação clara</li>
<li>A comunidade está convidada a ajudar a definir as <a href="https://github.com/brson/rust-api-guidelines">guidelines</a></li>
<li>As análises serão feitas em vídeo e gravadas. Uma ótima oportunidade para aprender como pessoas que conhecem a linguagem analisam código.</li>
</ul>
</li>
<li>Serão criados Issues nos projetos, e toda a comunidade se mobilizaram para ajudar a tratar esses issues
<ul>
<li>A comunidade já possui uma convenção de marcar issues como “Bom para um primeiro commit”, “Easy”, ou “Disponível para mentorear”</li>
</ul>
</li>
<li>Depois de tratado os problemas, essa seria uma biblioteca com um selo de qualidade
<ul>
<li>Essas bibliotecas teriam exemplos simples para ajudar a fazer coisas na linguagem, como “Escrever em um arquivo em paralelo”, “Baixar o conteúdo de um site”</li>
<li>Esses exemplos estarão em um <a href="https://brson.github.io/rust-cookbook/">guia</a></li>
</ul>
</li>
</ul>
<p>Acho bem interessante o esforço que a comunidade tem colocado em gerar esse tipo de material.</p>
<p>Documentação e didática tem sido um foco bem interessante do projeto. Esse esforço de trazer pessoas novas e separar issues para incentivar o desenvolvimento também, além de tentar ajudar a distribuir o esforço das autoras de bibliotecas.</p>
<h2 id="rustfest-2017---youtube">RustFest 2017 - <a href="https://www.youtube.com/channel/UCaYhcUwRBNscFNUKTjgPFiA">YouTube</a></h2>
<p>Esse último mês aconteceu o 2o Rust Fest, cheio de apresentações que me deixaram interessados.</p>
<p>Os vídeos já começaram a ser publicados no canal deles no YouTube.</p>
<p>Eu estou particularmente interessado em ouvir como a Ashley Williams, desenvolvedora do NPM (Node Package Manager), convenceu a equipe dela a adotar Rust. Ainda não temos Rust executando no seu computador quando você executa `npm install`, mas a infraestrutura do repositório oficial sim, pelo menos foi o que entendi dos slides.</p>
<p><a href="https://ashleygwilliams.github.io/rustfest-2017/">https://ashleygwilliams.github.io/rustfest-2017/</a></p>
<p>Falando em executar Rust no seu computador, todas as vezes que você fizer uma busca com um Visual Studio Code atualizado, você estará executando um pedaço de Rust.</p>
<p>Houve um PR para adicionar a biblioteca de regex em Rust como parte do VSCode. Isso demonstra essa coexistência pacífica da linguagem com outras linguagens no mesmo projeto. Achei a discussão interessante de ler, mesmo apenas para conhecer os argumentos.</p>
<p><a href="https://github.com/Microsoft/vscode/issues/19983">https://github.com/Microsoft/vscode/issues/19983</a></p>
<h2 id="coexistindo-com-outras-linguagens-no-mesmo-projeto---helix">Coexistindo com outras linguagens no mesmo projeto - <a href="https://usehelix.com/">Helix</a></h2>
<p>Tenho ouvido cada vez mais sobre empresas no Brasil adotando Rust em seus projetos Ruby/Rails, de Fintechs a Chatbots. Eu sou super entusiasta dessa capacidade de Rust ser inserido em projetos como bibliotecas.</p>
<p>Recentemente houve uma atualização do projeto <a href="https://usehelix.com/">Helix</a> , que quer deixar fácil escrever código Rust em projetos Ruby.</p>
<p>Para projetos em C/C++, a biblioteca que permite gerar os arquivos necessários para ajudar.</p>
<p><a href="https://servo.github.io/rust-bindgen/">https://servo.github.io/rust-bindgen/</a></p>
<p>Isso, integrado com o Corrode, um programa que tenta gerar código Rust válido a partir de código C, ajudaria muito a transformar partes de projetos aos poucos.</p>
<p>O <a href="https://github.com/jameysharp/corrode">Corrode</a> ainda está em desenvolvimento, e não gera códigos idiomáticos, mas os <a href="http://jamey.thesharps.us/2017/04/corrode-update-control-flow-translation.html">updates</a> do projeto me deixam animado.</p>
<p>Ah, e faz um tempo que o Firefox já executa pedaços de Rust no seu computador. <a href="https://hacks.mozilla.org/2016/07/shipping-rust-in-firefox/">Um post bem legal para entender como foi o processo de adicionar isso está no blog da Mozilla</a> também foi publicado recentemente.</p>
<h1 id="como-começar">Como começar</h1>
<p>Se eu te deixei animado, segue uma lista de recursos para começar com Rust.</p>
<h2 id="instale-o-rustup-no-seu-computador">Instale o `rustup` no seu computador.</h2>
<p>Esse é o jeito mais fácil de instalar o compilador.</p>
<p><a href="https://www.rustup.rs/">https://www.rustup.rs/</a></p>
<p>Programas escritos em Rust (na grande maioria das vezes) não precisam de mais nada para serem executados em outros computadores além do binário.</p>
<p>Mas para gerar esse binário, você precisa de ter o compilador no seu computador, que é exatamente o que o `rustup` configura.</p>
<p>Funciona em Mac, Linux e Windows, e eu testei no Windows inclusive.</p>
<h2 id="leia-o-livro-do-rust">Leia o livro do Rust</h2>
<p><a href="https://doc.rust-lang.org/stable/book/">https://doc.rust-lang.org/stable/book/</a></p>
<p>O livro do Rust é o documento mais oficial para aprender a linguagem. Ele tem sido reescrito para melhorar a didática aos poucos, mas ainda é uma boa fonte de informação, mesmo durante o processo.</p>
<p>Feedbacks são bem aceitos.</p>
<h2 id="pratique-rust-com-exercícios">Pratique Rust com exercícios</h2>
<p><a href="http://exercism.io/languages/rust/about">http://exercism.io/languages/rust/about</a></p>
<p>O projeto Exercism possui vários desafios e exercícios feitos para Rust. O site é bem legal e tem instruções de como começar a resolver os problemas.</p>
<h2 id="utilize-o-template-para-gerar-binários-continuamente-no-seu-projeto">Utilize o template para gerar binários continuamente no seu projeto</h2>
<p>Existe um projeto com um template para Travis e AppVeyor que permite que você gere binários para todas as principais plataformas que o Rust suporta: Mac, Linux, Windows e *BSD.</p>
<p>Os binários podem ser configurados para gerar a versões para diferentes arquiteturas: ARM, 32 e 64bits, e outros.</p>
<p>O script também permite validar o seu projeto com as versões futuras da linguagem, garantindo que uma versão nova da linguagem (que é lançada a cada 6 semanas) não pegue o seu projeto desprevenido.</p>
<p><a href="https://github.com/japaric/trust">https://github.com/japaric/trust</a></p>
<h2 id="busque-mais-conteúdos">Busque mais conteúdos</h2>
<p>Existem alguns repositórios com séries de artigos, posts, vídeos e outros materiais sobre Rust, que pode ajudar a recapitular o que já foi publicado.</p>
<ul>
<li><a href="https://github.com/kud1ing/awesome-rust">https://github.com/kud1ing/awesome-rust</a></li>
<li><a href="https://github.com/rust-unofficial/patterns">https://github.com/rust-unofficial/patterns</a></li>
<li><a href="https://github.com/ctjhoa/rust-learning">https://github.com/ctjhoa/rust-learning</a></li>
<li><a href="https://brson.github.io/rust-cookbook/">https://brson.github.io/rust-cookbook/</a></li>
<li><a href="https://github.com/brson/rust-api-guidelines">https://github.com/brson/rust-api-guidelines</a></li>
</ul>
<h2 id="converse-com-o-pessoal">Converse com o pessoal</h2>
<p>O pessoal tende ser muito receptivo com pessoas novas, então sempre vale passar pra dar um oi, pedir ajuda ou anunciar projetos e posts, mesmo que sejam pequenos.</p>
<ul>
<li><a href="https://users.rust-lang.org/">Fórum de usuários</a></li>
<li><a href="https://kiwiirc.com/client/irc.mozilla.org/#rust">#rust</a> no IRC da Mozilla</li>
<li><a href="https://kiwiirc.com/client/irc.mozilla.org/#rust-beginners">#rust-beginners</a> no IRC da Mozilla</li>
<li><a href="https://www.reddit.com/r/rust/">Reddit</a></li>
</ul>
<h2 id="siga-os-updates-semanalmente---this-week-in-rust">Siga os updates semanalmente - <a href="https://this-week-in-rust.org/">This Week in Rust</a></h2>
<p>O This Week in Rust tem um email semanal com novidades. Recomendo visitar e se inscrever se quisr acompanhar as novidades.</p>
<p>Espero que tenham gostado e achado o post informativo.</p>
<p>Happy Hacking</p>
Expressando o domínio através do sistema de tipos2017-01-18T00:00:00-02:00https://blog.bltavares.com/2017/01/18/expressando_o_dominio_atraves_do_sistema_de_tipos<p>(Note: This post should be Google Translate friendly. I’ve refrained from using slangs to help with that.)</p>
<p>Este post é para que eu possa desenvolver melhor a ideia sobre a relação de tipos e domínio, além de mostrar um pouco, de forma mais prática, as vantagens de utilizar um sistema de tipos expressivo, em relação a sistemas de tipos mais simples.</p>
<p>Antes de tudo, vamos definir um pouco quais tipos entraram na categoria de sistema de tipos expressivo. Muitos dos sistemas de tipo que considero expressivo geralmente não são os que estamos acostumados, e que geralmente vem na nossa mente, como Java ou C#.</p>
<p>O Gary Bernhardt escreveu um Gist interessante sobre <a href="https://gist.github.com/garybernhardt/122909856b570c5c457a6cd674795a9c">“Types”</a> em que é possível entender diferentes aspectos de cada linguagem.</p>
<p>Esse não é um post para dizer que utilizando uma linguagem como JavaScript, Python ou Ruby não poderíamos chegar na mesma arquitetura. É um post para analisar como a existência do sistema de tipos estimula um outro tipo de design.</p>
<p>Sistemas de tipos mais dinâmicos possuem suas vantagens, mas vou focar nas vantagens dos tipos estáticos, sem compará-los diretamente - talvez isso seja um assunto para outro artigo.</p>
<p>Demonstrarei a seguir um dos aspectos de um sistema de tipo mais restritivo e como aproveitar o investimento que é “definir melhor o seu programa” - mesmo que isso queira dizer um pouco mais verboso e enrijecido.</p>
<h1 id="qual-sistema-estático-vou-utilizar">Qual “Sistema estático” vou utilizar?</h1>
<p>Esse post foi pensado em Rust, que tem algumas características um pouco peculiares, se comparados com o sistema de tipos estático mais comuns (Java ou C#).</p>
<p>Algumas das características peculiares se comparado com essas linguagens:</p>
<h2 id="null-não-é-um-habitante-de-todos-os-tipos"><em>Null</em> não é um habitante de todos os <em>Tipos</em>.</h2>
<p>Em Java, por exemplo, a seguinte assinatura de método requer que o corpo da função seja inspecionado para descobrir se <code class="language-plaintext highlighter-rouge">null</code> pode ser retornado.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">File</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">File</span> <span class="nf">open</span><span class="o">(</span><span class="nc">String</span> <span class="n">path</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//....</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Em Rust, não temos <code class="language-plaintext highlighter-rouge">null</code>. Funções que retornariam <code class="language-plaintext highlighter-rouge">null</code> em outras linguagens precisam retornar em Rust uma estrutura, indicando que o valor é opcional.</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">mod</span> <span class="n">file</span> <span class="p">{</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="k">-></span> <span class="nb">Option</span><span class="o"><</span><span class="n">File</span><span class="o">></span> <span class="p">{</span>
<span class="c">// ....</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Assim, é preciso verificar se o valor está presente ou não, antes de continuar o processamento. Essa declaração agora também é parte da assinatura, e nos informa da possível falta do valor retornado.</p>
<h2 id="é-possível-expressar-que-um-valor-será-invalidado-após-uma-operação">É possível expressar que um valor será invalidado após uma operação.</h2>
<p>Rust possui o conceito de <a href="https://doc.rust-lang.org/book/ownership.html">posse do valor</a> (em inglês, <strong>ownership</strong>), que define que um escopo precisa ser dono de seus valores, invalidando qualquer outra referência, caso não seja possível copiar ou clonar o dado ao trocar de escopo. Isso traz mais expressividade, mas ao mesmo tempo um conceito a mais para aprender.</p>
<p>A ideia de posse do valor é um conceito que Rust traz como novidade em comparação a outras linguagens, e que para mim é um ótimo motivo para estudar a linguagem. O conceito é um pouco difícil, inclusive por ser novidade, e mais pra frente no texto trarei alguns exemplos.</p>
<p>Tratar essas peculiaridades como benefícios, como sempre, são escolhas de benefício x valor. Vamos ver o que é possível expressar utilizando essas características, para podermos considerar o valor.</p>
<p>Para isso, vamos escrever código e observar o que é conseguimos entender do domínio, mesmo sem ter o corpo das funções.</p>
<h2 id="como-compilar-os-exemplos-de-código">Como compilar os exemplos de código</h2>
<p>Trarei exemplos de código em Rust, com links para o exemplo completo de cada transformação.</p>
<p>É preciso ter instalado no seu computador o compilador do Rust para compilar os exemplos e recomendo seguir as instruções do <a href="https://www.rustup.rs/">rustup.rs</a> para ter instalado o <code class="language-plaintext highlighter-rouge">rustc</code>.</p>
<p>Pela linha de comando você então poderá chamar o compilador de uma das seguinte maneiras:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Chamada simples</span>
rustc exemplo.rs
<span class="c"># Chamada ignorando alguns alertas por não utilizarmos os argumentos ou funções</span>
rustc <span class="nt">-A</span> unused_variables <span class="nt">-A</span> dead_code exemplo.rs
</code></pre></div></div>
<h1 id="domínio-do-problema">Domínio do problema</h1>
<p>Vou escolher problemas em um domínio com algumas características arbitrárias (descritas abaixo) para exercitar melhor os conceitos que o sistema de tipos de Rust possui.</p>
<p>Estamos escrevendo um sistema de pedidos.</p>
<hr />
<ul>
<li>Nossos pedidos acontecem por uma API em um servidor</li>
<li>Um pedido não pode ter quantidades negativas</li>
<li>Como podemos ficar fora de estoque, em caso de erro devemos voltar ao produto com uma mensagem
<ul>
<li>É preciso iniciar o processo inteiro novamente e nenhuma outra thread poderia usar nosso pedido</li>
</ul>
</li>
<li>Toda transação precisa receber um token de sessão</li>
<li>Toda sessão é iniciada por um token de autorização</li>
</ul>
<hr />
<p>Depois dessas regras arbitrárias, vamos ver o que é possível descrever do nosso domínio apenas pelo sistema de tipos e regras de visibilidade.</p>
<p>A implementação das funções não importa no momento.</p>
<p>Vamos observar quais informações podemos extrair das assinaturas, como se estivéssemos utilizando uma biblioteca de um terceiro.</p>
<h1 id="implementação-inicial">Implementação inicial</h1>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">authorize</span><span class="p">(</span><span class="n">auth_token</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="k">-></span> <span class="nb">String</span> <span class="p">{</span>
<span class="nd">unimplemented!</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">send_order</span><span class="p">(</span><span class="n">session_token</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
<span class="n">amount</span><span class="p">:</span> <span class="nb">u8</span><span class="p">,</span>
<span class="n">product</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="p">{</span>
<span class="nd">unimplemented!</span><span class="p">()</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">session_token</span> <span class="o">=</span> <span class="nf">authorize</span><span class="p">(</span><span class="s">"My initial token"</span><span class="nf">.into</span><span class="p">());</span>
<span class="nf">send_order</span><span class="p">(</span><span class="n">session_token</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="s">"Bananas"</span><span class="nf">.into</span><span class="p">())</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Essa é uma implementação inicial e pode ser amadurecida.</p>
<ul>
<li>Temos nossa função principal do problema, <code class="language-plaintext highlighter-rouge">send_order</code>, com os conceitos de: quantidade, produto e token de sessão.</li>
<li>Existe uma função que pode gerar um token de sessão.</li>
</ul>
<p>Estamos com essas duas funções, mas de nenhuma forma estou definindo no programa que essas funções mantém uma relação bem próxima.</p>
<p>Sem essa definição de relação, uma outra pessoa:</p>
<ul>
<li>Poderia chamar <code class="language-plaintext highlighter-rouge">send_order</code> sem chamar a função <code class="language-plaintext highlighter-rouge">authorize</code></li>
<li>Poderia chamar a função <code class="language-plaintext highlighter-rouge">send_order</code> com uma <em>String</em> arbitrária como token, e ter um erro de parsing, validação ou qualquer outra coisa.</li>
</ul>
<p>Vamos deixar nosso programa melhor definido escrevendo mais código.</p>
<h1 id="extraindo-o-conceito-de-session-token">Extraindo o conceito de Session Token</h1>
<p>Temos um relacionamento entre a <code class="language-plaintext highlighter-rouge">String</code> de saída do <code class="language-plaintext highlighter-rouge">authorize</code>, e a <code class="language-plaintext highlighter-rouge">String</code> na entrada do <code class="language-plaintext highlighter-rouge">send_order</code>. No nosso domínio, isso é o token da sessão.</p>
<p>Vamos fazer uma pequena alteração no código, e extrair o conceito do token da sessão em uma estrutura retornada ao iniciar a sessão.</p>
<p>Vou mostrar um <em>diff</em> da mudança, e um <a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_02.rs">link para o código pronto para ser compilado.</a></p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_01.rs b/order_02.rs
index cfce64f..9b95b16 100644
</span><span class="gd">--- a/order_01.rs
</span><span class="gi">+++ b/order_02.rs
</span><span class="p">@@ -1,8 +1,10 @@</span>
<span class="gd">-pub fn authorize(auth_token: String) -> String {
</span><span class="gi">+pub struct SessionToken(String);
+
+pub fn authorize(auth_token: String) -> SessionToken {
</span> unimplemented!()
}
-pub fn send_order(session_token: String,
<span class="gi">+pub fn send_order(session_token: SessionToken,
</span> amount: u8,
product: String) {
unimplemented!()
</code></pre></div></div>
<p>Sem se ater muito aos detalhes, esse novo snippet introduz uma estrutura que encapsula uma <em>String</em>. A nossa estrutura <code class="language-plaintext highlighter-rouge">SessionToken</code> faz a conexão entre o retorno de <code class="language-plaintext highlighter-rouge">authorize</code> com a entrada de <code class="language-plaintext highlighter-rouge">send_order</code>.</p>
<p>Ao analisarmos as assinaturas, a conexão entre as duas funções agora vai além dos nomes e entra no nível de estruturas de dados que o compilador pode verificar.</p>
<p>Nosso código de uso no <code class="language-plaintext highlighter-rouge">main</code> se manteve o mesmo.</p>
<p>Fica mais intuitivo (e com a ajuda de um auto-complete) associar as duas funções. Menos um erro de runtime.</p>
<p>Ainda podemos chamar a nossa função com uma <em>String</em> arbitrária, caso seja necessário, como em um teste.</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">send_order</span><span class="p">(</span><span class="nf">SessionToken</span><span class="p">(</span><span class="s">"My test token"</span><span class="nf">.into</span><span class="p">()));</span>
</code></pre></div></div>
<h1 id="reutilizando-o-session-token">Reutilizando o Session Token</h1>
<p>Um problema interessante acontece se tentarmos fazer dois pedidos compartilhando o mesmo token com o código anterior:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">let</span> <span class="n">session_token</span> <span class="o">=</span> <span class="nf">authorize</span><span class="p">(</span><span class="s">"My initial token"</span><span class="nf">.into</span><span class="p">());</span>
<span class="nf">send_order</span><span class="p">(</span><span class="n">session_token</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="s">"Bananas"</span><span class="nf">.into</span><span class="p">());</span>
<span class="c">// Adicionamos mais um pedido</span>
<span class="nf">send_order</span><span class="p">(</span><span class="n">session_token</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="s">"Peras"</span><span class="nf">.into</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Ao compilar o programa, temos o seguinte erro:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rustc ~/order.rs
error[E0382]: use of moved value: `session_token`
--> /Users/bruno/order.rs:16:16
|
15 | send_order(session_token, 10, "Bananas".into());
| ------------- value moved here
16 | send_order(session_token, 5, "Peras".into());
| ^^^^^^^^^^^^^ value used here after move
|
= note: move occurs because `session_token` has type `SessionToken`, which does not implement the `Copy` trait
error: aborting due to previous error
</code></pre></div></div>
<p>Toda essa mensagem de erro está relacionada ao conceito de <a href="https://doc.rust-lang.org/book/ownership.html">posse do valor</a> que Rust tem.</p>
<p>Da forma que a assinatura da nossa função está escrita, temos que enviar todo o valor, junto com o registro <em>posse</em> do <code class="language-plaintext highlighter-rouge">SessionToken</code> para fazer um pedido.</p>
<p>A posse do valor do token pertence à variável com o escopo em <code class="language-plaintext highlighter-rouge">main</code>. Ao chamarmos a função <code class="language-plaintext highlighter-rouge">send_order</code> pela primeira vez, esse valor é movido para o escopo na primeira chamada de <code class="language-plaintext highlighter-rouge">send_order</code> e não está mais disponível para fazermos mais um pedido.</p>
<p>Como a função <code class="language-plaintext highlighter-rouge">session_token</code> só precisa do token <a href="https://doc.rust-lang.org/book/references-and-borrowing.html"><em>emprestado</em></a> (em inglês, <strong>borrowing</strong>), precisamos mudar a assinatura da nossa função a fim de demonstrar a intenção que queremos o valor temporariamente e que não vamos reescrever ou alterar o token, só vamos pegar <em>emprestado</em> para poder fazer o pedido.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_02.rs b/order_03.rs
index 9b95b16..f3f939e 100644
</span><span class="gd">--- a/order_02.rs
</span><span class="gi">+++ b/order_03.rs
</span><span class="p">@@ -4,7 +4,7 @@</span> pub fn authorize(auth_token: String) -> SessionToken {
unimplemented!()
}
-pub fn send_order(session_token: SessionToken,
<span class="gi">+pub fn send_order(session_token: &SessionToken,
</span> amount: u8,
product: String) {
unimplemented!()
<span class="p">@@ -12,5 +12,6 @@</span> pub fn send_order(session_token: SessionToken,
fn main() {
let session_token = authorize("My initial token".into());
<span class="gd">- send_order(session_token, 10, "Bananas".into())
</span><span class="gi">+ send_order(&session_token, 10, "Bananas".into());
+ send_order(&session_token, 5, "Peras".into());
</span> }
</code></pre></div></div>
<p>A mudança é pequena na assinatura: trocando de <code class="language-plaintext highlighter-rouge">SessionToken</code> para <code class="language-plaintext highlighter-rouge">&SessionToken</code> e corrigindo como passamos o argumento do token. <a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_03.rs">Segue o link para copiar e compilar o código completo.</a></p>
<p>Temos agora definido no nível da assinatura que não vamos alterar o valor da variável <code class="language-plaintext highlighter-rouge">session_token</code> ao chamar <code class="language-plaintext highlighter-rouge">send_order</code> e que um mesmo token pode ser reutilizado, inclusive compartilhado por várias threads ao realizar o pedido.</p>
<h1 id="expondo-apenas-uma-maneira-de-criar-um-session-token-válido">Expondo apenas uma maneira de criar um Session Token válido</h1>
<p>Ainda lidando com o conceito de <code class="language-plaintext highlighter-rouge">SessionToken</code>, senti a necessidade de tornar o relacionamento entre <code class="language-plaintext highlighter-rouge">authorize</code> e <code class="language-plaintext highlighter-rouge">send_order</code> mais forte.</p>
<p>Com o código anterior, ainda seria possível criar um token inválido:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="c">// Session tokens precisam seguir um formato específico</span>
<span class="c">// ASDF não deveria ser um token válido</span>
<span class="nf">send_order</span><span class="p">(</span><span class="nf">SessionToken</span><span class="p">(</span><span class="s">"ASDF"</span><span class="nf">.into</span><span class="p">()),</span> <span class="mi">10</span><span class="p">,</span> <span class="s">"Bananas"</span><span class="nf">.into</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A estrutura <code class="language-plaintext highlighter-rouge">SessionToken</code> no exemplo tem um token inválido, em um formato que não seria aceito pelas APIs. Se utilizarmos uma restrição na visibilidade do que é exportado, podemos definir que <code class="language-plaintext highlighter-rouge">SessionTokens</code> sejam criados só se forem válidos.</p>
<p>Como temos todo o código no mesmo arquivo, todas os construtores e funções estarão disponíveis para a função <code class="language-plaintext highlighter-rouge">main</code> nesse momento.</p>
<p>Em Rust, além de podermos utilizar um outro arquivo para criar módulos, é possível criar um módulo no mesmo arquivo. Vamos introduzir um módulo para controlarmos melhor quais construtores estarão visíveis.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_03.rs b/order_04.rs
index f3f939e..c31b445 100644
</span><span class="gd">--- a/order_03.rs
</span><span class="gi">+++ b/order_04.rs
</span><span class="p">@@ -1,3 +1,4 @@</span>
<span class="gi">+mod lib {
</span> pub struct SessionToken(String);
pub fn authorize(auth_token: String) -> SessionToken {
<span class="p">@@ -9,6 +10,9 @@</span> pub fn send_order(session_token: &SessionToken,
product: String) {
unimplemented!()
}
<span class="gi">+}
+
+pub use lib::*;
</span>
fn main() {
let session_token = authorize("My initial token".into());
</code></pre></div></div>
<p>Criamos um módulo <code class="language-plaintext highlighter-rouge">lib</code> ao redor do nosso código, e no escopo do arquivo, importamos apenas as funções públicas com <code class="language-plaintext highlighter-rouge">pub use lib::*</code>.</p>
<p>Apesar da nossa estrutura ser pública, o campo interno de dados não é.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error[E0450]: cannot invoke tuple struct constructor with private fields
--> ~/order.rs:18:15
|
2 | pub struct SessionToken(String);
| ------- private field declared here
...
18 | let s = SessionToken("ASDF".into());
| ^^^^^^^^^^^^ cannot construct with a private field
error: aborting due to previous error
</code></pre></div></div>
<p>Tanto o acesso para leitura e escrita dos campos privados da estrutura estarão disponíveis apenas para as funções dentro do módulo. Assim, caso o desenvolvedor queira um <code class="language-plaintext highlighter-rouge">SessionToken</code>, é preciso chamar <code class="language-plaintext highlighter-rouge">authorize</code>.</p>
<p>E como <code class="language-plaintext highlighter-rouge">send_order</code> precisa de um token, a relação entre as duas funções é mais forte e validada pelo compilador.</p>
<p>Experimentem descomentar a linha comentada no <a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_04.rs">exemplo</a> no <code class="language-plaintext highlighter-rouge">main</code>, e ver o erro.</p>
<h1 id="extraindo-o-conceito-de-pedido">Extraindo o conceito de Pedido</h1>
<p>Uma regra do domínio que está escrita nas entrelinhas é que temos o conceito de um pedido válido. Deveríamos ter apenas pedidos com números positivos, já que não podemos entregar -10 maçãs.</p>
<p>Como no passo anterior, podemos extrair o conceito de <em>Pedido</em> em uma estrutura, e prover apenas uma maneira de criar essa estrutura, que requer validação da quantidade.</p>
<p>Vamos precisar de alguns passos intermediários para poder chegar lá.</p>
<p>Primeiro, vamos criar uma estrutura que encapsula o conceito de pedido, chamada <code class="language-plaintext highlighter-rouge">Order</code>.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_04.rs b/order_06.rs
index c31b445..47f56d9 100644
</span><span class="gd">--- a/order_04.rs
</span><span class="gi">+++ b/order_06.rs
</span><span class="p">@@ -1,13 +1,17 @@</span>
mod lib {
pub struct SessionToken(String);
+ pub struct Order {
<span class="gi">+ pub amount: u8,
+ pub name: String,
+ }
+
</span> pub fn authorize(auth_token: String) -> SessionToken {
unimplemented!()
}
pub fn send_order(session_token: &SessionToken,
<span class="gd">- amount: u8,
- product: String) {
</span><span class="gi">+ order: &Order) {
</span> unimplemented!()
}
}
<span class="p">@@ -16,6 +20,7 @@</span> pub use lib::*;
fn main() {
let session_token = authorize("My initial token".into());
<span class="gd">- send_order(&session_token, 10, "Bananas".into());
- send_order(&session_token, 5, "Peras".into());
</span><span class="gi">+
+ let first_order = Order { amount: 10, name: "Bananas".into() };
+ send_order(&session_token, &first_order);
</span> }
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_06.rs">O código completo para compilar está aqui.</a></p>
<h1 id="criando-apenas-pedidos-válidos">Criando apenas Pedidos válidos</h1>
<p>Agora com nossa estrutura sendo utilizada pelo <code class="language-plaintext highlighter-rouge">main</code> e pelo <code class="language-plaintext highlighter-rouge">send_order</code>, podemos permitir que pedidos tenham uma quantidade válida para criar um <code class="language-plaintext highlighter-rouge">Order</code>.</p>
<p>Da mesma maneira que fizemos com a estrutura do <code class="language-plaintext highlighter-rouge">SessionToken</code>, podemos transformar a estrutura interna privada, permitindo que apenas uma função dentro do módulo acessem os campos.</p>
<p>Vamos criar uma função <code class="language-plaintext highlighter-rouge">send_order</code>, que valida, cria e retorna nossa estrutura <code class="language-plaintext highlighter-rouge">Order</code>. Isso seria como um construtor, mas que inclui as regras de validação.</p>
<p>Com as regras de visibilidade, esse será o único método que retorna a estrutura <code class="language-plaintext highlighter-rouge">Order</code> no nosso módulo.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_06.rs b/order_07.rs
index 47f56d9..a13f381 100644
</span><span class="gd">--- a/order_06.rs
</span><span class="gi">+++ b/order_07.rs
</span><span class="p">@@ -2,8 +2,15 @@</span> mod lib {
pub struct SessionToken(String);
pub struct Order {
<span class="gd">- pub amount: u8,
- pub name: String,
</span><span class="gi">+ amount: u8,
+ name: String,
+ }
+
+ pub fn create_order(amount: u8, name: String) -> Order {
+ if amount <= 0 {
+ unimplemented!()
+ }
+ unimplemented!()
</span> }
pub fn authorize(auth_token: String) -> SessionToken {
<span class="p">@@ -21,6 +28,6 @@</span> pub use lib::*;
fn main() {
let session_token = authorize("My initial token".into());
- let first_order = Order { amount: 10, name: "Bananas".into() };
<span class="gi">+ let first_order = create_order(10, "Bananas".into());
</span> send_order(&session_token, &first_order);
}
</code></pre></div></div>
<p>Criamos um relacionamento forte entra a saida de <code class="language-plaintext highlighter-rouge">create_order</code> com a entrada de <code class="language-plaintext highlighter-rouge">send_order</code>, assim como fizemos anteriormente.</p>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_07.rs">O código completo para compilar está aqui.</a></p>
<h1 id="indicando-que-um-pedido-pode-ser-inválido">Indicando que um pedido pode ser inválido</h1>
<p>Uma pergunta surgiu com o código anterior: O que acontece se a validação falhar?</p>
<p>Como eu não posso retornar nulos (Rust não tem nulo) e nem lançar exceções (Rust não tem exceções), tenho duas opções:</p>
<ol>
<li>Abortar o programa inteiro (eg: panic!)</li>
<li>Retornar uma estrutura de dados que indica a possibilidade de falha da nossa operação</li>
</ol>
<p>A opção 1 é não é ideal. Eu não gostaria que meu programa falhasse completamente apenas por ter um pedido inválido. Além do mais, nossas regras de negócio possuem instruções sobre o que fazer em caso de erro.</p>
<p>Precisamos de estratégias para lidar com pedidos inválidos.</p>
<p>Vamos aproveitar uma estrutura chamada <a href="https://doc.rust-lang.org/std/result/index.html"><em>Result</em></a> que está disponível na <code class="language-plaintext highlighter-rouge">stdlib</code> da linguagem. Nós poderíamos reescrever essa estrutura nós mesmos, mas já existem várias funcionalidades que ganhamos ao utilizar a estrutura da <code class="language-plaintext highlighter-rouge">stdlib</code>.</p>
<p>O conceito de <code class="language-plaintext highlighter-rouge">Result<T, U></code> é uma estrutura que tem duas variações de tipos. Temos o <code class="language-plaintext highlighter-rouge">Result::Ok(T)</code>, que envolve o valor em caso de sucesso, e o <code class="language-plaintext highlighter-rouge">Result::Err(U)</code> com o valor em caso de erro.</p>
<p>Um valor com tipo <code class="language-plaintext highlighter-rouge">Result<Order, String></code> significa:</p>
<ul>
<li>Caso a operação tenha dado certo, <code class="language-plaintext highlighter-rouge">Result::Ok(Order)</code>, você poderá extrair um valor do tipo <code class="language-plaintext highlighter-rouge">Order</code>;</li>
<li>E caso tenha um erro, <code class="language-plaintext highlighter-rouge">Result::Err(String)</code>, você tera um valor do tipo <code class="language-plaintext highlighter-rouge">String</code>.</li>
</ul>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_07.rs b/order_08.rs
index a13f381..8521912 100644
</span><span class="gd">--- a/order_07.rs
</span><span class="gi">+++ b/order_08.rs
</span><span class="p">@@ -6,7 +6,7 @@</span> mod lib {
name: String,
}
- pub fn create_order(amount: u8, name: String) -> Order {
<span class="gi">+ pub fn create_order(amount: u8, name: String) -> Result<Order, String> {
</span> if amount <= 0 {
unimplemented!()
}
<span class="p">@@ -29,5 +29,8 @@</span> fn main() {
let session_token = authorize("My initial token".into());
let first_order = create_order(10, "Bananas".into());
<span class="gd">- send_order(&session_token, &first_order);
</span><span class="gi">+
+ if let Ok(order) = first_order {
+ send_order(&session_token, &order);
+ }
</span> }
</code></pre></div></div>
<p>Com a assinatura atualizada, sou obrigado a considerar alguma estratégia para verificar se o pedido foi criado corretamente. A estratégia poderia ser falhar o programa em caso de erros chamando <code class="language-plaintext highlighter-rouge">.unwrap()</code>, mas vou utilizar <em>pattern matching</em>, e apenas enviar o pedido caso eu tenha um resultado <em>Ok</em> no <code class="language-plaintext highlighter-rouge">main</code>.</p>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_08.rs">O código completo para compilar está aqui.</a></p>
<p>Aproveitamos e criaremos uma estrutura bem específica para que possamos comunicar qual tipo de erro aconteceu ao criar nosso pedido. Assim, a assinatura do nosso método fica mais explícita sobre os possíveis tipos de erro, ao invés de ser uma <em>String</em> qualquer.</p>
<p>A estrutura chamada <code class="language-plaintext highlighter-rouge">InvalidOrder</code> terá a uma mensagem de erro, e encapsula bem o domínio do possível erro na nossa função.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_08.rs b/order_09.rs
index 8521912..8d9b087 100644
</span><span class="gd">--- a/order_08.rs
</span><span class="gi">+++ b/order_09.rs
</span><span class="p">@@ -1,12 +1,14 @@</span>
mod lib {
pub struct SessionToken(String);
+ pub struct InvalidOrder(String);
<span class="gi">+
</span> pub struct Order {
amount: u8,
name: String,
}
- pub fn create_order(amount: u8, name: String) -> Result<Order, String> {
<span class="gi">+ pub fn create_order(amount: u8, name: String) -> Result<Order, InvalidOrder> {
</span> if amount <= 0 {
unimplemented!()
}
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_09.rs">O código completo para compilar está aqui.</a></p>
<h1 id="trazendo-o-mesmo-conceito-de-possível-falha-ao-iniciar-uma-sessão">Trazendo o mesmo conceito de possível falha ao iniciar uma sessão</h1>
<p>Aprendemos no passo anterior que é possível expressar possíveis falhas como parte da assinatura das funções.</p>
<p>Pedir um token de sessão envolve fazer uma chamada a um serviço, então podemos ter falhas que deveriam ser comunicados ao desenvolvedor para que tomem uma decisão sobre o que fazer.</p>
<p>As razões de erro podem ser inúmeras nesse caso. Por exemplo, podemos ter um erro ao fazer o parsing do <em>JSON</em> ou a nossa conexão cair.</p>
<p>Essa enumeração dos erros que vamos nos preocupar pode ser descrita por um <a href="https://doc.rust-lang.org/book/enums.html"><em>enum</em></a>.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_09.rs b/order_10.rs
index 8d9b087..b6290cb 100644
</span><span class="gd">--- a/order_09.rs
</span><span class="gi">+++ b/order_10.rs
</span><span class="p">@@ -3,6 +3,11 @@</span> mod lib {
pub struct InvalidOrder(String);
+ pub enum ApiError {
<span class="gi">+ ParsingError(String),
+ IoError(String),
+ }
+
</span> pub struct Order {
amount: u8,
name: String,
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_10.rs">O código completo para compilar está aqui.</a></p>
<p>Com a nossa lista de possíveis erros, agora podemos alterar a assinatura do método para informar que pedir um token pode falhar.</p>
<p>Essa mudança na assinatura também requer uma mudança no <code class="language-plaintext highlighter-rouge">main</code>.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_10.rs b/order_11.rs
index b6290cb..1958286 100644
</span><span class="gd">--- a/order_10.rs
</span><span class="gi">+++ b/order_11.rs
</span><span class="p">@@ -20,7 +20,7 @@</span> mod lib {
unimplemented!()
}
- pub fn authorize(auth_token: String) -> SessionToken {
<span class="gi">+ pub fn authorize(auth_token: String) -> Result<SessionToken, ApiError> {
</span> unimplemented!()
}
@@ -33,7 +33,7 @@ mod lib {
pub use lib::*;
fn main() {
<span class="gd">- let session_token = authorize("My initial token".into());
</span><span class="gi">+ if let Ok(session_token) = authorize("My initial token".into()) {
</span>
let first_order = create_order(10, "Bananas".into());
@@ -41,3 +41,4 @@ fn main() {
send_order(&session_token, &order);
}
}
<span class="gi">+}
</span></code></pre></div></div>
<p>Como só posso continuar com o processo e fazer o pedido caso a autorização estaja <code class="language-plaintext highlighter-rouge">Ok</code>, utilizamos a mesma estratégia de <em>pattern matching</em> que utilizamos ao criar o pedido.</p>
<h1 id="invalidando-uma-ordem-depois-que-ela-é-enviada">Invalidando uma ordem depois que ela é enviada</h1>
<p>Revisando a lista de problemas que temos para resolver:</p>
<hr />
<ul>
<li><del>Nossos pedidos acontecem por uma API em um servidor</del></li>
<li><del>Um pedido não pode ter quantidades negativas</del></li>
<li>Como podemos ficar fora de estoque, em caso de erro devemos voltar ao produto com uma mensagem
<ul>
<li>É preciso iniciar o processo inteiro novamente e nenhuma outra thread poderia usar nosso pedido</li>
</ul>
</li>
<li><del>Toda transação precisa receber um token de sessão</del></li>
<li><del>Toda sessão é iniciada por um token de autorização</del></li>
</ul>
<hr />
<p>Temos bem claro que depois que um pedido é feito e temos um erro, deveríamos iniciar o fluxo novamente. Assim, não tentamos fazer o mesmo pedido com um número maior que o estoque, por exemplo.</p>
<p>Isso pode ser interpretado da seguinte maneira: assim que eu enviar o pedido, independente do resultado, eu não deveria enviar o mesmo Pedido.</p>
<p>Se imaginarmos que nosso código será usado em um ambiente com multi-thread, poderíamos trazer essa regra para a nossa assinatura e fazer com que o compilador reforce essa regra. Se uma thread enviar um pedido, outra thread não poderá enviar o mesmo pedido.</p>
<p>Como em Rust temos o conceito de <em>ownership</em> que falamos antes, podemos expressar isso pela assinatura. Alterando a assinatura em <code class="language-plaintext highlighter-rouge">send_order</code>, ao invés de pegar <em>emprestado</em> o valor do <em>Pedido</em>, podemos pedir a posse do valor também.</p>
<p>Com a mudança de <code class="language-plaintext highlighter-rouge">&Order</code> para <code class="language-plaintext highlighter-rouge">Order</code>, transmitimos que o pedido não estará mais disponível depois de chamar <code class="language-plaintext highlighter-rouge">send_order</code>, dado que o valor da variável será movido para outro contexto.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_11.rs b/order_12.rs
index 1958286..dbae30a 100644
</span><span class="gd">--- a/order_11.rs
</span><span class="gi">+++ b/order_12.rs
</span><span class="p">@@ -25,7 +25,7 @@</span> mod lib {
}
pub fn send_order(session_token: &SessionToken,
<span class="gd">- order: &Order) {
</span><span class="gi">+ order: Order) {
</span> unimplemented!()
}
}
<span class="p">@@ -38,7 +38,7 @@</span> fn main() {
let first_order = create_order(10, "Bananas".into());
if let Ok(order) = first_order {
<span class="gd">- send_order(&session_token, &order);
</span><span class="gi">+ send_order(&session_token, order);
</span> }
}
}
</code></pre></div></div>
<p>Nosso caso para o <code class="language-plaintext highlighter-rouge">Order</code> é o inverso do que esperamos para o token ao fazer um pedido. Nós gostaríamos de compartilhar o mesmo token com vários envios, mas o mesma estrutura de pedido não deveria ser reutilizada.</p>
<p>Nesse caso, gosto de pensar que o pedido foi “consumido” por <code class="language-plaintext highlighter-rouge">send_order</code>, invalidando que outras partes do código utilize um valor já enviado.</p>
<p>Na maioria dos casos, os problemas irão preferir utilizar o valor “emprestado”, mas as nossas regras arbitrárias geraram esse cenário e gostaria de compartilhar esse exemplo com vocês.</p>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_13.rs">O código completo para compilar está aqui.</a> Descomente a linha no exemplo para ver o compilador reforçando que nosso pedido não pode mais ser utilizado.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rustc -A unused_variables -A dead_code ~/order.rs
error[E0382]: use of moved value: `order`
--> ~/order_13.rs:43:28
|
41 | send_order(&session_token, order);
| ----- value moved here
42 | // Tente descomentar para falhar
43 | send_order(&session_token, order);
| ^^^^^ value used here after move
|
= note: move occurs because `order` has type `lib::Order`, which does not implement the `Copy` trait
error: aborting due to previous error
</code></pre></div></div>
<h1 id="trazendo-uma-resposta-sobre-o-resultado-do-pedido">Trazendo uma resposta sobre o resultado do Pedido</h1>
<p>Nosso domínio traz regras sobre o que fazer em caso de erro ao fazer um pedido. Nossa assinatura deveria refletir as nossas intenções e demonstrar que existe uma resposta e sobre a possível falha ao fazer um pedido.</p>
<p>Primeiro, vamos converter a resposta em <em>JSON</em> para uma estrutura na linguagem.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_12.rs b/order_14.rs
index dbae30a..4277e4c 100644
</span><span class="gd">--- a/order_12.rs
</span><span class="gi">+++ b/order_14.rs
</span><span class="p">@@ -13,6 +13,12 @@</span> mod lib {
name: String,
}
+ pub struct OrderResponse {
<span class="gi">+ pub name: String,
+ pub status: String,
+ pub amount: u8,
+ }
+
</span> pub fn create_order(amount: u8, name: String) -> Result<Order, InvalidOrder> {
if amount <= 0 {
unimplemented!()
<span class="p">@@ -25,7 +31,7 @@</span> mod lib {
}
pub fn send_order(session_token: &SessionToken,
<span class="gd">- order: Order) {
</span><span class="gi">+ order: Order) -> OrderResponse {
</span> unimplemented!()
}
}
</code></pre></div></div>
<p>Também vamos indicar que nosso envio do pedido pode falhar, assim como acontece ao iniciar uma sessão.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_14.rs b/order_15.rs
index 4277e4c..dee3edd 100644
</span><span class="gd">--- a/order_14.rs
</span><span class="gi">+++ b/order_15.rs
</span><span class="p">@@ -31,7 +31,7 @@</span> mod lib {
}
pub fn send_order(session_token: &SessionToken,
<span class="gd">- order: Order) -> OrderResponse {
</span><span class="gi">+ order: Order) -> Result<OrderResponse, ApiError> {
</span> unimplemented!()
}
}
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_15.rs">O código completo para compilar está aqui.</a></p>
<p>Uma grande vantagem de utilizar a estrutura <em>Result</em> que vem junto da <code class="language-plaintext highlighter-rouge">stdlib</code>, é que o compilador entende a semântica de erros. Nosso código faz uma chamada que pode falhar ao enviar o pedido, mas nunca está verificando se a resposta está Ok.</p>
<p>O compilador sabe que <code class="language-plaintext highlighter-rouge">Result</code> tem a semântica de uma operação que pode falhar, e nos avisa se não utilizamos o valor.</p>
<p>Obrigado <code class="language-plaintext highlighter-rouge">rustc</code>!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rustc -A unused_variables -A dead_code ~/order.rs
warning: unused result which must be used, #[warn(unused_must_use)] on by default
--> ~/order.rs:46:13
|
46 | send_order(&session_token, order);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</code></pre></div></div>
<h1 id="definindo-possíveis-status-de-um-pedido">Definindo possíveis status de um pedido</h1>
<p>Ainda aproveitando para demonstrar a expressividade do sistema de tipos, podemos definir melhor quais os possíveis estados de um pedido.</p>
<p>Ao invés de aceitar qualquer tipo de <code class="language-plaintext highlighter-rouge">String</code>, vamos criar uma enumeração com todos os possíveis estados que nos importamos.</p>
<p>Uma vantagem de utilizar um enum é não precisamos nos preocupar se devemos utilizar números, strings em minúsculo, strings em maiúsculo, capitalizadas, etc. ao criar um pedido.</p>
<p>Agora também estamos permitindo que:</p>
<ul>
<li>alguém que esteja explorando a documentação saiba os possíveis estados;</li>
<li>que o compilador verifique se cobrimos todos os casos em um <em>pattern match</em>;</li>
<li>a responsabilidade de transformar os valores a serem transmitidos e parseados para a parte que seja delegada para a parte de comunicação do programa.</li>
</ul>
<p>Vamos introduzir a estrutura <code class="language-plaintext highlighter-rouge">OrderStatus</code> no nosso código.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_15.rs b/order_16.rs
index dee3edd..b4b6269 100644
</span><span class="gd">--- a/order_15.rs
</span><span class="gi">+++ b/order_16.rs
</span><span class="p">@@ -15,10 +15,17 @@</span> mod lib {
pub struct OrderResponse {
pub name: String,
<span class="gd">- pub status: String,
</span><span class="gi">+ pub status: OrderStatus,
</span> pub amount: u8,
}
+ pub enum OrderStatus {
<span class="gi">+ Waiting,
+ Shipping,
+ Shipped,
+ Delivered,
+ }
+
</span> pub fn create_order(amount: u8, name: String) -> Result<Order, InvalidOrder> {
if amount <= 0 {
unimplemented!()
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_16.rs">Link para o código pronto para ser compilado.</a></p>
<h1 id="dando-um-nome-mais-bonito-para-nossas-respostas-da-api">Dando um nome mais bonito para nossas respostas da API</h1>
<p>Assim que começarmos a criar mais e mais funções que utilizam comunicação com nossa API, veremos o tipo <code class="language-plaintext highlighter-rouge">Result<T, ApiError></code>, várias e várias vezes. Inclusive, já temos duas funções com esse retorno na assinatura.</p>
<p>Vamos criar um tipo <code class="language-plaintext highlighter-rouge">ApiResponse</code> para que todos saibam que essa é uma chamada para a API, e que todas as respostas que tem esse tipo, terão os mesmo possíveis erros para se preocupar.</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/order_16.rs b/order_17.rs
index b4b6269..c064e9c 100644
</span><span class="gd">--- a/order_16.rs
</span><span class="gi">+++ b/order_17.rs
</span><span class="p">@@ -26,6 +26,8 @@</span> mod lib {
Delivered,
}
+ pub type ApiResponse<T> = Result<T, ApiError>;
<span class="gi">+
</span> pub fn create_order(amount: u8, name: String) -> Result<Order, InvalidOrder> {
if amount <= 0 {
unimplemented!()
<span class="p">@@ -33,12 +35,12 @@</span> mod lib {
unimplemented!()
}
- pub fn authorize(auth_token: String) -> Result<SessionToken, ApiError> {
<span class="gi">+ pub fn authorize(auth_token: String) -> ApiResponse<SessionToken> {
</span> unimplemented!()
}
pub fn send_order(session_token: &SessionToken,
<span class="gd">- order: Order) -> Result<OrderResponse, ApiError> {
</span><span class="gi">+ order: Order) -> ApiResponse<OrderResponse> {
</span> unimplemented!()
}
}
</code></pre></div></div>
<p><a href="http:/assets/expressando_o_dominio_atraves_do_sistema_de_tipos/order_17.rs">Aqui temos o codigo com o resultado final, pronto para ser compilado</a></p>
<h1 id="conclusão">Conclusão</h1>
<p>Depois de todos esses passos, o domínio no nosso programa está bem mais definido do que no início, mas com mais linhas de código também.</p>
<p>Trocamos verbosidade e tamanho de código por um programa expressando melhor nosso domínio.</p>
<p>Começamos com um programa bem simples que resolveu nosso problema e evoluímos aos poucos para trazer algumas das suposições e expectativas que guardavamos em nossa cabeça como algo verificável pelo compilador.</p>
<p>Poucas das vezes tivemos que alterar o código no <code class="language-plaintext highlighter-rouge">main</code>. As alterações necessárias aconteceram para definir estratégias que antes estava definidas implicitamente e que por padrão seria abortar o programa inteiro com um erro.</p>
<p>Algumas categorias de erro em runtime foram removidos, como <em>null pointer exception</em> ou <em>undefined is not a function</em>.</p>
<p>Foi possível criar um relacionamento mais claro entre as saídas e entradas das funções, tornando mais fácil navegar pelo módulo e definir a ordem das chamadas de métodos.</p>
<p>Mesmo sem escrever a implementação dos nosso metódos, podemos extrair algumas informações sobre nosso domínio. Saber extrair e definir essas informações e intenções também é uma prática a ser melhor explorada pelos desenvolvedores.</p>
<p>É preciso conhecer a semântica e regras do sistema para poder extrair e descrever melhor a intenção do código. Essa é uma habilidade a ser desenvolvida, assim como a habilidade de interpretação de texto.</p>
<p>Uma apresentação que trabalha a idea de limitar os estados impossíveis do domínio através do código é a <a href="https://www.youtube.com/watch?v=IcgmSRJHu_8">“Making Impossible States Impossible”</a> pelo Richard Feldman, com exemplos em Elm. Recomendo assistir também, mesmo em outra linguagem, no intuito de focar no conceito.</p>
<p>Esse resultado final não está tão idiomático e pode melhorar. Mas já temos o suficiente para explorar a expressividade de um sistema de tipos estáticos como o de Rust para o dominio através de código.</p>
<p>Como não cheguei a implementar o corpo das funções e quis apenas focar na informação que a assinatura contém, não cheguei a explorar como TDD pode nos ajudar a evoluir nosso design em conjunto dos tipos. Isso pode ser material para outro post.</p>
<p>Espero que você tenha gostado do texto e que consiga explorar esta ideia nas suas implementações futuras. Me enviem um post-resposta para discutirmos mais sobre este tema! (Mesmo em outro idioma :)</p>
Why I'm having so much fun with Rust2015-08-10T00:00:00-03:00https://blog.bltavares.com/2015/08/10/why-im-having-fun-with-rust<p>So, Rust is stable and has 1.x on it’s name. And now I’m playing with
it as there is no more syntax breaking changes. And it is being a lot
of FUN!</p>
<p>This blog post is an attempt to write up many of the reasons I’m
liking the language and the community.</p>
<h1 id="being-exposed-to-lower-level-concepts">Being exposed to lower level concepts</h1>
<p>I’ve been on web development for a while already. Working on Garbage
Collected languages under the HTTP Request Response cycle, both on
the client side and the backend means that many of the times I
barely need to worry about memory stuff.</p>
<p>Having to learn about differences between having a value on the Heap
or the Stack is something new to me. And it is really fun. Knowing
that there are different allocation and dis-allocation times and how
dependent values may behave, while the compiler has your back on it
is fun.</p>
<p>As Rust also output binaries and have inter-op with C. This means I’m
learning about compilers, runtime dependencies, libraries and
embedding. There are people on the community that consider a 14kb
binary too big. That is so far from what I’m used to, which means
there is a lot to learn.</p>
<h1 id="amazing-community">Amazing community</h1>
<p>Rust community is very lively. The IRC channel is always full of
chats and people try to be helpful and inclusive. This is a big plus
as they are trying to build a new language, which makes everybody
beginners most of the time.</p>
<p>The language development has a <a href="https://www.rust-lang.org/conduct.html">code of conduct</a>, as well as the
forum, the <a href="https://chat.mibbit.com/?server%3Dirc.mozilla.org&channel%3D%2523rust">IRC</a>, the <a href="http://rustcamp.com/conduct.htmlLink:%20http://rustcamp.com/conduct.html">subreddit</a> and the <a href="http://rustcamp.com/conduct.html">first conference</a>. The
moderators try to no feed trolls, specially when others try to
compare Rust against other similar languages, in a battle ‘til death.</p>
<blockquote>
<p>[…]</p>
<p>Both communities talk respectfully about the other, despite the languages having been pit against each other by the world.</p>
<p>[…]</p>
<p>I think if someone placed the Rust and Go community in a room and asked them to fight, we’d probably just all order pizza and geek out over languages.</p>
</blockquote>
<p>Quoted from <a href="https://www.reddit.com/r/rust/comments/3cj69b/why_go_and_rust_are_competitors/csw5t5v">a comment</a> about Go vs Rust.</p>
<p>I’m always lurking on the IRC channel. Many of the times I have no
clue what is being discussed, but that keeps teasing my curiosity.
When I interact, as a beginner, I never experienced down talk, but
interest in helping me.</p>
<h1 id="evolving-language">Evolving language</h1>
<p>The compiler is amazing and is on constant evolution.
The way that changes are proposed feels very interesting from an
outsider. All proposed solutions comes from a public discussed <a href="https://github.com/rust-lang/rfcs">RFC</a>,
with examples of the benefits of implementing the change, alternatives
implementations, drawbacks. They are proposed as Pull Requests, and
when they get accepted, after all the discussion, it gets merged and
implemented on the compiler.</p>
<p>Carol Nichols wrote a bit on this <a href="http://carol-nichols.com/2015/08/01/rustc-discovery/">post</a> about getting a change landed
in, and it does feel that the community is open to change just by
reading it.</p>
<h1 id="lot-of-potential">Lot of potential</h1>
<p>As it is an evolving language and really new, there is a lot of
libraries that need to be written. As you go, you will find the need
of a JSON parsing tool, or async I/O, which is still in development
as libraries. That means you can help with that! Get that sweet
little IRC bot written with little competition or <a href="https://users.rust-lang.org/t/survey-what-libraries-would-you-like-to-see-in-the-future/2234">check what the
community wants to see being developed now that Rust is 1.0.</a></p>
<p>One other thing that I find interesting. Many of the concepts that
on other languages are implemented on the language itself, are
possible as libraries. For example, <a href="https://github.com/carllerche/mio">async I/O</a> or <a href="https://github.com/BurntSushi/chan">green threads</a>, are
already being developed as libraries. That means that the language
is simple and powerful enough to delegate some of the decisions to
libraries, when the community feels the need.</p>
<p>Many of the concerns that the team have is to be able to have a
“minimal runtime” and “efficient C bindings”. This means embedding,
while still maintaining “guaranteed memory safety” is a
thing. All this quoted goals are extracted from <a href="https://www.rust-lang.org/">the main page of the
project.</a></p>
<p>Writing a Ruby gem that uses Rust code: a <a href="http://blog.skylight.io/bending-the-curve-writing-safe-fast-native-gems-with-rust/">thing</a>.</p>
<p>Writing node.js modules that uses Rust code: a <a href="https://blog.risingstack.com/how-to-use-rust-with-node-when-performance-matters/">thing</a>.</p>
<h1 id="powerful-type-system-and-compiler">Powerful type system and compiler</h1>
<p>I’m a big fan of algebraic data types, as it is implemented in
Rust. Modeling the application with enums and expressing the
guarantees of a function through it’s type signature makes code
navigation and documentation so much more insightful. That means
that <code class="language-plaintext highlighter-rouge">Option<String></code> as the result of a function call could
possibly not have the value I want because of something, and that is
better than having a null pointer exception blowing up your runtime.</p>
<p>It also have niceties like pattern matching and is immutable by
default. The combination of features makes you feel you are writing
a high level functional language, with the power of small runtime
of a system language. I’m quite fond of this features.</p>
<p>The compiler is quite smart and yells at you when you make
mistakes. After you get used to being pointed your mistakes on
compilation, you start to thank <code class="language-plaintext highlighter-rouge">rustc</code>. Things that could lead to
accessing uninitialized memory means that your code won’t even
compile. And for me that is a great thing, as I don’t know much
about dealing with memory myself. I much prefer to let a program do
that instead.</p>
<p>Many of the error messages comes with a longer explanation of why
you are not allowed to do such things. On the error, there is a
suggestion to run <code class="language-plaintext highlighter-rouge">rustc --explain E0001</code> to read more about, and
you can check many of the errors on <a href="http://doc.rust-lang.org/error-index.html">this page</a>.</p>
<h1 id="documentation-is-first-class">Documentation is first class</h1>
<p>To be honest, it took me a while to get used to the documentation
format and links. There is a lot of information on it, but it is
treated really well by the community.</p>
<p>You can write example code on your comments, and it is compiled
during the test phase! It is a failure of compilation if your
examples are bad.</p>
<p>Because the function signature is explicit, the documentation tool
can generate links between them, and you can happily navigate.</p>
<h1 id="some-killer-projects">Some killer projects</h1>
<p>As Mozilla is planning to use Rust on it’s rendering engine for
Firefox, there is already a killer-project being produced. And many
of the development is being done on small, focused libraries, which
others could benefit from. One example, the <a href="https://github.com/servo/html5ever">html5ever</a> is the HTML
parser being used by <a href="https://github.com/servo/servo">servo</a>, the new engine. It means you can benefit
of the parsing engine that powers a browser on your own project.</p>
<p>Big win here.</p>
<h1 id="conclusion">Conclusion</h1>
<p>The language has it’s issues, like some syntax peculiarities, which
is rather pointy (hi, turbo-fish operator <code class="language-plaintext highlighter-rouge">::<></code>), the compiler yells
at you and you catch yourself many times thinking if you need a
string on the Heap or on the Stack, but it is being really FUN!</p>
<p>The potential this language has, with the combination of features
and placement of the low-high level programming spectrum is quite
unique. I will keep exploring Rust for sure.</p>
How tty.space came to be and how I see it2015-07-04T00:00:00-03:00https://blog.bltavares.com/2015/07/04/about-tty<h1 id="how-ttyspace-came-to-be">How tty.space came to be</h1>
<p>A while ago, <a href="http://tilde.club/~ford/">Paul Ford</a> created tilde.club, <a href="https://medium.com/message/tilde-club-i-had-a-couple-drinks-and-woke-up-with-1-000-nerds-a8904f0a2ebf">while he was drunk</a>. And a
bunch of people liked the idea and joined it.</p>
<p>It had streak me as a very interesting project at the time, but as
things happen when they hit Hacker News, it was all crazy hyped. There
was no way to get an account, and I didn’t want to dedicate time for
trying to be part of that.</p>
<p>But the other day, I was browsing and reading some about the new TLDs
when one pair of TLDs got my attention. tilde.club has a really cool
new .club TLD, and there was a .space TLD as well. The price was
affordable and there was a bunch of namehacking available on this
fresh new TLD spaces (pun intended).</p>
<p>I got really excited. “I could run my own tilde.club!”. After all, it
is just a server with a HTTP server and users willing to play with it.
I asked a bunch of friends around some cool domain names, and settled
on <a href="http://tty.space/">tty.space</a>. Short, geeky and cool domain hack.</p>
<h1 id="how-do-i-see-ttyspace">How do I see tty.space</h1>
<p><a href="http://tty.space">tty.space</a> is just one more web server on the cloud. But I see
potential on it.</p>
<p>It is kinda of a nostalgia from a time I didn’t participate. I keep
reading about how the internet was made of small distributed
connections, sharing news all over the world over between small groups
of conencted nodes, not assuming that the network is reliable and I
want to see how that was.</p>
<p>It sounds like a vibrant community, getting together on a shared
resource and sharing knowledge. A resource that feels just enough
handcrafted compared to the cloud. It could be rebuilt, but it will be
not the same.</p>
<p>I’ve learned so much about NNTP, email, wall, processes from other
users, and permissions. Tiny bash scripts generating HTML pages. And
there is no rush feeling of needing to be web scale or real time. No
feelings of shame on the management scripts. No fear of crashing
production.</p>
<p>And it is OK. This is a space to mess with things, to hack it open and
learn with the crashes. I see the potential to build a little small
hacker community amidst so many other production line communities.</p>
<p>Happy Hacking.</p>
Criação de variáveis e contextos léxicos em Clojure2015-01-28T00:00:00-02:00https://blog.bltavares.com/2015/01/28/criacao-de-variaveis-e-contextos-lexicos-em-clojure<p>Clojure é uma linguagem funcional, em que podemos tratar funções como
qualquer outro primitivo da linguagem, passando como argumentos,
retornos e salvando em estruturas de dados.</p>
<p>Como funções são tão importantes, nós iremos criar diversas delas nos
nossos programas. Mas qual a diferença entre criar uma função com
<code class="language-plaintext highlighter-rouge">(defn funcao [arg] arg)</code> e <code class="language-plaintext highlighter-rouge">(fn funcao [arg] arg)</code> ?</p>
<p>Antes de tentar responder essa questão, eu gostaria de explorar um
pouco como valores são associados a símbolos em Clojure.</p>
<h1 id="associando-valores-em-namespaces">Associando valores em namespaces</h1>
<p>Quando falamos de váriaveis em Clojure, nós estamos nos referindo
ao valor que esta associado a um simbolo em um escopo. Quando
criamos um arquivo e adicionamos um namespace no topo, nos estamos
mudando qual o contexto atual que iremos associar nossos valores.</p>
<p>Podemos fazer uns exemplos em um REPL para explorar um pouco a
ideia de variáveis.</p>
<p>Primeiro, vamos criamos nosso namespace <code class="language-plaintext highlighter-rouge">exemplo</code>, e para associar
o valor “exemplo” e recuperar ele de volta, podemos fazer o
seguinte:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="ss">'exemplo</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">variavel</span><span class="w"> </span><span class="s">"exemplo"</span><span class="p">)</span><span class="w"> </span><span class="n">variavel</span><span class="w"> </span><span class="c1">;; => "exemplo"</span><span class="w">
</span></code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">def</code> é uma forma especial para você atribuir valores dentro do
namespace. Quando digitamos apenas um simbolo, fora de um macro, o
clojure irá tentar buscar a referencia no namespace atual. Nos
também podemos especificar com um qualificador de namespace, qual
simbolo nos queremos nos referir explicitamente.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">variavel</span><span class="w"> </span><span class="c1">;; => "exemplo"</span><span class="w">
</span><span class="n">exemplo/variavel</span><span class="w"> </span><span class="c1">;; => "exemplo"</span><span class="w">
</span></code></pre></div></div>
<p>O que estiver antes do <code class="language-plaintext highlighter-rouge">/</code> no simbolo sera considerado o namespace,
também chamado de simbolo qualificado (qualified symbol).</p>
<p>De forma gráfica, podemos imaginar o contexto como uma tabela que
utilizamos para consultar os valores.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+----------------------+
|ns exemplo |
+----------------------+
|variavel = "exemplo" |
| |
| |
+----------------------+
</code></pre></div></div>
<p>Os valores associados ao namespace serão exportados com ele,
permitindo que outros namespaces façam uso daqueles valores. É
assim que você pode usar uma função definida em <code class="language-plaintext highlighter-rouge">clojure.string</code> ou
qualquer outra biblioteca.</p>
<p>Como incluir outros namespaces na caminho de procura sem
qualificadores nos símbolos merece um post separado, que envolve
algumas formas mais especificas na hora de definir qual o namespace
atual com o <code class="language-plaintext highlighter-rouge">ns</code>.</p>
<h1 id="outras-formas-de-criar-escopos">Outras formas de criar escopos</h1>
<p>Além do escopo do namespace, nos temos a possibilidade de criar
escopos locais.
Nem sempre queremos definir um valor que faz sentido de ser
exportado, como por exemplo, variáveis locais em uma função.</p>
<p>A forma especial <code class="language-plaintext highlighter-rouge">let</code> permite criar um novo escopo, estendendo o
escopo atual. Além de termos acesso aos valores associados no
escopo atual, nos teremos novos valores para fazer a consulta.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">variavel</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">nova-variavel</span><span class="w"> </span><span class="mi">2</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">variavel</span><span class="w"> </span><span class="n">nova-variavel</span><span class="p">)))</span><span class="w">
</span><span class="n">variavel</span><span class="w"> </span><span class="c1">;; => 1</span><span class="w">
</span><span class="n">nova-variavel</span><span class="w"> </span><span class="c1">;; => Erro</span><span class="w">
</span></code></pre></div></div>
<p>A forma do <code class="language-plaintext highlighter-rouge">let</code> aceita um vetor de pares entre binding-form e
valor, que estarão disponíveis nas expressões seguintes, ainda
dentro do <code class="language-plaintext highlighter-rouge">let</code>.</p>
<p>Uma visualização gráfica possível para os contextos acima seria algo assim:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+-------------------------------------+
| ns exemplo |
+-------------------------------------+
| variavel = 1 |
| |
| +---------------------------------+
| | let |
| +---------------------------------+
| | nova-variavel = 2 |
| | |
| | |
| | (println |
| | (+ variavel nova-variavel)) |
| | |
+---|---------------------------------+
</code></pre></div></div>
<p>É possível criar escopos dentro de escopos também.
As atribuições introduzidas pelo novo escopo tem precendência na
consulta do valor, podendo obscurecer símbolos associados previamente.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">exemplo</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">nova-variavel</span><span class="w"> </span><span class="mi">2</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="n">exemplo</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">outra-variavel</span><span class="w"> </span><span class="mi">3</span><span class="w">
</span><span class="n">exemplo</span><span class="w"> </span><span class="mi">4</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">exemplo</span><span class="w"> </span><span class="n">nova-variavel</span><span class="w"> </span><span class="n">outra-variavel</span><span class="p">))))</span><span class="w">
</span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="n">exemplo</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Para não deixar faltar, vamos visualizar graficamente os contextos.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+------------------------------+
|ns exemplo |
+------------------------------+
|exemplo = 1 |
| |
| +--------------------------+
| |let |
| +--------------------------+
| |nova-variavel = 2 |
| | |
| | +----------------------+
| | | let |
| | +----------------------+
| | | outra-variavel = 3 |
| | | exemplo = 4 |
| | | |
| | | (println ...) |
+---|---|----------------------+
</code></pre></div></div>
<p>Dentro do primeiro <code class="language-plaintext highlighter-rouge">let</code>, o valor para <code class="language-plaintext highlighter-rouge">exemplo</code> continua sendo o do
contexto anterior. Dentro do segundo <code class="language-plaintext highlighter-rouge">let</code> nos associamos outro
valor para <code class="language-plaintext highlighter-rouge">exemplo</code>, e assim que saímos dos <code class="language-plaintext highlighter-rouge">let</code>’s vemos que o
valor em <code class="language-plaintext highlighter-rouge">exemplo</code> continua o mesmo.</p>
<p>Criar uma função também introduz um novo contexto léxico, de uma
forma similar ao <code class="language-plaintext highlighter-rouge">let</code>. Os argumentos terão o valor associado quando
a função for chamada, mas o contexto ainda retém acesso aos valores
dos escopos em que ele foi criado.</p>
<p>Para demonstrar, vou criar uma função dentro de um outro contexto, e
atribuir ela a um símbolo no meu namespace com o <code class="language-plaintext highlighter-rouge">def</code>.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">funcao</span><span class="w"> </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">valor</span><span class="w"> </span><span class="mi">1</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">outro</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">outro</span><span class="w"> </span><span class="n">valor</span><span class="p">))))</span><span class="w">
</span><span class="n">funcao</span><span class="w"> </span><span class="c1">;; => Referencia a função</span><span class="w">
</span><span class="p">(</span><span class="nf">funcao</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">;; => 3</span><span class="w">
</span><span class="p">(</span><span class="nf">funcao</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="c1">;; => 4</span><span class="w">
</span><span class="n">valor</span><span class="w"> </span><span class="c1">;; => Erro</span><span class="w">
</span></code></pre></div></div>
<p>Quando nós chamamos a <code class="language-plaintext highlighter-rouge">função</code>, as expressões que vamos executar
terão os valores passados associado aos argumentos, além do contexto
que possui o <code class="language-plaintext highlighter-rouge">valor</code>.</p>
<p>Se você quiser explorar mais sobre como essa propriedade de manter
os contextos em que a função foi criada para escrever programas, dê
uma pesquisada em closures. Falar sobre isso também mereceria um
outro post.</p>
<h1 id="voltando-a-pergunta-sobre-as-diferenças-de-criar-funções">Voltando a pergunta sobre as diferenças de criar funções</h1>
<p>Acho que agora que entendemos um pouco melhor como o Clojure utiliza
os contextos para salvar valores podemos voltar a pergunta.</p>
<p>Qual a diferença entre criar uma função com
<code class="language-plaintext highlighter-rouge">(defn funcao [arg] arg)</code> e <code class="language-plaintext highlighter-rouge">(fn funcao [arg] arg)</code> ?</p>
<p><code class="language-plaintext highlighter-rouge">(defn funcao [arg] arg)</code> é um atalho para <code class="language-plaintext highlighter-rouge">(def funcao (fn [arg] arg))</code>.
Como vamos criar diversas funções no nosso namespace, para
bibliotecas, para ser utilizado em outros módulos, ou porque apenas
faz sentido estar no contexto do namespace, o atalho <code class="language-plaintext highlighter-rouge">defn</code> é um
idioma bem comum e bem útil.</p>
<p><code class="language-plaintext highlighter-rouge">(fn funcao [arg] arg)</code> é uma variação de <code class="language-plaintext highlighter-rouge">(fn [arg] arg)</code> que dá um nome a função.
Esse nome estará disponível dentro do contexto criado pela função,
referenciando ela mesma.</p>
<p>Fora daquele escopo, você ainda não tem o valor associado a função
que você criou.</p>
<p>Na maior parte do tempo que você quiser criar uma função com um
nome, você vai acabar usando <code class="language-plaintext highlighter-rouge">defn</code>, já que assim ela estará
disponível em todo o namespace.</p>
<p>O próximo caso de criar funções mais comum sera funções anonimas,
como callbacks ou funções de alta ordem (map, filter). São funções
importantes para o contexto local, e não serão utilizadas em outros
lugares do seu namespace.</p>
<p>Funções com nomes, como <code class="language-plaintext highlighter-rouge">(fn nome [])</code> são uteis para identificar
intenção ou ajudar a se localizar quando exceções acontecerem, ou
para casos recursivos de callbacks.</p>
<p>Vamos supor que temos uma função que permite identificar uma
mudança no sistema e executa um callback. Assim que o callback for
executado, nos precisamos registrar que estamos interessado em
identificar mudanças novamente.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">onChangeIdentified</span><span class="w">
</span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">funcao</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span><span class="p">(</span><span class="nf">notify</span><span class="w"> </span><span class="s">"admin@example.com"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">onChangeIdentified</span><span class="w"> </span><span class="n">funcao</span><span class="p">)))</span><span class="w">
</span></code></pre></div></div>
<p>O exemplo acima notifica um administrador assim que uma mudança no
sistema for identificada, e logo depois registra outra chamada para
executar de novo no final.</p>
<p>Casos de recursão da mesma função fazem melhor uso de <code class="language-plaintext highlighter-rouge">recur</code> ao
invés de função nomeada. Com <code class="language-plaintext highlighter-rouge">recur</code>, nos vamos evitar de chegar no
limite máximo de chamadas de função (StackOverflow)</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Ao invés de utilizar funções nomeadas</span><span class="w">
</span><span class="p">((</span><span class="k">fn</span><span class="w"> </span><span class="n">recursiva</span><span class="w"> </span><span class="p">[</span><span class="nb">index</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="nb">index</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="s">"Done"</span><span class="w">
</span><span class="p">(</span><span class="nf">recursiva</span><span class="w"> </span><span class="p">(</span><span class="nb">dec</span><span class="w"> </span><span class="nb">index</span><span class="p">))))</span><span class="w"> </span><span class="n">Integer/MAX_VALUE</span><span class="p">)</span><span class="w">
</span><span class="c1">;; utilize o recur</span><span class="w">
</span><span class="p">((</span><span class="k">fn</span><span class="w"> </span><span class="n">recursiva</span><span class="w"> </span><span class="p">[</span><span class="nb">index</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="nb">index</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="s">"Done"</span><span class="w">
</span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="p">(</span><span class="nb">dec</span><span class="w"> </span><span class="nb">index</span><span class="p">))))</span><span class="w"> </span><span class="n">Integer/MAX_VALUE</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<h1 id="links">Links</h1>
<ul>
<li><a href="http://clojure.org/special_forms#Special Forms--(def symbol init?)">Documentacao do Clojure sobre o def</a></li>
<li><a href="http://clojure.org/special_forms#Special%20Forms--(let%20%5Bbindings*%20%5D%20exprs*)">Documentacao do Clojure sobre o let</a></li>
<li><a href="http://clojure.org/special_forms#Special%20Forms--(fn%20name?%20%5Bparams*%20%5D%20condition-map?%20exprs*)">Documentacao do Clojure sobre o fn</a></li>
<li><a href="http://clojure.org/special_forms#Special%20Forms--(recur%20exprs*)">Documentacao do Clojure sobre o recur</a></li>
</ul>
<p>Obrigado <a href="https://twitter.com/mariane_sm">Mariane</a>, <a href="https://twitter.com/erickpintor">Erick</a> e <a href="https://github.com/renanreismartins">Renan</a> pelo review.</p>
binding-form e associação de valores em Clojure2015-01-19T00:00:00-02:00https://blog.bltavares.com/2015/01/19/binding-forms<p>Se você der uma lida na <a href="http://clojure.org/special_forms">documentação</a> do Clojure você vai acabar
encontrando <code class="language-plaintext highlighter-rouge">binding-form</code> escrito em alguns lugares que permite você
associar valores a símbolos, como no caso do <code class="language-plaintext highlighter-rouge">let</code> e do <code class="language-plaintext highlighter-rouge">defn</code>.</p>
<p>No Clojure, existe o conceito de <code class="language-plaintext highlighter-rouge">forms</code>, que se refere ao formato da
estrutura de dados que aquela função ou macro aceita.
Lembrando que código também é dado em Clojure, então formas podem se
referir a forma da interface de um método ou macro.</p>
<p>Quando nos referimos a forma de associação, estamos falando da
estrutura de dados que podemos utilizar para dar valores a símbolos em
um contexto.
Vamos utilizar o <code class="language-plaintext highlighter-rouge">let</code> como exemplo. Com ele, podemos introduzir um
novo contexto com símbolos associados a valores, e ele possui a forma</p>
<p><code class="language-plaintext highlighter-rouge">(let [pares-de-associação...] expressões...)</code></p>
<p>Cada par de associação ira associar o primeiro elemento com o valor do segundo.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">par1</span><span class="w"> </span><span class="s">"valor1"</span><span class="w">
</span><span class="n">par2</span><span class="w"> </span><span class="s">"valor2"</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">par1</span><span class="w"> </span><span class="s">" e "</span><span class="w"> </span><span class="n">par2</span><span class="p">))</span><span class="w"> </span><span class="c1">;; # => "valor1 e valor2"</span><span class="w">
</span></code></pre></div></div>
<p>Essa é a forma mais simples de associação: utilizar um simbolo para um
valor.
A ideia de desestruturar um valor na hora da atribuição não é exclusiva
do Clojure.</p>
<p>Mas existem outras formatos que podemos utilizar, chamadas de desestruturação.</p>
<h1 id="desestruturação-de-listas">Desestruturação de Listas</h1>
<p>O primeiro exemplo que vou utilizar esta na desestruturação de listas.
Podemos na hora de associar os valores, pegar elementos de dentro da lista diretamente.</p>
<p>Você pode inspecionar a estrutura de dado que será atribuída aos
símbolos e relacionar partes dela ao invés de ter que chamar funções e
fazer criar variáveis consecutivas.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">lista</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w">
</span><span class="n">primeiro</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="n">lista</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="n">segundo</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="n">lista</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span><span class="n">terceiro</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="n">lista</span><span class="w"> </span><span class="mi">2</span><span class="p">)]</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">primeiro</span><span class="w"> </span><span class="n">segundo</span><span class="w"> </span><span class="n">terceiro</span><span class="p">))</span><span class="w"> </span><span class="c1">;; => 6</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">lista</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w">
</span><span class="p">[</span><span class="n">primeiro</span><span class="w"> </span><span class="n">segundo</span><span class="w"> </span><span class="n">terceiro</span><span class="p">]</span><span class="w"> </span><span class="n">lista</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">primeiro</span><span class="w"> </span><span class="n">segundo</span><span class="w"> </span><span class="n">terceiro</span><span class="p">))</span><span class="w"> </span><span class="c1">;; => 6</span><span class="w">
</span></code></pre></div></div>
<p>Escrevendo um <code class="language-plaintext highlighter-rouge">let</code> assim, podemos explorar esse aspecto da associação em Clojure.
Ao invés de tentar associar o valor da lista apenas para um símbolo,
nos criamos uma outra forma, uma lista com símbolos na posição dos
valores que queremos associar a eles.</p>
<p>Esse tipo de desestruturação indexada funciona para estruturas
sequenciais, que respondem a <code class="language-plaintext highlighter-rouge">nth</code>, como Strings, Listas e Vetores.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[[</span><span class="n">x</span><span class="p">]</span><span class="w"> </span><span class="s">"exemplo"</span><span class="w">
</span><span class="p">[</span><span class="n">y</span><span class="p">]</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="n">z</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">]]</span><span class="w">
</span><span class="p">[</span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="n">z</span><span class="p">])</span><span class="w"> </span><span class="c1">;; => [\e 1 4]</span><span class="w">
</span></code></pre></div></div>
<p>Para estruturas sequenciais, ainda temos mais algumas opções de formas
para desestruturar.
Podemos combinar a atribuição de valores posicionais e capturar o
restante da estrutura em outro símbolo.</p>
<p>Trabalhando com listas, é bem comum ter interesse no primeiro
elemento, e fazer uma recursão no resto da lista.
Podemos utilizar a forma <code class="language-plaintext highlighter-rouge">[a b c & rest]</code> para pegar os valores
restantes que não foram atribuídos por índice.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">lista</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="n">lista</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="n">tail</span><span class="w"> </span><span class="p">(</span><span class="nf">nthnext</span><span class="w"> </span><span class="n">lista</span><span class="w"> </span><span class="mi">1</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">head</span><span class="w"> </span><span class="n">tail</span><span class="p">])</span><span class="w"> </span><span class="c1">;; => [1 [2 3]]</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">lista</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w">
</span><span class="p">[</span><span class="n">head</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">tail</span><span class="p">]</span><span class="w"> </span><span class="n">lista</span><span class="p">]</span><span class="w">
</span><span class="p">[</span><span class="n">head</span><span class="w"> </span><span class="n">tail</span><span class="p">])</span><span class="w"> </span><span class="c1">;; => [1 [2 3]]</span><span class="w">
</span></code></pre></div></div>
<p>E uma ultima opções que temos ao desestruturar sequências, é pegar o
valor completo, mesmo depois de desestruturar, com a forma de <code class="language-plaintext highlighter-rouge">[a b c :as tudo]</code>.</p>
<p>Podemos combinar os exemplos anteriores em uma única forma.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[[</span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">resto</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">letras</span><span class="p">]</span><span class="w"> </span><span class="s">"Ola Mundo"</span><span class="p">]</span><span class="w">
</span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="n">resto</span><span class="w"> </span><span class="n">letras</span><span class="p">])</span><span class="w"> </span><span class="c1">;; => [\O \l \a (\space \M \u \n \d \o) "Ola Mundo"]</span><span class="w">
</span></code></pre></div></div>
<h1 id="desestruturação-de-mapas">Desestruturação de Mapas</h1>
<p>Uma segunda estrutura de dados muito utilizada em Clojure são os Mapas.
Da mesma forma que temos facilidades para trabalhar com valores dentro
de Sequências, temos um <code class="language-plaintext highlighter-rouge">binding-form</code> para Mapas. Eles permitem
desestruturação baseada na chave, para que você possa associar os símbolos
valores direto no contexto.</p>
<p>Desta vez meus exemplos serão utilizando funções. Definir uma função
no nível do namespace atual tem a seguinte forma.</p>
<p><code class="language-plaintext highlighter-rouge">(defn nome forma-de-associação expressões...)</code></p>
<p>A forma de associação será comparada contra os argumentos na hora de
chamar a função, e tera os símbolos associados aos valores dentro do
contexto das expressões.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">exemplo1</span><span class="w"> </span><span class="p">[</span><span class="n">mapa</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">str</span><span class="w">
</span><span class="s">" :chave => "</span><span class="w"> </span><span class="p">(</span><span class="no">:chave</span><span class="w"> </span><span class="n">mapa</span><span class="p">)</span><span class="w">
</span><span class="s">" :nome => "</span><span class="w"> </span><span class="p">(</span><span class="no">:nome</span><span class="w"> </span><span class="n">mapa</span><span class="p">)))</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo1</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="n">,</span><span class="w"> </span><span class="no">:nome</span><span class="w"> </span><span class="s">"Bruno"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => abcd :nome => Bruno"</span><span class="w">
</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">exemplo2</span><span class="w"> </span><span class="p">[{</span><span class="n">chave</span><span class="w"> </span><span class="no">:chave</span><span class="w"> </span><span class="n">nome</span><span class="w"> </span><span class="no">:nome</span><span class="p">}]</span><span class="w">
</span><span class="p">(</span><span class="nb">str</span><span class="w">
</span><span class="s">" :chave => "</span><span class="w"> </span><span class="n">chave</span><span class="w">
</span><span class="s">" :nome => "</span><span class="w"> </span><span class="n">nome</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo2</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="n">,</span><span class="w"> </span><span class="no">:nome</span><span class="w"> </span><span class="s">"Bruno"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => abcd :nome => Bruno"</span><span class="w">
</span></code></pre></div></div>
<p>Cada um dos símbolos dentro da forma <code class="language-plaintext highlighter-rouge">{símbolo chave símbolo chave}</code> será
associado com o valor da respectiva chave no Mapa.</p>
<p>As vezes, nos podemos querer um valor padrão quando uma chave não
estiver presente no Mapa que estamos desestruturando.
Com a adição de um <code class="language-plaintext highlighter-rouge">:or</code> na forma, nos podemos dar valores padrões aos
símbolos que não foram associados a nenhum valor.</p>
<p>Ele passa a ter a seguinte forma, como você vera no exemplo.</p>
<p><code class="language-plaintext highlighter-rouge">{símbolo chave ... :or {símbolo valor símbolo valor}}</code></p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">exemplo1</span><span class="w"> </span><span class="p">[</span><span class="n">mapa</span><span class="p">]</span><span class="w">
</span><span class="p">(</span><span class="nb">str</span><span class="w">
</span><span class="s">" :chave => "</span><span class="w"> </span><span class="p">(</span><span class="no">:chave</span><span class="w"> </span><span class="n">mapa</span><span class="w"> </span><span class="s">"<sem chave>"</span><span class="p">)</span><span class="w">
</span><span class="s">" :nome => "</span><span class="w"> </span><span class="p">(</span><span class="no">:nome</span><span class="w"> </span><span class="n">mapa</span><span class="w"> </span><span class="s">"<sem nome>"</span><span class="p">)))</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo1</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="n">,</span><span class="w"> </span><span class="no">:nome</span><span class="w"> </span><span class="s">"Bruno"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => abcd :nome => Bruno"</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo1</span><span class="w"> </span><span class="p">{</span><span class="no">:nome</span><span class="w"> </span><span class="s">"Bruno"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => <sem chave> :nome => Bruno"</span><span class="w">
</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">exemplo2</span><span class="w"> </span><span class="p">[{</span><span class="n">chave</span><span class="w"> </span><span class="no">:chave</span><span class="w">
</span><span class="n">nome</span><span class="w"> </span><span class="no">:nome</span><span class="w">
</span><span class="no">:or</span><span class="w"> </span><span class="p">{</span><span class="n">chave</span><span class="w"> </span><span class="s">"<sem chave>"</span><span class="w"> </span><span class="n">nome</span><span class="w"> </span><span class="s">"<sem nome>"</span><span class="p">}}]</span><span class="w">
</span><span class="p">(</span><span class="nb">str</span><span class="w">
</span><span class="s">" :chave => "</span><span class="w"> </span><span class="n">chave</span><span class="w">
</span><span class="s">" :nome => "</span><span class="w"> </span><span class="n">nome</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo2</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="n">,</span><span class="w"> </span><span class="no">:nome</span><span class="w"> </span><span class="s">"Bruno"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => abcd :nome => Bruno"</span><span class="w">
</span><span class="p">(</span><span class="nf">exemplo2</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => " :chave => abcd :nome => <sem nome>"</span><span class="w">
</span></code></pre></div></div>
<p>Da mesma forma que fizemos nas Sequências, podemos atribuir o valor do
Mapa inteiro utilizando <code class="language-plaintext highlighter-rouge">:as</code> enquanto estivermos desestruturando o valor.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">example</span><span class="w"> </span><span class="p">[{</span><span class="n">a</span><span class="w"> </span><span class="no">:a</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">mapa</span><span class="p">}]</span><span class="w">
</span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">mapa</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nf">example</span><span class="w"> </span><span class="p">{</span><span class="no">:a</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="no">:b</span><span class="w"> </span><span class="mi">2</span><span class="p">})</span><span class="w"> </span><span class="c1">;; => [1 {:a 1, :b 2}]</span><span class="w">
</span></code></pre></div></div>
<p>Muitas das vezes, quando trabalhando com mapas, nos utilizamos um
símbolo como o mesmo nome que a chave do valor que buscamos.
Para evitar digitar a mesma palavra, temos um atalho para buscar os
valores de um mapa, de forma reflexiva.</p>
<p>O Clojure tem mais 3 opções para buscar valores na forma do Mapa:
<code class="language-plaintext highlighter-rouge">:keys</code>, <code class="language-plaintext highlighter-rouge">:strs</code> e <code class="language-plaintext highlighter-rouge">:syms</code>. Esses atalhos recebem uma vetor de
símbolos que serão convertidos para keywords, strings ou símbolos
respectivamente, antes de fazer a consulta no mapa.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">mapa</span><span class="w"> </span><span class="p">{</span><span class="no">:a</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="ss">'b</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="s">"c"</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="no">:d</span><span class="w"> </span><span class="mi">4</span><span class="p">}</span><span class="w">
</span><span class="p">{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">d</span><span class="p">]}</span><span class="w"> </span><span class="n">mapa</span><span class="w">
</span><span class="p">{</span><span class="no">:syms</span><span class="w"> </span><span class="p">[</span><span class="n">b</span><span class="p">]}</span><span class="w"> </span><span class="n">mapa</span><span class="w">
</span><span class="p">{</span><span class="no">:strs</span><span class="w"> </span><span class="p">[</span><span class="n">c</span><span class="p">]}</span><span class="w"> </span><span class="n">mapa</span><span class="p">]</span><span class="w">
</span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="n">d</span><span class="p">])</span><span class="w"> </span><span class="c1">;; => [1 2 3 4]</span><span class="w">
</span></code></pre></div></div>
<p>Nos podemos combinar todas essas opções para definir nossa forma de
associação e desestruturar os valores.</p>
<p>Um ultimo ponto importante é que podemos combinar todas essas formas
aninhadas. Podemos extrair o terceiro elemento de uma sequência
associada a uma chave em um mapa utilizando o que vimos agora, por
exemplo.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">meu-mapa</span><span class="w"> </span><span class="p">{</span><span class="no">:chave</span><span class="w"> </span><span class="s">"abcd"</span><span class="w">
</span><span class="no">:valores</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="p">]})</span><span class="w">
</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">terceiro-valor</span><span class="w">
</span><span class="p">[{[</span><span class="n">_</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="n">terceiro</span><span class="p">]</span><span class="w"> </span><span class="no">:valores</span><span class="p">}]</span><span class="w">
</span><span class="n">terceiro</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">terceiro-valor</span><span class="w"> </span><span class="n">meu-mapa</span><span class="p">)</span><span class="w"> </span><span class="c1">;; => 3</span><span class="w">
</span></code></pre></div></div>
<h1 id="exemplos-de-código">Exemplos de código</h1>
<p>Utilizar os vários formatos de <code class="language-plaintext highlighter-rouge">binding-form</code> é uma pratica bem comum
em projetos Clojure, e você pode conferir pelo Github como as pessoas
costumam utilizar.</p>
<ul>
<li>Extraindo valores de mapas - <a href="https://github.com/Raynes/lazybot/blob/master/src/lazybot/plugins/debug.clj#L27">debug.clj</a></li>
<li>Pegar o primeiro grupo capturado por um regex - <a href="https://github.com/Raynes/lazybot/blob/master/src/lazybot/plugins/debug.clj#L27">ping.clj</a></li>
<li>Valores de mapas dentro de mapas - <a href="https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L53-L54">compiler.clj</a></li>
</ul>
<p>Com o tempo você vai começar a ver onde seu código ficaria melhor
utilizando as desestruturações.</p>
<h1 id="mais-links">Mais links</h1>
<ul>
<li><a href="http://clojure.org/special_forms#binding-forms">http://clojure.org/special_forms#binding-forms</a></li>
<li><a href="https://gist.github.com/john2x/e1dca953548bfdfb9844">https://gist.github.com/john2x/e1dca953548bfdfb9844</a></li>
<li><a href="https://clojurebridge.github.io/community-docs/docs/clojure/destructuring/">https://clojurebridge.github.io/community-docs/docs/clojure/destructuring/</a></li>
<li><a href="http://www.braveclojure.com/do-things/#3_3_3__Destructuring">http://www.braveclojure.com/do-things/#3_3_3__Destructuring</a></li>
</ul>
Quick intro to Make2014-05-03T00:00:00-03:00https://blog.bltavares.com/2014/05/03/quick-intro-to-make<p>Our daily job requires us to create files.
Sometimes we want to get a minified JavaScript file or compile a sass file into css.</p>
<p>We have several different tools to do such tasks. Rake, Grunt, Gulp, SCons and many others.</p>
<p>On the times of C, Make was the one.
It is present on many projects.
It is installed on lots of dev machines.
It has small requirements to run.
And it is very concise.</p>
<p>Make embraces the Unix style of communicating,
providing pipes and calls to external commands like a shell would do to generate a file.</p>
<p>Let’s see how we can write a Makefile for your project,
no matter which main language it is written in.</p>
<h2 id="writing-your-makefile">Writing your Makefile</h2>
<p>While writing your Makefile,
you may need to change the way you are used to defining your tasks.
The idea is to define which files should be <em>generated</em> instead of defining the tasks themselves.</p>
<p>A Makefile is constructed of <em>rules</em>, each <em>rule</em> using the following format:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">targets </span><span class="o">:</span> <span class="nf">prerequisites</span>
<span class="err">command</span> <span class="err">1</span>
<span class="err">command</span> <span class="err">2</span>
<span class="err">...</span>
</code></pre></div></div>
<p>We define a <em>target</em> file that will be the output of the build.
Each <em>target</em> can specify <em>prerequisites</em> and a set of commands to build the <em>target</em>.
The commands must be indented with tabs to be part of the <em>rule</em>.</p>
<p>Lets take the following rule as example:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">target-file</span><span class="o">:</span> <span class="nf">source-file</span>
<span class="err">parse</span> <span class="err">source-file</span> <span class="err">--output</span> <span class="err">target-file</span>
</code></pre></div></div>
<p>Whenever the <code class="language-plaintext highlighter-rouge">source-file</code> is newer than the <code class="language-plaintext highlighter-rouge">target-file</code> the command on the rule will be executed to generate/update it.</p>
<p>The common way of thinking on some other tools is to define first the sources, and how it will produce an output.
Instead, on Make, there is a reverse way of thinking,
which you declare what is the file you would like to have generated out of the build, the target,
and declare the prerequisites of the target, in order to be generated.</p>
<h2 id="making-multiple-files-using-the-same-rule">Making multiple files using the same rule</h2>
<p>From now on, lets have in mind we want to get a minified JavaScript file out of source files.
Let’s use a very simple project.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>project
├── dist
├── index.html
└── src
├── render.js
└── request.js
</code></pre></div></div>
<p>We would like to generate minified files for each of those <code class="language-plaintext highlighter-rouge">src</code> files.
A <em>target</em> can be multiple files,
with each of them mapping directly to a single <em>prerequisite</em>.</p>
<p>To define a relationship between the target file and its prerequisites,
we can use the <code class="language-plaintext highlighter-rouge">%</code> character.
On the target, <code class="language-plaintext highlighter-rouge">%</code> will match anything,
similar to file globbing on a shell,
and replace the <code class="language-plaintext highlighter-rouge">%</code> character on the prerequisites side with what was matched previously.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">dist/%.min.js</span><span class="o">:</span> <span class="nf">src/%.js</span>
</code></pre></div></div>
<p>We have defined a rule, where we want to generate one minified file on the <code class="language-plaintext highlighter-rouge">dist</code> folder for each JavaScript file on <code class="language-plaintext highlighter-rouge">src</code>.
We now need to tell it how the file will be generated from it sources.</p>
<h2 id="automatic-variables">Automatic variables</h2>
<p>Make provides you with some <a href="https://www.gnu.org/software/make/manual/make.html#Automatic-Variables">Automatic variables</a>.
They are filled in with information from the <em>rule</em> it is running on.</p>
<p>We are going to use two variables, <code class="language-plaintext highlighter-rouge">$@</code> and <code class="language-plaintext highlighter-rouge">$<</code>, the <em>target</em> name and the <em>prerequisite</em> name, respectively.</p>
<p>With this you can build a rule that generates minified JavaScript when running the <code class="language-plaintext highlighter-rouge">minify</code> command:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">dist/%.min.js</span><span class="o">:</span> <span class="nf">src/%.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">$@</span> <span class="err">$<</span>
</code></pre></div></div>
<p>This rule will be expanded, and executed, as if you had written those lines:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">dist/render.min.js</span><span class="o">:</span> <span class="nf">src/render.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">dist/render.min.js</span> <span class="err">src/render.js</span>
<span class="nl">dist/request.min.js</span><span class="o">:</span> <span class="nf">src/request.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">dist/request.min.js</span> <span class="err">src/request.js</span>
</code></pre></div></div>
<p>You can now run <code class="language-plaintext highlighter-rouge">make dist/render.min.js</code> and <code class="language-plaintext highlighter-rouge">make dist/request.min.js</code> and it will generate your minified files for you.
But this is still not ideal.</p>
<h2 id="phony-targets">Phony targets</h2>
<p>Ideally, we would like to ask Make to minify all scripts with one command.
Lets start defining defining a <em>rule</em> with the <em>target</em> of <code class="language-plaintext highlighter-rouge">minify</code>,
requiring the minified files as <em>prerequisites</em>,
so we can run <code class="language-plaintext highlighter-rouge">make minify</code>.</p>
<p>So lets define a target:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">minify</span><span class="o">:</span> <span class="nf">dist/render.min.js src/render.min.js</span>
<span class="nl">dist/%.min.js</span><span class="o">:</span> <span class="nf">src/%.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">$@</span> <span class="err">$<</span>
</code></pre></div></div>
<p>There is no need do define a command to run for the rule,
because the success definition for the target is to have the prerequisites satisfied.</p>
<p>As we talked before,
Make expects you to define a <em>file</em> as the target,
and it checks for the the last modified date of the target file to know if it needs to update.</p>
<p>As long as there is no file called <code class="language-plaintext highlighter-rouge">minify</code>,
there won’t be a last modified date and it will assume it needs to create this allegedly <code class="language-plaintext highlighter-rouge">minify</code> file.
Also,
we don’t want a <code class="language-plaintext highlighter-rouge">minify</code> file to be created as part of our rule,
nor would be ideal on the situation we create a file called <code class="language-plaintext highlighter-rouge">minify</code> by mistake,
to stop our build to work because there is a modified date to check for now.</p>
<p>To solve this last issue we can make the target <code class="language-plaintext highlighter-rouge">minify</code> a prerequisite to a special target called <code class="language-plaintext highlighter-rouge">.PHONY</code>,
which is the way to tell Make that the target is just a nice sound for a more complex set of requirements and not a file to be generated.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">minify</span>
<span class="nl">minify</span><span class="o">:</span> <span class="nf">dist/render.min.js src/render.min.js</span>
<span class="nl">dist/%.min.js</span><span class="o">:</span> <span class="nf">src/%.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">$@</span> <span class="err">$<</span>
</code></pre></div></div>
<p>Running <code class="language-plaintext highlighter-rouge">make minify</code> will now generate the files for you and update the ones that need to be updated.</p>
<h2 id="calculating-the-generated-files-based-on-the-source-files">Calculating the generated files based on the source files</h2>
<p>We can already generate our minified files,
but what happens when we add a new javascript file?</p>
<p>So far, our set of prerequisites of the <code class="language-plaintext highlighter-rouge">minify</code> target is hardcoded.
Let’s make our set of prerequisites dynamic, based on our list of source files.</p>
<p>First, lets grab all the source files and store on a variable.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">javascript_sources</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">wildcard</span> src/<span class="k">*</span>.js<span class="nf">)</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">wildcard</code> function expands to the list of files that exists on the <code class="language-plaintext highlighter-rouge">src</code> folder, matching the pattern passed as argument.
<code class="language-plaintext highlighter-rouge">src/*.js</code> means any file ending with <code class="language-plaintext highlighter-rouge">.js</code> in the <code class="language-plaintext highlighter-rouge">src</code> folder.</p>
<p>On our project, it would be expanded to the following.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">javascript_sources</span> <span class="o">=</span> src/request.js src/render.js
</code></pre></div></div>
<p>We would like to have files with the same basename in a different folder,
following a pattern, substituting some parts of it.
Make has a function, called <code class="language-plaintext highlighter-rouge">patsubst</code>, an abbreviation for “pattern substitution”.</p>
<p>The <code class="language-plaintext highlighter-rouge">patsubst</code> function receives a pattern to match, a pattern to substitute and the paths to apply the substitutions.
The matching pattern can use the <code class="language-plaintext highlighter-rouge">%</code> character to match anything,
similar to the <code class="language-plaintext highlighter-rouge">*</code> character as we saw on the <code class="language-plaintext highlighter-rouge">wildcard</code> function,
while passing the grabbed value to the <code class="language-plaintext highlighter-rouge">%</code> on the substitution pattern.</p>
<p>For example:</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">minified_javascript</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> src/%.js, dist/%.min.js, src/request.js<span class="nf">)</span>
</code></pre></div></div>
<p>will expand to</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">minified_javascript</span> <span class="o">=</span> dist/request.min.js
</code></pre></div></div>
<p>Instead of using a single string on the end, we can substitute it with our previous list of files set on the <code class="language-plaintext highlighter-rouge">javascript_sources</code> variable.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">minified_javascript</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> src/%.js, dist/%.min.js, <span class="nv">$(javascript_sources)</span><span class="nf">)</span>
</code></pre></div></div>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>After having our variables defined, we can tell the <code class="language-plaintext highlighter-rouge">minify</code> target what are the prerequisites it has.</p>
<div class="language-make highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">javascript_sources</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">wildcard</span> src/<span class="k">*</span>.js<span class="nf">)</span>
<span class="nv">minified_javascript</span> <span class="o">=</span> <span class="nf">$(</span><span class="nb">patsubst</span> src/%.js, dist/%.min.js, <span class="nv">$(javascript_sources)</span><span class="nf">)</span>
<span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">minify</span>
<span class="nl">minify</span><span class="o">:</span> <span class="nf">$(minified_javascript)</span>
<span class="nl">dist/%.min.js</span><span class="o">:</span> <span class="nf">src/%.js</span>
<span class="err">minify</span> <span class="err">--output</span> <span class="err">$@</span> <span class="err">$<</span>
</code></pre></div></div>
<p>Whenever we add a new file, <code class="language-plaintext highlighter-rouge">make minify</code> will add it as a prerequisite and generate it.</p>
<h2 id="parallelising-the-build">Parallelising the build</h2>
<p>In this situation, our minified files can be generated in parallel.
Make accepts a job option,
<code class="language-plaintext highlighter-rouge">-j</code>,
where you can define the maximum number of jobs to run,
like <code class="language-plaintext highlighter-rouge">make -j 2 minify</code>,
or let it use the maximum amount by not specifying a number,
like <code class="language-plaintext highlighter-rouge">make -j minify</code>.</p>
<p>If you made this far, I hope you liked this quick intro to Make.
If you are curious or want help on defining more complex tasks, the <a href="http://gnu.org/software/make/manual/make.html">manual</a> can provide more information.</p>
<p>Happy coding (:</p>
Baseline and Vagrant integration2014-03-20T00:00:00-03:00https://blog.bltavares.com/2014/03/20/baseline-and-vagrant-integration<p>Hi there.</p>
<p>As part of the conversations I have with colleagues about Baseline there is often a confusion on how does it integrate Vagrant and where Puppet fits on the overall story.</p>
<p>I will address the Baseline decisions and structure of a project on this post.</p>
<h2 id="what-constitute-a-baseline-project">What constitute a baseline project?</h2>
<p>The general structure of a project with Baseline enabled is the following:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>|- project
| |- .baseline
| | |- Vagrantfile
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">baseline init</code> receives as argument the target project and a git url.
It will check it out under <code class="language-plaintext highlighter-rouge">project/.baseline</code> folder and the only expectation is to have a Vagrantfile in there.</p>
<p>The intention with that was to have the Vagrant project outside of the target project, to let you reuse environments.</p>
<p>You could link <code class="language-plaintext highlighter-rouge">.baseline</code> to the target project folder, and have all the commands working.
<code class="language-plaintext highlighter-rouge">ln -s .baseline .</code> on a project that comes with a Vagrantfile and voilà.</p>
<h2 id="baseline-as-a-wrapper">Baseline as a wrapper</h2>
<p>Baseline delegates everything to Vagrant, with the addition of some extra environment variables.
You will have access through the <code class="language-plaintext highlighter-rouge">ENV</code> constant.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">ENV</span><span class="p">[</span><span class="s1">'baseline_box'</span><span class="p">]</span> <span class="c1"># ;=> true</span>
<span class="no">ENV</span><span class="p">[</span><span class="s1">'host_name'</span><span class="p">]</span> <span class="c1"># ;=> concatenated environment options or baseline when not set</span>
</code></pre></div></div>
<p>Because it is located in a directory down the target project, you need to add a <code class="language-plaintext highlighter-rouge">synced_folder</code> pointing up, <code class="language-plaintext highlighter-rouge">..</code>, on the presence of <code class="language-plaintext highlighter-rouge">ENV['baseline_box']</code>.</p>
<p>Unless you use the link approach for the <code class="language-plaintext highlighter-rouge">.baseline</code> folder, you will want to add this configuration.</p>
<p>Apart from that, Baseline will delegate it to Vagrant on most of the commands.</p>
<h2 id="that-is-it">That is it</h2>
<p>Baseline is a simple command line tool. The magic relies on the project it checks out.
That project should provision and decide the environments to bring up.</p>
<p>Using an outside project configuration is ideal when the project does not provide a Vagrantfile, or to quickly play with something new without messing your current project/computer.</p>
Story from the trenches: Baseline workflow2014-03-01T00:00:00-03:00https://blog.bltavares.com/2014/03/01/story-from-the-trenches-baseline-workflow<p>Hi there you,</p>
<p>Today I would like to show a bit of my workflow with <a href="https://github.com/bltavares/baseline">Baseline</a>.
I’ve been using it on several different personal ideas and exploring others’ ideas.</p>
<p>The intention of this blog post is to show the usage of ephemeral,
provisioned development environments,
that are easily reproducible and
how I use them to tinker with different languages and projects.</p>
<p>On this blog post, I will share a real workflow that I’ve done using Baseline.</p>
<h2 id="once-upon-a-time-hack-day-spike">Once upon a time: Hack day spike</h2>
<p>On my current project, we have what we call The Hack Day.
It is a day to hack.</p>
<p>We share pains and ideas and try to fix, improve, or just try different approaches and technologies.</p>
<p>I like having a lean development setup, with few applications that I don’t use.</p>
<p>One good candidate for keeping environments contained is a container.</p>
<p>Docker is a good candidate for using containers.</p>
<p>On my last Hack Day, I decided to spike on putting our test runners,
less compilers and so on in its own containers.
First, I would need to discover the minimal amount of tools that the project needs to run,
so I could containerise it.</p>
<p>I started the day pulling the latest changes from the project.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>project
git pull
<span class="o">[</span>...]
</code></pre></div></div>
<p>I use a Mac, which is <em>slightly</em> different than what I would have running on a container.
And it is all configured already.</p>
<p>Removing all the configuration from my working environment wouldn’t be a good idea.
While it is a day for hacking, we need to go back to delivering features the next day.</p>
<p>Also,
it would be preferable to get the setup working on a Linux machine, which is what my container will run.</p>
<p>Baseline came to rescue.</p>
<h3 id="init-the-spike">Init the spike!</h3>
<p>On the project folder, from my Mac, I type:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>baseline init
baseline up
baseline ssh
vagrant@baseline <span class="nv">$ </span><span class="nb">cd</span> /vagrant
</code></pre></div></div>
<p>At this moment, I had a minimal Linux box.
The code is being shared under <code class="language-plaintext highlighter-rouge">/vagrant</code>, and I could use all my editor tools installed on my Mac to develop.</p>
<p>“This is what I need to get started.”</p>
<p>The following step is to run frequent commands we use on the codebase,
for example,
to bringing up the less server.</p>
<p>And errors would come up, lurking behind every <ENTER>.</ENTER></p>
<p>‘node: Command not found’.
‘npm: Command not found’.
‘Couldn’t find “less” module’.</p>
<p>I would list the requirements,
whenever those errors suddenly show on my screen.
With the list of required tools on hand,
it was time to start writing it down on a Dockerfile.</p>
<h3 id="whats-in-the-container-whats-in-the-container">What’s in the container?! What’s in the container?!</h3>
<p>The Dockerfile is a set of instructions that helps docker to build a container.
There you put your dependencies,
commands to run,
file dependencies,
environment variables and
the all the configuration to have a container.</p>
<p>It is important to write a Dockerfile,
it enables other people to reproduce your container.</p>
<p>From my Mac,
I bring up the text editor of my choice, and
write out a minimal Dockerfile.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FROM ubuntu:12.04
RUN apt-get update -y
RUN apt-get install -y nodejs
CMD bash
</code></pre></div></div>
<p>This is enough to have a container with node installed.</p>
<p>Because I am already using Baseline, I could install docker very easily on my VM.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vagrant@baseeline <span class="nv">$ </span>provision docker
<span class="o">[</span>...]
vagrant@baseeline <span class="nv">$ </span>docker <span class="nb">help</span>
</code></pre></div></div>
<p>And I could start building containers for our project.
Thanks to Baseline, I had the spike done by the end of the day.</p>
<h3 id="wrapping-up">Wrapping up</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>baseline init
baseline up
baseline ssh
</code></pre></div></div>
<p>This is how I usually start an idea.
I am free to mess around, knowing I can easily spin up another VM from scratch.</p>
<p>This is one example of a workflow with Baseline.
There are more workflows waiting to be discovered.</p>
<p>The docker experience on that day could become a blog post on its own (and will become eventually).</p>
Thoughts about variadic functions2013-12-02T00:00:00-02:00https://blog.bltavares.com/2013/12/02/thoughts-about-variadic-functions<p>I’ve been analyzing languages and their features.
This is part of a bigger quest, which is helping me think of useful features for a interesting personal project that is coming up in the future.</p>
<p>I would like to talk about variadic functions,
and do a quick analyses on why I find that it is not a very useful feature for languages with array literals.
(or any language that makes it easy to make languages)</p>
<h2 id="examples-of-variadic-functions">Examples of variadic functions</h2>
<p>On the <a href="http://rosettacode.org/wiki/Variadic_function">Rosetta Code</a>
you can find several examples of variadic functions on different languages.</p>
<p>Lets use a one Java sample that we can find on Rosetta Code of a Java variadic function:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">printAll</span><span class="o">(</span><span class="nc">Object</span><span class="o">...</span> <span class="n">things</span><span class="o">){</span>
<span class="c1">// "things" is an Object[]</span>
<span class="k">for</span><span class="o">(</span><span class="nc">Object</span> <span class="nl">i:</span><span class="n">things</span><span class="o">){</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">i</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>A variadic function is a bit of syntax sugar when you want to pass several arguments to the function</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">printAll</span><span class="o">(</span><span class="mi">4</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">5</span><span class="o">,</span> <span class="mi">6</span><span class="o">,</span> <span class="mi">4</span><span class="o">,</span> <span class="mi">3</span><span class="o">);</span>
<span class="n">printAll</span><span class="o">(</span><span class="mi">4</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">5</span><span class="o">);</span>
<span class="n">printAll</span><span class="o">(</span><span class="s">"Rosetta"</span><span class="o">,</span> <span class="s">"Code"</span><span class="o">,</span> <span class="s">"Is"</span><span class="o">,</span> <span class="s">"Awesome!"</span><span class="o">);</span>
</code></pre></div></div>
<p>In Java, creating arrays is quite verbose. Having that <code class="language-plaintext highlighter-rouge">Object...</code> is a quite sweet syntax sugar.</p>
<p>Now, lets take a look on a more functional language.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> 3</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> 6</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> 10</span><span class="w">
</span><span class="p">(</span><span class="nb"><</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> true</span><span class="w">
</span><span class="p">(</span><span class="nb"><</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> true</span><span class="w">
</span><span class="p">(</span><span class="nb"><</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> false</span><span class="w">
</span></code></pre></div></div>
<p>The function <code class="language-plaintext highlighter-rouge">+</code> and <code class="language-plaintext highlighter-rouge"><</code> are variadic functions in Clojure.
You can pass as many arguments as you want, as long as you are typing each argument.
If you have dynamic values (e.g: variables), things will look quite similar.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Having a variadic function is quite handy when you are <strong>typing</strong> each of the arguments.
In case you have a list of values that you want to sum, the implementation of the language for that syntax sugar
can get in the way.</p>
<p>As we can see in Clojure, <code class="language-plaintext highlighter-rouge">+</code> does not accept lists.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">))</span><span class="w"> </span><span class="c1">;=> NOPE</span><span class="w">
</span></code></pre></div></div>
<p>To accept lists you need to change your approach.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<h2 id="what-i-would-rather-see">What I would rather see</h2>
<p>I find that variadic functions gives you much less benefits on non-verbose languages.
The benefits happens as long as you are typing each of the arguments of the function,
with them being either a literal value or a dynamic value.</p>
<p>When you start having dynamic values, that you want to apply it, the variadic function just turns out
to not be as powerful as it sounded.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="p">[</span><span class="nb">list</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="nb">list</span><span class="p">))</span><span class="w">
</span><span class="c1">; As long you are typing yourself the values, variadic functions feels better</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">(</span><span class="nb">first</span><span class="w"> </span><span class="n">xs</span><span class="p">))</span><span class="w">
</span><span class="c1">; If you introduce dynamic values, the variadic functions need a hand</span><span class="w">
</span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nb">concat</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]))</span><span class="w">
</span><span class="c1">; However, if we had fixed arguments functions, we could do the same.</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">x</span><span class="p">])</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">(</span><span class="nb">first</span><span class="w"> </span><span class="n">xs</span><span class="p">)])</span><span class="w">
</span><span class="c1">; And the style doesn't change if you introduce dynamic values</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">+</span><span class="o">'</span><span class="w"> </span><span class="p">(</span><span class="nb">concat</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">])</span><span class="w">
</span></code></pre></div></div>
<p>The changes doesn’t seems much, both will work.
But there is another point that I find more pleasant to have fixed-arity functions.</p>
<h2 id="currying">Currying</h2>
<p>I am a big fan of currying. Lots of time, a simple lambda could have been removed.
Let’s try out to create a function that adds 1 to the next argument in Clojure.
Assuming <code class="language-plaintext highlighter-rouge">+</code> is a binary operation, lets try out.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">increment-1</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span><span class="w"> </span><span class="c1">;=> 1</span><span class="w">
</span><span class="p">(</span><span class="nf">increment-1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> NOPE</span><span class="w">
</span></code></pre></div></div>
<p>Looking back, our <code class="language-plaintext highlighter-rouge">+</code> function is a variadic function, and after you pass the arguments to it, it will assume the function is complete.
To accomplish what we wanted to do, we need to use a different method.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">increment-1</span><span class="w"> </span><span class="p">(</span><span class="nb">partial</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="nf">increment-1</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="c1">;=> 3</span><span class="w">
</span></code></pre></div></div>
<p>Using <code class="language-plaintext highlighter-rouge">partial</code> is quite noisy when chaining with function calls.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="p">(</span><span class="nb">partial</span><span class="w"> </span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">))</span><span class="w">
</span><span class="c1">; compare to a curried version</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p>Having variadic functions makes currying <a href="http://lambda-the-ultimate.org/node/3024#comment-44195">very</a> complicated.</p>
<p>You can still use <code class="language-plaintext highlighter-rouge">partial</code>, but it is not the same thing.
On can try to <a href="https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md">simulate</a>
variadic functions in curried languages, but it is something that you wouldn’t need most of the time.</p>
<p>By making composing functions more complicated, you have to change your design also.</p>
<h3 id="design-changes-for-not-allowing-currying">Design changes for not allowing currying</h3>
<p>Let’s look again at Clojure. Not having currying make you need to rely on the <code class="language-plaintext highlighter-rouge">-></code> and <code class="language-plaintext highlighter-rouge">->></code> macros.
It will allow you to rewrite the form to append the result of the next operation as the first argument or as the last one.
It will make you design your code to either be thread-first or threaded-last.</p>
<p>Having bits of functions with the desired dynamic part (the part you don’t usually want to fix) as the last argument (map, reduce and so on)
won’t hurt you much. You can always use the <code class="language-plaintext highlighter-rouge">partial</code> function that comes shipped in.
But what happens when the function was designed to use with thread-first?</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">use</span><span class="w"> </span><span class="ss">'clojure.string</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="p">(</span><span class="nb">partial</span><span class="w"> </span><span class="nb">join</span><span class="w"> </span><span class="s">","</span><span class="p">)</span><span class="w"> </span><span class="o">'</span><span class="p">((</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)))</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">split</span><span class="w"> </span><span class="n">%</span><span class="w"> </span><span class="o">#</span><span class="s">","</span><span class="p">)</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="s">"hello,world"</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">split</code> is an example of a Clojure function designed to be used with thread-first macro,
while <code class="language-plaintext highlighter-rouge">join</code> is designed to use with a thread-last macro.</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">use</span><span class="w"> </span><span class="ss">'clojure.string</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">-></span><span class="w"> </span><span class="s">"hello,world"</span><span class="w">
</span><span class="p">(</span><span class="nf">split</span><span class="w"> </span><span class="o">#</span><span class="s">","</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="nf">->></span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nb">join</span><span class="w"> </span><span class="s">","</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p>Dealing with collections will tend to make your functions to have the operators to behave under <code class="language-plaintext highlighter-rouge">->></code>,
while dealing with Java interop will tend to make your functions have the first argument thread-able by <code class="language-plaintext highlighter-rouge">-></code>.</p>
<p>Sometimes, you will need to decide how are you designing your functions arguments based on where it is being called,
leading to the “other threading” to have to deal with it.</p>
<h2 id="conclusion">Conclusion</h2>
<p>As an awesome syntax sugar for verbose languages, variadic functions can not be as sweet for other languages.</p>
<p>Having fixed-arity functions and currying as the design of the language allows you to have much more consistence in the design of your code.</p>
<p>I personally would trade variadic functions any time in order to have currying.</p>
Contexto de classes na declaracao de tipos em Haskell2013-11-21T00:00:00-02:00https://blog.bltavares.com/2013/11/21/contexto-de-classes-na-declaracao-de-tipos-em-haskell<p>Durante um dos <a href="https://groups.google.com/forum/#!forum/coding-dojo-tw-poa">dojos</a>
nos ficamos bastante curiosos com o sistema de tipos.
(algo que acontece recorrentemente quando estamos programando em Haskell)</p>
<p>Nos estávamos tentando criar um tipo para dinheiro.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">Money</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">USD</span> <span class="n">a</span>
</code></pre></div></div>
<p>Mas nos queríamos dar mais contexto para quais os possíveis tipos <code class="language-plaintext highlighter-rouge">a</code>
que poderíamos utilizar dentro do nosso tipo <code class="language-plaintext highlighter-rouge">Money</code></p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">Fractional</span> <span class="n">a</span> <span class="o">=></span> <span class="kt">Money</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">USD</span> <span class="n">a</span>
</code></pre></div></div>
<p>Entao, nos deparamos com o seguinte Warning.</p>
<blockquote>
<p>Warning: -XDatatypeContexts is deprecated: It was widely considered a misfeature, and has been removed from the Haskell language.</p>
</blockquote>
<p>Uma parte importante da mensagem de Warning diz:</p>
<blockquote>
<p>It was widely considered a misfeature</p>
</blockquote>
<p>O que levou a tornar DatatypeContexts um <em>misfeature</em>?</p>
<p>Uma pesquisa rapida no google me levou ao <a href="http://stackoverflow.com/questions/7438600/datatypecontexts-deprecated-in-latest-ghc-why">link</a>.
La eles mostram uma sintaxe alternativa que extende Haskell (GADTs),
mas que também precisa ser ativada com um flag na hora de compilar.</p>
<h2 id="mas-ainda-assim-por-que-e-considerado-um-misfeature">Mas ainda assim, por que e’ considerado um misfeature?</h2>
<p>Um link para a [wiki oficial]
(https://ghc.haskell.org/trac/haskell-prime/wiki/NoDatatypeContexts)
do Haskell mostra como o compilador lida com a declaração de tipos.</p>
<blockquote>
<p>The problem is that the constraint is not actually on the datatype, but rather, on the type of the constructor. Worse, the dictionary is not stored in the constructor, but simply discarded.</p>
</blockquote>
<p>Quando nos colocamos restrições no datatype, elas na verdade são descartados.
Precisamos escrever na função que utiliza nossos sistemas, quais os tipos possíveis de qualquer forma.</p>
<h2 id="como-eu-posso-garantir-que-meu-money-nao-vai-ter-um-book">Como eu posso garantir que meu Money nao vai ter um Book?</h2>
<p>Antes de tudo precisamos entender um pouco mais sobre visibilidade de módulos.</p>
<p>Recentemente eu estava assistindo a algumas <a href="https://www.coursera.org/course/proglang">aulas</a>
falando sobre ML e o sistema de módulos.
Haskell foi fortemente inspirado em ML e existe uma forma de fazer isso.</p>
<p>O modulo pode definir quais funções serão vistas quando importadas
(Construtores como <code class="language-plaintext highlighter-rouge">USD</code> são apenas funções também).</p>
<p>No dojo estávamos exportando tudo, mas no caso de uma biblioteca, isso não seria o ideal.</p>
<p>Para entender melhor como um modulo funciona o Learn you Haskell possui um
<a href="http://learnyouahaskell.com/modules#making-our-own-modules">capitulo</a>,
assim como a <a href="http://www.haskell.org/onlinereport/modules.html">documentação online</a>.</p>
<p>Podemos garantir as propriedades do nosso tipo <code class="language-plaintext highlighter-rouge">Money</code> expondo apenas a função criadora
que garantira que nossas propriedades serão mantidas.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">module</span> <span class="nn">Money</span> <span class="p">(</span><span class="nf">dollar</span><span class="p">)</span> <span class="kr">where</span>
<span class="kr">data</span> <span class="kt">Money</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">USD</span> <span class="n">a</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Show</span><span class="p">)</span>
<span class="n">dollar</span> <span class="o">::</span> <span class="kt">Fractional</span> <span class="n">a</span> <span class="o">=></span> <span class="n">a</span> <span class="o">-></span> <span class="kt">Money</span> <span class="n">a</span>
<span class="n">dollar</span> <span class="o">=</span> <span class="kt">USD</span>
</code></pre></div></div>
<p>Nós podemos inclusive fazer outra versão que garante que nunca poderemos ter dinheiro negativo.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">module</span> <span class="nn">Money</span> <span class="p">(</span><span class="nf">dollar</span><span class="p">,</span>
<span class="nf">nonNegativeDollar</span><span class="p">)</span> <span class="kr">where</span>
<span class="kr">data</span> <span class="kt">Money</span> <span class="n">a</span> <span class="o">=</span> <span class="kt">USD</span> <span class="n">a</span> <span class="o">|</span> <span class="kt">NoMoney</span> <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Show</span><span class="p">)</span>
<span class="n">dollar</span> <span class="o">::</span> <span class="kt">Fractional</span> <span class="n">a</span> <span class="o">=></span> <span class="n">a</span> <span class="o">-></span> <span class="kt">Money</span> <span class="n">a</span>
<span class="n">dollar</span> <span class="o">=</span> <span class="kt">USD</span>
<span class="n">nonNegativeDollar</span> <span class="n">x</span>
<span class="o">|</span> <span class="n">x</span> <span class="o"><</span> <span class="mf">0.0</span> <span class="o">=</span> <span class="kt">NoMoney</span>
<span class="o">|</span> <span class="n">otherwise</span> <span class="o">=</span> <span class="kt">USD</span> <span class="n">x</span>
</code></pre></div></div>
<p>E para utilizar o nosso modulo</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">import</span> <span class="nn">Money</span>
<span class="c1">-- error:</span>
<span class="c1">-- USD 16.00</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">dollar</span> <span class="mf">16.00</span> <span class="c1">-- USD 16.00</span>
</code></pre></div></div>
Comments on Single Responsibility Principle2013-11-02T00:00:00-02:00https://blog.bltavares.com/2013/11/02/comments-on-single-responsibility-principle<p>Juan <a href="http://juanibiapina.com/articles/2013-11-01-single-responsibility-principle/">blogged</a> about SRP and it made me analyze some of my previous encounters with feature envy classes.
I am not sure if it something common to happen on every class that is a big feature gluton, but it was enjoyable to notice this on the last refactoring on the codebase of one of the projects.</p>
<p><strong>Classes that respect SRP are not visited frequently</strong></p>
<p>We had this class called Config.
The Config had everything on it.
It had location of files, it had methods to write to files.
It had property lookups on it.</p>
<p>We used to revisit the class often, add some methods, tweak others and pass it all around.
One day we realized that it was doing to much. And we refatored it to 3 different objects.</p>
<p>We then created one object called ConfigLocation that deal with the file location.
You give it an object that should be in a file and it gives you back a File.
Simple and soft.</p>
<p>Also, a property lookup was removed. It was not required anymore.
The variables were used to define which folder should the object be in and also the $PREFIX.
Less code, less bugs.</p>
<p>And the file writing: We wrapped it on a simple class that we pass a file and a string.
No need to deal with Stream and so on.</p>
<p>And then we never revisited those classes again.</p>
Following the error: Spring Autowired and bean collectors2013-08-19T00:00:00-03:00https://blog.bltavares.com/2013/08/19/following-the-error-spring-autowired-and-bean<p>Hi there,</p>
<p>Today’s following the error will feature Spring dependency injection framework. Spring is very popular in the Java world, and have a bunch of helpful classes.</p>
<p>There is a lot of documentation < <a href="http://static.springsource.org/spring/docs/2.5.3/reference/beans.html"><a href="http://static.springsource.org/spring/docs/2.5.3/reference/beans.html">http://static.springsource.org/spring/docs/2.5.3/reference/beans.html</a> </a>></p>
<p>Lets start setting up some context.</p>
<p><strong><em>Beans… BEANS…</em></strong></p>
<p><strong><em><br/></em></strong>Imagine this scenario: You want a program that will have Extractor’s, and a class that will pick all those Extractor’s and run it. It is quite simple.</p>
<p>So, to use it with Sprin beans, which are components that can be injected around your code, you annotate it with @Component. @Autowired annotations will try to assign components that match that type.</p>
<script src="https://gist.github.com/bltavares/6273600.js?file=ObjectsExtractor.java" type="text/javascript"></script><p></p>
<p>The get an object with the variables annotated filled with values you rely on the Spring Context.</p>
<script src="https://gist.github.com/bltavares/6273600.js?file=Main.java" type="text/javascript"></script><p><em>I wont be explaining much of the context.xml, but that is what Spring will read to setup the beans and scan your code for @Component’s annotations.</em></p>
<p><strong><em>Oh… So Spring can do that?!</em></strong></p>
<p><strong><em><br/></em></strong>So far, so good. Now we just need to feed that list of Extractor’s to the component. But how to do that?</p>
<p>A cool thing of the dependency injection system that Springs implements is that when you @Autowire a List, it will select all the beans that match the type of the List and put it there.</p>
<p>It means that if I create several different extractors, all of then will be injected into that list.</p>
<p>We just need to create our different beans to get our little app working.</p>
<p>That is pretty cool. </p>
<p><strong>And the requirement changes.</strong></p>
<p><strong><br/></strong>We were happy that everything was coming up together, and the world changes. We need to have different Extractor’s for different Spring Profiles. We have one profile that includes 3 extractors, and another one that have 0.</p>
<p>"That is pretty easy. You just need to skip the creation of the beans."</p>
<p>Yes.</p>
<p><strong>Let the errors begin.</strong></p>
<p><strong><br/></strong>No. A stack trace. *phh*</p>
<p>We face that big pile of red lines. </p>
<script src="https://gist.github.com/bltavares/6273600.js?file=no-extractors.log" type="text/javascript"></script><p></p>
<p>Let’s see. Hum, no matching bean type. Oh, there is no Extractor’s now. It requires an Extractor to inject. But what I want is an empty list if it does not exist.</p>
<p>Lets see if we can say “Hey, that is not required”.</p>
<p><strong>@Autowired( required = false )</strong></p>
<p><strong><br/></strong>We discover that the @Autowired annotation have an option to say it is not required. “Yes” - you say.</p>
<p>Ok, let’s try it out.</p>
<script src="https://gist.github.com/bltavares/6273600.js?file=autowired-false.log" type="text/javascript"></script>
<p>Not again… “But I just said it is not required”.</p>
<p>I tried searching on the documentation about another ways to say something is not required. There is a @Required tag, but it is only possible to use on fields, not on methods or type annotations.</p>
<p><strong>Lets dive in the code.</strong></p>
<p><strong><br/></strong>After spending some time struggling with annotations and tweaking configurations I decide to take a look on the source code for Spring.</p>
<p>It is a big framework, but the last stacktrace have some clues on where to start digging.</p>
<p><span>org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:774)</span></p>
<p>That is where I start. The code is a bit dense to read, and after a while, reading both the code and the documentation I understand what the @Autowired( required = false ) means.</p>
<p>On the url < <a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html%20"><a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html">http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html</a> </a>> you see that you can have multiple @Autowired’s constructors.</p>
<p>On the documentation there is this line <<a href="%20http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s11.html%20"> http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s11.html </a>></p>
<blockquote>
<p><span>but multiple non-required constructors can be annotated. In that case, each will be considered among the candidates and Spring will use the </span><span class="emphasis"><em>greediest</em></span><span> constructor whose dependencies can be satisfied.</span></p>
</blockquote>
<p><span> Reading the code something clicks in my mind. Saying that @Autowired is not require only means that it will skip the injection of the beans in case of failure, but because it is the constructor, it cannot create the component at all if it skips.</span></p>
<p><strong><span> </span></strong></p>
<p><strong><span>Fixing the code</span></strong></p>
<p><span>We need to fix to things to keep coding. One is to create the component if there is no components and the other is to keep an empty list for the Extractor’s list.</span></p>
<p><span> </span></p>
<p><span>To create a component without @Autowired, Spring tries to use the default constructor for the object. We create a constructor and annotate it with @Deprecated in order to inform other people that you shouldn’t use that constructor.</span></p>
<p><span>Spring is happily creating our component now.</span></p>
<p><span> </span></p>
<p><span>Now that we know that a @Autowired(required = false) do, we can use it.</span></p>
<p><span>Because it will skip the initialisation using that method due to the error on the missing bean, Spring will fallback to the default constructor only in this case.</span></p>
<p><span>Then, we can initialise the list with an empty list, as we wanted before.</span></p>
<script src="https://gist.github.com/bltavares/6273600.js?file=final-ObjectsExtractor.java" type="text/javascript"></script>
Following the error: lein-cljsbuild and :foreign-libs2013-08-09T00:00:00-03:00https://blog.bltavares.com/2013/08/09/following-the-error-lein-cljsbuild-and-foreign-libs<p>Everyday we stumble across cryptical error messages and complicated stack traces. Some of them requires you to go to different websites and documentation, and if it keeps getting in the way, check the source code to finally understand the Why.</p>
<p>I want to document my line of thoughts when I come across those little problems that really make you sad.</p>
<p>Todays problem was when I was trying out Clojurescript. I started out with a simple `lein new project` and added the cljsbuild < <a href="https://github.com/emezeske/lein-cljsbuild">https://github.com/emezeske/lein-cljsbuild</a> > plugin to start the fun.</p>
<h3>Some context before the error happens</h3>
<p>I wanted to play around with some graphics and I just start drawing squares on a <canvas> tag. No libraries required so far, just some old js functions to grab elements and draw on the canvas.</p>
<p>I realised that I would need another way to draw on the browser. The canvas won’t get mouse events unless I keep track of it and that was too cumbersome for me.</p>
<p>SVG sounded better, but the api to work with it in the browser is not so fun. A quick google search and raphaeljs.com is on the way.</p>
<h3>Investigating the Clojurescript integration with different libraries</h3>
<p><em>"Raphael.js is an awesome graphical library for JavaScript. Let’s see how it integrates with clojurescript".</em></p>
<p>The first search for clojurescript and raphael takes me to the blogpost < <a href="http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html">http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html</a> ></p>
<p>It is a very complete blog post that gives you different examples of how to integrate cljs with other js libs.</p>
<p>"Wow. it is just one line, let me add this :foreign-libs"</p>
<h3>Let the error hunt begin</h3>
<p><em>"But I followed all the instructions" said the baffled developer.</em></p>
<p>Going to raphaeljs website there is a big button to download the code. Right-click and copy url. Paste on the proper space on the project.clj and we should be good. Right?!</p>
<p>After that, no code was downloaded. “Well, I forgot the require”. Ok, added on the file and we have an error on the webpage.</p>
<p><em>"goog.require raphael.core is not found"</em></p>
<p>That lead me to understand better the integration of Clojurecsript and the Google Closure framework.</p>
<p>On the blog post of Luke VanderHart, there is a comment about the version where the :foreign-libs was introduced. The code is not so complicated and reading the changeset gives us a nice insight < <a href="https://github.com/clojure/clojurescript/commit/96b38e2c951ef07b397e9d">https://github.com/clojure/clojurescript/commit/96b38e2c951ef07b397e9d</a> ></p>
<p>"Well, the code should inject that remote file when compiling everything together". `ack raphael` and no files are reported on the directory, but the project.clj and the require’s statements.</p>
<h3>Approaching the light</h3>
<p><em>'That is super weird. I need more help.'</em></p>
<p>I thought something was configured wrong. Reading the sources, documentations and everything seems to be on the right place. But what was wrong? At this point, asking other people is the best way to get better ideas.</p>
<p><span>IRC app. /j #clojure. HALP!</span></p>
<p><span>dnolen suggested to try using a local file. ‘IT WORKS!’. But it works is not enough. Why it didn’t work before?</span></p>
<h3><span>First step: Is the error related to using a remote file?</span></h3>
<p><span>`python -m SimpleHTTPServer` and changing the project.clj to point to http://localhost:8000/raphael-min.js</span></p>
<p><span>Works. Yay! But why the other one does not work?</span></p>
<p><span> </span></p>
<h3><span>Second step: What is the status of the file I am pointing to?</span></h3>
<p><span>`wget <raphael-url>` gave me some redirects. This might be related. First I get a 301. Moved permanently. To the HTTPS version.</span></p>
<p><span>Interesting… redirects…</span></p>
<h3><span>Third step: Why a redirect does not work?</span></h3>
<p><span>Reading the source, cljsbuild generate a InputStream for that content. InputStream is part of java. This is not in the plugin anymore.</span></p>
<p><span>With some search, we end up on this bug report </span><a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4620571">http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4620571</a></p>
<p>Quoting the reply of java’s engineers:</p>
<blockquote>
<div>After discussion among Java Networking engineers, it is felt that we shouldn’t automatically follow redirect from one protocol to another, for instance, from http to https and vise versa, doing so may have serious security consequences. Thus the fix is to return the server responses for redirect. Check response code and Location header field value for redirect information. It’s the application’s responsibility to follow the redirect</div>
</blockquote>
<p><span> </span></p>
<p><span>The error happened because of the protocol change not being followed, as we are used to have in the browser.</span></p>
<p><span>Ah, now I can sleep.</span></p>
<p><span> </span></p>
<p></p>
Kata problem: Git wrong commit2013-05-23T00:00:00-03:00https://blog.bltavares.com/2013/05/23/kata-problem-git-wrong-commit<p>Hi there,</p>
<p>This is a Git problem I put up to the office and I really liked practicing the various different ways that people came up with.</p>
<p><span>I thought to share this, as it could be used in a Git dojo to get the feeling of rewriting the commit history.</span></p>
<p><strong>As lots of my colleagues pointed out</strong>: this is easy to be done because it is a offline branch.</p>
<p>When you share this code with a remote repository it is really complicated to rewrite history, because you need to force the new history on the remote, which can corrupt or lose commits that already exist there and are not in sync.</p>
<p>Here is the problem:</p>
<p><!-- more --></p>
<p><em>Me and my pair was working with one project on my machine. It uses git to keep track of the files.</em></p>
<p><em>The workflow of the project is that the master is always green, we have features on branches to keep track of the work, but we merge it back often.</em></p>
<p><em>We were playing one story and it was merged on master already. After we moved the story to validation, we picked up a new story.</em></p>
<p><em>One of the QA’s found an IE misalignment on the feature, really simply to fix. So we fixed the issue and committed.</em></p>
<p><em>But we forgot to change the branch to master before committing.</em></p>
<p><em>We ended up with this state:</em></p>
<p><em>$ git branch</em></p>
<blockquote>
<p><em> master* search_project</em></p>
</blockquote>
<p><em>$ git log —graph —decorate —oneline —branches</em></p>
<blockquote>
<p><em>* 7ff891f (<strong>HEAD</strong>, <strong>search_project</strong>) [USL-107] Fix css alignment of the user search box</em></p>
<p><em>* 7c5b3c1 [USL-108] Use autocomplete when searching projects</em></p>
<p><em>* 7fa2aef [USL-108] Search projects</em></p>
<p><em>* 8655896 (<strong>master</strong>) [USL-107] Search users using autocomplete</em></p>
</blockquote>
<p><em>The challenge here is to move the commit we created to the right branch.</em></p>
<p><em>The end state should be this:</em></p>
<p><em>$ git branch</em></p>
<blockquote>
<p><em> master* search_project</em></p>
</blockquote>
<p><em>$ git log —graph —decorate —oneline —branches</em></p>
<blockquote>
<p><em>* 3e8322a (<strong>HEAD</strong>, <strong>search_project</strong>) [USL-108] Search projects</em></p>
<p><em>* 1090110 [USL-107] Fix css alignment of the user search box</em></p>
<p><em>* cfc2c36 (<strong>master</strong>) [USL-108] Use autocomplete when searching projects</em></p>
<p><em>* 8655896 [USL-107] Search users using autocomplete</em></p>
</blockquote>
<p><em><a href="http://ubuntuone.com/5J4Nfg54q8ELCn9gtXDeeF" target="_blank">Here</a> is the repo in the initial state.</em></p>
<p><em>Have fun.</em></p>
Mozilla's Hackday on Porto Alegre - Review2012-09-02T00:00:00-03:00https://blog.bltavares.com/2012/09/02/mozillas-hackday-on-porto-alegre-review<p>Hello there!</p>
<p>One day after BrazilJS 2012, Mozilla had the idea of promoting a hackday here in Porto Alegre, Brazil. They talked about a Firefox OS and it got my attention.</p>
<p>So, I went there. I and loved the idea.</p>
<p>We started the day with a good breakfast, had some presentations around the new Firefox OS and some news about webapps. After that, we got up stairs to the ThoughtWorks office to start the hacking.</p>
<p>On the end of the day, <strong>a lot of</strong> documentation was translated to portuguese and we had a lot of cool demos.</p>
<p>There were some interesting points:</p>
<p><strong>The Firefox OS</strong></p>
<p><strong><br/></strong>The Firefox OS is a mobile framework. Really light-weight, fast, customizable, and powered by JavaScript/HTML/CSS! The idea is to have a small linux kernel booting up the phone interface on a custom firefox browser, and providing phone apis on javascript (like contacts and more).</p>
<p>It would make it a good OS for low-end smartphones, for places where smartphones are expensive (like Brazil).</p>
<p>It is powered by Gecko, and you can run the phone interface (a.k.a. Gaia) on your computer using Firefox Nightly build. If you are running the Nightly build, you can install applications even on your computer, without the Gaia interface. You can provide a good looking icon in your applications list of your preferred OS, like any native app, and it will run on a web wrapper, with the application name as the title. It is completely cross-platform!</p>
<p>Creating applications is really easy. You use a manifest to say it is installable, and build it like a normal webapp. This means it run on any OS, since it is a small webapp running on the internet (or even locally). You can write everything using javascript, bundle it using a cache manifest file, and run everything locally. (<strike>Awesome for todo lists in js ;</strike>)</p>
<p><strong>Mozilla Marketplace</strong></p>
<p>Mozilla has a beta marketplace, where you can publish your applications, like Google’s Play or Apple’s Appstore. It will provide ways to comercialize apps (70-39% if you want to sell it). They are using Mozilla Persona on the website, which might help to spread Persona for non-tech people.</p>
<p>There is no developer fee, which is interesting for spiking super small apps, check the acceptance by the market and keep moving. </p>
<p><strong>Hackday results</strong></p>
<p><strong><br/></strong>We had a lot of cool games, using canvas and Mozilla WebGameStub <<a href="https://github.com/mozilla/WebGameStub/"><a href="https://github.com/mozilla/WebGameStub/">https://github.com/mozilla/WebGameStub/</a></a>>. During the talks, someone asked about screen reading capabilities, and it inspired me to try out a speech-to-text webapp. So, me and Tainã (<a href="http://twitter.com/tainaonichi">@tainaonichi</a>) sat down on a hot evening and coded it! The result it here <<a href="https://gist.github.com/3603997"><a href="https://gist.github.com/3603997">https://gist.github.com/3603997</a></a>></p>
<p><strong>Final thoughts</strong></p>
<p>The day was really interesting, with a lot of cool stuff from Mozilla’s labs. A lot of talk about gaming, some cool 3d examples and a super light phone OS. I would totally buy a Firefox OS phone, if the price is as low as they said when it comes out.</p>
Improving the user/password combo2012-08-06T00:00:00-03:00https://blog.bltavares.com/2012/08/06/improving-the-user-password-combo<p>Hi there!</p>
<p>I’ve been playing around with cryptography and security, and every time I stumble on asymmetric keys I get amazed! All my deployments rely on it.</p>
<p>All my connections to another machine rely on the identity provided by my private key.</p>
<p>We have been building our identity on the internet. And we don’t like to let other people impersonate you. That is <em>YOU, </em>nobody can be you!</p>
<p>That is why we set up a password for our online services. That is why we have PGP signatures. But it is boring to remember passwords all the time.</p>
<p>Some initiatives have been done to address this issue, like OpenID, OAuth and password managers. I really like how OAuth provides a user identity and restricts usage of these identities, giving you the choice to allow them to do some actions in your name. I like the way OpenID provides an online identity, identifying the user to a profile. And I think the way 1Password integrates with the browser is awesome.</p>
<p>Mozilla is doing an interesting experiment, <a href="http://www.mozilla.org/en-US/persona/">Mozilla Persona</a>, to provide some of the OpenID benefits through the browser.</p>
<p>And then, asymmetric keys always come to my mind. This magic way of telling any other user that I am the right ‘Bruno’ by using a secure key. Some companies already use that authentication format to deploy code, upload files, and store data.</p>
<p>I’ve been thinking different ways to use the power of PGP to identify myself on websites. With the right implementation we could give the user the choice to not user a password at all!</p>
<p>The most recent idea I had is something like this:</p>
<ul><li>Manage your PGP keys using subkeys. (Keep your master key completely <em>SECURE</em>). That way, if any of your keys get compromised, you still can revoke access to it and restore your user identity.</li>
</ul><div></div>
<ul><li>Using a challenge-response method in a two way encryptation. The service provider sends a encrypted random message, that should be decrypted by you, and then, respond encrypting with the server public key. It would secure the user authentication on another level, by proving the current website is the correct one, not a fake server.</li>
</ul><div></div>
<ul><li>A browser/desktop/mobile API, so that you don’t need have too much hassle responding to the challenge. It could be also a kind of local OAuth provider, in a way that you could choose what the provider could do in your name.</li>
</ul><p>We don’t need to get rid of the password login, but we could add a small advanced login link on the registration/security form, which you could provide the initial public key to access your computer.</p>
<p><img src="http://media.tumblr.com/tumblr_m8d0p8mbbJ1qamcq2.png"/></p>
<blockquote>
<p>I would like to see something like this.</p>
</blockquote>
<p>The implementation still have some flaws, and I am thinking ways to implement it at the same time I am writing this post. That is the initial draft I have for now.</p>
<p>I would like to, some day, use my private key to login in on Twitter.</p>
Cleaning database after testing on C#2012-03-10T00:00:00-03:00https://blog.bltavares.com/2012/03/10/cleaning-database-after-testing-on-c<p>Hi there.</p>
<p>Some times you need to test your queries to know that you are bring the correct data.</p>
<p>But it’s so boring to setup the data on the database and then clean-up everything else, then do it over and over again.</p>
<p>There must be a simpler way to do it! We may create the data on the test and delete it again.</p>
<p>What if the data is automatically removed?</p>
<p>In this case, I’m using Entity Framework and <span>Microsoft’s Test Unit tools.</span></p>
<p>We can achieve it using transactions. We’ll be using .Net’s <span>TransactionScope do do it.</span></p>
<p><span>First, we create a TransactionalTest class.</span></p>
<p><span><br/></span></p>
<script src="https://gist.github.com/2008502.js?file=TransactionalTest.cs" type="text/javascript"></script><p><span><br/></span></p>
<p><span>To test this class, I created a test case and then setup a Ordered Test list.</span></p>
<p><span><br/></span></p>
<script src="https://gist.github.com/2008502.js?file=TestTransactionClass.cs" type="text/javascript"></script><p><span>It worked for my needs (:</span></p>
Delegate and Decorators2012-01-26T00:00:00-02:00https://blog.bltavares.com/2012/01/26/delegate-and-decorators<p>After reading <a href="http://avdi.org/devblog/2011/11/15/early-access-beta-of-objects-on-rails-now-available-2/">Object on Rails</a> and some blog posts (like <a href="http://robots.thoughtbot.com/post/14825364877/evaluating-alternative-decorator-implementations-in">Thoughtbot’s</a> one) I started playing with the Ruby’s delegate lib.</p>
<p>Let’s suppose I want to decorate an object, to wrap some instance methods. An simple inheritance from SimpleDelegator would to it</p>
<p>But now, let’s suppose I want to decorate and object and it’s class, to wrap some instance methods <em>AND</em> some class methods.</p>
<p>Like this pseudo code (It won’t work)</p>
<p><strong>#UPDATE</strong></p>
<p>Now, I got some tested code, deployed as gem if you want.</p>
<p>Check it out <a href="https://github.com/bltavares/delegate-class"><a href="https://github.com/bltavares/delegate-class">https://github.com/bltavares/delegate-class</a></a></p>
<p>I also found it useful to wrap ActiveRecord models and use the rails methods that require it to be an instance of ActievRecord, like #form_for</p>
<script src="https://gist.github.com/1682339.js"> </script><p><del>After playing with DelegateClass, I ended up with this <<a href="https://gist.github.com/1680411"><a href="https://gist.github.com/1680411">https://gist.github.com/1680411</a></a>> code.</del></p>
<script src="https://gist.github.com/1680411.js"> </script><p><del>It works but I still don’t know if there is a real reason to use it.</del></p>
<p><del>But</del> I’m happily playing with delegates. Maybe it is useful to someone (:</p>
Já conhece o Eufori?2011-12-23T00:00:00-02:00https://blog.bltavares.com/2011/12/23/ja-conhece-o-eufori<p>Final de ano, correria e muito estudo.</p>
<p>Fiquei animado de escrever no blog e queria compartilhar com a internet uma das minhas atuais alegrias.</p>
<p>Eu sempre adorei esportes! Karate, bicicleta, skate, patins, judo, capoeira, parkour, natação e moto são umas das coisas que mais gosto(ei) de fazer.</p>
<p>Mas eu tinha(tenho) um grande problema de saber onde esta acontecendo passeios, competições, campeonatos e tudo mais. Diversas vezes tive amigos saindo para competir e só fiquei sabendo quando voltaram.</p>
<p>Como sempre estive em contato com organizadores, principalmente de moto, sei como é difícil ter um lugar para divulgar, em que a mídia está saturada de futebol o tempo todo.</p>
<p>O Eufori <<a href="http://eufori.com.br" title="Eufori - Todos <3 Esportes"><a href="http://www.eufori.com.br">http://www.eufori.com.br</a></a>> foi a solução que encontrei para esses meus problemas. Tem sido bastante interessante fazer tudo isso e saber que posso ajudar mais apaixonados por esportes.</p>
<p>Fica o convite pessoal de usar o <a href="http://www.eufori.com.br">Eufori</a> para todos que gostam de esportes, seja como atleta ou organizador, ou até mesmo para marcar o campeonato de StarCraftII na casa do amigo.</p>
<p>Toda sugestão é bem vinda (:</p>
Atualizações no Cabinet2011-12-23T00:00:00-02:00https://blog.bltavares.com/2011/12/23/atualizacoes-no-cabinet<p>Olá pessoal,</p>
<p>Tem bastante tempo que não falo nada sobre o Cabinet.</p>
<p>Esse final de ano foi muito corrido e como o projeto é mais para brincadeira, não mexi muito nele.</p>
<p>No final do ano, dei uma refatorada no código e implementei algumas coisinhas de pouco em pouco. Dê uma olhada no commit <<a href="https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5"><a href="https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5">https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5</a></a>></p>
<p>Um dos professores pediu um trabalho simples, de um app de gerenciamento de estoque e que achei que ficou com um código simples. Resolvi colocar ela como exemplo do Cabinet. <<a href="https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5"><a href="https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5">https://github.com/bltavares/CabiNet/commit/944692d23c3a7255a17702642c20710e520c3fe5</a></a>></p>
<p>Não sei o futuro do Cabinet, agora que me formei no colégio técnico.</p>
<p>Quem sabe não acontece um outro release, depois de passar nos vestibulares?</p>
<p>Abraços (:</p>
BDD vs TDD2011-09-21T00:00:00-03:00https://blog.bltavares.com/2011/09/21/bdd-vs-tdd<p>No ultimo <a href="http://www.facebook.com/event.php?eid=259399660758409" target="_blank">#DevDojo</a>, apareceu uma discussão interessante entre as diferenças entre o BDD e o TDD.</p>
<p>A melhor técnica para entender melhor algo é realizando ela na pratica. Decidi aplicar as duas técnicas para resolver o mesmo problema.</p>
<p><strong>O problema</strong></p>
<p>O problema é bem simples.</p>
<p>Quero um objeto Calculadora que some, subtraia, multiplique e divida dois números. A única peculiaridade é que a divisão deve retornar números decimais e que lance uma exception na divisão por 0 e não Infinito, como ocorre com divisão de decimais.</p>
<p>O resultado pode ser visto aqui <<a href="https://github.com/bltavares/BDD-vs-TDD" target="_blank"><a href="https://github.com/bltavares/BDD-vs-TDD">https://github.com/bltavares/BDD-vs-TDD</a></a>>.</p>
<p><strong>As semelhanças</strong></p>
<p>Ambas as técnicas geram confiança no desenvolvimento. O código se torna algo saudável de manter e de desenvolver novas funcionalidades.</p>
<p>Uma coisa interessante é a implementação feita pelo minitest do bdd.</p>
<p>Uma expectativa é um assert renomeado.</p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lrup4hhiGf1qamcq2.png"/></p>
<p><em>Então, eles são iguais?</em></p>
<p><strong>As diferenças</strong></p>
<p>Se vocês seguirem os commits de cada branch, com os testes e os códigos lado a lado, verá que a maior diferença entre as duas técnicas está na organização e expressividade.</p>
<p>Desenvolvendo em bdd, senti que entendia melhor o motivo de um método existir e o que ele deveria fazer. A forma que você se aproxima do problema e suas soluções parecem ficar mais claras.</p>
<p>O código se torna mais organizado, mostrando o comportamento dos objetos e não apenas um teste dele sobre uma condição específica.</p>
<p>O tdd é mais rápido, mas me senti em dúvida sobre como deveria nomear metodos de acordo com o nome do teste. Ele não tornou claro para mim qual a especificação do objeto eu estava demonstrando.</p>
<p><strong>As ferramentas</strong></p>
<p>Utilizei o testunit para o TDD e o RSpec para o bdd. Vou apontar algumas características que afetam os frames e não as técnicas.</p>
<p>O testunit possui implementado tanto um framework de bdd quanto de tdd, permitindo que o dev escolha qual ele irá usar.</p>
<p>Uma coisa MUITO bacana dele é que os testes rodam de forma aleatória cada vez que você testa. Isso garante que nenhum dos casos esteja afetando outro caso.</p>
<p>Ele é bastante rápido, mas a saida de erro dele não foi muito interessante.</p>
<p><em>Código</em></p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lrupriOovH1qamcq2.png"/></p>
<p><em>Teste errado</em></p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lrups5uFEi1qamcq2.png"/></p>
<p>Instalando um novo tipo de output, consegui melhorar um pouco a saida de erro</p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lruptccD7N1qamcq2.png"/></p>
<p>Com a nova saida, e tudo ok.</p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lrupuwCAtG1qamcq2.png"/></p>
<p>Com o rspec, acho bem mais espressivo a saida em formato de documentação, além de que, com um describe apenas é possivel setar o metodo subject como a instancia da classe sobre teste.</p>
<p><em>Ao descrever uma classe, o metodo subject instancia ela por padrão para você</em></p>
<p><em><img alt="image" src="http://media.tumblr.com/tumblr_lruq74NDvX1qamcq2.png"/><br/></em></p>
<p><em>Código</em></p>
<p><img alt="image" src="http://media.tumblr.com/tumblr_lrupzc9i3O1qamcq2.png"/></p>
<p><em>Teste errado</em></p>
<p><em><img alt="image" src="http://media.tumblr.com/tumblr_lruq14FUpp1qamcq2.png"/></em></p>
<p><em>Teste ok</em></p>
<p><em><img alt="image" src="http://media.tumblr.com/tumblr_lruq2nsmf11qamcq2.png"/></em></p>
<p><strong>Conclusão</strong></p>
<p>Apesar que os testes em tdd sejam bem mais rápidos, acho que vale a pena utilizar o bdd.</p>
<p>A melhor expressividade que essa aproximação para testes oferece ajuda a pensasr no problema real e não apenas no código, facilitando a comunicação de requerimentos entre programadores-stackholders, e inclusive programadores-programadores.</p>
<p>As duas formas são muito boas e bastante parecidas, cabendo ao dev escolher qual encaixa melhor ao seu estilo.</p>
<p>Mas o mais importante que trago desta experiência é: TEST IT!</p>
1.8.0 rc2011-09-19T00:00:00-03:00https://blog.bltavares.com/2011/09/19/1-8-0-rc<p>E foi meu aniversário esse sábado. E como todo #dev de verdade, tive que ir programar.</p>
<p>Antes de sair para a festa decidi fazer uma pequena brincadeirinha. Estava levando o laptop para passar clips em um projetor no meio do salão e pensei em deixar quem não poderia ir participar da festa.</p>
<p>Comecei a codar um pequeno app em python para mostrar na tela twittes para mim com a hashtag #festa. Fail total!</p>
<p>Não estava acustumado com as novas bibliotecas do python3 e acabei usando ruby¹.</p>
<p>Queria agradecer todas as pessoas que puderam ir, ou que queriam ir, que eu conheci e papeie nesses ultimos 18 anos.</p>
<p><em><strong>Obrigado galerinha do mau! (:</strong></em></p>
<p>¹</p>
<script src="https://gist.github.com/1225749.js"> </script>
How I’ve setup Git for continuous deployment on a PHP project2011-09-16T00:00:00-03:00https://blog.bltavares.com/2011/09/16/how-ive-setup-git-for-continuous-deployment-on-a-php<p>I’ve been amazed with git’s powers lately. After using svn, bzr and hg, I can understand why there is so much talking about git.</p>
<p>Let me talk about this php project. It’s been built by 3 dev and a designer, versioned under SVN.</p>
<p><strong>WHAT?! Is it about GIT or SVN?</strong></p>
<p>That’s one of the reasons I’ve been amazed with Git. I got a few problems with the integration, so there are some tips:</p>
<ul><li>From time to time run ‘git fsck’ to check your expository’s health</li>
<li>Some times, ‘git commit —amend’ require you to rebase your project before commiting it to SVN.</li>
<li>Never use ‘git checkout —force’! I lost half of my code doing it ):</li>
<li>Listen to what Git says. Don’t skip the messages about what is happening. I broke all my object database once trying to pull changes from the SVN without reading the messages.</li>
</ul><p><strong>Let me introduce the problems that I solved with Git and RSync</strong></p>
<p>After a lot of local testing, the team gave me the instruction to deploy the project every day at 5:00pm on the outside testing environment.</p>
<p>So, for 3 days at 5:00pm a had task to upload everything using FTP, change the configuration files and check the system. All those .snv folders, images and stuff were such slow.</p>
<p><em>It was boring!</em></p>
<p>I decided to give a try to Git-Svn and set up a deploy branch to let the configurations ready to deploy. The .svn folders were gone and the problem was solved, right?</p>
<p><strong>No, it was slow </strong><strong>still </strong><strong>):</strong></p>
<p>On the other day, the project migrated to another host. I was now on beta stage. And now the server has ssh. I got a smile on my face (:</p>
<p><strong>RSync: It’s really fast!</strong></p>
<p>With the deploy branch set up with the correct configurations, some continuous merges and a small bash script, the continuous deployment was ready to go.</p>
<p>The rule: <em>Master is good and always can be deployed.</em></p>
<p>The steps:</p>
<ol><li>ssh-copy-id user@host #we don’t want that boring password prompt</li>
<li>write deploy.sh¹</li>
<li>run it and be happy</li>
</ol><p>Now, every change made on the project are almost instantly on production.</p>
<p>You should give a try to those “native” tools on *nix some times (:</p>
<p>¹</p>
<script src="https://gist.github.com/1221081.js"></script>
_CanHaz: ICanHaz for Underscore2011-07-26T00:00:00-03:00https://blog.bltavares.com/2011/07/26/canhaz-icanhaz-for-underscore<p>Today I started a new project and wanted to use a js templater.</p>
<p>I’m already using Underscore.js and Jquery, and I liked how ICanHaz.js handles the templates.</p>
<p>So I decided to create the <a href="http://github.com/bltavares/underscorecanhaz.js">_CanHaz.js</a>, giving you the ability to handle templates like ICanHaz.js but using the Underscore template method.</p>
<p>You should check the <a href="http://documentcloud.github.com/underscore/#template">documentation</a> for the template method.</p>
<p>Improvements are welcome. (:</p>
CoderWall Konami Code Bookmarklet2011-07-21T00:00:00-03:00https://blog.bltavares.com/2011/07/21/coderwall-konami-code-bookmarklet<p>I really liked the new homepage of <a href="http://coderwall.com">Cowerwall</a>. And I wanted to make something funny on it.</p>
<p>So I’ve develop a small konami code easter egg to use on the new homepage of <a href="http://coderwall.com">Cowerwall</a>.</p>
<p>Just drag it to your bookmark bar and click when you visit coder wall:</p>
<p><a href="javascript:var%20s%20=%20document.createElement('script');s.type='text/javascript';document.body.appendChild(s);s.src='https://raw.github.com/gist/1097639/be7bb1070356d4aa5cf9ec18135cae4b779c9c63/inject.js';void(0);">CoderWall Bookmarklet</a></p>
<p>Enjoy (:</p>
<p><em><strong>UPDATE: </strong>Now, Coderwall has a konami code bundled, so to activate this hack you should perform konamicode + Enter (:</em></p>
CabiNet 0.0.1 Released2011-07-16T00:00:00-03:00https://blog.bltavares.com/2011/07/16/cabinet-0-0-1-released<p>E depois de uma semana bem punk e sem possibilidade nenhuma de codar, consegui pegar o código dos servidores da escola.</p>
<p>Nessa versão temos:</p>
<ul><li>Generate CREATE Query</li>
<li>Persistência dos campos que você definir</li>
<li>MaxLength e NotNull validations</li>
<li>Relationships (simples ainda, nada de queries complexas ainda)</li>
<li>Gerador das classes</li>
<li>e é claro, o CRUD</li>
</ul><p>Quem quiser colaborar e até mesmo testar, fique <a href="https://github.com/bltavares/cabinet">a vontade</a></p>
Primeiro teste do Cabinet na vida real - ou não2011-07-08T00:00:00-03:00https://blog.bltavares.com/2011/07/08/primeiro-teste-do-cabinet-na-vida-real-ou-nao<p>Essa semana deu pra fazer umas coisas legais no Cabinet. Gerar as Create Tables queries e um gerador de classes, mesmo sendo semana de prova.</p>
<p><strong>E colocando o CabiNet em teste</strong></p>
<p>Essa semana tive uma prova prática, envolvendo C# e MySql. Provinha bem fácil, criar uma tabela no banco com 5 campos, criar uma classe relativa a essa tabela, inserir e buscar o registro e ter ao menos um Throw/Catch no aplicativo.</p>
<p>E eu tinha o Cabinet. Ainda em “beta” kkk. Resolvi usar ele, e estava quase tudo na mão. Só tive q modificar um pouco o código dele por causa da visibilidade das minhas classes de exception.</p>
<p>E ele funcionou bem bacana! Hoje até deu para fazer o gerador de classes funcionar antes de ir fazer prova de química.</p>
<p>Até semana que vem, antes das férias, devo conseguir pegar o código fonte dele e levar pra casa</p>
<p><em>(:</em></p>
Yelly Rspec formatter - Now for linux too!2011-07-07T00:00:00-03:00https://blog.bltavares.com/2011/07/07/yelly-rspec-formatter-now-for-linux-too<p>Today I got ath <a href="http://codebrawl.com/">CodeBrawl</a> and really got interest in one of the chalenges.</p>
<p>Reading the Rspec Format chalenge Yelly, The Yellingist Formatter, writen by Chad Humphries<<a href="https://github.com/spicycode">github</a>> got my attention. The only problem is that I don’t code on Mac, so I don’t have the `say` command.</p>
<p>So, I made an improvement to use it under Linux. It requires esound (for sound routing) and festival (for speech synthesis)</p>
<p>On Arch, you can set it up using</p>
<blockquote>
<p># pacman -S esound festival</p>
</blockquote>
<p>And here is the result. You may get it here <<a href="https://gist.github.com/1070850"><a href="https://gist.github.com/1070850">https://gist.github.com/1070850</a></a>></p>
<script src="https://gist.github.com/1070850.js"> </script>
Speech input to Simple_form2011-07-01T00:00:00-03:00https://blog.bltavares.com/2011/07/01/speech-input-to-simple-form<p>Some days before, I’ve implemented a easy way to insert a input speech using Simple_form.</p>
<p>But I’ve gone to specific. So, let’s share how to easily implemente it on your app.</p>
<script src="https://gist.github.com/1059315.js?file=speech_input.rb"></script>
Rails migration and column names2011-07-01T00:00:00-03:00https://blog.bltavares.com/2011/07/01/rails-migration-and-column-names<p>After creating a migration on Rails, I discovered you can’t set a column name as type.</p>
<p><em>It will break.</em></p>
<p>To fix it, pick the number on the begining of the migration file name and run:</p>
<blockquote>
<p>rake db:migrate:down VERSION={the number you found}</p>
</blockquote>
CabiNet e as relationships2011-07-01T00:00:00-03:00https://blog.bltavares.com/2011/07/01/cabinet-e-as-relationships<p>O CabiNet esta ficando bem bacana. Essa semana foi bem produtiva. Inclusive passei um exemplo para dois colegas de sala testarem.</p>
<p>As relationships estão funcionando mais ou menos da forma que eu queria. Quero cachear elas ainda, por causa da performance.</p>
<p>Só que hoje começa a semana de prova. Estou trancado do lado de fora dos meus arquivos pessoas e não posso disponibilizar ele ainda.</p>
<p>Assim que eu tiver acesso aos arquivos, libero no github :)</p>
Tip: Fabricator 1.0 and memoization2011-06-22T00:00:00-03:00https://blog.bltavares.com/2011/06/22/tip-fabricator-1-0-and-memoization<p>Last night I faced a bug on my tests using Fabricator and decided to share it. It took some time to solve a problem using memoizations and Fabricator together.</p>
<p><strong>Some context:</strong></p>
<p>I got users on teams, and teams has many memberships. I wanted to cache the accepted members to improve performace. When I was testing, the cache always returned empty, even changing the name of variables or using diferent techniques to cache.</p>
<p>And I became suprised when I tested it the memoized code on console and it was running perfectly</p>
<p>The fabricator of user is something like that:</p>
<blockquote>
<p>Fabricator(:user) do</p>
<p> name { Faker::Name.name}</p>
<p> email { |person| “#{person.name.parameterize}@example.com” }</p>
<p> password “123”</p>
<p> teams [Fabricate(:team)]</p>
<p>end</p>
</blockquote>
<p>And the Fabricator of Team is:</p>
<blockquote>
<p>Fabricator(:team) do</p>
<p> name { Faker::Name.name }</p>
<p>end</p>
</blockquote>
<p><strong>The problem:</strong></p>
<p>I was using the already created team by the fabricator relationship to create more memberships. But somehow, when I cached things, either using instance variables or ActiveSupport::Memoizeable I always got an empty {}.</p>
<p>So, after turning this:</p>
<blockquote>
<p>@user = Fabricate(:user)</p>
<p>@second_user = Fabricate(:user, teams: [])</p>
<p>@team = @user.teams.first</p>
<p>@team.members « @second_user</p>
</blockquote>
<p>to that:</p>
<blockquote>
<p>@user = Fabricate(:user)</p>
<p>@second_user = Fabricate(:user, teams: [])</p>
<p>@team = @user.teams.create!({ name: “Teste”})</p>
<p>@team.members « @second_user</p>
</blockquote>
<p>things worked like a charm on the tests.</p>
<p>(:</p>
Novidades e dilemas no design do Cabinet 2011-06-22T00:00:00-03:00https://blog.bltavares.com/2011/06/22/novidades-e-dilemas-no-design-do-cabinet<p>Pois é, semana com feriado e menos dias para eu poder mexer no Cabinet. Apenas hoje tive a oportunidade de adicionar novidades e inclusive surgir um dilema.</p>
<p><strong>Surgem relationships</strong></p>
<p>A grande jogada de um framework de banco são as relationships. Elas precisam parecer quase mágicas. </p>
<p>Para ter uma idéia de como está mais ou menos a estrutura, tem esse desenho (Muitas classes de suporte foram retiradas, é apenas para me ajudar a pensar)</p>
<p><img src="http://media.tumblr.com/tumblr_ln7zj5JLBd1qamcq2.jpg"/></p>
<p>Agora é pensar como passar a conexão para a Relationship</p>
<p>(:</p>
E nasce o CabiNet2011-06-17T00:00:00-03:00https://blog.bltavares.com/2011/06/17/e-nasce-o-cabinet<p>Essa semana eu comecei a fazer o framework. E o começo é decidir o nome.<em> CabiNet</em>.</p>
<p>Cabinet é um lugar com Shelfs para guardar Things (Os componentes básicos do sistema). Como não tenho versionamento, resolvi descrever um pouco sobre ele.</p>
<p>Tive cerca de 3 horários (50 minutos cada) para trabalhar nele essa semana. CRUD básico completo. Testei com duas tabelas diferentes e ficou bem legal.</p>
<p>Agora comecei a me concentrar em validar as propriedades. Com mais meio horário consigo terminar alguns casos simples (NotNull e MaxLength)</p>
<p>Quero fazer algumas relationships bem legais semana que vem (:</p>
Desafio do Ano2011-06-16T00:00:00-03:00https://blog.bltavares.com/2011/06/16/desafio-do-ano<p>E semana passada me veio uma ideia. No meio da aula, com o professor começando a explicar como conectar ao MySQL através do ODBC na raça <em>(ic!)</em>, resolvi fazer tudo direito. Diminuir o POG das simples atividades e concentrar em algo interessante e divertido (<em>Tem gente que acha programar divertido, acredite!</em>).</p>
<p>Resolvi montar um Framework.</p>
<p><strong>OHMY! Outro framework? (Justo o que precisavamos)</strong></p>
<p>A ideia não é fazer nada comercial. A ideia não é subistituir o EF nem o NHibernate. É a simples vontade de fazer algo pra passar o tempo nas aulas. Pra me distrair enquanto ouço minha música durante as minhas manhãs.</p>
<p><strong>Objetivos</strong></p>
<p>Passar o tempo fazendo algo interessante. Só isso mesmo.</p>
<p><strong>Mas qual a graça de fazer mais um framework?</strong></p>
<p>Fazer frameworks é normal. Tantas pessoas fazem. Pra ficar bem divertido existem muitas <em>contraints </em>no desenvolvimento.</p>
<ul><li>Ambiente controlado</li>
</ul><p>Estou em um laboratório de informática de uma escola, sem poder instalar nenhum programa nem decidir quais ferramentas usar.</p>
<ul><li>No internet for you</li>
</ul><p>Sem internet. Preciso dizer algo mais?</p>
<ul><li>Sem integração .Net, IDE e banco</li>
</ul><p>Tenho que fazer todos os comandos do banco manualmente. Nada de EF ajudando. Nada de SqlServer integrado com o Visual Studio. Não posso usar outros drivers de conexão de banco. Nada de PostgreSql, No-Sql, Sem-sql…</p>
<p>Somente MySQL e ODBC.</p>
<ul><li>Só posso mexer no código no meu tempo livre (durante as aulas)</li>
</ul><p>Quero usar meu <em>spare time </em>durante as aulas em laboratório para desenvolver. Somente depois da atividade proposta pronta eu posso abrir a solução. Não posso levar nada pra casa. Apenas durante o tempo que estiver dentro da sala.</p>
<p>Então, agora é brincar um pouco. O que será que isso vai dar?</p>