segunda-feira, junho 02, 2008

Princípios de OO segundo Alan Knight (e Dilbert) (parte 2)

Essa é a segunda parte desse post aqui.

Evite responsabilidades

Objetos devem ser preguiçosos ao extremo. Evite responsabilidades, se tiver que aceitá-las, mantenha-as vagas e delegue o trabalho de verdade para outros. O efeito final é que cada método vai fazer um fragmento muito pequeno de trabalho. Segundo o próprio Alan Kay, em um sistema orientado a objetos bem feito, você não consegue saber onde o trabalho está sendo realmente feito, quando você vê, já foi. Apesar de um fluxo em específico ser mais difícil de seguir (experimenta debugar em Smalltalk q vc vai entender do que eu estou falando), os métodos todos são tão simples que você consegue entendê-los em segundos. A segunda parte da proposição: "mantenha a responsabilidade vaga", significa que você deve desconfiar de especificações do tipo "o objeto deve persistir em banco todas as entradas". Isso porque ele contém detalhes de implementação, na verdade, o que interessa para os outros objetos não é como a informação vai ser guardada, mas como ela vai ser recuperada. Uma especificação melhor seria "o objeto deve saber informar as entradas feitas". Se isso será feito em banco de dados, em arquivo texto, distribuído na rede ou por sinal de fumaça, não interessa, o que nos dá muito mais flexibilidade. No final a idéia é aumentar o reuso. Evitando responsabilidades e delegando o trabalho, na verdade estou procurando reutilizar o que outras classes já fazem. Mantendo as responsabilidades vagas estou escondendo como faço as coisas (encapsulamento).

terça-feira, maio 20, 2008

Princípios de OO segundo Alan Knight (e Dilbert) (parte 1)

(nossa como faz tempo que não posto... :p) Faz uns anos eu achei um artigo artigo obscuro escrito por Alan Knight por volta de 2000 ou 2001 que é um excelente resumo de como deve ser um bom código orientado a objetos. O mais interessante é que o artigo faz analogia aos princípios "Dilbert", e por incrível que pareça, a analogia encaixa como uma luva. O texto é curto e muito divertido, recomendo a leitura! Como sempre mostro esse artigo pra todo mundo que eu conheço, achei que já era hora de citar ele no blog e fazer um resumo em português pra quem não conhece bem o gringolês. Como posts grandes ninguém lê, vou postando os princípios aos poucos. Nota: AS IDÉIAS AÍ EMBAIXO NÃO SÃO MINHAS, OKAY? EU GOSTO MUITO DELAS, MAS O AUTOR ORIGINAL É O "TIUZÃO TOP FODA" ALAN KNIGHT! Avisados? Ótimo! Senão depois o TaQ briga comigo por estar levando crédito por idéias alheias :).

Princípio 1: Nunca faça nada que alguém possa fazer para você.

Esse é basicamente o princípio do "tell, don't ask". Basicamente, objetos não podem ser caras legais. Nada de "Olha, preciso do total dos custos desde o começo do mês, mas não se incomode, me dê os dados aí que eu mesmo faço o cálculo, não deve ser muito complicado, não é?"
  total = centro_de_custo.itens.inject(0) do|soma, item| 
    if item.data > Date.parse('2008-05-01')
      soma += item.valor 
    else
      soma
    end
  end
Objetos devem ser grandes FDPs. Objeto bom é grosso como seu chefe: "Cara, quero o total dos custos desde o começo do mês! Não quero nem saber e não me interessa como você calcula isso, quero o resultado, e quero JÁ!".
  total = centro_de_custo.total_desde('2008-05-01')
Em Java, vejo muito uma coisa um pouco mais esquisita, normalmente envolve um DAO, injeção de dependência e costumeiramente um Date que não se pode construir diretamente pois o construtor está "deprecated":
  // getCentroDeCustoDAO foi alimentado antes pelo Spring
  // e "new Date" costuma ser gerado via Calendar, pq esse
  // construtor está deprecated faz tempo...
  List itens = getCentroDeCustoDAO().procurarPorDataDesde(new Date(2008, 4, 1));
  BigDecimal resultado = new BigDecimal(0);
  for(Item item : itens) {
    resultado = resultado.add(item.getCusto());
  }
Mesmo que você goste muito desse padrão, seria um pouco melhor do jeito abaixo. Embora já tenha ouvido que isso é regra de negócio e não deveria ser feita no DAO.
  // getCentroDeCustoDAO foi alimentado antes pelo Spring
  // e "new Date" costuma ser gerado via Calendar, pq esse
  // construtor está deprecated faz tempo...
  BigDecimal resultado = getCentroDeCustoDAO().calcularCustoTotalPorDataDesde(new Date(2008, 4, 1));
"Tell, don't ask" <= "Mande, não peça"...

segunda-feira, março 17, 2008

Avanço tecnológico às avessas...

Não sei se porque ando lendo coisas subversivas mas ando com a nítida impressão que estamos andando em círculos ao invés de fazer avanços na área de software... Alguns fatos me deram essa impressão: 1 - "Redescoberta" de closures -> coisa que antes do hype do Ruby ninguém dava bola, e agora é a discussão do momento. Só que isso existe desde 58 com LISP. Ou, se vc quiser uma roupagem mais moderna, desde 78 com Smalltalk. (Clipper tb tinha, alguém lembra?) 2 - Domain Driven Development -> não entrei muito a fundo, mas me parece basicamente o que o pessoal do movimento O.O. de 1970 e uns quebrados pregava. 3 - TDD -> okay, mesmo o Kent Beck confessava que isso não era novidade. 4 - Uma entrevista com John McCarthy (criador do LISP) na InfoQ -> Tem uma pergunta quase no final da entrevista sobre LISP sendo citado como influência para novas linguagens: "...many modern programming languages like Ruby are claiming big influences from Lisp..." McCarthy confessa que não conhece Ruby, mas pergunta: "Does it use, for example, list structures as data?" O entrevistador responde negativamente, e McCarthy completa: "So if you want to compute with sums and products, you have to parse every time? So, in that respect Ruby still isn't up to where Lisp was in 1960." Interessante... Existem alguns outros pequenos fatos aqui e ali, pequenos demais pra eu estar totalmente consciente deles, mas ando sentindo um "deja vu" desgramado. Será que sei pouco e na verdade há um avanço nessas coisas que não estou percebendo ou será que sei o suficiente e realmente estamos andando em círculos em algumas coisas? Como eu sempre assumo que não sei o suficiente, a questão agora está em saber o que não estou percebendo. Toca estudar mais... :)

quarta-feira, março 12, 2008

Sobrecarga de métodos em Ruby

Uma das coisas muito legais que o Java possui é sobrecarga de métodos (várias vezes confundido com polimorfismo) que é a capacidade de possuir métodos diferentes com mesmo nome, mas com parâmetros diferentes. Bom, isso não existe em Ruby, mas nada impede que isso seja implementado. Rascunhei isso aqui: class Object
  
  def self.generate_method_name_for(method_name, *parameter_types)
    # Usamos espaços no nome dos métodos gerados para evitar chamadas acidentais
    "#{method_name}_#{parameter_types.collect{|it| it.to_s}.join(' ')}".to_sym
  end
  
  def self.def_method(method_name, *parameter_types, &block)
  
    # Definindo o método genérico da classe,
    define_method method_name.to_sym do |*params|
      send("#{method_name}_#{params.collect{|it| it.class.to_s}.join(' ')}", *params)
    end unless self.method_defined?(method_name.to_sym)
    
    #Definindo cada método específico
    specific_method = generate_method_name_for(method_name, *parameter_types)
    
    define_method(specific_method, &block)
    
  end
end
E para usar: class Test
  def_method :test, String, String do |a, b|
    puts "Duas strings"
  end
  
  def_method :test, String do |a|
    puts "Uma string"
  end
  
  def_method :test, Fixnum do |a|
    puts "Um número"
  end
end


x = Test.new

x.test("a", "b")
x.test("a")
x.test(1)
É lógico que isso custa desempenho, mas serve. Acho também que o código poderia ser grandemente melhorado, até pq não sei se isso funcionaria corretamente com herança e polimorfismo, mas não quis perder mais tempo brincando nisso :) Moral da história: adoro classes abertas.

segunda-feira, janeiro 14, 2008

O que é preciso para DSLs?

(Se vc não sabe o que é DSL, Akita explica... se quiser uma discussão aprumada e ajeitada sobre o assunto, dá uma olhada no que diz o tio Ronaldo) Alguns dizem que Smalltalk, Ruby e Lisp são boas linguagens para criar DSLs. Mas Java, C# e afins não são tão boas? Por quê? Depois de ler um tanto e experimentar mais outro tanto, acredito que para criar DSLs internas (veja o que diz Martin Fowler sobre DSLs internas e externas), uma linguagem precisaria dos seguintes items:
  1. Reflexão(de verdade), ou seja, capacidade de inspecionar e alterar suas próprias definições em tempo de execução - DSL normalmente envolve criar e inspecionar código, e sem reflexão decente não dá pra fazer metaprogramação
  2. Metaprogramação, ou seja, código que gera código - Muito da DSL na verdade é fazer com que pouco código faça muita coisa, às vezes de maneiras pouco convencionais. Para isso sua linguagem precisa conseguir criar código "on the fly" sem grandes maracutaias, porque afinal, você já vai estar fazendo maracutaias, aí a metaprogramação fica maracutaia ao quadrado :p
  3. Closures (ou lambdas) - Permitir passar blocos de código pra cima e pra baixo são essencias para você codificar em um ponto e poder executar em outro, normalmente após preparar o terreno para a execução da closure
  4. Sintaxe flexível - Não é essencial, mas ajuda a vc criar uma DSL simples. Sintaxes rígidas limitam a maneira com a qual você pode se expressar nas DSLs e elas acabam ficando mais complicadas sem necessidade. Um exemplo desse princípio é a tal da "interface fluente". Sem um sintaxe flexível, ela fica meio canhestra.
  5. Classes abertas - Isso é uma extensão da "Reflexão", na verdade é permitir que você possa redefinir tipos básicos como String, Integer e outros. Se você olhar a tal da "interface fluente" vai ver que com classes abertas ficaria bem mais fácil criá-las
Tem gente que acha que uma linguagem de programação que permita essas coisas deveria ser queimada, triturada, empalada e que todos que programam nela são hereges que deveriam queimar no Inferno de Knuth. No final, tenho uma teoria (grandes coisa minhas teorias, mas como o blog é meu, vou postar). Tenho a teoria que, na verdade, Orientação a Objeto é uma maneira de criar DSLs internas, mas sem que pensemos em termos de linguagem. Toda boa API OO me lembra muito DSLs. Acho que nosso trabalho é puramente criar abstrações, quanto melhores, mais somos produtivos e menos dores de cabeça temos. Em um texto, as abstrações são tão maiores quanto mais técnico é o texto, onde uma única palavra (por exemplo: "Façade") abstrai uma idéia um bocado complexa. Do nosso lado, criar classe, métodos e refatorar código é basicamente melhorar as abstrações. Estou certo? Estou errado? Não importa muito, isso é mais retórico do que prático, no final. Mas esse tipo de pensamento muda um pouco minha maneira de encarar o que eu aprendo de novo... Editado: um "PS" aqui... esse artigo estava rascunhado no meu blog faz quase um ano... tou ficando velho e preguiçoso, e talvez um pouco lelé...

quinta-feira, janeiro 10, 2008

Desgaste de informação

Hoje me deparei com uma situação que todo mundo passa, conhece, mas parece que ninguém toma medidas para conter o problema: quanto mais gente no meio entre a fonte de informação e o utilizador (EU!), pior a informação vai ficando. Cliente pede uma feature -> Relacionamento com cliente repassa para Gerente de projeto -> Gerente de projeto passa para Analista -> Analista passa para desenvolvedor. Nesse caminho, o que o cliente pediu já foi interpretado de maneiras diferente QUATRO vezes (Relacionamento, Gerente, Analista e Desenvolvedor). Em cada interpretação a informação sofreu um certo desgaste, detalhes se perderam e o pior: detalhes que podem ser irrelevantes foram adicionados. Esse é de longe o maior problema da informática, depois da comunicação falha (que é relacionada, mas não é a mesma coisa). Alguém sabe se existe alguma área que estuda o que acontece com a informação?

quinta-feira, dezembro 20, 2007

Closures para quê?

“Beware of the Turing tar-pit in which everything is possible but nothing of interest is easy.”—Alan Perlis, “Epigrams on Programming”

(Esse artigo tem exemplos em Java e Ruby. Estou ignorando as sutis diferenças entre closures e blocos de código no Ruby)

Outro dia, num papo nerd com um colega (“O Francês”), ele me disse que não via nenhuma utilidade para closures com bons olhos a inclusão de Closures no Java. Que até já tinha olhado e brincado um pouco, mas que tudo que closures fazem é perfeitamente possível de fazer sem usá-las.(É... ele me fez corrigir o texto :) )

Bom, ficou bem difícil argumentar aquilo no momento. Realmente, tudo que se pode fazer com closures também é possível fazer sem, da mesma maneira que é possível escrever um programa web em C (muita gente ainda faz e adora) ou escrever um aplicativo comercial em Assembly.

Depois dessa conversa comecei a tentar catalogar usos interessantes de closures. Pode ser que isso não convença ninguém de que são úteis, mas ao menos me serviu para organizar minhas próprias idéias. A seguir listo uma série de usos bem interessantes e bastante comuns de closures.

Bom, minha intenção não é explicar o que são closures – para isso o Akita tem um excelente artigo – mas sim mostrar onde o uso de closures é legal.

Callbacks

Talvez um dos melhores usos de closures sejam callbacks), ou seja, uma função que será executada posteriormente. Trocando em miúdos, é um código que queremos que seja executado quando algum evento acontece no sistema, por exemplo quando um botão é pressionado (conhecido como “events”...), quando uma aplicação inicia, quando algo é gravado ou alterado (“triggers” ou “listeners”...?), ou quando algum estado no sistema muda (“hooks”...?).

Cada linguagem tem sua solução para implementar callbacks, como ponteiros para funções (C e afins), a função como “cidadão de primeira classe” (Python, Javascript), classes anônimas (Java), “delegates” (C#) ou … closures, óbvio (que é solução para Smalltalk e Ruby)!

Cada um defende sua linguagem como gosta, mas independente disso, closures são muito práticas. Eu posso definir um callback de um botão da seguinte forma:

(Código em Ruby/GTK2)

 # Cria um botão
 button = Gtk::Button.new("Click me")

 # Quando clicar, imprime "Cliquei no botão"
 button.signal_connect("clicked") { puts "Cliquei no botão" }

A parte do ’{ puts “Cliquei no botão” }’ é um closure. Nesse caso, é o código que vai ser usado quando o botão for ativado (“puts” é para imprimir o texto na console).

Simples assim, sem declarações, sem pré-requisitos, sem detalhes. Simplesmente “toma aqui esse código para executar depois”.

Iteradores (“visitors”)

Estamos sempre processando coleções e iterando sobre elementos. Na maior parte dos casos, um simples loop resolve o problema, mas em outros, somos obrigados a repetir o mesmo loop em uma série de métodos diferentes pois as operações são parecidas, mas não idênticas. Em outros casos a lógica de iteração é um pouco mais complexa e se mistura com a lógica que processa cada elemento.

Closures são fantásticos para resolver esses problemas. Vejamos um exemplo que aconteceu recentemente comigo. Eu precisava substituir o mapeamento do Hibernate em umas 400 classes java. Fiz um pequeno método que encontrava as classes e para cada uma encontrada, eu aplicava a lógica de substituição.

O método para percorrer as classes ficou assim:

 def on_java_classes
   Find.find(@root) do |file_name|
     yield(file_name) if file_name =~ /\/vo\/.*\.java$/
   end
 end

Esse método percorre toda a árvore de diretórios abaixo de @root e se o arquivo encontrado estiver sob um diretório “vo” e terminar com ”.java”, o bloco de código é executado.

E para usar o método para trocar um mapeamento fica assim:

 on_java_classes do |file_name|
   change_hibernate_mapping(file_name)
 end

É lógico que eu poderia usar esse loop e meu método tudo em um bolo só, mas agora eu tenho um método genérico que me permite percorrer essas classes e executar o que eu quiser com elas sem duplicar a lógica que itera sobre as classes. Posso, por exemplo, listar todos os mapeamentos, contar quantos “VOs” tenho, vasculhar se existem mapeamentos fora do padrão e outras coisas do tipo.

A coisa fica tão transparente, que posso usar coisas como “next” (para processar o próximo elemento) e “break” (para parar a iteração) dentro dos closures e eles funcionam como esperado. Por exemplo, se eu quisesse apenas fazer um teste com os 10 primeiros arquivos, poderia colocar um “break” no meio, dessa forma:

   i = 1
   on_java_classes do |file_name|
       break if i > 10 # passou de 10 arquivos, caia fora do método
       change_hibernate_mapping(file_name)
       i += 1
   end

Processamento “durante”

Quase todas as operações que fazemos de IO precisam de algo para “abrir” a operação e garantir que ela seja “fechada” quando terminamos o que precisamos. Isso vale para streams, arquivos, sockets, transações, record sets e sei lá mais quantas coisas.

Isso implica em uma lógica bastante incoveniente que costuma ser repetida à exaustão: abra conexão, execute o que precisar, garanta que foi fechado (normalmente com um bloco para tratamento de exceção).

Conexões com bancos de dados são particularmente um porre, porque costumam abrir e fechar vários objetos.

Com closures, resolvemos isso com facilidade. Aqui um exemplo de como se usar o Ruby-DBI da maneira tradicional. O exemplo foi tirado da própria página do Ruby-DBI, mas com o tratamento de exceções apropriado.

 require 'dbi'

 dbh = nil

 begin
   dbh = DBI.connect('DBI:Mysql:test', 'testuser', 'testpwd')

   sth = nil
   begin
     sth = dbh.prepare('select * from simple01')
     sth.execute

     while row = sth.fetch do
       p row
     end

   # Precisamos tentar fechar o statement, não importa qual o erro
   ensure
     sth.finish if sth
   end

 # Precisamos tentar fechar a conexão também
 ensure
   dbh.disconnect if dbh
 end

Com closures, a coisa fica bem mais simples. Podemos criar coisas para serem executadas ao redor do bloco de código e simplesmente esquecermos da necessidade de ficar abrindo e fechando objetos. (Aviso: o DBI já tem métodos que funcionam assim).

Primeiro, criamos dois métodos:

 # Esse método cuida de abrir a conexão, executar algo
 # e garantir q a conexão seja fechada.
 def connect(uri, user, password)
   dbh = nil
   begin
     dbh = DBI.connect(uri, user, password)
     yield(dbh)
   ensure
     dbh.disconnect if dbh
   end
 end

 # Esse método executa algo para cada registro recuperado
 # em um SQL. Ele cuida de fechar os objetos envolvidos
 # no processo. 
 def for_each_record_in(dbh, sql)
   sth = nil
   begin
     sth = dbh.prepare(sql)
     sth.execute

     while row = sth.fetch do
       yield(row)
     end
   ensure
     sth.finish if sth
   end
 end

E agora, o código para fazer exatamente a mesma coisa que o primeiro exemplo passa a ser:

 connect('DBI:Mysql:test', 'testuser', 'testpwd') do |connection|
   for_each_record_in(connection, 'select * from simple01') do |record|
     p record
   end
 end

Toda vez que precisamos de um código “de preparação” e um código “de finalização” podemos usar closures para poupar trabalho. Além das óbvias vantagens de redução de duplicação, fica bem mais difícil esquecer de fechar algo :)

Só para constar, existe um padrão pra isso, é o “Open During” do Kent Beck. Está no livro dele de “Best Smalltalk Patterns”.

Lógica condicional

Não somente de “ifs” e “switches” vivem os condicionais. Com closures, podemos simular condicionais para condições mais complexas.

Digamos que eu tenha um analisador de texto que me retorne palavrões encontrados em um HTML qualquer. Caso eu encontre qualquer palavrão, quero mostrar uma mensagem de erro.Uma maneira de fazer isso seria assim:

 # O método "find_dirty_words me retorna a coleção de palavrões
 # encontrados no texto.
 dirty_words = html.find_dirty_words
 unless words.empty?
   show_error_message(html, dirty_words, "Bad, bad, no cookies for you.")
 end

Por outro lado, posso criar isso em um método com closures dessa maneira:

 class Html
   def when_dirty_words_found
     dirty_words = html.find_dirty_words
     yield(dirty_words) unless words.empty?
   end
 end

E agora, posso usar assim:

 html.when_dirty_words_found do |dirty_words|
   show_error_message(html, dirty_words, "Bad, bad, no cookies for you.")
 end

Aliás, agora posso executar qualquer lógica com esses palavrões. Posso tentar limpá-los, contar sua frequência (estatística?), colocá-los em uma lista negra e assim por diante.

O melhor exemplo real de execução condicional com closures talvez seja o uso de REST no Rails (veja o método “respond_to” no “Listing.5”).

Domain Specific Language

Arrisco dizer que é impossível implementar uma boa DSL Interna (definição segundo Martin Fowler) sem closures.

Isso porque eles permitem uma grande flexibilidade na sintaxe, permitindo que você use os closures como blocos de código que podem ser armazenados, executados, repetidos, omitidos, reestruturados, postergados ou quaisquer que sejam as transformações necessárias para sua DSL funcionar.

Exemplos ótimos de DSL são o XML Builder e o Rake. Com pouco esforço você conseguem sintaxes perfeitas que se encaixam dentro do Ruby como se fosse parte da linguagem.

Veja por exemplo, como construir um xml com o XML Builder:

 require 'builder'

 xml = Builder::XmlMarkup.new(:target=>STDOUT, :indent=>2)
 xml.usuario(:id => 127) do
 xml.nome("Ronie")
 xml.sobrenome("Uliana")
 xml.idade(31, :type => "integer")
 xml.preferencias do
   ["strogonoff", "lasanha", "bolo de carne"].each do |item|
     xml.comida(item)
   end
 end

Isso gera o seguinte xml:

<usuario id="127">
 <nome>Ronie</nome>
 <sobrenome>Uliana</sobrenome>
 <idade type="integer">31</idade>
 <preferencias>
   <comida>strogonoff</comida>
   <comida>lasanha</comida>
   <comida>bolo de carne</comida>
 </preferencias>
</usuario>

Nesse exemplo, cada aninhamento é um closure, e o builder os rastreia para saber como montar o xml. Muito simples e prático, na verdade.

Generators

Esse eu confesso que nunca me resolveu nenhum grande problema até o momento, mas é uma técnica boa para se ter no cinto de utilidades.

Basicamente, é uma função que retorna outra, a primeira “configura” a segunda. Um exemplo simples que achei foi esse aí abaixo. Ele gera um closure que adiciona sempre o mesmo número ao número passado como parâmetro. Por exemplo, gero uma closure que adiciona sempre 5 a qualquer número que eu passe para ela. No exemplo abaixo criei dois desses, um “adicionador de cincos” e um “adicionador de oitos”.

O exemplo é meio bobo, mas se você pensar um pouco vai achar possibilidades interessantes para isso. Não sei se essas idéias seriam práticas, mas com certeza serão interessantes.

 def create_adder(number)
   lambda {|x| number + x}
 end

 add5 = create_adder(5)
 add8 = create_adder(8)

 puts add5.call(10) # retona 15, ou seja, 10 + 5

 # "add5.call(10)" é a mesma coisa que fazer add5<sup><a href="#fn10">10</a></sup>
 # Pra facilitar, vamos usar essa notação nos exemplos abaixo
 puts add8[ 30 ] # retona 38, ou seja, 30 + 8
 puts add8[ add5[ 1 ] ] # retona 14, ou seja, 1 + 5 + 8
 puts add5[ add5[ add5[ 0 ] ] ] # retorna 15... adivinha porquê :)

Um bocado complicado de entender? Bom, “lambda” é uma função que pega um bloco de código (o que está entre ”{}”) e retonar uma closure de verdade. Na prática, estou retornando uma função que será atribuída a uma variável para ser executada mais tarde. A parte legal é que essa função é “configurada” com o parâmetro “number”.

Esse é realmente embaçado, acho que fazer um equivalente em Java pode ajudar alguns (só espero não complicar o resto do povo)

 public class ClosureExample {

   public static interface Adder {
     public int call ( int x );
   }

   public static Adder createAdder ( final int number ) {
     return new Adder () {
       public int call ( int x ) {
         return x + number;
       }
     };
   }

   public static void main ( String [] args ) {
     Adder add5 = createAdder ( 5 );
     Adder add8 = createAdder ( 8 );

     System.out.println ( add5.call ( 10 ) );
     System.out.println ( add8.call ( 30 ) );
     System.out.println ( add8.call ( add5.call ( 1 ) ) );
     System.out.println ( add5.call ( add5.call ( add5.call ( 0 ) ) ) );
   }
 }

Com uma pequena variação disso da para fazer acumuladores. Ou seja, uma função que preserva a memória cada vez que é executada.

 def create_accum
   memory = 0
   lambda{|x| memory += x}
 end

 accum = create_accum
 puts accum[ 5 ] // retorna 5
 puts accum[ 10 ] // retorna 15
 puts accum[ 130 ] // retorna 145

Conclusão

Closures são muito úteis para várias tarefas comuns da computação. Não é porque sua linguagem favorita não tem e você acha que se vira muito bem nela que Closures deixam de ter sua utilidade. :)

Fechando o artigo do mesma maneira que abri:

“Beware of the Turing tar-pit in which everything is possible but nothing of interest is easy.”—Alan Perlis, “Epigrams on Programming”

Have a nice coding! :)