La importancia de los Nombres en la Ingenieria del Software

beezow

Creo que ya hemos hecho este ejercicio antes pero, solo para recalcar el punto, te pregunto: cual es la actividad mas frecuente que realizamos como programadores?

Como ya te lo había mencionado en otras oportunidades la respuesta a esta pregunta es LEER!!!!!

Con “L” mayúscula, y todos los signos de exclamación que podamos adjuntarle.

En todo momento leemos: cuando revisamos los directorios donde se encuentran nuestros archivos, cuando distinguimos cual de estos archivos necesitamos, cuando evaluamos el código existente, cuando escribimos código, cuando hacemos revisión de código propio o ajeno; el quid del asunto es que siempre estamos leyendo.

Pero si te pregunto, cual es la segunda actividad que mas realizamos? cual seria tu respuesta? Considera por un momento y piensa detenidamente, que actividad hacemos en común para todo directorio, archivo, clase, atributo, método o variable?

Pues la respuesta es obvia, les asignamos nombres*.

*: El primero que mencione las funciones anónimas pierde.

Es por esto que en favor de impulsar los principios del Código Limpio y la Programación Limpia uno de los ejercicios mas importantes es acostumbrarnos a nombrar de forma correcta todos los componentes de nuestro sistema, no solo a aquellos que afectan directamente al código, sino también sus contenedores, y con esto me refiero a estructuras de directorios, archivos e inclusive los descriptores de implementación si utilizamos sistemas de distribución como Maven o Gradle.

Pensando en esto, quisiera compartir contigo algunas de las consideraciones de nomenclatura que he aprendido y me han sido útiles para desarrollar código de forma limpia.

Los Nombres deben transmitir Intención

Obvio, no es así?

De hecho, creo que es la cuarta vez que toco este punto en mi blog; pero esto debería ilustrarte la importancia de este punto.

Cuando vemos el nombre de un elemento, deberíamos saber de forma automática su propósito. No deberíamos verificar documentación externa o wikis o cualquier elemento adicional para entender lo que hace nuestro código.

Como dice el Tio Bob “la verdad siempre radica en el código“.

Este es un problema que vemos muy recalcado en código de enseñanza en las universidades (por lo menos esa fue mi experiencia), donde vemos como la idea de descripción de una variable seria algo como

int d; // los dias activos del usuario

El problema radica en que la explicación de propósito a través de un comentario vive y muere en el comentario; en las siguientes oportunidades que consigamos a la variable d por si sola es irrelevante ya que no nos dice nada, ni mucho menos demuestra su intención, cuando muchos podremos inferir que su propósito esta relacionado a una palabra con la letra “d”.

Si bien pareciera ahorrar tiempo y optimizar el programa, la realidad técnica es que no hay diferencias entre ese nombre y algo mas descriptivo como

int diasActivosUsuario;

Como vemos, el renombrar la variable nos permite eliminar el comentario (que en general son distracciones en el código fuente, pero ese tema lo tocaremos luego) ya que es redundante y a la vez en cada invocación de la variable nos permite saber a que nos estamos refiriendo.

NOTA: Es común, en ejercicio de mejorar la legibilidad, aplicar la técnica del Camel Case a los nombres de las variables que son compuestas de varias palabras para diferenciarlas entre si; esto consiste en iniciar en minúsculas y luego usar una letra mayúscula para el inicio de cada palabra. En mi experiencia esta es una buena practica que siempre recomiendo.

Ya vimos esto en un caso aislado, pero veamos como se eleva a nivel de un método

protected List findAllFiltered(CriteriaQuery criteria) throws NoResultException
{
List l=em.createQuery(criteria).getResultList();
if(l.size()==0)
{
throw new NoResultException(ConstantesEntidades.MENSAJE_LISTA_VACIA);
}
return l;
}

Cual es el propósito de  este método? Según el nombre del método (en ingles) debería “encontrar todo filtrado”, pero encontrar qué? y cómo?

Si tratamos de descifrar estas dudas a través de los parámetros y las variables que funcionan dentro de  la misma, nos encontraremos con poca información, existe un objeto CriteriaQuery al que simplemente llamamos criteria y asumimos cumple con el objetivo de contener el filtro, pero esto solo lo podemos inferir porque es un parámetro; igualmente vemos a una variable llamada em que hace uso de una serie de métodos por los cuales podemos detectar que esta variable es de tipo EntityManager si y solo si conocemos el API de esta interfaz; vemos una variable l es el valor de retorno y que no nos dice nada sobre los tipos de datos que estamos manejando en este método.

Como vemos, a pesar de que se disimula tener una nomenclatura elaborada, al utilizar codificaciones en los nombres y dejar el método con una descripción tan abstracta de si mismo y utilizar una nomenclatura tan vaga, el autor (quien actualmente escribe este articulo) no nos dice nada sobre lo que ocurre en el método.

Mucho se puede justificar diciendo que estamos tratando de crear un método para una clase abstracta (el único indicio de esto es que es un método protected) y que debe ser lo mas genérico posible en su implementación o cualquier otra excusa; pero el punto final es que debido a malas practicas, el código que genere fue de carácter obtuso.

Veamos por el contrario un ejemplo de código que también tiene la finalidad de ser usado de forma genérica pero que expresa mucho mejor su intención.

public T findByIntKey(int key)
{
T entity=entityManager.find(entityClass, key);
if(entity==null || entity.getEstatusRegistro()==EstatusRegistro.ELIMINADO)
{
throw new NoResultException();
}
return entity;
}

En este caso, mucho de la descripción y nombre del método nos dice que es de carácter genérico (si conoces desarrollo en Java, la T es un indicador de tipos genéricos). Si vemos el nombre nos dice que va a hacer una búsqueda utilizando una clave de tipo int; esta idea es reforzada por el dato que se recibe como parámetro, pero si queremos adentrarnos al funcionamiento del mismo, vemos que el valor de retorno es una entidad (su nombre entity asi lo revela) a pesar de que su tipo de dato es genérico; igualmente, vemos que hace uso de un EntityManager y la clase de la entidad para realizar la búsqueda por el valor clave.

En este caso, vemos como el uso de una nomenclatura mas explicita revela mas del método con una lectura sencilla. Por lo que podemos decir que este método revela su intención de forma clara.

El Profesionalismo ante todo

Es muy importante mantener una actitud profesional en nuestros proyectos y al momento de nombrar los componentes de los mismo.

Para ilustrar esta idea, compara estos dos Enums

public enum Regiones
{
AMERICA_NORTE, AMERICA_SUR, EUROPA_ESTE, EUROPA_CENTRAL, EUROPA_OESTE, ASIA_MENOR, ASIA_CENTRAL
}

public enum Regiones2
{
GRINGOS, DROGOS, EUROPEOS, COMUNISTAS, COMUNISTAS_OTROS, CHINOS, GOKUS
}

Quizás el ejemplo es un poco extremo y ofensivo, pero la idea en general es que la codificación de nuestros proyectos, si bien es un arte y debemos disfrutar lo que hacemos, no es un chiste y mucho menos un lugar donde debemos demostrar ejemplos de ética tan vergonzosos como el que acabo de utilizar.

Los Nombres deben permitir Comunicación

Existe una diferencia clave entre el trabajo con Código Limpio y el trabajo con Código Sucio que va mas allá de la legibilidad y esta es la capacidad de establecer conversaciones ilustradas por el código.

Imagina que algún usuario te plantea la siguiente falla “estoy teniendo un problema con al autenticar mi usuario, me muestra por pantalla un error diciendo que no hay valor de password“, y al proceder a revisar el código del controlador de usuarios consigues un método identificado de la siguiente manera

public Usuario auntenticarUsuario(String email, String password) throws NoResultException, IllegalArgumentException, AuthenticationException

Si no eres la persona que mantiene ese código puedes inmediatamente establecer una conversación con la persona que lo mantiene o si es tu código puedes pedir un poco mas de información al usuario y seguir de forma mas clara que es lo que ocurre con el password en cuestión.

Ahora por el contrario imagina una misma situación en la cual en lugar de encontrar este método, consigas algo como

public Response usrAuth(String pwd)

Pues te puedo asegurar por experiencia propia que tu trabajo se acaba de complicar; a primera vista pareciese que el código esta bien identificado y que las variables están debidamente identificadas, pero es allí donde caemos en la trampa. Las abreviaciones (o Notación Húngara) son enemigas naturales de la comunicación; no es lo mismo “Auth” que “autenticar” al momento de establecer una conversación, de igual manera no es lo mismo “usr” o “pwd”que “usuario” o “password”, podemos creer que esta conversión sera algo natural pero este no siempre es el caso.

Es importante no recaer en el uso de mnemónicos o siglas ya que oscurecen el significado de un código y obligan al programador a estar constantemente pensando en decodificar estos nombres (hay excepciones como por ejemplo al hablar de estándares como SQL o REST).

Un Nombre solo debe revelar Intención no Estructura

Siempre recuerdo en mis inicios profesionales como programador en Informix cuando me toco preguntar por una variable llamada “tbl_datausrs_col_password_str” en un procedimiento almacenado que me pidieron revisar.

Esto me llamo la atención no fue tanto por la complejidad de nomenclatura sino porque me dio a entender que mientras programara en ese equipo tendría que utilizar este tipo de convenciones, lo cual a ciencia cierta, es un procedimiento agotador y poco amigable.

Si bien existió una época en la que era necesario identificar en los nombre estructuras complejas por limitaciones en los editores e IDEs, la verdad es que en la actualidad estas decisiones tienden a involucrar a algún gerente formado en esas épocas que aún se resiste a reconocer los avances de las herramientas y que cree que esto es una buena practica.

No lo es.

Evitar Prefijos o Sufijos de Tipo

La idea de identificar los tipos de datos que estamos manejando en una variable tampoco es importante; cualquier editor moderno puede indicarnos el tipo que se maneja de ser necesario utilizando solo el mouse, y esto si estamos utilizando un lenguaje tipificado; si usamos lenguajes como PHP, Python o Ruby, esto ni siquiera tiene sentido.

Prefijos de Agrupación

Si tenemos datos que deban agruparse como por ejemplo

int usrCodigo;
char* usrNombre;

Entonces lo ideal es agregarlos a una estructura o clase que los agrupe y utilizarlos dentro de la misma.

Por ejemplo, asumiendo que trabajamos en lenguaje C++ pudiesemos utilizar un struct de la siguiente manera

struct usuario
{
int codigo;
char* nombre;
}
//el resto del programa
usuario.codigo=1;

Lo mismo ocurre si queremos especificar prefijos que agrupen variables en un ambito, por ejemplo si tenemos la siguiente clase

public class Usuario
{
private int m_codigo;
public Usuario(int Codigo)
{
m_codigo=codigo;
}
public getCodigo()
{
return m_codigo;
}
}

En este caso, utilizamos el prefijo m_ para definir los atributos (también conocidas como variables miembro) de la clase y diferenciarlos de parámetros con los que puede compartir el nombre; esta practica es innecesaria ya que con el mismo propósito pudiésemos utilizar el identificador this que es parte de la gran mayoría de los lenguajes modernos.

Quedaríamos con algo como esto

public class Usuario
{
private int codigo;
public Usuario(int Codigo)
{
this.codigo=codigo;
}
public getCodigo()
{
return codigo;
}
}

De esta manera no comprometemos la legibilidad del código en general por acomodar algunos escenarios puntuales.


Por ahora, dejaremos este punto hasta aquí ya que el post se esta extendiendo de forma significativa; pero te recalco que este la discusión sobre nomenclatura es muy importante y que solo hemos tocado la superficie de este tema.

Como siempre espero haya sido de tu agrado y recuerda que cualquier comentario es bien recibido.

Hasta la próxima.

Anuncios
Esta entrada fue publicada en Blogging y etiquetada , , , . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s