De un tiempo a esta parte, con la experiencia de los últimos proyectos en los que he trabajado, me he dado cuenta de que al inicio de un proyecto (y en fases regulares del mismo) es muy importante establecer unas convenciones de código y de diseño.

Aunque sea algo que en apariencia se presupone, no deberíamos de tomarlo como tal, ya que en muchos casos no se lleva a cabo.

Como bien se decía en la saga “Piratas del Caribe”, es fundamental “parlamentar” para establecer una reglas mínimas con el acuerdo de todos los miembros técnicos del equipo.

¿En qué consiste esta problemática? ¿Qué podemos hacer para darle solución? Veamos algunas pautas que podemos tener en cuenta como una sencilla y breve guía.

¿Qué galimatías es este?

Basado en experiencia pasada y presente en algunos casos, voy a intentar trasladaros los problemas que he visto en diferentes proyectos respecto a convenciones de diseño, código etc...

Ciertamente, no parece un problema excesivamente importante mientras “el código funcione” o “mientras ese botón haga lo que tiene que hacer”.

Pero para los que estamos a niveles de diseño y codificación, cuando nos encontramos con este tipo de problemas resulta engorroso abstraerse para tener una foto clara del proyecto, es complicado mantener el código y, sobre todo, imposible de establecer una homogeneidad como equipo y no como entes individuales en el cada uno tiene su estilo.

Unos son elegantes, otros son efectivos… pero al final el objetivo es que todo el mundo siga una convención para que el software sea claro y mantenible a todos los niveles.

Y no me estoy refiriendo a que una interfaz debe de ser algo como “ICustomerService” y que su implementación debe ser un “CustomerServiceImpl” (que también). O que los atributos de una clase debe de comenzar en minúsculas, o que tenemos que tener javadoc, o que haya que cumplir checkstyle o PMD, etc..

Me estoy refiriendo a varios niveles que explicaremos con más detalle más adelante:

  1. A nivel de paquetería no se separan correctamente los dominios o áreas funcionales. E incluso tampoco se empaquetan bien los componentes, beans, clases de utilidades en su correspondiente paquetería.
  2. A nivel de diseño se utilizan patrones con nombres incorrectos, bien por desconocimiento del propio patrón, o bien por reutilización mal enfocada a nivel conceptual.
  3. A nivel de codificación, y esto se explica muy fácilmente con un ejemplo: en ciertos proyectos me he encontrado con Helpers, Utils, Tools, Managers, Handlers, Services, Component, Validators, Process, etc... ¡Todos juntos! Un auténtico batiburrillo. La pregunta que me asaltaba al ver este galimatías de clases y nombres era: ¿qué hace cada uno? ¿Por qué a un Helper no lo llamo Tools o a un Tools como Utils o un Manager como Component? ¿Qué diferencia a nivel conceptual y funcional hay entre estos componentes? Respuesta: “cada uno codifica un poco como quiere”. Pues mal camino llevamos.

Homogénesis

Vamos a aplicar un término de biología, para que en lo sucesivo vuestro conjunto de reglas y/o convenciones sean lo más similar posible a la idea original, siempre y cuando esa idea original exista.

Paso 1: Comunicación

Lo primero que, desde mi punto de vista, se debe de hacer en un proyecto de desarrollo (obviando, evidentemente, las fases de toma de requisitos, metodología, planificación, refinamientos, etc.), con independencia del área a la que está destinada dicho proyecto, es establecer una serie de reglas.

Normalmente, cada empresa o ente (por ejemplo, un Ministerio) establece sus propias convenciones de nombrado y paquetería, no hay un estándar definido más allá de las pautas que marca Sun.

Un ejemplo bien documentado de cómo establecer un marco de desarrollo con una convención de nombres, paquetería, etc. cohesionada y coherente lo podríamos ver en este ejemplo de la Junta de Andalucía.

Para ello, deberán convocarse diferentes reuniones donde los distintos miembros técnicos del proyecto, es decir, arquitectos, analistas, desarrolladores, etc. lleguen a un acuerdo de cómo diseñar y codificar una aplicación.

De tal manera que demos un modelo lo suficientemente flexible como para admitir cambios de forma consensuada, sin que ello suponga el “desparrame”. Este es el paso 1, la comunicación y acuerdo entre los miembros del equipo.

Paso 2: No encaja lo que estoy haciendo con la convención, ¿qué hago?

No hay que dudar en comunicarlo con los responsables técnicos y, en caso necesario, ellos considerarán cómo encajarlo dentro de las “reglas” que se han preacordado.

O bien establecer nuevas reuniones con los demás miembros para llegar a un nuevo marco (no debe ser algo traumático). Por resumir este punto aún más: “vemos cómo encajarlo, en caso contrario vaya al paso 1”.

Os voy a poner un ejemplo de un caso real que me ocurrió hace unos años. A nivel de diseño necesitaba una capa que interactuara entre dos dominios diferentes, ya que no teníamos esta consideración de forma inicial.

Se lo comuniqué a mi arquitecto, reunimos al equipo, investigamos y llegamos a un acuerdo para que cuando pasara esto, se creara una nueva nomenclatura para este tipo de clases (ACL-Capa anticorrupción). Todo ello respetando el modelo anterior, es decir, sin ser algo traumático.

Paso 3: Let’s go there!

Como hemos dicho, vamos a dividir esta sección en diferentes áreas donde hay que indagar.

En este punto hay que llegar a un acuerdo de cómo vamos a separar nuestros paquetes. Desde un punto de vista práctico, lo ideal, según mi criterio, sería seguir una estructura de paquetes de este estilo:

es.[empresa].[area].[aplicación].[subsistema].[capa].[tipo]

Por ejemplo podríamos tener algo como esto:

es.serviciosdocumentales.logistica.sdapp.distribution.business.interfaces

Como vemos, está claro que el proyecto pertenece a la empresa serviciosdocumentales, en el área logística, la app la hemos denominado sdapp, el subsistema es distribución (en logística podemos tener logística de aprovisionamiento, distribución, producción, almacenaje etc..). Estamos en la capa de negocio (business) y vamos a declarar una interfaz.

Hasta [aplicacion] creo que no es necesario indagar más allá, así que vamos a darle forma a los demás campos.

En [subsistema] podemos tratarlo como una separación funcional, o un dominio. Por ejemplo, y siguiendo con el ejemplo de servicios documentales, podríamos tener valores como provisioning, distribution, production, storage**.**

En [capa] podemos definir un modelo MVC y dividir las capas en: presentación, negocio, persistencia *(*presentation, business, persistence).

En [tipo] tenemos libertad para definir paquetería en función de nuestro diseño. Es decir, si tenemos una capa de servicios deberíamos de nombrar el paquete como “services”, si tenemos un patrón “builder”, ídem.

Si por ejemplo tenemos un bean específico para dicho builder deberíamos de crear un subpaquete “beans”.

Por otro lado, a nivel de diseño también he visto que muchas veces se confunden patrones y se nombran de forma equivocada.

Por ejemplo, un patrón builder (que es un patrón creacional donde se crean objetos complejos a partir de un objeto fuente) es utilizado en multitud de ocasiones como si fuera un “factory” (donde creamos una jerarquía de clases).

En este punto solo hay que tener algo claro, y es saber la particularidad de cada uno de los patrones de diseño existentes y cómo aplicarlos en cada caso.

Esto no es un tema de reglas, pero influye directamente en la convención ya que no se utiliza de forma correcta.

Aquí es donde he visto mayor número de problemas, con multitud de clases que reciben nombrados diferentes, pero que tiene una finalidad similar o común.

En este punto sería interesante establecer un diseño claro para que todos desarrollos lleven una estructura similar.

Por ejemplo, como ya definí en DDD-Dominio implica crecer fuerte, una propuesta interesante en un proyecto back-end (sin capa de presentación) sería:

Si tomamos como referencia el ejemplo anterior, no tendría sentido declarar por ejemplo un Handler, cuya función sería similar al facade o incluso un “mixing” entre la capa Facade y Service.

Por supuesto, si es necesario un patrón de diseño, se puede utilizar como cualquier otro componente (y siguiendo el punto 2).

Con esto conseguimos que cada uno de los desarrollos del proyecto lleven la misma estructura, de tal forma que será fácil de determinar en qué capa se produce un error en caso de existir, o donde abordar un evolutivo concreto.

Y si además lo tenemos separado correctamente en paquetes como hemos explicado antes, tendremos identificado en qué área funcional, de forma clara y precisa, tendremos que tocar.

Conclusión

Como hemos visto, en los distintos proyectos, bien sea por dejadez, falta de iniciativa por parte del equipo, imposiciones del cliente (prisas, prisas...), o simplemente desconocimiento, es interesante sentarse un tiempo con los distintos miembros del equipo antes de comenzar a codificar y alcanzar acuerdos de convenciones de código a alto nivel, para que el proyecto de sensación de homogeneidad.

¿Qué nos proporciona esto? Para mí está claro, nos provee de legibilidad, mantenibilidad, acorta tiempos en resolución de incidencias...

He tenido experiencias de capas sobreescritas unas sobre otras con nombres diferentes y el hecho de buscar algo se ha convertido en un auténtico infierno. Pero, sobre todo, nos da limpieza y sensación de “situación controlada” por parte del equipo de desarrollo.

Cuéntanos qué te parece.

Enviar.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.