Páginas

Saturday, January 31, 2009

O que houve com você, Google?

Hoje por volta de 13h todos os resultados de uma busca no Google apresentaram a seguinte mensagem: "This site may harm your computer".


Não era possível prosseguir após se clicar em algum resultado.
Um aviso em seqüência era exibido:



Bom, no momento que escrevo esta mensagem o problema já foi resolvido. Uns 10 minutos depois.
Não gostaria de especular nenhuma causa para o ocorrido, nem propor uma falsa dicotomia, atribuindo o problema a uma invasão ou falha interna.
Independente da causa ter sido interna ou externa o problema foi corrigido em pouco tempo. Isso demonstra no mínimo eficiência por parte da empresa.

Thursday, January 22, 2009

Dojo chuvoso na PUC

Ontem tivemos mais uma Dojo na PUC, o segundo do ano. Estava chovendo muito no Rio, e com isso o trânsito estava um verdadeiro caos.
Felizmente não tive tanta dificuldade em chegar na PUC, porém só a Janaína estava lá.
Esperamos um tempo até começarmos para ver se mais alguém chegava. Ninguém.

Fizemos pair programming do problema de converter números inteiros para números romanos. A Lilian chegou um pouco depois de termos começado, e se juntou a nós para resolver o problema. Nesse momento estávamos fazendo ping pong pair programming.

Mesmo com poucos presentes, foi uma sessão muito boa, pois felizmente experimentei algo diferente de Python em um dojo. Resolvemos usar o Eclipse e o JUnit, e assim surgiu meu primeiro dojo em Java!

Foi legal notar algumas diferenças, como self.assertEqual em Python vira assertEqual em Java (estávamos escrevendo this.assertEqual, mas o Eclipse me avisou que tinha algo de estranho...). Ainda não estou certo se é assim mesmo, preciso estudar :P

Ficamos programando até 21:40... e na hora de ir embora... Bem, o Ronald não estava lá para me alojar na casa dele, então tive que encarar o longo trajeto pra casa. Mas deu tudo certo!

Depois de dois dojos no CEFET e dois na PUC, já é mais que hora de parar para refletir um pouco. Tem sido uma experiência maravilhosa para mim, e espero estar ajudando a disseminar boas práticas aqui no Rio de Janeiro. Eu fiquei espantado com a quantidade de pessoas que participam do grupo de emails, muito legal ter tanta gente envolvida. E conhecer algumas das pessoas da lista, e outras que nem nela estão, pessoalmente no dojo é ótimo.

Esta tem sido uma experiência sem igual em minha vida. E na quarta-feira que vem tem mais! Estarei lá na PUC faça chuva ou faça sol :P

No ano passado, conversando com o Tapajós, vislumbramos a possibilidade de retomar as atividades do XPRio, porém eu acabei não me engajando devido aos outros compromissos com Iniciação Científica, Empresa Júnior e faculdade... Hoje, o dojo parece cumprir um pouco do papel do XPRio, levando TDD e Pair Programming para desenvolvedores cariocas. Quero eu poder me engajar também com o Movimento Ágil e o Python (via PythOnRio), e porque não a comunidade Django Brasil. Falta organizar as horas do dia para dar conta disso tudo!

Saturday, January 17, 2009

TDD em cantigas de roda - parte 2

Na semana passada comecei a falar sobre abordar outros tipos de situação, não diretamente relacionadas com programação, através de testes, fazendo uma espécie de exercício de abstração.

Na última quarta, no Dojo Rio, eu conversei com o pessoal sobre o assunto. Ao invés de ter sido o aquecimento, como proposto pelo Falcão, foi apenas um bate-papo após a nossa retrospectiva. Como eu imaginava, estranharam um pouco, porém acho que consegui passar a idéia num tom sério o bastante para não me ignorarem :D

Voltando ao problema iniciado na parte 1, parei justamente após escrever um teste exercitando a presença de objetos em namespaces diferentes. Por enquanto temos o seguinte, com o último teste falhando:
# -*- coding: utf-8 -*-
u"""
paunogato.py - Implementação usando TDD da cantiga de roda "Atirei o Pau
no Gato", seguindo a idéia de Dojo Lúdico proposta por
Jorge Falcão.
Referências:
* http://lifeatmymind.blogspot.com/2009/01/tdd-em-cantigas-de-roda-parte-1.html
* http://lifeatmymind.blogspot.com/2009/01/tdd-em-cantigas-de-roda-parte-2.html

by Rodolfo Carvalho
2009/01/08
"""
import unittest

class DonaChica(object):
admirada = False

class Gato(object):
def berrar(self):
DonaChica.admirada = True

class Vila(object):
def adicionar(self, obj):
pass

class TestAtireiOPauNoGato(unittest.TestCase):
def test_admiracao(self):
dona_chica = DonaChica()
gato = Gato()

self.assertFalse(dona_chica.admirada)
gato.berrar()
self.assertTrue(dona_chica.admirada,
"A dona Chica nao se admirou com o berro do gato!")

def test_admiracao_com_outro_gato(self):
dona_chica = DonaChica()
gato = Gato()
outro_gato = Gato()
vila = Vila()
vila.adicionar(dona_chica)
vila.adicionar(gato)

self.assertFalse(dona_chica.admirada)
outro_gato.berrar()
self.assertFalse(dona_chica.admirada,
"A dona Chica admirou-se com o berro de outro gato!")

if __name__ == "__main__":
unittest.main()


Notem que eu adicionei o objeto Vila e seu método adicionar (vazio).

Agora vamos criar uma interface para disparar e capturar eventos. Primeiro vou definir um Ser, que seria uma abstração acima de DonaChica e Gato, e ajustar as heranças:

class Ser(object):
def __init__(self):
self._vila = None

def definir_vila(self, vila):
self._vila = vila

def notificar(self, evento):
print self, "recebeu o evento <%s>" % (evento,)

class DonaChica(Ser):
def __init__(self):
super(DonaChica, self).__init__()
self.__admirada = False

@property
def admirada(self):
return self.__admirada

def notificar(self, evento):
super(DonaChica, self).notificar(evento)
if evento == "berro":
self.__admirada = True

class Gato(Ser):
def berrar(self):
if self._vila is not None:
self._vila.notificar("berro")

class Vila(object):
def __init__(self):
self._seres = []

def adicionar(self, ser):
ser.definir_vila(self)
self._seres.append(ser)

def notificar(self, evento):
for ser in self._seres:
ser.notificar(evento)


Foi um passo bem longo. Tirei a idéia central daqui, porém no caso em questão todos os seres tem que ouvir os eventos de todos os outros, enquanto no exemplo da Wikipedia diversos Listeners ouvem eventos de apenas um único Subject.

Basicamente, o que aconteceu agora é que ao adicionar um ser (Gato, Dona Chica, etc) a uma vila este ser sabe a que vila ele pertence.
Assim sendo, quando um ser disparar um evento, ele avisa a vila, que por sua vez propaga o evento para todos os seres nela contidos.

Rodando os testes, temos uma supresa: nosso segundo teste test_admiracao_com_outro_gato passa, mas sofremos uma regressão — o test_admiracao falhou!
Por que será? Bem, uma coisa é certa, usando testes automatizados nós ganhamos a segurança de caminhar sem medo, pois estamos protegidos das regressões. O teste protege o código, e o que muitos não percebem: o código protege o teste!

O que aconteceu não é que o código está errado, e sim o teste. Desde que inventamos o conceito de vila, um gato e uma dona chica precisam estar na mesma vila para que um ouça o outro. Logo, precisamos consertar o primeiro teste para ficar bem parecido com o segundo:

    def test_admiracao(self):
dona_chica = DonaChica()
gato = Gato()
vila = Vila()
vila.adicionar(dona_chica)
vila.adicionar(gato)

self.assertFalse(dona_chica.admirada)
gato.berrar()
self.assertTrue(dona_chica.admirada,
"A dona Chica nao se admirou com o berro do gato!")


E finalmente estamos com tudo passando!

Tem mais um detalhe, o que acontece se quem berrar for a dona_chica? Ela não pode ser admirar com o próprio berro, mas sim com o berro de um gato!
Para ficar mais claro, não vou fazer a dona_chica berrar, mas sim adicionar um novo ser na brincadeira, um cachorro. Se um cachorro berrar, bem, a dona_chica continua no mesmo estado de não-admiração...


class Cachorro(Ser):
def berrar(self):
if self._vila is not None:
self._vila.notificar("berro")
...

def test_admiracao_com_um_cachorro(self):
dona_chica = DonaChica()
gato = Gato()
cachorro = Cachorro()
vila = Vila()
vila.adicionar(dona_chica, gato, cachorro)

self.assertFalse(dona_chica.admirada)
cachorro.berrar()
self.assertFalse(dona_chica.admirada,
"A dona Chica admirou-se com o berro do cachorro!")

Note que eu utilizei uma nova forma de adicionar seres a uma vila, e com isso precisamos refatorar:

class Vila(object):
def __init__(self):
self._seres = []

def adicionar(self, ser, *outros_seres):
ser.definir_vila(self)
self._seres.append(ser)
if outros_seres:
self._seres.extend(outros_seres)
...


E, para minha surpresa, os testes passaram! Isso quer dizer que tem algo de errado, pois eu esperava que o teste falhasse. Bem, não demorou muito para ver que eu não estava definindo a vila outros_seres. O refactoring ficou assim:

    def adicionar(self, *seres):
for ser in seres:
ser.definir_vila(self)
self._seres.append(ser)


Agora sim o teste falhou, menos mal :D
Vamos melhorar nossa comunicação de eventos, podemos passar a informação de quem está disparando o evento. Desta forma, podemos distinguir entre berros de gatos e cachorros...

class DonaChica(Ser):
...
def notificar(self, evento, origem):
super(DonaChica, self).notificar(evento, origem)
if evento == "berro" and isinstance(origem, Gato):
self.__admirada = True

E ajustamos para passar self quando cachorros e gatos berram:
class Gato(Ser):
def berrar(self):
if self._vila is not None:
self._vila.notificar("berro", self)

class Cachorro(Ser):
def berrar(self):
if self._vila is not None:
self._vila.notificar("berro", self)


Testes passando!
Podemos então refatorar. O que me incomoda bastante é a duplicação de código — as classes Cachorro e Gato tem o mesmo código! Não vejo razão para um ser qualquer não poder gritar... a não ser que seja de uma subclasse Mudo(Ser)...
Então:

class Ser(object):
...
def berrar(self):
if self._vila is not None:
self._vila.notificar("berro", self)

class Gato(Ser):
pass

class Cachorro(Ser):
pass


Testes OK.
Já estou bastante satisfeito em saber que, quando o gato berrar, dona Chica irá certamente se admirar...
Mas ainda quero poder atirar o pau no gato, sem causar sua morte...

Este post já está demasiadamente longo, então é melhor continuar depois.

Terceira Sessão do Dojo Rio / Novidades

Depois de nosso terceiro encontro, agora na PUC-Rio, criamos um blog dedicado ao Coding Dojo Rio, e um espaço no Google Code para colocarmos nosso código.

Eu tirei algumas fotos lá na PUC, que podem ser encontradas aqui.

Estou muito feliz por ter conhecido mais participantes do grupo de emails, e por ter compartilhado algumas horas com eles :D

Legal também rever o Flávio e o Raphael. O Flávio, apesar de cursar história, é super envolvido com programação, também fazendo parte do grupo PythOnRio. Conheci ele lá na PyCon 2008. Nós dois participamos do dojo como mencionei em outro post.

E o Raphael foi quem nos ajudou a conseguir espaço no CEFET. Sem ele não teriam acontecido nossas duas sessões de 2008, e a consequente consolidação do grupo.

Outra presença ilustre foi a do Ronald, que trabalha comigo lá no Labase/UFRJ, e estava me devendo uma aparição no Dojo. Costumamos praticar pair programming juntos, e algumas vezes acabo me referindo a fatos relacionados ao dojo... bem, agora o Ronald já faz parte do time!

Não posso deixar de agradecer a Janaína, que levou o Dojo Rio para a PUC em Janeiro/2009. Foi bacana conhece-la pessoalmente, após vários emails pelo grupo ou privados. Graças a ela o Dojo Rio se mantém de pé em 2009.

Obrigado também a todos os que participaram até o fim, e convido a todos que não puderam ir ou não puderam ficar até o fim que compareçam na próxima quarta lá na PUC.

Ah, os nomes:

  • Daniel Mendonça
  • Flávio Amieiro
  • Janaína Horácio
  • Lilian Mendes
  • Mariana
  • Pedro Grojsgold
  • Raphael Almeida
  • Rodolfo Carvalho
  • Ronald Kaiser
  • Silvia Resende


Foi com certeza a sessão com maior número de presentes! Neste encontro nós abordamos o problema "Overlapping Areas", usando mais uma vez Python, em um ambiente Windows. O editor foi o IDLE.

Gostaríamos de ter feito o problema em Java, porém, o Daniel não sabia se ia ficar até o fim para ajudar a gente com o JUnit. De qualquer forma, que bom que ele ficou!

Começamos 18:45, com eu fazendo uma rápida apresentação para o pessoal novo (a mesma utilizada na primeira sessão lá no CEFET), em seguida escolhemos o problema e iniciamos o pair programming. Programamos até por volta de 20:50, depois fizemos um retrospectiva e conversamos sobre outros assuntos, como o as práticas adotadas no Dojo e as práticas de Desenvolvimento Ágil, e um pouco sobre Dojo Lúdico.

Para os que estão se perguntando "Cadê o post sobre a Segunda sessão do Dojo?", infelizmente eu estava tão enrolado que o tempo foi passando e eu não escrevi nada. Na blog oficial do dojo haverá alguma coisa, pode procurar lá!

Wednesday, January 7, 2009

TDD em cantigas de roda - parte 1

Bem, resolvi implementar minha própria cantiga usando TDD.
Pode parecer estranho, mas é apenas uma variação do que o Falcão fez e que eu comentei no post anterior.

Vamos então começar com a cantiga, "Atirei o Pau no Gato":

Atirei o pau no ga-to-to
mas o ga-to-to
não morreu-rreu-rreu
dona chica-ca
adimirou-se-se com o berro
que o gato deu
miiiiaaaaaaauuuuuuuu.


Olhada com os olhos certos, essa cantiga infantil de aparência simples, que vem sendo ensinada de forma alterada para evitar a extinção dos gatos domésticos, pode ser uma bela fonte para análise e discussão. Possivelmente minha abordagem não será a melhor, porém essa não é a idéia. É apenas a minha expressão de como encarei as coisa no ônibus voltando para casa...

O primeiro teste:
class TestAtireiOPauNoGato(unittest.TestCase):
def test_admiracao(self):
dona_chica = DonaChica()
gato = Gato()

self.assertFalse(dona_chica.admirada)
gato.berrar()
self.assertTrue(dona_chica.admirada)


E... hmm... precisamos de uma implementação para fazer os testes passarem! Então surge o primeiro "problema". Eu já escrevi os outros testes que acredito serem pertinentes a cantiga, mas não tinha escrito nada de implementação.
E o primeiro estalo foi: "o berro do gato tem que disparar um evento e a DonaChica é listener... quando o gato berra ela admira-se".

Como fazer essa comunicação? Veja que legal, chegamos num ponto — ainda bem no início da discussão — em que podemos aplicar um padrão de projeto (design pattern), o Observer pattern. Mais uma vez deixo claro que está é minha implementação, e faço o que quiser com ela: é minha!!!

Ah, mas... ok, antes de fazer algo super bonito, que tal fazermos o teste passar?

class DonaChica(object):
admirada = False

class Gato(object):
def berrar(self):
DonaChica.admirada = True


E rodando os testes: verde!
Eu não gosto desse código, alterar um atributo de classe não faz sentido, já que só uma instância de DonaChica, no caso dona_chica, ficou admirada.
Podemos explicitar isso fazendo mais um teste.

Queremos que possam existir diversas Donas Chicas espalhadas pelo mundo, ou em diferentes cidades, ou mesmo em dimensões distintas. O mesmo vale para os gatos... nada de singletons. Logo, para possibilitar diversos "namespaces" pensei em, ao invés de criar mais uma nível de objeto, e enfiar o gato e a dona_chica lá dentro, seria interessante ter uma Vila (vamos supor que nossa Dona Chica mora em uma, e lá existe ao menos um gato). A Vila nada mais é que o gerenciador de eventos, fazendo então a junção do gato e da dona Chica em um ambiente em que um pode interagir com o outro, e outros gatos, outras donas chicas, simplesmente não afetam/ são afetados.

Então vamos adicionar a dona_chica e o gato a uma Vila e descrever o que acontece caso um gato externo berre:

    def test_admiracao_com_outro_gato(self):
dona_chica = DonaChica()
gato = Gato()
outro_gato = Gato()
vila = Vila()
vila.adicionar(dona_chica)
vila.adicionar(gato)

self.assertFalse(dona_chica.admirada)
outro_gato.berrar()
self.assertFalse(dona_chica.admirada,
"A dona Chica admirou-se com o berro de outro gato!")


E como esperávamos, vermelho nos testes!
Vamos implementar:

Mas não agora, em breve!
Hora de dormir.

Dojo Lúdico

O Falcão falou ontem num tom muito engraçado sobre novas abordagens para o Coding Dojo.
Uma das melhores coisas do Dojo são as discussões geradas, debates sobre modelagem, sobre como abordar uma certa situação, entre outras.
O que ele inventou foi implementar cantigas populares usando TDD! É, pode até parece louco, mas faz sentido depois que acostumamos com a idéia. Ele postou sobre o assunto aqui.

O grande barato é que estamos trabalhando com elementos da língua falada, componentes sintáticos que exprimem condicionais, existência, conteúdo, etc. Não sou especialista em linguística, porém, dá pra notar que ter a presença de alguns nesse tipo de dojo seria bastante válido - ninguém precisa escrever uma linha de código!

Trabalhar exercícios que fogem totalmente do nosso cotidiano ajuda a treinar nosso poder de abstração. Podemos tentar fazer isso antes das sessões regulares do dojo, como uma forma de aquecimento.

Por hora, os exemplos do Falcão já mostram bem qual é a idéia, quem sabe um pouco mais descansado consigo pensar em coisas igualmente doidas e legais. Hora de pegar o ônibus pra casa, ótima oportunidade de dar uma viajada...