Código expressivo e programação funcional em Java com LambdaJ
Há um certo tempo refatoramos o sistema que trabalhamos. Migramos de uma arquitetura definida pelo Fowler como Transaction Script (explicada nesse edição da MundoJ) para uma arquitetura essencialmente O.O Domain Model. Por incrível que pareça, o que mais nos chamou a atenção nesse processo não foi o fato de transferir a lógica de negócios para as entidades responsáveis, visto que delegar responsabilidades é complicado e é isso que faz do O.O tão desafiante, mas sim a qualidade na expressividade do código que atingimos.
Alguns sinais de que seu código não esteja expressivo são os comentários. A lógica é que, se você está explicando com comentários algo que o próprio código deveria dizer, é um smell, neste caso um forte sinal da falta de expressividade (não para a linguagem, mas não está se expressando bem para outro programador).
Sabemos que programador odeia ver código de outro programador, e nos tempos atuais onde a agilidade e ideia de código coletivo estão cada vez mais em alta, código expressivo passa a ser uma exigência, quase que um requisito não funcional. Vamos considerar o código abaixo, tente lê-lo você mesmo:
public void imprimirEstatisticasDeVenda(Vendedor vendedor) { BigDecimal total = BigDecimal.ZERO; BigDecimal comissao = BigDecimal.ZERO; for (Venda venda : vendedor.getVendas()) { total = total.add(venda.getQuantidade().multiply(venda.getPreco())); if(venda.getQuantidade().doubleValue() >= 5) { if(venda.getPreco().doubleValue() >= 5) { comissao = comissao.add(venda.getQuantidade(). multiply(venda.getPreco()).multiply(new BigDecimal(0.05))); venda.priorizarDespache(); } } } System.out.println(vendedor.getNome() + " - Total arrecadado: " + df.format(total) + " - Comissao: " + df.format(comissao)); }
Se analisarmos linha a linha, veremos que este código calcula o total arrecadado a partir das vendas, o total de comissão que deve ser pago ao vendedor que efetuou as vendas, e finalmente prioriza aquelas vendas que tiveram quantidade e preço maior que cinco.
Ele poderia ser melhorado? Sim, de diversas formas: poderíamos ter extraído varias partes desse código para métodos menores e com nomes significativos para torná-lo mais limpo. Outra opção é buscar por bibliotecas ou criar suas próprias DSL's.
Para não esperar as closures do Java 8, conseguimos um pouco de programação funcional utilizando a biblioteca LambdaJ, dando um toque de cálculo de lambda ao Java. Ao reesrever o código utilizando essa biblioteca, temos algo mais enxuto:
public void imprimirEstatisticasDeVenda(Vendedor vendedor) { List<Venda> vendas = vendedor.getVendas(); BigDecimal totalArrecadado = sumFrom(vendas).getValorDaVenda();
List<Venda> vendasComissionaveis = select(vendas, comQuantidadeMaiorOuIgualA(5).and(comPrecoMaiorOuIgualA(5))); forEach(vendasComissionaveis).priorizarDespache();
BigDecimal comissao = sumFrom(vendasComissionaveis) .getValorDaVenda().multiply(new BigDecimal(0.05));
System.out.println(vendedor.getNome() + " - Total arrecadado: " + df.format(totalArrecadado) + " - Comissao: " + df.format(comissao)); }
Seria esse um código mais expressivo? Consideramos que sim, mas alguns vão criticar que estamos escondendo uma certa complexidade do sistema, que deveria estar a vista dos programadores. E a performance? O LambdaJ tem suas inicializações e objetos temporários, sendo um pouco mais lento que a versão anterior, podendo trazer problemas em laços. Há também o problema de ser uma biblioteca de fora da API padrão, e os desenvolvedores precisam de um tempo, mesmo que curto, para se adaptar às novas ideias trazidas por ela. Se você já cursou o FJ-16, pode conferir a modelagem em Scala, mais funcional.
Expressividade de código derruba alguns conceitos que aprendemos, principalmente sobre Design Patterns. Afinal, o que o seu cliente entende: Usar um BO para alterar o VO e persistir usando o DAO no MYSQL ou "salvar cliente no repositório de cadastros"?