Li ontem um artigo chamado Polyglote Programming do Neal Ford, autor do “The Productive Programmer” comentado pelo Erich aqui no TecBlog.

Esse artigo, publicado numa antologia de artigos de funcionários da ThoughtWorks, fala sobre a necessidade de saber programar em várias linguagens não só para saber usar a linguagem mais apropriada para cada sistema mas também, dentro de um único sistema, saber usar a linguagem mais apropriada para a tarefa a ser resolvida.

De uma certa forma, o desenvolvimento de sistemas web já é poliglota, pois precisamos saber SQL, javascript, XML, HTML e alguma linguagem (Ruby, PHP, Java, etc.) para unir tudo. Mas a idéia do Neal Ford é ir além e usar as plataformas poliglotas (JVM, C#) para desenvolver cada pedaço de código com a linguagem mais apropriada para o que aquele pedaço de código precisa resolver.

Um exemplo que ele cita é a leitura de arquivos, que pode ser bastante trabalhosa em Java:

package com.nealford.polyglot.linenumbers;

import java.io.*;
import static java.lang.System.*;

public class LineNumbers {
  public LineNumbers(String path) {
    File file = new File(path);
    LineNumberReader reader = null;
    try {
      reader = new LineNumberReader(new FileReader(file));
      while (reader.ready()) {
        out.println(reader.getLineNumber() + ":"
          + reader.readLine());
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        reader.close();
      } catch (IOException ignored) {
      }
    }
  }

  public static void main(String[] args) {
    new LineNumbers(args[0]);
  }
}

Mas que em Groovy, que roda em JVM, ficaria:

def number=0
new File (args[0]).eachLine { line ->
  number++
  println "$number: $line"
}

Outro exemplo é um pedaço de código tirado do projeto Apache Commons para determinar em Java quando um string é vazio:

public static boolean isBlank(String str) {
  int strLen;
  if (str == null || (strLen = str.length()) == 0) {
    return true;
  }
  for (int i = 0; i < strLen; i++) {
    if ((Character.isWhitespace(str.charAt(i)) == false)) {
      return false;
    }
  }
  return true;
}

Usando Jruby teríamos:

class String
  def blank?
    empty? || strip.empty?
  end
end

E os testes para comprovar que está tudo certo:

require "test/unit"
require "blankness"

class BlankTest < Test::Unit::TestCase
  def test_blank
    assert "".blank?
    assert " ".blank?
    assert nil.to_s.blank?
    assert ! "x".blank?
  end
end

Outra dica que ele dá é usar uma linguagem funcional (Haskell, Scala, F#) para resolver a dificuldade que linguagens imperativas como Java e C# tem em lidar com threading:

class SafeArray{
  private final Object[] _arr;
  private final int _begin;
  private final int _len;
  public SafeArray(Object[] arr, int len){
    _arr = arr;
    _begin = begin;
    _len = len;
  }

  public Object at(int i){
    if(i < 0 || i >= _len){
      throw new ArrayIndexOutOfBoundsException(i);
    }
    return _arr[_begin + i];
  }
  public int getLength(){
    return _len;
  }
}

A mesma funcionalidade em Jaskell, a implementação de Haskell para JVM:

newSafeArray arr begin len = {
  length = len;
  at i = if i < begin || i >= len then
    throw $ ArrayIndexOutOfBoundsException.new[i]
  else
    arr[begin + i];
}

E o último exemplo do artigo compara construção de testes com JMock, para testar a interação entre uma classe Order com uma classe Warehouse:

package com.nealford.conf.jmock.warehouse;

import org.jmock.Mock;
import org.jmock.MockObjectTestCase;

public class OrderInteractionTester extends MockObjectTestCase {
  private static String TALISKER = "Talisker" ;

  public void testFillingRemovesInventoryIfInStock() {
    //setup - data
    Order order = new OrderImpl(TALISKER, 50);
    Mock warehouseMock = new Mock(Warehouse.class);

    //setup - expectations
    warehouseMock.expects(once()).method("hasInventory" )
      .with(eq(TALISKER),eq(50))
      .will(returnValue(true));
    warehouseMock.expects(once()).method("remove" )
      .with(eq(TALISKER), eq(50))
      .after("hasInventory" );

    //exercise
    order.fill((Warehouse) warehouseMock.proxy());

    //verify
    warehouseMock.verify();
    assertTrue(order.isFilled());
  }
}

E com JRuby:

require 'test/unit'
require 'rubygems'
require 'mocha'

require "java"
require "Warehouse.jar"
%w(OrderImpl Order Warehouse WarehouseImpl).each { |f|
  include_class "com.nealford.conf.jmock.warehouse.#{f}"
}

class OrderInteractionTest < Test::Unit::TestCase
  TALISKER = "Talisker"

  def test_filling_removes_inventory_if_in_stock
    order = OrderImpl.new(TALISKER, 50)
    warehouse = Warehouse.new
    warehouse.stubs(:hasInventory).with(TALISKER, 50).returns(true)
    warehouse.stubs(:remove).with(TALISKER, 50)
    order.fill(warehouse)
    assert order.is_filled
  end
end

Para terminar esse post, aqui vai um link para um vídeo do Neal Ford explicando o conceito de programação poliglota:

http://www.nofluffjuststuff.com/media.jsp?id=28

*Post retirado do blog Tecnologia da Internet da locaweb