Qué es Exactamente un Nombre — Parte II: Las malas Costumbres

Estamos todos de acuerdo: un buen nombre es siempre lo más importante. ¡A corregirlos!

Maximiliano Contieri
DotTech
6 min readSep 14, 2020

--

Foto por Big Dodzy en Unsplash

Todos utilizamos nombres para programar, no importa si el lenguaje es de alto o bajo nivel, o si es Imperativo, Funcional o de Objetos. Los nombres están por todos lados. Pero seguimos utilizándolos mal. En esta segunda parte refutaremos algunas malas prácticas.

La búsqueda ya comenzó

En un artículo anterior presentamos diversas definiciones y técnicas para buscar buenos nombres.

En esta nota intentaremos demostrar algunos problemas presentes sobre nomenclatura con el fin de ir mejorando nuestras prácticas.

No necesitamos ayuda

Todos los objetos ayudan, no hay objetos “no solidarios”.

En el mundo real no hay helpers.

Tenemos una única regla de diseño. Si un concepto no existe en el mundo real y no se lo podemos explicar a un experto del dominio, dicho objeto no debe existir.

Regla 9: Los helpers no existen.

No necesitamos Jefes

Todos los objetos nacen iguales. Nuestros diseños serán igualitarios y cooperativistas. No hay jefes, sólo existen objetos con responsabilidades distintas.

En el mundo real no hay managers (salvo que estemos modelando roles laborales.)

Regla 10: Los managers no existen.

Foto por Amy Hirschi en Unsplash

No necesitamos decir “objetos”

Los objetos están omnipresentes. Nombrar una clase diciendo Object… es un code smell como los mencionados más arriba.

Regla 11: Los objetos no existen. Todos lo son.

Todas sus base son nos pertenecen

A menos que estemos modelando un sistema espacial o militar no deberíamos nombrar a nuestras clases con el nombre Base.

Base representa la ausencia de un concepto abstracto del mundo real y la probable intención de reutilizar código mediante la herencia. Otro code smell.

Esto viola el principio de diseño que nos sugiere favorecer la composición (dinámica) de objetos por sobre la herencia (estática) de clases.

Regla 12: Los objetos Base no existen.

Todos estos nombres son muy malos. Existen sitios de humor que los generan automáticamente.

No necesitamos accessors

Como vimos en artículos previos, tener setters y getters genera violación del encapsulamiento y una mala asignación de responsabilidades.

Debemos sospechar de toda funcion getXXXX() o setXXXX(). No solemos encontrar en la biyección del mundo real estas responsabilidades en entes del dominio.

No existen responsabilidades set() y get() en los modelos de negocio.

En el caso accidental de coincidir una responsabilidad con un atributo llamaremos a la función de la misma manera sin el prefijo get():

Regla 13: No existen metodos setXXXX ni getXXXX

No preguntes quién soy

Las funciones que comienzan con isXXXX() suelen ser implementativas. Preguntan por un tipo (evitando el patrón de double dispatch), generan acoplamiento y siempre van acompañadas de un if.

Como regla general, deberíamos restringir el uso de booleanos a las situaciones en las que existen dichos booleanos en el mundo real.

Como corolario, y siempre pensando en el MAPPER, debemos desconfiar de los métodos isXXXX().

Regla 14: No existen métodos isXXXX().

Si huele a interfaz es Interfaz

Nombres como iterable, serializable, etc. predican sobre las responsabilidades de los objetos de una clase. Serán excelentes nombres de interfaces y por lo tanto, no debemos utilizarlos para nombrar a las clases.

Regla 15: Los nombres …able quedan para las interfaces (por lo tanto no pueden ser instanciados.)

El pato de la boda

Los patos están siempre presentes en el desarrollo del software. Está la técnica de depuración del patito de goma y está la técnica del duck typing.

Foto por Jordan M. Lomibao en Unsplash

Cuando veo un ave que camina como un pato, nada como un pato y suena como un pato, a esa ave yo la llamo pato. — James Whitcomb Riley

Esta técnica nos sugiere entender al objeto por sus responsabilidades y su rol en el contexto. Un corolario consiste en poner un nombre de acuerdo a dicha responsabilidad.

Regla 16: Utilizar nombres luego de observar el comportamiento.

Patrones de nombres

El mayor beneficio de los patrones de diseño es la unificación de un lenguaje común. Todos sabemos qué es un decorator, un strategy, un adapter o una fachada.

Y sabemos que jamás hay que usar Singletons:

Regla 17: Utilizar nombres de patrones para conceptos implementativos.

Si es abstracto tiene un nombre abstracto

Nuestro lenguaje es muy rico y tiene muchas palabras que modelan conceptos. Si queremos agrupar conceptos mediante la técnica aristotélica de clasificación, nombraremos a las clases con dichos nombres.

El ejemplo clásico para mostrar herencia:

La superclase común de {Auto, Bote, Avión} no debería ser AbstractCar ni BaseCar, ni BaseBoat ni Movable, sinoVehículo.

Regla 18: Los nombres abstractos deben ser descubiertos. No inventados.

Corolario 18: No utilizar la palabra abstract como parte de un nombre.

La responsabilidad es el mejor nombre

La mejor regla para nombrar una clase es buscar su correspondiente en la biyección.

Si esto se torna difícil, deberíamos entender el concepto en base a sus responsabilidades.

Como ejemplo supongamos el dominio conocido de los contenedores.

Si se puede recorrer, se puede agregar y eliminar, no es un ArrayHelper, ni un ArrayManager, ni un BaseArray, y mucho menos un ArrayObject.

Por ejemplo al intentar agrupar: Array, Set, LinkedList, Multiset, Stack, Queue etc. podremos derivar la palabra que mejor los describe a todos.

Su responsabilidad principal es recolectar elementos, por lo tanto, estamos en presencia de una Collection.

Esto lo aprenderemos cuando conocemos sus subclases utilizando el Liskov Substitution Principle (la L de Solid).

Regla 19: Para nombrar conceptos debemos conocer el protocolo.

Hablamos el mismo idioma

Como hispanoparlantes, muchas veces los alumnos nos consultan si deben asignar nombres en español (el idioma del negocio) o en inglés (el idioma base de los lenguajes de programación).

Si vamos a ser consistentes con el polimorfismo de las funciones debemos utilizar siempre el mismo idioma. Para que el iterador foreach() sea polimórfico con todos los objetos iterables debe tener su nombre en inglés. Si creamos un objeto con una función recorrer(), perderemos el polimorfismo y tendremos que acoplarnos con un if.

Regla 20: El código debe estar escrito en inglés.

Resumen de Reglas

  • Los nombres deben ser declarativos y no implementativos.
  • Los nombres deben ser contextuales.
  • No mezclar tipo con rol.
  • No usar setters ni getters.
  • No utilizar términos inexistentes como Manager, Helper, Base.
  • No utilizar términos demasiado genéricos, como Object.
  • Asignar responsabilidades antes de asignar nombres.
  • Ante la duda, poner pésimos nombres.
  • Evitar los comentarios.

Conclusiones

Poner buenos nombres es un arte que requiere un conocimiento profundo del dominio de problema que estamos modelando.

Agradecimientos

Colaboraron con la edición y aportaron ideas y correcciones: Carlos E. Ferro y Pablo Casullo.

Parte del objetivo de esta serie de artículos es generar espacios de debate y discusión sobre diseño de software.

Esperamos comentarios y sugerencias sobre este artículo.

Este artículo también está disponible en inglés aquí.

También puedes escribirme en twitter.

--

--

Maximiliano Contieri
DotTech

I’m a senior software engineer specialized in declarative designs. S.O.L.I.D. and agile methodologies fan. Maximilianocontieri.com