Putting it together

by Luismi Cavallé

Hace unos meses, cuando decidí que quería poner un blog y empecé a preparar borradores, me guardé un link a un post de Martin Fowler que me pareció interesante para comentar. Este post hace referencia, a su vez a un par de ensayos que argumentan acerca de la necesidad de que, como buena práctica de la POO, todo objeto oculte su estado interno al mundo exterior. En este sentido se referían a los getter y a los setter de Java como métodos malignos que ponen al descubierto las vergüenzas de nuestros objetos.

Uno piensa que esta discusión debería estar ya resuelta, incluso asumida, pero parece que no es así, al menos en lo que a modelos de objetos de negocio se refiere: En Rails, el estado de las clases del modelo está completamente expuesto; por su parte Hibernate y otros ORM pueden persistir el estado de los objetos tanto a través de accesors publicos y privados, como accediendo directamente a los campos (toda esta violación de la encapsulación gracias a la magia del Reflection); Rockford Lhotka, por otro lado, se queja de que Linq, la inminente tecnología de Microsoft, te obligue a utilizar propiedades públicas para poder persistir (DLinq) y hacer querys de los objetos…

Los dos ensayos a los que se refiere Fowler en su post plantean una visión clásica y purista del concepto de encapsulación en la orientación a objetos, y me llevaron en su momento a dedicarle cierta atención a la ley de Demeter. Esta norma pretende gobernar la comunicación entre objetos restringiendo a todo objeto la comunicación a sus amigos íntimos. Esto se concreta en que desde un método “M” de un objeto “O” solo se puede llamar a los siguientes métodos:

  1. Otros métodos del propio objeto “O”
  2. Métodos de los parámetros recibidos en “M”
  3. Métodos de objetos creados/instanciados en “M”
  4. Métodos de los campos (componentes) de “O”

Queda por lo tanto prohibida todo tipo de llamada en cadena al estilo:

obj1.getObj2().getObj3().getObj4();

En su momento traté de aplicar esta norma en el diseño de mis clases y los beneficios fueron casi automáticos: La lógica de negocio se repartía adecuadamente en las distintas clases, el acoplamiento entre clases se minimizaba y la cohesión mejoraba, los métodos se aligeraban y los cambios, cuando surgían, eran mucho más localizados y sencillos de realizar. En definitiva, muchos de los beneficios de la OO con solo aplicar esta sencilla norma.

Sin embargo era incapaz de quitarme de encima los getter y los setters (en mi caso, las propiedades de C#). A pesar de que ya no necesitaba exponer todo el estado interno de un objeto para colaborar con el resto de objetos de negocio, sí que lo seguía necesitando, al menos, en los siguientes casos:

  1. En los tests de unidad
  2. En la interfaz de usuario (¡qué comodas resultaban las llamadas en cadena que tan prohibidísimas estaban!)
  3. Al persistir los objetos en la base de datos

Además, en ciertos casos, la ley de Demeter resultaba demasiado restrictiva y continuamente me tenía que inventar excepciones a la regla.

En definitiva, estaba experimentando lo que criticaba Fowler en su post y es el error de intentar primar un único trade-off respecto a cualquier otro, en este caso el de la encapsulación.

El problema no estaba tanto en la ley de Demeter, como en la interpretación rígida que inicialmente traté de aplicar. A lo que he llegado después de verme forzado a relajar mis objetivos es al principio del Dí, No Preguntes que complementa a Demeter de la siguiente manera: “Venga, vale, puedes exponer parte del estado de un objeto siempre y cuando no utilices esta información para tomar decisiones fuera del mismo. Cualquier decisión basada en el estado de un objeto debe ser tomada dentro del propio objeto”

Este enfoque, aparte de proporcionar los beneficios antes comentados, suele poder aplicarse de manera natural en cualquiera de las infraestructuras orientadas a objetos sobre las que se trabaje. Y nos ayuda a conseguir “poner cada cosa en su sitio”