Cairo Noleto

O que eu não curti em go

| Comments

O título desse artigo poderia ser “Minhas impressões sobre go”. Mas não, esse tipo de artigo é fácil encontrar por aí :)

Enfim, das coisas que eu não curti em go, uma delas é a forma como você lida com atribuições de um resultado do banco de dados.

Por exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package main

import (
  "database/sql"
  "errors"
  "fmt"
  _ "github.com/lib/pq"
  "os"
)

type Category struct {
  Id       int64
  Name     string
  ParentId int64
}

const (
  FIND_SQL = `SELECT id, name, parent_id FROM categories WHERE id = $1`
)

func connection() *sql.DB {
  db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
  if err != nil {
      fmt.Println("Error: ", err)
  }
  return db
}

func FindCategory(id int64) (Category, error) {
  db := connection()
  var parentId sql.NullInt64
  category := Category{}

  err := db.QueryRow(FIND_SQL, id).Scan(&category.Id, &category.Name, &parentId)

  if err != nil {
      fmt.Println("Error: ", err)
  }

  if parentId.Valid {
      category.ParentId = parentId.Int64
  }

  switch {
  case err == sql.ErrNoRows:
      return category, errors.New("Record Not Found")
  case err != nil:
      return category, errors.New(err.Error())
  }

  return category, nil
}

func main() {
  category, err := FindCategory(1)

  if err == nil {
      fmt.Println(category)
  }
}

No código acima, no seguinte trecho:

1
2
3
if parentId.Valid {
  category.ParentId = parentId.Int64
}

O que acontece é que após a consulta, eu preciso verificar se o parentId que é retornado na consulta é válido, se ele for, só aí eu atribuo o category.ParentId.

Esse tipo de tratamento, eu não curto.

Infelizmente go tem dessas, várias e várias vezes você precisa fazer esse tipo de verificação para poder continuar.

Uma outra coisa que eu não curto é a organização de arquivos do código em go, saca só:

example

Fica tudo dentro da raiz do projeto, não existe organização por diretórios. Para quem é acostumado com a estrutura de projetos em Rails é um martírio!

Que eu me lembre são esses pontos. Depois eu faço um artigo contando o que eu curto em go que sinto falta em outras linguagens.

RubyConf Brasil 2013

| Comments

Por incrível que pareça, essa foi a minha primeira RubyConf Brasil! O mais engraçado nisso, é que estou na comunidade desde 2009 e nunca tive uma oportunidade de ir.

Nos anos anteriores acompanhei quase tudo pela Eventials, mas esse ano vi ali ao vivo algumas palestras. Algumas porquê tive motivos profissionais que conflitaram com algumas palestras.

Sobre as palestras, não tenho muito o que falar. Elas foram ok, algumas apresentaram alguma coisa nova.

Mas a parte mais importante foram as pessoas. Cada uma das que fizeram esse evento funcionar, as que foram lá prestigiar e esse foi o maior motivo que me fez querer ir para a RubyConf.

Tive oportunidade de rever amigos que há tempos não via, também conheci pessoas com quem trabalhei na minha antiga empresa e conheci pessoalmente aquelas que só conhecemos por avatares!

Não vá para um evento apenas para ver as palestras, vá para conhecer as pessoas, conversar, discutir sobre tecnologia e tudo mais!

P. S. Sempre leve uma roupa de frio pra São Paulo, ela sempre vai ter surpreender :P

PORO - Pure Old Ruby Object

| Comments

Este post foi escrito no README de um projeto depois de um refactoring.

Hoje, no dia 22 de janeiro de 2011, resolvi fazer um refactoring neste código e explicar mais sobre uma dúvida que o dannluciano me perguntou no twitter de como estavamos usando PORO em nossos projetos na Nohup.

Para começarmos, PORO é um acrônimo para Pure Old Object Ruby, que é mais um movimento da comunidade Ruby em trazer de volta aquelas velhas classes puras do Ruby.

E como tudo na comunidade Ruby onde cada movimento vem com uma pitada de amadurecimento, com os POROs não podia ser diferente. Além de resgatar a utilização de classes puras do Ruby, sem ter que herdar (na sua grande maioria do ActiveRecord) de nenhuma outra classe, o uso dos POROs é para poder aplicar os conceitos de SOLID que o Uncle Bob introduziu no desenvolvimento de software e que o Lucas Húngaro explanou muito bem em uma série de blog posts que cobre os 5 princípios de SOLID e de como aplicá-los em Ruby.

O conceito de SOLID mais forte no uso de POROs é o de Single Responsibility, onde cada classe tem apenas uma única responsabilidade. Neste refactoring, a classe Cripto tinha a responsabilidade de criptografar e descriptografar um texto. Só que ele também tinha a responsabilidade de saber o dicionário de criptografia.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Cripto
  # Responsabilidade de criptografar  
  def cripto
    # …
  end

  # Responsabilidade de descriptografar
  def decript
    # …
  end

  # Responsabilidade de saber o dicionário
  def dicionario
    # …
  end
end

Fonte: 79236001445a2e04312825668f99114d80d849f1

Meu refactoring nesta classe foi em retirar o dicionário da classe Cripto e de usar outro princípio do SOLID, que é o de Dependecy Inversion, para preparar a classe Cripto a aceitar qualquer objeto que respondam a Object#[] e Object#key.

Neste caso então eu posso utilizar a class Hash, que implementa esses métodos, ou qualquer outra classe que eu possa criar e no caso eu criei a classe Dictionary.

E a implementação final da classe Cripto ficou da sequinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Cripto
  attr_accessor :dictionary

  def initialize(dictionary)
    self.dictionary = dictionary
  end

  def encrypt(text)
    process(:[], text)
  end

  def decrypt(text)
    process(:key, text)
  end

  private

  def process(method, text)
    processed_text = ""
    text.each_char do |ch|
      processed_text << (dictionary.send(method, ch) || ch)
    end
    processed_text
  end
end

Fonte: dfeecf4c00590b027017514723329562a46fa9d0

Aplicando esses conceitos em uma aplicação Rails

Eu falei antes que na Nohup nós não estamos utilizando callbacks, assim como reuniões, callbacks são tóxicos! No lugar deles, estamos usando POROs com a responsabilidade de fazer o que seria feito pelo callback e chamando nas actions onde eles seriam executados.

Uma coisa bastante comum em aplicações Rails é a geração de slugs. A regra mais comum para geração do slug é de sempre que o nome do usuário for passado pelo formulário para ser alterado, ele deve gerar um novo slug. A implementação mais comum é:

1
2
3
4
5
6
7
8
9
class User < ActiveRecord::Base
  before_save :slugify

  private

  def slugify
    self.slug = name.parameterize.to_s
  end
end

Essa abordagem fere um dos princípios que comentei anteriormente. A classe User deixa de ter somente a responsabilidade de lidar com os dados e adiciona a responsabilidade de gerar o slug sempre que o usuário for salvo.

A primeira coisa que fazemos nesse caso é extrair nossa regra de negócio para um PORO. Poderíamos fazer da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
  class SlugGenerator
    attr_accessor :slug

    def initialize(slug)
      self.slug = slug
    end

    def slugify!
      slug.parameterize.to_s
    end
  end

Então para finalizar, essa regra de negócio deve sempre ser executada quando o usuário for criado ou quando for atualizado, então nós alteramos o controller de users:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class UsersController < ActionController::Base
  def create
    @user = User.new(params[:user])

    @user.slug = SlugGenerator.new(@user.name).slugify!

    # …
  end

  def update
    @user = User.find(params[:id])

    @user.slug = SlugGenerator.new(@user.name).slugify!

    # …
  end
end

: Em muitos lugares diferentes da aplicação nós podemos salvar esse objeto e não necessariamente nós precisamos aplicar a regra de gerar um novo slug. O que geralmente acontece é que no uso de callbacks, você acaba tendo comportamentos inesperados na hora de salvar um objeto.

Daí na Nohup nós acabamos criando uma convenção, onde uma regra de negócio não deve ficar no model e sim em um PORO e que só deve ser executado nas actions que tem necessidade.

E ficamos com uma estrutura de diretórios assim:

app

Obviamente, dentro do diretório business estão todos os POROs com todas as regras de negócio da aplicação. Nossos models são bem simples, contendo apenas a lógica para lidar com os dados (validações, escopos de busca, etc) e toda as regras de negócio ficam dentro de business.

Espero que isso ajude a você a repensar melhor no design da sua aplicação.

Realmente existe diferença entre TDD e BDD?

| Comments

Recebi um comentário do Cândido Sales que me fez reler um texto meu antigo sobre a diferença entre TDD e BDD. Achei legal, interessante, mas vale a pena escrever mais um “dedinho” de palavras e incluir agora minha experiência de se usar TDD/BDD por algum tempo (Uns 2 anos, mais ou menos)!

Depois de toda a experiência que tenho hoje com desenvolvimento orientado a testes/comportamento vejo que não existe muita diferença entre as técnicas. Acredito, como já acreditava, que BDD faz parte da evolução de quem começa a praticar TDD.

Mas a parte mais importante, é que no final, essas duas técnicas não são apenas para testar a sua aplicação. Hoje considero que mais importante do que testar a aplicação é:

  • Fazer um design consciente da sua aplicação;
  • Melhorar a manutenção com a facilidade de se fazer refactoring! (Refactoring sem testes não é refactoring).

Design consciente:

Quando vamos desenvolver algum código, não temos ainda uma opinião forte de como deve ser esse novo código. Então praticamente não sabemos ainda nomes de classe, métodos, rotinas…

Então TDD/BDD entra para nos ajudar a modelar no inicio do desenvolvimento de nossa API. Se você considerar o desenvolvimento em baby steps, então teremos uma API que evolua naturalmente conforme nossa aplicação vai crescendo. E a base dessa evolução são os testes que criamos antes e que nos dá segurança no desenvolvimento.

Refactoring:

Refactoring é rescrever nossa API de forma mais simplificada e que os testes continuem passando e devemos evoluir nossos testes para acompanhar essa simplificação. Sem os testes não temos como garantir que essas alterações que visam simplificar o código continuem funcionando, por isso refactoring sem testes não é refactoring.

Conclusão

Hoje considero TDD e BDD como duas formas diferentes de design da aplicação e que você realmente deve estuda-lás (Ou escolher uma :P) e melhorar o design do seu código.

Não vejo muitas diferenças em se utilizar TDD ou BDD e que vai mais da escolha pessoal do programador ou da sua equipe. E que o mais importante, é que se você está usando alguma dessas técnicas, então isso demonstra que você já tem uma preocupação com a qualidade do código que você escreve.

Proc e lambda

| Comments

Você já deve ter ouvido que tudo em Ruby é objeto. Sim, sim, tudo é objeto. Menos blocos.

Blocos não são objetos. Mas existe duas formas de transformar blocos em objetos. Uma é usar Proc e a outra é usa lamda.

Para se criar um Proc existem algumas formas, a mais simples e mais utilizada é:

1
2
3
proc = Proc.new do |object|
  puts object.inspect
end

Depois que você criar o seu Proc, para chamar o bloco que você acabou de criar, você deve utilizar o método call:

proc.call Object

O método call é chamado para executar o bloco. Em blocos, vocês podem fazer o que quiser. Um caso interessante é para processamento sequencial. No rails é bastante utilizado na definição de named scopes.

Outra forma de fazer blocos virarem objetos é utilizar o lambda:

1
2
3
lambda = lambda do |object|
  puts object.inspect
end

Basicamente, Proc e lambda funcionam da mesma forma. Mas existe uma diferença, que é no caso de se utilizar controles de fluxo, no caso return, break, redo, retry e vários outros.

O problema nesse caso é que esses controles de fluxo quebram quando você está utilizando Proc.

Leia antes de lançar um produto

| Comments

Qual a sua definição de um bom produto? Ele tem que ser funcional?! Ele tem que ser útil?! Ou ele tem que despertar em você uma necessidade?

Todos falam sobre os produtos da Apple, sobre como o Steve Jobs consegue criar a necessidade e como todos acabam comprando (Eu sou um deles!).

Não importa o quanto revolucionário é o seu produto. Se ele não despertar a necessidade nos seus clientes, você não irá fazer sucesso. E a melhor maneira de despertar a necessidade é criando um fucking awesome produto!

Uau! Você chegou até aqui e com certeza nada do que você leu é novidade. Estou apenas pensando sobre um assunto que sempre é recorrente, principalmente se você é empreendedor.

Se você está fazendo um produto agora, que lançou um produto ou que ainda vai lançar um novo produto nunca esqueça de que antes da arquitetura da sua aplicação ou o quão rápido ela deve ser, o mais importante é que ela seja espetacularmente lindo e que tenha a melhor usabilidade ever.

Ruby Masters Conf

| Comments

Eis que mais uma vez a e-Genial surpreende anunciando o Ruby Masters Conf, que é uma maratona de palestras com os maiores feras de Ruby do Brasil e ainda com convidados internacionais!

A e-Genial é conhecida no Brasil pela excelência dos seus cursos (Já ministrei um por lá \o/) e também conhecida por ter uma das melhores plataformas de ensino a distância do país, o TreinaTom.

O evento vai ser todo através do TreinaTom, com a possibilidade de você conhecer muita gente boa e no final poder ter as palestras sempre que você quiser, tudo vai ser gravado e disponibilizado para quem se inscrever!

O Ruby Masters Conf é um evento para espalhar conhecimento e ajudar projetos OpenSource. Foi escolhidos dois projetos, o RubyInstaller, para quem usa windows, e o Passenger, dos carinhas da Phusion.

O RubyInstaller é um binário executável que faz todo o processo de instalação do Ruby no Windows. É bastante usado pelos alunos da e-Genial nos cursos de Rails ministrado pelo Daniel Lopes.

Já o Passenger é usado na hora de colocar sua aplicação em produção por quase todos os grandes players do Brasil e do Mundo.

Esses dois projetos são muito importantes, o primeiro por permitir que a simplicidade do Ruby chegue na complexidade que é o Windows e com todas aquelas telas azuis, e o segundo por fazer o deployment de aplicações Ruby (Só precisa ser Rack!) ser mais simples como é muito coisa no Ruby!

Eu já estou divulgando por aqui e nos vemos no Ruby Masters Conf!

:D

Meu ambiente de desenvolvimento em 7 itens

| Comments

Fui convidado pelo @danillos para descrever mais sobre o meu ambiente de trabalho :)

1. Sistema operacional

Mac OS X e Ubuntu.

E já estou indo para o meu terceiro ano com Mac OS, simplesmente fantástico, não só pelo software, mas pelo casamento com o hardware. E o Ubuntu ainda tenho em um desktop que as vezes eu utilizo no Jusplex, sinceramente não muito, mas uso.

2. Terminal

Indispensável. Abre junto com a inicialização do sistema operacional e continua até ser desligado.

3. Git

Se você ainda não usa nenhum tipo de controle de versão, você merece ser marcado com brasa quente! Não passe pelo mesmo problema que o Jonny Ken teve nesse ano de 2010.

4. TDD/BDD

“Test all the f*cking time” é um “vício” que surgiu na comunidade Ruby e quando você vai pra outra linguagem percebe o quanto isso é importante no dia a dia em desenvolvimento.

5. Editor de texto

Vim/TextMate. Atualmente entrei na modinha do vim, então resolvi dar o braço a torcer por ele e ele é realmente legal (E funciona da mesma forma no Linux e no Mac OS X). O TextMate consegue ser a killer app de editores no Mac OS X, fantástico!

Se você precisar mais do que isso, você é um Javeiro que só consegue fazer as coisas usando o Eclipse! :trollface:

6. Google Chrome

Preciso de memória, eu sempre estou com um monte de coisa aberto, e sempre tem uma aba no Gmail, que pesa muito depois de muito tempo aberto.

Testei todos os browsers suportados no Mac OS X, e o que me deu a melhor resposta foi o Google Chrome.

Funciona sobre o WebKit, existe uma boa ferramenta para desenvolvimento e recentemente abriu a app store.

7. Água

Combustível diário para desenvolvimento. Sem água nada funciona.

Para continuar a série eu convido o Daniel Lopes, o Vedovelli e o Cássio Marques!

Extraindo informações usando Ruby

| Comments

Hoje lancei uma aplicação que faz a análise dos palpites de um bolão (O bolão da Marko Informática) e mostra um gráfico com a quantidade de palpites por placa em um determinado jogo.

Para extrair essas informações eu não precisei acessar o banco de dados. Apenas consumi o que todos já podem ver, como por exemplo este link.

Essa brincadeira de extrair essas informações do bolão da Marko Informática começou com uma dúvida da minha esposa se tinha condição de ver no site os palpites dos outros participantes. Em menos de cinco minutos depois eu vi que tinha a possibilidade de ver essa informação, mas que infelizmente para mim é irrelevante.

Essa informação é desorganizada e não vai me ajudar a tomar uma decisão quanto aos meus palpites. Para mim é mais importante ter esses dados sumarizados de forma que eu não perca tempo analisando todos os palpites, um por um. Então, organizar a informação para que eu saiba quantos apostaram em 2x1 é mais interessante do que ter que contabilizar isso manualmente.

Para fazer isso em ruby eu utilizo a gem nokogiri, que faz justamente a análise e busca em html/xml. Com ela eu posso facilmente consumir o conteúdo de uma página e extrair os dados que realmente importa.

Nada muito complexo de se aprender, como você pode ver aqui.

Eu pensei em fazer usando o Rails 3, mas depois de fazer o primeiro protótipo, vi que não seria necessária algo tão grande, então tirei o Rails e coloquei o Sinatra.

Para montar o gráfico eu perguntei no Twitter quem indicaria bibliotecas js que fizessem Chart. Depois de olhar todas, a do Google Charts foi a que eu achei mais simples e sem burocracia para colocar no site.

E por fim, para fazer deploy da aplicação eu usei o Heroku, que é um serviço Cloud para aplicações em Ruby.

Trabalhando com datas naturalmente com Chronic

| Comments

Esta semana passei gastando um tempão implementando um Parser que me retornaria um dia em que um evento ocorre em uma determinada data.

Mas a data seria algo “Quero trazer todos os usuários que se cadastraram na terceira terça feira do mês de janeiro”. A forma que eu estava implementando não era assim tão segura, apesar de todos os testes estarem passando.

Então hoje eu encontro o Chronic. É uma gem ruby que faz justamente o que eu precisava:

1
2
irb(main):005:00> Chronic.parse("3rd tuesday in january", :context => :past)
=> Tue Jan 19 12:00:00 -0300 2010

Simples e rápido.