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…)

Unobtrusive Javascript

Um monte de gente tem falado sobre Unobtrusive Javascript (ou UJS, para simplificar), mas há poucos que mencionam COMO fazer. Da mesma forma, o próprio Rails parece não ser muito decidido às melhores práticas (o que, sinceramente, é uma pena dada a idéia original do Rails de facilitar o desenvolvimento web). Aliás, talvez algumas mudanças do Rails valeriam para outro post, mas por hora, vamos para UJS.

A idéia do UJS, basicamente, é não misturar Javascript com HTML nas views. O que, sinceramente, é uma ótima idéia ao meu ver. O problema é como fazer isso de forma não-traumática. Para este exemplo, vamos ver inicialmente qual era a abordagem que eu usei, no passado, sobre UJS:

Antes, eu usava algum helper do Rails e criava as tags tipo <a href="algumaUrl" data-remote="true>, e no controller eu pedia para renderizar um template .js.erb. Isso trazia diversos problemas, por exemplo:

$('div').html(&quot;&lt;%= @user.name %&gt;&quot;);

Mas se o usuário tiver espaços no nome, precisaremos de "escape_javascript"… e aí começam alguns antipatterns (imagine HTML+ERB, mas dessa vez com todos os problemas de Javascript incorporados).

O ideal, e algo que tanto o Twitter como outros serviços web estão fazendo, é manter uma API web que renderiza os dados, e seu ambiente web nada mais é do que uma interface que consome esses dados (e renderiza algo na tela). Para esse exemplo, só vou usar jQuery e nada de Rails/Ruby/Whatever…
(more…)

Testes de Controller – a Saga

Semana passada comecei finalmente um projeto do zero usando Rails 3.1. A experiência foi novidade para mim, que por causa de uma série de legados (e também por questão de performance) estava preso no Rails 2.3, e não tive a oportunidade de ver como os testes funcionam no Rails 3.

Mas antes de chegar no assunto, vamos rever que o Rails não é puramente MVC. O “Controller” do Rails agrega coisas que deveriam ser feitas na view (basicamente, buscar o objeto para ser exibido). Para mais detalhes, ver meu post anterior.

Por esse motivo, e unicamente por este motivo, eu não acredito ser possível fazer teste unitários de controllers.

Um teste unitário deve, em teoria, testar um pedaço do sistema, isoladamente de outras partes. Como fazer um teste unitário de algo que é, essencialmente, um “glue code”, ou seja, um código que une regras de negócio (Models) e interfaces (Views)?

Antes do Rails 3, eu usava uma abordagem mais “integrada” para esses specs. No controller, eu usava a palavra-chave do rspec-rails “integrate_views”, e testava o par “controller-view”. Os specs ficavam mais ou menos assim:

describe PeopleController do
  integrate_views
  
  it 'should show people on &quot;index&quot;' do
    sessions[:user_id] = Factory(:user).id
    Factory :person, :name =&gt; &quot;Foo Bar Baz&quot;
    get :index
    response.should be_success
    response.body.should include(&quot;Foo Bar Baz&quot;)
  end
  
  it 'should render &quot;new&quot; view if validation failed&quot; do
    sessions[:user_id] = Factory(:user).id
    post :create, :person =&gt; { }
    response.should render_template(&quot;new&quot;)
  end
end

Claramente, isso não é um teste unitário, mas há um grande ganho nessa abordagem: se eu resolver mudar a variável “@users” para “@records”, e atualizar a view, não preciso mexer em nenhum spec. Na prática mesmo, eu não preciso mexer em nenhum SPEC se eu mudar o layout, adicionar mais informações na view, buscar mais registros no controller e atualizá-los na view, enfim, em qualquer momento eu sei, exatamente, se o teste está falhando ou passando, sem as fragilidades que mocks podem oferecer.
(more…)

Model View Controller

Ultimamente, Rails tem se popularizado, e com ele o famoso (e já antigo) MVC. Porém, como todas as coisas, a prática acabou sobrepondo a teoria, então achei que seria interessante falar um pouco sobre MVC, já que parece-me que algumas confusões começaram a acontecer. Esse post é imensamente baseado nesse post do Martin Fowler sobre arquiteturas GUI, então seria interessante ler ele também.

Enfim, vamos lá: no Rails, quando fazemos um “scaffold”, é criada uma combinação de coisas para nós: uma “migration”, que cria uma tabela no banco. Um “model”, que basicamente é o mapeamento dessa tabela para um objeto. Um “controller”, que faz a busca do registro certo e repassa para a renderização da tela. Por exemplo, a ação “edit”:

  def edit
    @foo = Foo.find(params[:id])
    render :action =&gt; 'edit' #Isso é redundante, mas deixa explícito um aspecto importante.
  end

Além disso, há uma série de boas-práticas, tais como não concentrar código de regra de negócio no controller, não colocar lógica nas views, enfim. Porém, essas “regra gerais” pecam em um ponto:

Rails não é 100% MVC…
(more…)

Ensaio Sobre Graduação

Depois de assistir a palestra do Tenderlove no RubyConfBR (e ficar impressionado porque estava estudando EXATAMENTE os assuntos de Automatos há pouco tempo atrás), vi uns tweets sobre graduação. Na verdade, foi principalmente o tweet do @dannluciano que trouxe uma série de respostas de outros tweets que eu concordo até certo ponto, e discordo de muitos outros pontos.

Proponho uma pergunta: qual é a idéia da graduação, nos tempos como hoje? Explicando, em tempos de Wikipedia, de Google, aonde entra uma graduação? Acho que aqui, temos que separar duas coisas: Faculdade, Universidade, e Colegial Técnico.

Pra maior parte das pessoas (e infelizmente, para nosso país e o mercado de trabalho e governo dele), a graduação é um “upgrade” da formação média, e o “colegial técnico” fica meio perdido nesse meio do caminho… além disso, muitos professores (e infelizmente eu conheço isso, tendo trabalhado numa universidade federal) ainda acham, nos dias da Wikipedia, que são donos do conhecimento, e ninguém chega ao conhecimento sem o intermédio deles.

Os que me acompanham no Twitter devem ter visto que eu prestei o Poscomp. Num dos livros que peguei, havia a seguinte frase:

Função injetora é aquela que, para dois elementos distintos a, a’ ∈ A, f(a) ≠ f(a’)

Uhn… então, eu resolvi ir para a Wikipedia:

Uma função diz-se injectiva (ou injetora) se e somente se quaisquer que sejam x1 e x2 pertencentes ao domínio da função, se x1 é diferente de x2 implica que f(x1) é diferente de f(x2)

Há um “Link” para “domínio”, e há um gráfico mostrando graficamente essa explicação. Não precisa ser um gênio para entender que a explicação da Wikipedia está mais simples e melhor explicada e exemplificada. Ok. Mas, e isso é importante notar, eu não chegaria ao artigo da Wikipedia sem o livro, sem o poscomp, e não teria entendido a palestra do Tenderlove sem ter estudado para o Poscomp (ainda que eu tenha usado os livros como “grandes índices” e a Wikipedia como forma de aprender, propriamente dita).
(more…)

Sou um Anti-Identação

O título desse post parece estranho, mas vamos lá. De fato, eu sou um anti-identação, não gosto de ver meu código identado.

Não estou dizendo que eu não idento meu código-longe disso. Apenas que eu prefiro evitar a identação sempre que for possível. Mas vamos por partes…

Primeira coisa, isso começou há algum tempo quando uma pessoa propôs o seguinte problema: montar uma lista encadeada (Linked List) com as seguintes regras:

1) A lista deve validar se ela está vazia, e lançar um erro caso tente-se retirar um item da lista vazia
2) Cada método pode ter, no máximo, uma linha
3) Não se pode usar “if” em momento algum

Claro que é uma bela loucura, mas depois que eu consegui resolver esse código, pensei: se eu consegui resolver um problema desses com apenas uma linha por método, será que meus códigos não tem coisa demais?

Aí, comecei a experimentar isso em código de produção. Isso meio que criou um estilo de codificar bem interessante, e vou tentar mostrar aqui com alguns exemplos:
(more…)

Orientado a Objetos versus Funcional

Bom, esses dias estava estudando Scala. Uma linguagem multi-paradigma, mas que parece mais “funcional” do que “imperativa”. Scala cai numa posição ainda nebulosa para a maior parte das pessoas (e acho até que para o mercado também). Afinal, imutabilidade é “programação funcional”? Scala não faz nada que impede “side-effects” no código, como Haskell por exemplo, então ela é funcional mesmo?

Como mesmo eu não tenho muitos conhecimentos em linguagens funcionais, resolvi propor um problema para mim mesmo: implementar uma árvore binária em Ruby, e depois portá-la para Scala, tentar uma abordagem imutável em Scala, e depois portar para Haskell. O código está no github, mas algumas coisas vão ser discutidas aqui.

Primeiramente, a árvore imutável é feita recriando a árvore inteira. Claro, não podemos re-criar apenas um nó e apontar, digamos, a referencia de seu pai para esse novo nó, porque o pai é imutável (assim como qualquer outro aspecto do programa).

class Node[A &lt;% Ordered[A]](value: A = None, left: Option[Node[A]] = None, right: Option[Node[A]] = None) {
    def insertNew(newValue: A): Node[A] = value match {
        case v if(newValue &lt; v) =&gt; insertLeft(newValue)
        case _ =&gt; insertRight(newValue)
    }

    private def insertLeft(newValue: A) = new Node(value, newChild(left, newValue), right)
    private def insertRight(newValue: A) = new Node(value, left, newChild(right, newValue))
    private def newChild(child: Option[Node[A]], newValue: A) = child match {
        case Some(child) =&gt; Some(child insertNew newValue)
        case None =&gt; Some(new Node(newValue))
    }
}

(more…)

Regras de Negócio e Rails

Bom, esse post é resultado de uma conversa que tivemos no Grupo de Usuários de Ruby de SP. Mas, antes de entrar no que interessa, vamos divagar um pouco sobre “Model” e “Rails”.

Muitos programadores Rails sabem a regra “Controllers magros, Models gordos”. É interessante também saber um pouco sobre o porque dessa regra, mas antes disso, vamos discorrer sobre o que é o “Model” de Rails, comparando com o “Model” da maior parte dos frameworks Java (lembrando que eu não sou programador Java, se eu falar qualquer besteira, me corrijam).

Pegando por exemplo o Hibernate, normalmente há uma classe que mapeia um objeto para uma tabela, e outra classe que faz as buscas (chamada normalmente de Facade). Então, teríamos um diagrama como: JDBC -> Model -> Facade. Já no caso do Rails, o mapeador ActiveRecord já abstrai a parte de “ter que mapear um objeto para uma tabela”, e também já nos oferece formas de buscar esses registros. Resultado, que o “Model” do Rails é meio que uma junção de “Model” e “Facade” do Java, e isso sozinho. Parece então óbvio que regras de negócio vão para ele, não é? Senão, qual o uso de uma classe vazia?

Bom, minha abordagem não é bem essa. E para isso, eu uso o princípio das CRC Cards, da metodologia XP.
(more…)

AgileBrazil 2011 – parte 2

Essa parte é sobre minha palestra no AgileBrazil 2011. Sexta-feira, resolvi que apenas apresentaria minha palestra, depois iria curtir Fortaleza (sério, aquele lugar é muito bom!).

Enfim, minha palestra foi Mantendo a Qualidade dos Códigos de Teste, e nela resolvi arriscar duas coisas novas: primeira, em fazer uma palestra para pessoas de nível intermediário, para não ter que ficar explicando o que são mocks, stubs, etc. Segundo, que a palestra seria de duas horas, para dar tempo de falar tudo o que eu queria.

Claro, a segunda opção quase me deu um tiro no pé. Primeiro, porque para não soar irreal, eu resolvi que todo o código da palestra (que por sinal, está disponível no link acima. Recomendo que vocês baixem o link, a versão do slideshare esconde algumas coisas) ficaria disponível no Github, com exemplos reais (assim, qualquer pessoa poderia rodar os códigos e ver que é possível sim fazer testes daquela forma). Segundo, porque essas duas idéias me tomaram um tempo absurdo para escrever a palestra. Demorei MUITO para fazê-la, bem mais do que eu esperava. E terceiro, porque descobri que duas horas também não é muito tempo…
(more…)

AgileBrazil 2011 – parte 1

Bom, pensei em como escrever um post sobre o AgileBrazil E Fortaleza ao mesmo tempo, mas não dá. Há muito o que contar sobre ambos, então vai um post de cada vez. O de hoje, falarei sobre o evento.

O AgileBrazil é uma convenção muito boa de métodos ágeis de desenvolvimento de software. Frequentei-o ano passado, e esse ano achei a organização muito melhor do que da outra vez (e o lugar também foi uma excelente escolha). Porém, senti uma queda no nível das palestras, embora eu não sei se foi por má escolha minha ou porque o nível estava mais baixo mesmo. Por sinal, todas as palestras estão disponíveis no site oficial do AgileBrazil, para quem quiser baixá-las (a minha estará em breve também).

No primeiro dia, quarta-feira, optei pela palestra Slicing and dicing your user stories. Achei fraquíssima, até porque a palestra mesmo foi muito abstrata: o assunto foi tão vago que eu senti que, se eu estivesse falando de maçãs ao invés de user-stories, o resultado final seria o mesmo. Faltou profundidade, tudo ficou muito superficial, e sendo bem sincero eu não entendi direito aonde eles queriam chegar.
(more…)