Monthly Archive for January, 2007

Entediar-se não é uma opção

Programar um novo sistema é como projetar seu próprio mundo. É preciso descrever como as coisas vão interagir e como as mudanças vão se propagar no ambiente. Os programadores podem começar com nada mais que uma idéia, materializá-la em código e produzir algo vivo. Como bônus extra, suas criações podem ainda ajudar a resolver algum problema do mundo real. Ao projetar seus sistemas eles têm a oportunidade de experimentar a alegria da criação, a surpresa da descoberta, o prazer da invenção e tudo que houver no meio.

Ter seu próprio mundo de faz-de-conta e ainda usá-lo para resolver problemas do mundo real parece tão divertido que deve ser praticamente impossível de se tornar um trabalho chato.

Mas a verdade é que muitas vezes se torna. Afinal de contas a vida não é um conto de fadas. Mais cedo ou mais tarde, vem aquela vontade de repetir estruturas de código familiares, aplicar soluções não muito apropriadas e — pasmem! — copiar e colar código. O pior problema das soluções sujas é a capacidade de atrair mais janelas quebradas. Para se afundar na lama do código ruim, basta cometer a primeira transgressão. As demais virão naturalmente simplesmente porque o código já está sujo e as pessoas vão começar a pensar que uma gambiarra a mais ou a menos não vai fazer mal a ninguém.

A boa notícia é que existe um detector natural para quando se está fazendo besteira. Algo como um canário em uma mina de carvão. Este algo é o tédio. Escrever código repetido é chato. Tentar adaptar uma solução onde ela não se encaixa muito bem é chato. Copiar código de um lugar para outro é chato. Tédio é um subproduto natural do trabalho impensado, então basta eliminar suas causas para evitar boa parte dos danos ao código.

Programar pode ser um dos exercícios intelectuais mais desafiadores. Quando o desafio e a diversão são substituídos pelo tédio, alguma coisa está errada. A solução para boa parte dos casos é procurar uma forma de eliminar a repetição e — adivinhe só — computadores foram feitos justamente para isso. Se trabalhamos para evitar que os outros façam trabalho repetido, por que iríamos nós mesmos nos repetir? Por que se entediar quando a máquina pode executar a mesma tarefa indefinidamente sem cansar nem reclamar?

Eliminar repetição não é fácil e justamente por isso é divertido. Da próxima vez que estiver programando, imagine que você não pode repetir a mesma idéia duas vezes. Veja repetição onde ninguém está prestando atenção. Observe o que é chato de ser feito. Procure resolver estes problemas sem criar outros. A sua solução pode vir em vários sabores: talvez haja uma nova abstração pronta para ser codificada, uma biblioteca querendo nascer ou uma nova linguagem escondida em algum lugar. Tente descobrir o que se aplica ao seu caso. Enquanto estiver fazendo isso, tenha em mente que você não deve se entediar em nenhum momento.

Mantenha o ânimo em alta para manter a sujeira em baixa.

EclipseFP fazendo história

Na última quinta-feira (dia 25) foi divulgada a versão final do artigo A History of Haskell: being lazy with class de Simon Peyton Jones, Paul Hudak, John Hughes e Philip Wadler. O artigo vai ser publicado na terceira Conferência de História das Linguagens de Programação (History of Programming Languages Conference – HOPL-III), a ser realizada em Junho de 2007. Os autores estão mais do que habilitados para contar a história da linguagem. Todos eles tiveram papéis importantes em vários eventos. Hudak, por exemplo, ficou responsável por pedir permissão à viúva do matemático Haskell B. Curry para que o nome dele fosse usado para batizar a linguagem.

Há mais curiosidades como esta no artigo. Ele está muito bem escrito (como era de se esperar destes gigantes) e é uma ótima leitura, apesar do tamanho (55 páginas). Altamente indicado para quem quer conhecer a linguagem e sua história. Não é todo dia que podemos ouvir história diretamente de quem fez história. Recomendo atenção especial para a seção de ferramentas. Eles foram suficientemente gentis para lembrar do EclipseFP.

Podcast estreando

Eduardo Fiorezi publicou ontem o primeiro episódio do que espero que seja uma longa série de podcasts sobre desenvolvimento de software e eu tive a honra de ser o primeiro entrevistado do programa. Ele está bastante interessado em abordagens ágeis, tecnologias para aumentar a produtividadefelicidade do programador e novidades na área de desenvolvimento de software. Portanto, o conteúdo deve interessar a eventuais leitores deste blog.

Só que o podcast tem a vantagem de não exigir atenção exclusiva dos seus olhos. Dá para escutar a caminho do trabalho, ao fazer seu exercício diário e até enquanto programa alguma parte chata do seu sistema. Se bem que se há algo de chato no seu sistema, há algo de errado.

Elephant typing

Devido à recente explosão de popularidade das linguagens dinâmicas, você provavelmente já deve ter ouvido falar de duck typing. É a noção que o tipo de um objeto é determinado exclusivamente pelas mensagens às quais ele pode responder. Se dois objetos quaisquer respondem a um mesmo conjunto de mensagens, eles podem ser considerados do mesmo tipo. É uma versão programática do já clássico dito “se algo grasna como um pato e nada como um pato, deve ser um pato.”

Para quem está acostumado com definição estática de tipos, talvez faça sentido pensar que é como se houvesse interfaces definidas dinamicamente de acordo com as necessidades do código em execução. Algoritmos de ordenação, por exemplo, conseguem trabalhar com qualquer conjunto de objetos comparáveis. Ou seja, que forneçam métodos de comparação como maior, menor e igual. Com duck typing, estes objetos não precisam indicar que satisfazem a interface Comparable, precisam apenas responder às mensagens esperadas e o algoritmo de comparação pode tratar todos como comparáveis. Afinal eles respondem se são maiores ou menores que os outros, portanto devem ser comparáveis.

O tempo passa, as linguagens evoluem, surgem novos conceitos e os animais vão ficando maiores. Steve de Korte, criador da linguagem Io, em uma entrevista de julho do ano passado (ouça a primeira parte também) introduziu um conceito que dá para chamar de elephant typing. Ele usa elefantes como analogia para explicar programação com protótipos.

O modo mais comum de criar um objeto em uma linguagem baseada em protótipos é clonar um objeto pré-existente e especializar o clone do modo que for necessário. O clone inicialmente possui as mesmas propriedades que o objeto original e pode ser descrito a partir daí evitando repetição. Para descrever o Dumbo por exemplo, você poderia dizer:

“Dumbo é um elefante como aquele que você viu no zoológico. Só que é um filhote e por isso é um pouco menor. As orelhas dele são bem maiores e ele pode voar. Além disso, ele carrega uma pena na tromba a maior parte do tempo por acreditar que é ela que o faz voar.”

Há objetos, mas não há classes. O programador especifica somente as diferenças do clone para o protótipo. Se mais tarde algo for descoberto sobre o protótipo, também vai valer para o clone. Por exemplo, se depois você descobre que o elefante do zoológico tem medo de ratos, pode presumir que Dumbo também tem. Trocando em miúdos, em Io, se você alterar um objeto adicionando um método novo ou modificando o valor de um atributo, a alteração é propagada para todos os descendentes. Entretanto, este não necessariamente é o comportamento dos protótipos das demais linguagens.

Andando de costas

Aqui vai um pequeno resumo de como adiciono recursos aos meus sistemas:

  1. Eu identifico (ou alguém me chama a atenção para) alguma necessidade
  2. Escrevo alguns testes para a necessidade
  3. Escrevo o código para fazer os testes passarem
  4. Depois que os testes estão devidamente esverdeados, reestruturo o código para que fique um pouco mais elegante
  5. Repito até que a necessidade esteja satisfeita

Este é o modo TDD de fazer as coisas e pode parecer estranho para quem não está acostumado. Mas o que não é estranho para quem não está acostumado?

Por conseqüência este modo esquisito também é o modo XP. Pelo menos para quem segue a cartilha. E, olhando por este lado, parece que XP inverte bastante as coisas. Você faz os testes antes de fazer o código e (re)define a estrutura depois de ter o código pronto. É como programação para caranguejos: você anda e consegue chegar aonde precisa, mas o modo como isso é feito não é muito parecido com o que se vê normalmente. A não ser, é claro, que você esteja vivendo entre caranguejos.

O que eu inicialmente aprendi na escola foi que deveria pensar um pouco em como estruturar a aplicação antes de começar a escrever código. Para registrar (ou documentar, para usar uma palavra um pouco mais corporativa) a estrutura, poderiam ser elaborados diagramas usando uma linguagem gráfica padrão. Depois era hora de implementar o design. Implementar, em corporativês, é escrever o código correspondente ao design (que é a palavra usada para indicar a estrutura pré-projetada). Finalmente, depois que o código estivesse escrito, chegava a hora de testar a coisa.

Em algum ponto do tempo, devo ter esquecido isso tudo. Pelo que eu descrevi, parece que estou fazendo tudo ao contrário, andando de costas. Afinal, eu começo pelos testes e só no final do ciclo me preocupo com a estrutura. Mas a verdade é que continuo fazendo tudo na mesma ordem. Os testes que faço no início servem para que eu pense um pouco e defina uma estrutura mínima para o código que estou prestes a escrever. Eles definem como o novo pedaço de código vai se ligar ao resto da aplicação, assim como fazem os diagramas. Só que têm uma vantagem bem importante: depois que eu quiser validar tudo, os testes já estão prontos. Do mesmo modo, a atividade final de reestruturação é uma preocupação principalmente com a estrutura da aplicação e, como isso tudo é um ciclo, estar no final é o mesmo que estar no início.

Máquinas carentes

Então você pensava que receber atenção era uma necessidade exclusivamente humana ou no máximo do seu cachorro — ou gato, não quero começar uma guerra cães vs. gatos aqui. A novidade é que isso acontece com máquinas também. Olhe estes velocímetros, por exemplo:

Velocímentro seguro de siVelocímetro carente

O velocímetro da direita é uma dessas máquinas carentes. A graduação é confusa porque os trastes usados para as velocidades numeradas são apenas um pouco mais espessos do que os das intermediárias. O problema fica mais evidente depois que se passa de cem quilômetros por hora. Os números de três dígitos precisam ficar bem próximos uns dos outros e, se você olhar rapidamente, não vai saber se está a 130 ou 140. É preciso parar e se concentrar para diferenciar qual o traste mais espesso. É preciso dispensar mais atenção do que deveria ser necessário para um velocímetro. Sem falar que não dá para fazer isso e olhar para a estrada ao mesmo tempo.

O da esquerda é muito mais seguro de si. Os trastes intermediários são bem mais finos que os principais. Como se não bastasse, eles são mais curtos também e o espaçamento é muito maior. Ele é um velocímetro que não implora para ser olhado, apenas fornece a informação e sai do caminho.

Se você projeta algum tipo de máquina (e todo programador faz isso), tome cuidado para não fazer uma dessas máquinas carentes. As pessoas já estão suficientemente ocupadas dando atenção para outras pessoas. As máquinas não devem competir com isso.

Ano novo, linguagem nova

Não que seja algum tipo de tradição pessoal de ano novo, está mais para coincidência. Mas ano passado, mais ou menos no começo do ano, comecei a estudar Ruby. Minha experiência anterior sempre tinha sido com linguagens compiladas e eu estava me interessando bastante pelo lado dinâmico e interpretado da vida. Aconteceu de Ruby estar bastante comentada na época e acabou sendo a escolha mais óbvia. Depois de um ano, a linguagem está bem mais na moda e o projeto que comecei para estudar está começando a tomar corpo.

A mente é uma fera faminta por novidades e, se você alimentá-la periodicamente, ela pode acabar gerando algumas maravilhas próprias. Uma linguagem nova é um ótima opção para essa dieta. Uma linguagem não é só uma ferramenta, é toda uma escola de pensamento nova e vem acompanhada de um mundo de idéias fresquinhas. Estar em contato com outros mundos é uma boa forma de expandir os horizontes e facilitar o surgimento das boas idéias. Ruby tem feito exatamente isto por mim. Conhecer duck typing, geração de código em tempo de execução e as tão faladas DSLs em Ruby com certeza abre algumas possibilidades para a imaginação, se não para o raciocínio. Mesmo que eu não esteja trabalhando com a linguagem para resolver um determinado problema, o que ela me ensinou já faz bem porque está enraizado na cabeça. Com certeza isso não é exclusividade de Ruby. Se você está trabalhando exclusivamente do lado compilado ou interpretado, aconselho conhecer o outro. E se você não sabe de que lado está, procure saber. O aprendizado é garantido.

Um ano não foi suficiente para que eu possa dizer que conheço profundamente Ruby e acho que vou continuar estudando por muito tempo ainda. Mas acho que já chegou o tempo de apresentar a mim mesmo novos paradigmas. Ultimamente tenho pesquisado sobre linguagens de programação baseadas em protótipos. O que posso dizer com meu limitado conhecimento é que programação baseada em protótipos é um tipo de orientação a objetos.

Só que sem classes!

Numa linguagem orientada a objetos baseada em protótipos o comportamento é inserido diretamente nos objetos. Para criar um método novo, você pega um objeto antigo e adiciona o método diretamente a ele. Não é preciso criar um classe previamente para isso. Se você olhar bem, classes são apenas objetos com instruções especiais sobre como criar outros objetos. Em orientação a objetos puramente baseada em classes, elas são o único meio de criar novos objetos. Com protótipos, objetos podem ser criados a partir de qualquer outro objeto pelo processo de clonagem. O objeto original é chamado de protótipo e daí vem o termo “baseada em protótipos”.

Só de conhecer essa idéia de protótipos, minha cabeça já passou por uma pequena remodelagem. Mas uma coisa é estar a par do conceito, outra é aprender uma linguagem construída sobre ele. Novamente posso estar falando besteira, mas um exemplo de linguagem bastante popular construída sobre a mesma idéia é Javascript. Mas não foi ela que eu escolhi. Se você pesquisar sobre linguagens baseadas em prótipos, vai acabar chegando a Self, que seria minha linguagem escolhida para este ano. Ela já está no pedaço desde os anos 80 e parece ser bastante madura. Uma pequena coisa que impediu de ir em frente foi o fato de não haver um compilador/interpretador disponível. Pelo menos não para quem não possui uma máquina Mac OSX ou SPARC com Solaris. Não por enquanto.

Depois de uma pequena saga em busca de uma linguagem baseada em protótipos que eu pudesse realmente usar, acabei chegando a Io, uma linguagem bem simples nascida em Abril de 2002 pelas mãos de um californiano (não sei se o cara realmente nasceu lá, mas é onde ele diz que mora). Já baixei e compilei meu interpretador e tudo parece estar funcionando corretamente por aqui. Até já fiz meu primeiro programa:

"Hello, Io!" println

Io não tem classes, nem operadores aritméticos e nem atribuição. Tudo isso é implementado a partir de passagem de mensagens. Bem simples e uniforme. Além disso, Io não tem palavras-chave.

Mesmo assim funciona.

Isso com certeza é surpreendente.