Buenas Prácticas de Programación (Parte 2 de 2)

Clases

Si los métodos cumplen un rol similar a los párrafos en la historia que cuenta el funcionamiento de un sistema, las clases serían equivalentes a una sección o encabezado. Así como una sección tiene un título que describe claramente el tema a desarrollarse con más detalle en sus párrafos, una clase debería tener un nombre que transmita claramente su responsabilidad en el sistema y contener únicamente los métodos necesarios para cumplir con dicha responsabilidad.

A continuación se mencionan algunas recomendaciones a tomar en cuenta a la hora de escribir clases:

Principio de Única Responsabilidad (SRP). Una clase debería tener un solo motivo para cambiar. Por ejemplo, si la clase “Circulo” se encarga de calcular el área o perímetro, de salvar su estado en disco y de mostrar el círculo en algún dispositivo de salida tiene claramente muchos motivos para cambiar: podría cambiar la forma en la que se salva el estado, la forma en la que se muestra y la gestión de sus atributos geométricos. Más aún, los requerimientos de cambio podrían llegar de fuentes y en momentos distintos. Para el caso de la clase “Circulo”, la gestión del almacenamiento del estado y la presentación en dispositivos de salida deberían residir en otras clases. Combinar varias responsabilidades en la misma clase implica al menos las siguientes desventajas:

  • Dificulta la compresión del código y por lo tanto su mantenimiento.
  • Dificulta la reutilización de código; por ejemplo, una clase interesada únicamente en los aspectos geométricos estaría obligada a depender indirectamente de librerías relacionadas con el almacenamiento en disco.
  • Genera acoplamientos innecesarios. Si realiza un cambio en la forma de almacenamiento en disco incluso las clases clientes que no emplean esa funcionalidad se ven afectadas por el cambio.

En los sistemas que siguen el principio SRP, la funcionalidad está distribuida en clases pequeñas que colaboran entre sí cada una encargada de una responsabilidad específica.

Cohesión. Las clases con un sólo motivo para cambiar tienden a ser pequeñas y cohesivas; cohesivas en el sentido de que la mayoría de la variables miembros se emplean en la mayoría de sus métodos. Una clase es completamente cohesiva cuando cada método accede a cada variable miembro de la clase.

Acoplamiento. Es una medida del grado en el cuál un componente (clases o módulo, por ejemplo) depende de otro. La colaboración entre objetos en tiempo de ejecución genera dependencias de manera inevitable. El propósito de un buen diseño orientado a objetos es eliminar o reducir al máximo las dependencias que dificultan la comprensión y mantenimiento del software como el acoplamiento a nivel de código fuente y el acoplamiento temporal.

Organización del código. Para facilitar la lectura de código en una clase, se recomienda que el código se organice de la siguiente manera:

  • Constantes
  • Variables
  • Constructores
  • Métodos públicos
  • Métodos privados

Los métodos deberán, en lo posible, organizarse de acuerdo a nivel de abstracción con los métodos con mayor nivel de abstracción ubicados antes que los métodos con mayor detalle.

Las clases tienden a ocultarse en métodos extensos y la forma usual de extraerlas es por medio de la aplicación de técnicas de refactorización de código (extract class, extract method object, extract method).

Combinar clases. Aunque menos frecuente, a veces es necesario combinar clases entre las cuales está dispersa alguna responsabilidad. La excesiva «envidia de capacidades» es una señal de que dos clases probablemente deberían fusionarse.

Sistemas

A nivel de sistema es recomendable:

Separar la construcción de sistema del uso del sistema. Estas funcionalidades tienen objetivos fundamentalmente diferentes; por lo tanto, es necesario crear un módulo separado del resto del sistema con el propósito de construir y vincular todos los objetos requeridos para ejecutar la aplicación. Este módulo, al que tradicionalmente se le ha llamado “main”, es el encargado de crear e iniciar la aplicación y crear cualquier objeto requerido en tiempo de ejecución; el  resto de código de la aplicación no debe tener ninguna dependencia a nivel del código fuente con el módulo “main” y se programa asumiendo que la aplicación ha sido adecuadamente construida; la forma más usual de implementar el módulo “main” es aplicando el patrón de diseño “Abstract Factory”  y herramientas de inyección de dependencias como Spring o Guice.

Servicios de infraestructura. La seguridad, la persistencia de datos y el manejo de transacciones son ejemplos de áreas funcionales comunes a muchas aplicaciones. Es importante evitar que este tipo de funciones estén dispersas en varias clases en el sistema; para facilitar la modularización de este tipo de funcionalidades, se recomienda emplear herramientas y técnicas de la programación orientada a aspectos.

Existen herramientas orientadas a facilitar la construcción del sistema y la provisión de servicios de infraestructura; empleando estas herramientas, el desarrollo puede enfocarse en las funcionalidades necesarias para satisfacer los requerimientos del sistema. Una de las herramientas de mayor aceptación en el mercado para estos propósitos es Spring.

Referencias

[1] Código Limpio: Manual de estilo para el desarrollo ágil de software

[2] Code Complete: A Practical Handbook of Software Construction, Second Edition

[3] Refactoring: Improving the Design of Existing Code

[4] Catálogo – Refactoring.com

[5] Catálogo – Refactoring.guru

[6] Hediondez del código

[7] JDeodorant

[8] Deuda Técnica

Comments are closed.