Parlamento, el código de honor de los javeros

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.

  • Paquetería

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”.

  • Diseño

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.

  • Codificación

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:

  • Facade. Entrada/salida del servicio. Lo único que hace esta capa es recoger los parámetros de entrada y con dichos parámetros llamar a un componente @Service.
  • Service. Capa que valida si los parámetros de entrada son correctos, es decir, comprueba que no haya valores nulos, que si los hay sean controlados y llama a la capa Component. En caso de que estos parámetros de entrada no sean válidos, se retorna una excepción controlada.
  • Component. Capa donde reside la lógica de negocio. En esta capa podemos hacer uso de componentes de utilidades (llamémoslo Tools) para, por ejemplo, establecer formatos de fecha, para realizar expresiones regulares, etc.
  • Repositorio. Capa que contiene la integración con el motor de persistencia. Si por ejemplo tenemos un framework como Spring Data, la clase que declara el repositorio se anotará con @Repository y nos proveerá  de interfaces concretas para realizar un CRUD.

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.

Ingeniero Informático con 11 años de experiencia en el desarrollo de aplicaciones web en entornos J2EE. Después de 8 años en Indra, donde trabajó en proyectos para el Ministerio de Educación, DGT (Dirección General de Tráfico), RFEF (Real Federación Española de Fútbol) y SELAE (Loterías y Apuestas del Estado), vio en Paradigma una oportunidad de seguir creciendo. Con gran experiencia en frameworks Spring (Spring 4, Spring Boot, Spring Webflow, Spring Data, etc.), actualmente inmerso en proyectos de eCommerce con ATG 10.2 para El Corte Inglés.

Ver toda la actividad de Raúl Martínez

Escribe un comentario