Com ou sem Lombok, nunca se esqueça da Orientação a Objetos

Willyan Guimarães
experienceCode
Published in
4 min readSep 28, 2021

O Lombok é uma biblioteca que resistiu ao tempo ( ̶n̶ã̶o̶ ̶d̶e̶v̶e̶r̶i̶a̶) e está presente em diversos ( ̶a̶l̶g̶u̶n̶s̶) projetos Java. A proposta é simplificar o trabalho do programador dado a verbosidade da linguagem. Com anotações, gera códigos boilerplate de classes, possui features para criar métodos estáticos, implementar Builders e por aí vai. Tem até a possibilidade de esconder complexidades com Exceptions. Algumas dessas features também estão disponíveis em IDEs, porém, vale considerar/analisar caso a caso o que é melhor, a ferramenta ou a biblioteca.

Existem alguns perigos nas facilidades que o Lombok, provê. Talvez a pior delas de fato seja na construção da unidade conceitual mais simples que existe em Orientação a Objetos: a classe. Vale um warning aqui, que sim; é possível usar com cuidado a biblioteca, sem grandes prejuízos. A questão é que muitas vezes dado os padrões que vão se adotando a preocupação de design com as classes fica menor exatamente pela facilidade com anotações. Mais uma vez, não é uma generalização.

Deixar de se preocupar com escolhas a serem feitas nesse nível, é colocar em jogo o design do micro ao macro. Logo mais tarde, a manutenção fica complexa, o acoplamento cresceu "e a única solução é começar do zero".

Algumas considerações e um exemplo

Sim, existe programação em Java sem Lombok!

Se voce é novo na linguagem, chegou em um momento muito bom. Tenha certeza, as coisas já foram mais difíceis. Mas se todos os contatos que teve com Java foi utilizando Lombok reconsidere fazer uma classes na mão para entender os conceitos que existem por trás delas.

@Data pode ser sempre conviente ?

Veja o cenário da classe abaixo:

@Data
public class ContaCorrente {
private String id; private String agencia; private String conta; private BigDecimal saldo; private List<Lancamento> lancamentos;
}

@Data é uma anotação que gera automaticamente vários membros para essa classe

  • Acessores, ou seja, getters e setters
  • equals e hashCode com todos os atributos sendo utilizados para cálculo e verificação de igualdade
  • toString
  • construtor(es)

Aqui nesse link você pode ver a respectiva geração da classe acima.

Vale refletir alguns questionamentos:

  • Faz sentido mesmo um método setSaldo ? Pela lógica (a mais simples a se pensar), o saldo de uma conta é o resultado de vários lançamentos de débito e crédito. Pensando assim, não faz sentido algum esse setter.
  • Dado um id para essa classe, faz sentido poder alterá-lo (setId) ? Mais uma vez, é certo que não já que dado a identificação ela é única e imutável.
  • Veja o método setLancamentos(): Também não é correto alterar a lista de lançamentos. Pela lógica, é bem provável que a única modificação nesse caso seja adicionar novos lançamentos a conta.

Esta classe representa um exemplo nítido de modelo anêmico. Anêmico porque possui apenas dados, e nenhum comportamento. Ela possui métodos acessores e construtores.

Pensando um pouco sobre cada membro de uma classe

A importância para o modelo de um construtor

Construtor é o estado do qual o objeto de uma classe surge. Será mesmo que uma conta corrente é criada com lancamentos ? Pode até ser que sim, mas a grande questão aqui é entender que como cada contexto é específico deve-se procurar pensar bastante em como criamos um objeto. Tão ruim quanto gerar métodos acessores para atributos que não deveria é criar construtores sem sentido.

Você precisa do toString mesmo ?

@Data acrescenta toString, a pergunta é se de fato será necessário para a classe.

equals e hashCode

O método equals criado faz comparação de todos os atributos da classe. É necessário mesmo ? Aqui uma pergunta válida para a criação de um método é entender o que realmente significa que um objeto daquela classe é igual a outro. Em vários cenários não precisamos de todos os atributos.

Bom, e se eu quiser manter o uso do Lombok, como eu poderia melhorar esse cenário?

Para melhorar essa classe podemos:

  • Identificar quais campos de fato fazem sentido métodos getter/setter
  • Entender como o objeto deve ser construído e quais campos são obrigatórios para sua criação
  • Entender quais atributos de fato representam a igualdade do objeto

Assim, chegaríamos a essa solução:

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class ContaCorrente {
@Getter
@EqualsAndHashCode.Include
private String id;
@Getter
private String agencia;
@Getter
private String conta;
@Getter
private BigDecimal saldo;
private List<Lancamento> lancamentos; public ContaCorrente(final String agencia, final String conta) {
this.id = UUID.randomUUID().toString();
this.agencia = agencia;
this.conta = conta;
this.lancamentos = new ArrayList<>();
}
public final List<Lancamento> getLancamentos() {
return List.of((Lancamento[]) lancamentos.toArray());
}
}

Atualmente, não existe no Lombok uma anotação que permita escolher quais fields serão incluídos no construtor. Logo, o caminho é criar na mão mesmo. No exemplo também criamos um método getter para a lista, fazendo assim que uma lista imutável seja retornada para o chamador, o que evita manipulações fora do contexto da classe. Também inserimos uma anotação que escolhe quais atributos fazem parte do método equals.

Concluindo

Enfim, com Lombok ou sem lembre-se que é preciso pensar em como escrever suas classes, como ela nasce como objeto, o que a descreve como igual a outro objeto do mesmo tipo de referência, o que a identifica e não menos importante quais os comportamentos ela possui.

A proposta acima melhora um pouco design mas ainda sim é pobre de comportamento. É importante ir além e entender o porque essa classe existe e o que ela faz. Para esse contexto poderíamos pensar em métodos para adicionar lançamentos, manipular saldo e vários outros cenários.

A discussão sobre usar ou não esse tipo de ferramenta divide muitas opiniões, mas uma coisa é unânime: não podemos nos afastar do conceito de orientação a objetos e portanto, trate de cuidar com carinho as escolhas que são feitas nessa camada.

Referências:

--

--