Em busca do nome adequado: métodos, variáveis e classes

Em busca do nome adequado: métodos, variáveis e classes
gas
gas

Compartilhe

É muito comum após alguns dias de trabalho em um projeto perceber que as escolhas de nomes de classes e métodos não condizem com o que cada um representa. Isso acontece pois, com o passar do tempo, aumenta o nosso conhecimento sobre o domínio do problema.

Também é natural surgir o desejo de mudança: a medida que nos especializamos nesse domínio, o modelo do negócio em nossa mente passa a ser diferente da visão inicial.

Um exemplo simples dessa mudança acontece quando em OO criamos um relacionamento bidirecional entre duas classes através de listas, como no exemplo a seguir:

 // a representação de um cliente, funcionário etc public class Pessoa { List<Conta> contas; }

// a representação de uma conta bancária (poupança, corrente, investimento etc) public class Conta { List<Pessoa> pessoas; } 

A primeira vista esse é o relacionamento entre as duas entidades mas em determinado momento notamos que na verdade a relação entre pessoa e conta é um Titular, que possue características próprias, como o contrato que ele como titular da conta assinou:

 public class Pessoa { List<Titular> titularidades; } public class Conta { List<Titular> titulares; } public class Titular { Conta conta; Pessoa pessoa; // outras características de uma titularidade } 

Nesse caso o processo de refatoração envolve extrair uma classe que representa tal relação, um Titular: um exemplo simples que demonstra como em OO é comum a existência de classes para representar informações intangíveis.

Outras questões simples mas fundamentais para o bom design e legibilidade da aplicação estão ligados aos nomes que escolhemos, não só em relação ao nome da classe e de seus métodos. No exemplo acima, por uma escolha fraca no nome da variável membro conta e pessoa acabamos com um código que parece repetitivo e pouco descritivo:

 Pessoa pessoa; 

Se em nosso sistema funcionários, gerentes, titulares e caixas são representados através de instâncias do tipo Pessoa, o mais adequado seria nomeá-los de acordo:

 public class Titular { Conta conta; Pessoa cliente; } 

A tendência natural do desenvolvedor em linguagens que obrigam a declaração do tipo é criar variáveis com nome identicos ao tipo declarado, por ser um atalho das IDEs e mais simples de escrever. Mas tais alternativas, como visto, dizem pouco sobre a variável que está sendo acessada. Por esses motivos, é muito comum encontrar código como:

 Cliente cliente = clienteDao.busca(13); Pagamento pagamento = pagamentoDao.busca(15); ProcessadorDePagamento processador = new ProcessadorDePagamento(); processador.processa(cliente, pagamento); 

Cliente, pagamento, processador: é somente desses três elementos que nosso domínio é composto? E nem mesmo Ruby foge disso, sendo comum encontrar:

 cliente = Cliente.find\_by\_id 13 pagamento = Pagamento.find\_by\_id 15 processador = Processador.new processador.processa cliente, pagamento 

Três aparições de cliente, três de pagamento, quatro de processador. Aqui existe uma visão distorcida de que variáveis são somente aquilo que o tipo descreve: um cliente, um pagamento, um processador. Na verdade elas referenciam instâncias específicas e especializadas de um tipo determinado. Só faria sentido chamar o cliente 13 de cliente se ele é o único cliente, um singleton. Especialize o nome de suas variáveis e crie um código mais legível:

 Cliente devedor = clientes.busca(13); Pagamento fatura = pagamentos.busca(15); ProcessadorDePagamento mensalidade = new ProcessadorDePagamento(); mensalidade.cobra(devedor, fatura); 

O mesmo pode ser refletido no exemplo de Ruby. E como trabalharemos nossos repositórios para permitir uma maior legibilidade do código?

 Pessoa pessoa = ...; List<Conta> contas = dao.contasDe(pessoa); 

Note como por causa da escolha do nome da variável pessoa fomos obrigados a colocar algo mais descritivo no método. Caso a variável possua um nome mais adequado, teríamos então:

 Pessoa cliente = ...; List<Conta> contas = dao.contasDe(cliente); 

Modificando nossa classe Conta para adicionar o gerente e o subgerente temos novamente o sentido das variáveis descrito não só pelo seu tipo, mas também pelo seu nome:

 public class Conta { List<Titular> titulares; Pessoa gerente; Pessoa subgerente; } 

Nesse instante a query ficaria mais complexa pois existem dois relacionamentos distintos com pessoa, requerendo a criação de uma DSL interna para query. No exemplo a seguir usamos um builder para facilitar a construção da query:

 Pessoa gerente = ...; Pessoa subgerente = ...; List<Conta> contas = dao.comGerenteESubgerente (gerente, subgerente): 

Essa é a abordagem que o jbehave 3.2 e o selenium utilizam, onde acabamos por ter uma sintaxe muito longa e repetitiva.

Retomando o problema do nome das variáveis, que pode ser resolvido com outra refatoração de rename: o código da terceira linha é mais descritivo que o anterior:

 Pessoa gerente = ...; Pessoa subgerente = ...; List<Conta> contas = dao.comGerente(gerente) .comSubgerente(subgerente): 

Em linguagens onde mapas podem ser representados através de literais, o ruído sintático é baixo e permite que seja escrito código como a seguir em Ruby:

 gerente = ... subgerente = ... contas = Conta.com :gerente => gerente, :subgerente => subgerente 

Novamente, a refatoração aqui é fundamental:

 principal = ... secundario = ... contas = Conta.com :gerente => principal, :subgerente => secundario 

A escolha dos nomes de nossas classes influencia o design e legibilidade de nosso código direta e indiretamente, primeiro pela declaração das variáveis e a nossa visão do domínio. Depois pelas consequências que o mesmo possui na escolha dos nomes das variáveis e métodos, que permitem um design mais ou menos legível.

Essa escolha é tão importante quanto o resto de seu design para facilitar a compreensão do que seu domínio é e qual o problema que está tentando atacar. Na próxima vez que for declarar uma variável com o mesmo nome que o tipo, pense duas vezes.

Veja outros artigos sobre Inovação & Gestão