lunes, 5 de julio de 2010

La ley de Demetrio y otras yerbas OO

Demeter: Diosa Griega de la agricultura, "Madre de la distribucion", fue elegida como nombre de una ley que tiene que ver con el Desarrollo de software. Es mencionada principalmente dentro del paradigma de la orientación a objetos, si bien no aplica exclusivamente a este paradigma y puede ser expresada de una manera genérica. El significado surgió dentro de una filosofía de programación botton-up como parte de un proyecto de desarrollo de la universidad Northeastern (Boston, Massachusetts).

Llendonos justamente para el lado de la tragedia Griega, es casi una tragedia que muy pocos programadores que trabajan con lenguajes orientados a objetos conozcan y apliquen la Ley de Demeter (lo de Demetrio es en chiste) y otros principios (o leyes) que asisten en el día a día a un programador para poder desarrollar un sistema mucho más mantenible (y sí, también un poco más reusable, ver Mantenibilidad vs Reusabilidad)

Pasemos a darle una revisada a los mismos.

Ley de Demeter (1987, Northeastern University) La ley de Demeter aplicada a objetos dice que:

Un método m, de una clase C, solo debe invocar métodos: 1 - De la misma clase C (métodos privados)
2 - De un objeto creado en m (Variable local)
3 - De un parámetro, pasado como argumento a m (parámetros)
4 - De una variable de instancia de C. (Variables de instancia de la clase)

En otras palabras, un objeto no debe conocer la estructura interna de los objetos directamente relacionados con él (sean variables de instancia de la clase, parámetros o objetos creados localmente), ni obtener a través de ellos a otros objetos para manipularlos o enviarles mensajes.

En un ejemplo abstracto, si tengo el método m1 de una clase C : public void m1(parametro1, parametro2) { parametro1.metodoA() // No viola principio de Demeter parametro2.getObjetoB().metodoDeB() // VIOLA el principio! }

Un truco nemotécnico para recordar la ley: "Habla con amigos, no con extraños", (Talk to friends, not to Strangers").

Notar que interesante que en general, un patrón tan utilizado como los Beans, en java, permite e incluso facilita (en principio, ya que hay que ver bien siempre el contexto en el que ocurre) la violación de este principio.

Que es lo que produce la violación de este principio? Si, lo adivinaron, un mayor acoplamiento!

Principio abierto/Cerrado - Open Closed Principle (Bertrand Meyer, 1988)

Las entidades de software (clases, módulos, métodos y funciones) deben ser abiertas para extensión y cerradas para modificación.

Es decir, uno no debería tener que modificar clases o código existente para hacer frente a un nuevo pedido o cambio de funcionalidad. Estos cambios o nueva funcionalidad deben ser agregados o bien extendiendo clases a través de la herencia o reusando código existente a través de la delegación.

En la práctica esto no siempre sucede así y hay situaciones en las que no queda otra alternativa que cambiar código existente pero incluso en estos casos, si uno utiliza TDD y refactoring, el cambio en realidad será un refactoring que, como efecto colateral, dejará al código más cerca de respetar el principio al cual nos estamos refiriendo.

Una clara indicación de que no se ha respetado este principio es cuando un solo cambio en un módulo de un programa implica una cascadas de cambios en otros módulos dependientes.

Principio de Única Responsabilidad - Single Responsability Principle (SRP)

No debe haber más de un único motivo para que una clase cambie. Cada clase debe tener una única responsabilidad.

El motivo del que se habla en la definición se refiere a las causas para que una clase cambie. Debe haber una única fuente de posibles cambios de una Clase. Esto es lo mismo que decir que una clase tenga una única responsabilidad. Cada responsabilidad implica un eje de cambio.

Cuando un requerimiento cambia se manifiesta como cambios en las responsabilidades de las clases y si una clase asume más de una responsabilidad entonces habrá múltiples motivos de cambio que es lo que intenta evitar este principio.

El SRP es en nuestra opinión uno de los principios centrales y más importantes para el desarrollo de software de calidad. Se relaciona profundamente con los beneficios que se producen al aplicar Tests de unidad, refactoring y TDD.

Respecto a los tests de unidad, justamente cuando una clase no respeta SRP y tiene 2 o más responsabilidades marcadas de manera difusa se dificulta grandemente la escritura de los tests de unidad, y esto es una clara indicación de que hay problemas de asignación de responsabilidades en la clase. Lo cual nos lleva a la necesidad de aplicar Refactoring.
Varias de las reglas de refactoring llevan justamente a tratar de identificar la responsabilidad de una clase si la misma se encuentra mezclada de manera difusa con otras responsabilidades en el código y refactorizarla para que justamente quede más cerca de cumplir este principio.
Por ejemplo, si un método no tiene que ver con la responsabilidad principal de una clase C1 es candidato a ser trasladado (refactor Move) a la clase C2 en la cual lo que esta haciendo este más cerca de la responsabilidad de C2.

Y si uno desarrollo usando TDD (Test Driven Development) uno de los beneficios, si no el principal, es que las clases que surgen de esta práctica tienden a quedar respetando SRP.

Esta lista de principios y reglas no quiere ser extensiva ni mucho menos, y hay muchisima más "teoría" en la programación orientad a objetos por estudiar, pero si queremos resaltar la importancia de estos tres como piedras fundacionales de la Programación Orientada a Objetos.

Para terminar, y que quede bien claro, como con los Patrones de Diseño (GOF) u otras reglas y principios, nosotros opinamos que no sirve de nada saberlos de memoria, sino aprenderlos e internalizarlos. Para ello el único camino que conocemos es a través de usarlos una y otra vez, es decir, a través de la experimentación y la práctica, en otras palabras, programando.

Si bien al principio uno debe releerlos a menudo y tratar de aplicarlos "por libro", después de un tiempo al internalizarlos la aplicación de los mismos es automática y uno se olvida del enunciado formal, simplemente son parte de la forma en que uno piensa.

En próximos posteos la idea es ir mostrando ejemplos de aplicación de estos principios.

Para terminar queremos compartir un texto japonés llamado "el camino del aprendizaje SHU-HA-RI", perdonen la traducción (desde el inglés aclaramos).

(La progresión Shu-Ha-Ri )
Nivel 1

Aprender una técnica que "funcione"
El éxito reside en seguir la técnica fielmente y obtener el resultado esperado.


Nivel 2

Aprender los límites de la técnica
El éxito esta en cambiar de una técnica a otra, la que aplique mejor.


Nivel 3

Nivel de Maestría "Fluido" - Cambia las herramientas y las combina momento a momento.
Uno es incapaz de distinguir las técnicas aplicadas.

No hay comentarios:

Publicar un comentario