Guia de Nomenclatura

A escrita de código passa inevitavelmente por criar nomes. Nomes de classes, de métodos e de variáveis. Praticamente todo o código que escrevemos — que não é uma palavra reservada da linguagem — é um nome que tivemos que criar em algum momento, ou o nome que alguém já criou. Porque uma grande parte do código são nomes é útil e conveniente ter uma convenção de nomenclatura.

Nomes cuidadosamente escolhidos tornam o código mais legível não apenas do ponto de vista da língua, mas também do propósito. Ao ser mais claro o propósito apenas pela leitura do código diminui a necessidade de comentários que expliquem o que o código faz. Pela diminuição de comentários, e clareza do código, o código se torna a sua própria melhor documentação.

O objetivo de uma convenção de nomenclatura é escolher certas regras que, se seguidas, produzem um nome legível, com significado e com uma mesma estrutura. Para escolher entre as regras temos que saber quais princípios elas devem obedecer, pois se criarmos uma regra de nomenclatura contrária a estes princípios, estaremos complicando o processo de criar nomes.

Princípios de Nomenclatura

Expresse intenções

A primeira coisa que um nome deve fazer é identificar. A identificação deve trazer à mente de quem lê uma imagem em particular. No código, o nome deve revelar a intenção por detrás daquele artefato (classe, método, variável, etc…​) [[1]] [[2]]

O nome deve ser claro, simples e único. Para ser claro não pode haver ambiguidade na identificação do nome com um, e apenas um, conceito. Para ser simples o nome deve ser composto do mínimo de palavras possível sem que obscureça o significado. Idealmente deve ser composto de apenas uma palavra. Para ser único o nome deve ser usado apenas para se referir a um único conceito no sistema.

Facilite a comunicação

Se nomeamos uma coisa é porque gostaríamos de nos referir a ela no futuro apenas usando o seu nome. Gostaríamos também que as outras pessoas soubessem ao que estamos nos referindo, apenas dizendo o nome. Para isto o nome tem que ser pronunciável. Nomes que são conjuntos de letras e nomes como 'a1" e "bc3to" onde somos obrigados a pronunciar as letras e os números um por um, são exemplo de maus nomes.

Outro fator que dificulta a pronuncia é a utilização de prefixos sem significado como começar todas as variáveis internas com underline ou o uso da Notação Hungara, muito famosa nos anos 70 em linguagens com modelos de tipos pouco definidos ou voláteis demais.

Outro fator que pode atrapalhar a comunicação é o uso de nomes com apenas uma letra como a ou b . Esta regra pode ser quebrada se estamos usando as letras i, j ou k como contador, pois pela tradição todos acabam entendendo que se trata de uma variável muda de iteração. Outro ponto onde usar uma só letra é quando estamos resolvendo um problema matemático onde o uso de x, y e z é facilmente reconhecível.

Para facilitar a comunicação os nomes não devem ter segundos significados, ou significados engraçados para a equipa e não devem ser usados sinônimos espertinhos em vez da palavra que seria esperada. Por exemplo um método que faz a aplicação terminar deve se chamar "terminar" e não "daOFora".

Preferência de Domínio Técnico

Em caso de duvida, ambiguidade ou dificuldade em encontrar um nome, nomes que estão relacionados aos conceitos técnicos usados no design devem ser preferidos. Em outras palavras nomes do domínio da solução devem ser preferidos a nomes do domínio do problema [[1]]. A razão para isto é que quem irá ler o código é um outro programador. Como programador ele terá que entender o propósito da classe apenas conhecendo o seu nome. Se usamos nomes do domínio do problema, o programador pode não estar familiarizado com o problema e portanto não entender o que está sendo feito pelo código.

Esta regra não é aplicável, obviamente, a classes que apenas existem como representações do domínio do problema; especialmente entidades.

Esta regra é útil para poder reaproveitar nomes facilmente usando nomes de padrões de projeto. Por exemplo um ServiceRegistry é uma classe que segue o padrão Registry e é usada para guardar e recuperar serviços.

Estilos de escrita

Todos os nomes devem seguir o padrão CamelCase em que as palavras são aglutinadas sem espaços ou sinais não alfabéticos. As palavras são diferenciadas colocando a primeira letra em caixa alta.

Nomes de tipos ( interface, interfaces, enumerações e anotações) devem seguir o estilo UpperCamelCase com a primeira letra da palavra grifada maiúscula.

Nomes de métodos ou variáveis devem seguir o estilo LowerCamelCase em que a primeira letra é grifada em minuscula.

Nomes de pacotes são escritos sempre em minuscula, com as várias partes que compõem o nome separadas por ponto final. Cada parte do nome é formada apenas por uma única palavra.

Abreviações não devem ser utilizadas na formação de nenhum nome. Existem algumas exceções como a abreviação Id que é usada tradicionalmente para abreviar Identification, mas como regra abreviações não devem ser usadas. Nomes devem ser completos e facilmente legíveis, abreviações não cooperam com estes princípios [[5]]

Siglas como HTTP, URL e AJAX (entre outros) devem seguir o estilo camel case normalmente como se fossem palavras, por exemplo um método assessor que recupere um URL seria getUrl() [[5]] e não getURL . A API Java padrão não adota uma politica especifica para estes casos. Por um lado termos a classe HttpServlet e por outro as classes URL e URLConnection demonstrando uma falta ou falha nas regras de nomenclatura.Embora essas diferenças tenham razões históricas, com certeza é um exemplo a não seguir.

Nomeando Pacotes

A plataforma de desenvolvimento não força regras para a nomenclatura de pacotes, contudo é recomendado que os nomes sejam escolhidos tal que o pacote seja universalmente único [[4]] . Para alcançar este objetivo é normalmente usado um caminho de domínio invertido como por exemplo com.javabuilding como pacote principal. O pacote principal é seguido do nome do projeto/aplicação. Dentro de pacote da aplicação são criados os pacotes para as partes da aplicação conforme o design utilizado.

Nomes dos pacotes internos da aplicação devem expressar o propósito das classes lá dentro da forma mais simples possível. Por exemplo, um pacote chamado org.enterprise.app.validation deverá conter classes que auxiliam a validação. Nomes de pacotes não devem ser usados para separar entres camadas ou andares da sua aplicação. Podem ser usados em casos especiais para separar entre nodos como org.enterprise.app.server e org.enterprise.app.client

Nomeando Classes

Os nomes das classes devem ser substantivos que designam o conceito ou a responsabilidade que a classe ocupa no sistema. Os nomes devem ser específicos o suficiente para estarem relacionados ao problema ou à solução e nomes genéricos como coleção, dados, informações, controlador ou processador, por exemplo.

Nomes de classes podem ter prefixo ou sufixos que tentam orientar o programador sobre o nível que a classe ocupa em uma hierarquia ou no design do sistema. Contudo prefixo ou sufixo que não adicionem informação devem ser evitados. Por exemplo, chamar um classe de NotafiscalPOJO ou NotaFiscalBean não faz sentido pois já é sabido que essas classes serão beans e POJOs. Especialmente classes que representam entidades do domínio como Cliente, Produto, Usuário, não precisam de qualquer afixo.

Outro prefixo que é inútil é um que identifique a aplicação [[1]]. Isso deve ser feito pelo nome de pacote da classe e não pelo nome da classe em si.

Nomeando Interfaces

As regras de nomenclatura de interfaces devem seguir os mesmos princípios das regras para classes. A única diferença é que podemos escolher não apenas substantivos, mas também adjetivos e advérbios.

Muitos gostam de prefixar suas interfaces com um I maiúsculo. Esta prática não é recomendada [[1]] por violar explicitamente o encapsulamento fornecendo informação demais. Além disso, se nos arrependemos depois e quisermos mudar para uma classe essa mudança irá provocar uma refatoramento desnecessário do código inteiro e até de código cliente já escrito por outras pessoas.

Nomeando Classes Abstratas e Implementações

A nomenclatura para classes abstratas é a mesma que para classes normais e interfaces normalmente adicionada do prefixo Abstract. Este recurso é especialmente importante no desenvolvimento de API de uso geral onde os elementos principais são definidos como interfaces e classes abstratas são implementadas para fornecer implementações padrão para a maior parte dos métodos da interface. O prefixo Abstract não é usado para significar que a classe precisa ser implementada, mas sim para posicionar a classe num patamar superior da hierarquia de classes (logo abaixo de interfaces, e acima de classes comuns). O prefixo Abstract no nome não força que a classe seja abstrata de fato ( marcada com abtract ), contudo, o fato da classe ser marcada com a abstrata força que o nome seja prefixado com Abstract.

A nomenclatura para implementações de classes abstratas ou interfaces segue a regra de usar o mesmo nome da classe/interface pai com um prefixo ou sufixo que a distinga como sendo a implementação. É comum utilizar o sufixo "impl" para designar a implementação. Contudo esta não é uma boa prática, pois no momento que queremos uma implementação diferente não mais podemos usar esse prefixo e muito menos podemos usar prefixos como "impl2". Além disso o uso do prefixo "impl" viola o principio da Facilidade de Comunicação ao forçar a pronuncia de um afixo abreviado e sem dar informação sobre no que aquela implementação é diferente das outras.

Prefixos e sufixos de implementações devem explicitar a forma em que aquela implementação é especifica e diferente das outras. Normalmente este afixo está relacionado ao algoritmo ou à tecnologia usada internamente naquela implementação. Exemplos clássicos são ArrayList que é a implementação de List usando um array, ou TreeSet que é a implementação de Set usando um algoritmo de arvore binária.

Quando estamos implementando uma interface ou classe abstrata mas não conseguimos ver à partida várias opções de implementação afixos como Simple , Default ou Actual são comuns; como em SimpleDateFormat e DefaultTableModel.

Nomeando métodos e construtores

Nomes de métodos devem ser verbos ( enviar, pagar, …​) com a possibilidade de serem compostos com advérbios ou substantivos relativos ao papel dos argumentos ( enviarProposta, pagarImpostos ) Métodos que representem assessores ou modificadores devem seguir a nomenclatura JavaBeans [[3]] começando com o prefixo get (assessor) ou com set (modificador).

Construtores são obrigados a ter o mesmo nome da classe (pelo menos em Java e C#) o que significa que se o construtor tiver parâmetros não temos como oferecer um auxiliar semântico para o significado de cada um. Neste caso é conveniente declarar métodos estáticos corretamente nomeados que informem o propósito dos argumentos e deixar os construtores com parâmetros privados seguindo o padrão Static Method Factory

Nomeando Exceções

Os nomes devem revelar a causa da exceção e devem terminar com o sufixo que representa a sua hierarquia de exceção: Exception ou Error . Por exemplo, em ArithemeticException sabemos que se trata de uma classe derivada de Exception , e não de Error , que foi causada por algum problema em uma operação aritmética.

Modelos de Nomenclatura

Algumas classes com utilidade especifica têm formas especificas de serem nomeadas. A seguir são listados alguns modelos de nomenclatura para estes conjuntos de classes, baseados nas regras anteriores.

Entidades

O nome de uma entidade é uma exceção ao principio de Preferência de Domínio Técnico. Nomes de entidades não devem conter sufixo ou prefixos de nenhum tipo, nem mesmo o popular Entity. Nomes de entidades, são exatamente isso, nomes. Substantivos que são recolhidos do domínio do problema e que normalmente guiam o objetivo ou a operação do software.

Repositório

A nomenclatura do padrão Repository segue o modelo: [Entidade]Repository

Esta nomenclatura segue o principio de Preferência de Domínio Técnico deixando o nome do padrão no fim do nome. O nome é precedido pelo nome da entidade a que este repositório se refere.

Serviço

O padrão Service tem duas peças: a interface do serviço e a implementação do serviço. A nomenclatura para a interface do padrão Service segue o modelo: [Proposito]Service . Esta nomenclatura segue o principio de Preferência de Domínio Técnico deixando o nome do padrão no fim do nome. O nome é precedido pela descrição do proposito em forma resumida, por exemplo: EmailSendingService.

O nome da implementação do serviço segue o modelo: [Tecnologia][Proposito]Service , em que ao nome da interface do serviço é adicionado um prefixo que denota o tipo de tecnologia ou algoritmo que o serviço utiliza para satisfazer a interface, por exemplo: JavaMailEmailSendingService

DAO

O padrão DAO , semelhante ao padrão Service tem duas peças: a interface do serviço/estratégia e a implementação. Para DAO associados a entidades, o nome da entidade é adicionado como prefixo para distinguir entre os contratos de cada entidade. O nome da interface segue o modelo [Entidade]DAO e o da implementação o modelo: [Tecnologia][Entidade]DAO. Esta nomenclatura segue o principio de Preferência de Domínio Técnico deixando o nome do padrão no fim do nome.

O nome da implementação começa com o nome da tecnologia de persistência que a implementação do DAO usa, seguindo pelo nome da interface que está sendo implementada, por exemplo JdbcCustomerDAO

Inglês vs Português

Muito do conceito de linguagem de programação é baseado na ideia de escrever o mais próximo da linguagem natural possível. Acontece que esta língua é normalmente o inglês. Por isso que as palavras reservadas são em inglês. A ideia é que se misturem bem com o resto dos nomes para prover uma leitura o mais fluida possível. É esta leitura fluida que promove a melhor documentação e o código mais limpo [[2]]

O problema acontece quando a língua natural do programador não é o inglês. Um programador cuja língua natural não é o inglês terá o entendimento do código dificultado à partida pois a leitura não mais é fluida. Mesmos assim, é possível adaptar regras de nomenclatura especificas à língua natural e ter os mesmos benefícios que antes. Todos excepto um: quem não souber ler aquele língua não entenderá o código. O problema não é apenas para quem tem o Português como língua natural, mas para todos aqueles que têm uma língua natural diferente do inglês. Por exemplo, o japonês. Embora java aceite código fonte em UTF-16 (permitindo assim a escrita de caracteres japoneses) apenas programadores que saibam ler e dominem o idioma podem entender o código.

Existem ocasiões em que obrigatoriamente teremos que usar o inglês. Afinal, o inglês é a língua franca de fato em programação. Isto acontece sempre que precisamos partilhar o código com outras pessoas em outros países ou culturas. Projetos Open Source são um exemplo. Projetos em Outsource são outro. Na realidade existem poucos exemplos de quando o seu código não seria partilhado com pessoas de outros países ou culturas.

Deve estar pensando que a sua aplicação é muito simples, que você vai vendê-la para um só cliente e nunca sairá das fronteiras do seu pais ou do seu controle. Isso pode ser verdade durante a vida inicial do software, mas se ele durar, se houver necessidade de dar manutenção, se você quiser ganhar mais dinheiro comercializando o fonte ou se simplesmente quiser fazer outsource , ou open source, do desenvolvimento porque os custos estão muito caros…​ você não poderá. Escrever código em uma língua natural que não o inglês limita automaticamente a evolução, expansão e vida útil do seu software.

Um detalhe que leva muita gente a não escrever em inglês é achar que certos conceitos são muito particulares da cultura e não podem ser expressos em inglês (como por exemplo o CPF ou o CNPJ). Então, mesmo quando escrevendo o resto do aplicativo em inglês é comum ver classes do domínio com nomes na língua natural do programador. Isto é um problema porque esses nomes não traduzem o conceito, violando diretamente o principio de Expressar Intensão. Ele é o nome dado no domínio do problema a um certo conceito. Porque o programador, não sabe ou não consegue abstrair esse conceito ele não consegue atribuir outro nome além daquele que conhece na sua língua natural. Ao abstrair o conceito, é mais fácil encontrar um equivalente em inglês. Por exemplo, o CPF e o CNPF representam apenas um conceito: o numero de identificação tributário. Que podemos facilmente nomear em inglês como TributaryIdentificationNumber ou TaxIdentificationNumber ( numero de identificação para pagamento de impostos).

Não é necessário que o nome em inglês seja a tradução direta porque isso pode causar outros problemas relativamente ao domínio. Por exemplo, nos EUA, os impostos são identificados usando o Social Security Number, que é o mesmo numero que a pessoa usa para se identificar em outras agencias do governo, não apenas a que recolhe os impostos e faz, para essa entidade o mesmo papel que o RG. Portanto, tentar a tradução direta é muitas vezes um erro em si mesmo porque não ha uma contraparte na cultura inglesa. Por isso temos que nos concentrar em criar um nome, e não em traduzir.

Por exemplo, boletos bancários são uma prática que não existe fora do Brasil assim como não existem no Brasil a prática de emitir Cashier’s Checks . Boleto bancário é, assim, intraduzível diretamente. Contudo, atendendo ao conceito facilmente podemos criar o nome de PrintableBankCreditTitle

Analisar o nome do conceito na sua língua natural e tentar passá-lo para o inglês o ajudará a criar maior poder de abstração e um maior poder de abstração o poderá ajudar a modelar orientado a objetos de uma forma mais simples e natural. Por outro lado, ao abstrair o conceito você pode ver novas hierarquias de objetos e classes

Ninguém o vai impedir de criar nomes em línguas naturais diferentes do inglês, mas tenha em mente que ao fazer essa escolha estará inevitavelmente restringindo a evolução do software que está escrevendo.

Bibliografia

[1] Robert C. Martin Clean Code: A Handbook of Agile Software Craftsmanship: Pearson Education (2009)

[2] Steve McConnell Code Complete: DV-Professional (2004)

[4] Code Conventions for the JavaTM Programming Language: Naming Conventions (http://java.sun.com/docs/codeconv/html/CodeConventions.doc8.html)

[5] Joshua Bloch Effective Java, 2nd Edition: Fonenix inc (2008)

Scroll to Top