Experiências com o Atom

Para adicionar um pouco de fogo na velha “editor wars”, eu resolvi testar o SublimeText, Zed, e o Atom.

Antes, um disclaimer: eu sou um usuário VIM. Não um super usuário VIM – eu, por exemplo, uso as setas para navegar dentro de um arquivo (oh, o horror!), uso poucos plugins, enfim. Aí resolvi testar o SublimeText, e achei ele fantástico – rápido, estável, e funciona bem. Só tem um problema: 70 dólares.

Eu acho válido pagar por algo que você vai usar todos os dias. Mas 70 dólares é 1/3 de um Office. Já que eu tinha alternativas, resolvi testar o Atom. Antes disso, eu tinha feito um plugin para o Sublime, para rodar coisas pelo TMUX, e resolvi portar o mesmo aplicativo para o Atom, como um exemplo.

O Atom usa tecnologias web – HTML + CSS + JS + Node.JS para funcionar. Basicamente, plugins (e customizações do Atom) são escritos em Coffeescript ou Javascript, usando Node.JS, toda a interface do Atom, incluindo menus, abas, telas, são feitas usando HTML + CSS, você pode re-estilizar a tela toda usando LESS ou CSS, e os arquivos de config são em CSON ou JSON. O ponto negativo disso é que basicamente o Atom consome tanto de memória como o Chrome / Chromium, já que na verdade, ele basicamente É a mesma coisa – um browser rodando uma página. Há muitas vantagens na abordagem do Atom – a tela inteira do seu editor é customizável.

O veredicto final eu achei bom: eu acabei gostando do Atom. Ele é um pouco mais lento do que eu gostaria, e consome uns 300 – 400mb de memória na minha máquina (o que é bem ruim na verdade para pessoas que tem máquinas com pouca RAM) . Outra coisa que é perceptível é a facilidade de se fazer plugins (há um “scaffolding” de plugins no Atom) e quão fácil é integrar dependências externas, testes dos próprios plugins, etc. O ponto baixo sempre será o consumo de memória e de disco, que o Atom simplesmente precisa melhorar – e muito.

Sobre cada um dos detalhes:

(more…)

“Copiando” um Linux

Esses dias, um amigo meu comprou um SSD para o notebook dele, e queria copiar o Linux dele para o SSD. O detalhe, ele não queria instalar o linux novamente, e queria manter o diretório /home dele no HD antigo. Depois de fazer o processo, resolvemos que seria uma boa idéia postar sobre como fazer isso.

Inicialmente, é importante falar (para quem não conhece direito) que o Linux tem uma estrutura de diretórios bem peculiar. Todos os dados pessoais estão apenas no diretório /home, as informações de boot estão no diretório /boot, e outras informações estão em outros lugares. Logo, tudo o que se precisa fazer é mover os diretórios para o novo HD (no caso, o SSD) e deixar o diretório /home no HD antigo. Mas tem um pouco mais do que isso.

(more…)

Como Comprar um Notebook

O post de hoje será mais uma conversa sobre a experiência de ter comprado um computador novo do que um post técnico mesmo.

Hoje em dia, não é mais fácil descobrir a velocidade de um processador somente olhando para o nome ou as especificações dele. Da mesma forma,  temos diversos fatores que devem ser pensados na compra de uma máquina seja para trabalho, jogos, ou simplesmente para uso no dia a dia. Comecemos então com as marcas:

Em primeiro lugar, é bem difícil identificar se um computador é bom ou não apenas por fotos ou pessoalmente: isso deve ser um trabalho de pesquisa, muitas vezes intensa. Quando estamos pesquisando, é comum pensarmos em marcas como HP, Dell, ou semelhantes como idéia de “marcas confiáveis”. Às vezes, erramos feio usando esse pensamento. Então, vamos pensar de outra forma: para que será usada a máquina?
(more…)

Evitando o null-driven-development

Quando a programação em C estava em alta, havia uma série de alocações e liberações de memória. Depois disso, a alocação/liberação passou para C++, e a partir daí tínhamos código como o seguinte:

Person *person = new Person();
delete person;

Algumas vezes, queríamos criar um objeto mas não tínhamos todas as informações dele. Era comum usarmos o ponteiro e só atribuir ele quando tivessemos a informação:

Person *person = null;
//do something in-between
person = new Person(name);

Isso causava um efeito estranho que, eventualmente, o objeto seria “nulo”, ou “não existente”. Isso era uma novidade até o momento, já que nas linguagens mais antigas (VB, QuickBasic, Pascal, etc) ou não havia esse conceito de “nulo” ou não era comum usar.

Quando as linguagens orientadas a objeto dominaram o mercado, esse “null-pattern” acabou também entrando no mercado. Em Java (e Scala), por exemplo, qualquer operação que envolva um null lança um “Null-pointer exception” (que muitos programadores simplesmente capturam com um try-catch, mandam imprimir no console o stacktrace, e continuam o programa, que normalmente para de funcionar). Em Ruby, as coisas são mais complexas…

Ruby é a primeira linguagem que eu conheço que meio que “institucionalizou” o uso de nulos.
(more…)

SQL Orientado a Objetos

O nome parece estranho, mas um ORM, dependendo de como ele for implementado, pode ser usado exatamente para isso.

Estou trabalhando numa lib em Scala chamada relational, na qual eu pretendo fazer um SQL inteiro virar um objeto Scala. Mais ou menos o que o Arel tenta fazer, porém de forma esquisita (meio compatível com Rails, meio compatível com álgebra relacional, e não 100% nada). Mas isso fica pra um outro momento…

No post anterior, eu falei bastante sobre SQL, e sobre todas as coisas que podemos fazer ao saber montar uma query. A idéia agora é tentar montar, de fato, uma query, mas com mais do que apenas fragmentos SQL, mas com o próprio ORM.

Vamos pensar que temos uma tabela de usuários, e uma de números de telefones. O número pertence a um usuário, um usuário tem muitos números de telefone (nada de “join-tables” e coisas mais complexas por agora). Digamos que eu queira saber números de telefone possuem o mesmo prefixo (os primeiros quatro números-vamos ignorar, por hora, os nono dígito para deixar o código mais fácil) de um determinado número.

A idéia, num primeiro momento, é fazer o código para um único número. Vamos, por simplicidade, deixar isso na classe de Telephone mesmo:

class User < ActiveRecord::Base
  has_many :telephones
end

class Telephone < ActiveRecord::Base
  belongs_to :user
  
  def self.same_prefix_of(telephone)
    where('SUBSTR(telephones.number, 0, 5) = ?', telephone.number[0...4])
  end
end

#Para usar:
Telephone.same_prefix_of(Telephone.first)

Por hora, tudo bem. Um código simples, porém é agora que a coisa começa a ficar divertida: generalização
(more…)

Programadores Precisam Aprender SQL!

De uns tempos para cá, tenho vistos muitos códigos bizarros acontecendo no mundo dos ORMs, que eventualmente me deixaram pensando: será que ORMs estão fazendo-nos esquecer como se faz SQLs?

No mundo Ruby/Rails, virou quase uma regra não-escrita que escrever SQLs na mão é errado. Quanto mais pudermos aproveitar o ActiveRecord (e algumas mágicas que ele faz por nós), melhor. Isso acaba trazendo algumas coisas bem esquisitas, tal como achar que 90% dos códigos nunca vão precisar de “OR” (e maior, menor, diferente, etc), já que a API do ActiveRecord não suporta isso, ou algumas outras práticas meio estranhas. Do outro lado, temos por exemplo o framework “Play!”, de Scala, que faz o extremo oposto: não usa nenhum ORM, e todas as queries SQL passam a ser feitas na mão…

O ponto é que quando temos um ORM, parece que abusamos dele e esquecemos que nem tudo é um “SELECT * FROM <table> WHERE <attribute> = <value>”. Por exemplo, no código abaixo:

users = User.all
users.each do |user|
  puts &quot;User #{user.name} has #{user.addresses.count} addresses&quot;
end

Temos o famoso caso do “N+1”: 1 busca para achar N usuários, e a partir daí “N” buscas para achar a contagem de endereços. O problema é que muita gente acha que apenas um “User.include(:addresses)” resolve o problema, quando na verdade não resolve: o “include” vai trazer todos os endereços, mas a contagem (se o Rails optar por usar “count”) vai continuar sendo feita em banco, ou então (se o Rails optar por não usar “count”) será feita em Ruby, e teremos trazido registros a mais do banco de dados sem necessidade. A solução, nesse caso, é usar um comando SQL mesmo:

users = User.all
num_addresses = Address.join(:user).group('user.id').count
users.each do |user|
  puts &quot;User #{user.name} has #{num_addresses[user.id]} addresses&quot;
end

Ok, mas SQL é difícil, chato, e é mais fácil fazer as coisas em Ruby, certo? Bom, sim e não. É mais fácil fazer os comandos em Ruby (ou na linguagem que você escolher) puramente por “costume”. Estamos acostumados a fazer a sequencia: buscamos uma lista, tratamos a lista, exibimos a lista. SQL não trabalha com “listas”, mas com “conjuntos”. E é isso que vamos ver a seguir:
(more…)

Resourceful Web

Todos sabem que, com o tempo, os frameworks web evoluem. Porém, o que poucas pessoas percebem é que além das mudanças nas APIs e na estrutura dos programas feitos com o framework, há uma mudança também nas idéias dos desenvolvedores e até mesmo nas metáforas que o sistema usou para definir-se. E o Rails não é exceção.

Por exemplo, no Ruby on Rails versão 1.x, a idéia do framework era a construção de aplicações web. Para tal, a idéia era que a aplicação fosse simples e divertida de desenvolver. Além disso, havia a idéia de web-services, XML-RPC e SOAP que nunca pegaram direito no mundo Rails (mas que estavam presentes na versão 1.x). Depois, na versão 2.x, surgiu o conceito de RESTful (em contraponto aos web-services do Rails 1) e, junto com ele, o conceito de “resource” ou “recurso”. Já no Rails 3, surgiu a idéia de separar o Javascript do HTML usando o conceito de Unobtrusive Javascript (Javascript não-intrusivo), e junto com essa idéia, veio a substituição do prototype pelo jQuery (que torna certas operações envolvendo AJAX mais fáceis). Junto também com a substituição por jQuery, o scaffold passou a fazer os controllers responderem por HTML e JSON, ao invés de HTML e XML como no rails 2.x.

E é essa a mudança mais importante.

Vamos começar pensando: qual seria o motivo de renderizar um JSON? A resposta é simples: JSON é mais fácil de ser entendido pelo browser, por Javascript, e por aplicativos de terceiros tais como em iOS ou Android. Antes, responder por XML não tinha aplicação real nenhuma nos próprios aplicativos Rails, e ficavam apenas como forma de comunicação com sistemas de terceiros (o velho “big design up front“) que nem sempre ocorriam. E hoje, renderizar JSON está muito pouco utilizado mesmo no mundo Rails, e há um motivo para isso:

Não sabemos o que é um “resource”.
(more…)

Redes Neurais – Parte 3

Ok, vamos finalmente para a terceira parte sobre Redes Neurais (e também, aonde será apresentado o código completo de uma rede neural em Ruby). Este post será sobre treinamento de redes neurais, especificamente sobre o treinamento dos pesos que saem dos neurônios de entrada e vão para os neurônios ocultos da rede. Antes de mais nada, vamos relembrar nosso desenho da rede neural:

Neural

Já vimos no post anterior que para achar o valor que MAXIMIZA a função de custo, usamos o métoodo chamado de “gradiente”. O método “gradiente” usa derivadas parciais, e como vamos achar o valor de um peso que sai do neurônio de entrada para o neurônio da camada oculta, precisamos calcular a derivada parcial da função de custo em relação a um destes pesos. Vamos usar o “peso_a1_b2” para este exemplo.

Antes de mais nada, vamos relembrar todas as contas que fazemos para nossa rede neural. Para tal, eu vou usar a notação “peso_ax_by” para indicar o peso que sai do neurônio “ax” e vai para o neurônio “by”. Note que NÃO EXISTE “peso_a1_b1”, porque o neurônio “b1” é o “bias”, logo o valor dele é sempre “1” (e não faria sentido calcular um valor se ele vai descartá-lo e usar “1”, no fim das contas). Sabemos que o valor de um neurônio oculto é a soma de todos os valores dos neurônios de entrada (multiplicados por seus devidos pesos) e aplicadas uma “função de ativação” (que no nosso caso, é a “Tangente Hiperbólica”). Eu vou chamar de “b_sem_ativacao_x” o valor desta soma dos neurônios de entrada, ANTES de se aplicar a função de ativação. Logo, nossas contas são:

b\_antes\_ativacao\_2 = a1 * peso\_a1\_b2 + a2 * peso\_a2\_b2 + a3 * peso\_a3\_b2 \\  b\_antes\_ativacao\_3 = a1 * peso\_a1\_b3 + a2 * peso\_a2\_b3 + a3 * peso\_a3\_b3 \\  b\_antes\_ativacao\_4 = a1 * peso\_a1\_b4 + a2 * peso\_a2\_b4 + a3 * peso\_a3\_b4 \\  \\  b2 = tanh(b\_antes\_ativacao\_2) \\  b3 = tanh(b\_antes\_ativacao\_3) \\  b4 = tanh(b\_antes\_ativacao\_4) \\  \\  c1 = b1 * peso\_b1\_c1 + b2 * peso\_b2\_c1 + b3 * peso\_b3\_c1 + b4 * peso\_b4\_c1 \\  c2 = b1 * peso\_b1\_c2 + b2 * peso\_b2\_c2 + b3 * peso\_b3\_c2 + b4 * peso\_b4\_c2 \\  \\  custo = \frac{1}{2 * N} * \sum\limits_{n=1}^N \sum\limits_{i=1}^2 (ci(do\ exemplo\ n) - yi(do\ exemplo\ n)) ^ 2
(more…)

Redes Neurais – Parte 2

No post anterior, vimos como montar a estrutura de uma rede neural. Neste post, veremos como fazer o treinamento dos pesos, para que a rede generalize nossos exemplos de teste e seja capaz de classificar exemplos que ainda não foram vistos. Num primeiro momento, vamos relembrar o desenho de uma rede neural:

Neural

Para facilitar, deixei um nome para cada neurônio (nota: provavelmente vocês não vão encontrar essa forma de nomear os neurônios em lugar algum-eu coloquei essa nomenclatura mais para facilitar o post do que para ser uma abordagem matemática mesmo). Os neurônios “a1” e “b1” são “bias”, conforme vimos no post anterior, e os neurônios “c1” e “c2” são os neurônios de saída. Note que este desenho de rede neural não representa nossa rede neural, pois nossa rede neural precisaria de 5 neurônios de entrada e 3 de saída. Bom, conforme vimos no post anterior, num primeiro momento os pesos sinápticos (as linhas ligando os neurônios, representadas pelas matrizes “input_weights” e “hidden_weights” no post anterior) são aleatórios, o que significa que a rede possuirá comportamento aleatório. A partir deste ponto, temos que alterar os pesos para tentar chegar num resultado melhor da rede. Para tal, precisamos de uma função que nos mostre quão bom é a solução atual: uma “função de custo”.
(more…)