lunes, 13 de abril de 2009

9 reglas para una mejor orientación a objetos.

Sebastian Hermida comparte unos posters y y folletos con las “9 rules for a better object orientation” inspiradas en el libro ThoughtWorks Anthology (hizo también algunas viñetas, la primera de ellas aquí).

En el artículo “Object Calisthenics” Jeff Bay propone el ejercicio de elaborar un programa de 1000 líneas siguiendo estas reglas estrictamente (verán que son terriblemente restrictivas) con el objetivo de mejorar la orientación a objetos de nuestro código.

Primero lean, luego seguimos con mi propia verborragia.

  1. Use only one level of indentation per method. If you need more than one level, you need to create a second method and call it from the first. This is one of the most important constraints in the exercise.

  2. Don’t use the ‘else’ keyword. Test for a condition with an if-statement and exit the routine if it’s not met. This prevents if-else chaining; and every routine does just one thing. You’re getting the idea.

  3. Wrap all primitives and strings. This directly addresses “primitive obsession.” If you want to use an integer, you first have to create a class (even an inner class) to identify it’s true role. So zip codes are an object not an integer, for example. This makes for far clearer and more testable code.

  4. Use only one dot per line. This step prevents you from reaching deeply into other objects to get at fields or methods, and thereby conceptually breaking encapsulation.

  5. Don’t abbreviate names. This constraint avoids the procedural verbosity that is created by certain forms of redundancy—if you have to type the full name of a method or variable, you’re likely to spend more time thinking about its name. And you’ll avoid having objects called Order with methods entitled shipOrder(). Instead, your code will have more calls such as Order.ship().

  6. Keep entities small. This means no more than 50 lines per class and no more than 10 classes per package. The 50 lines per class constraint is crucial. Not only does it force concision and keep classes focused, but it means most classes can fit on a single screen in any editor/IDE.

  7. Don’t use any classes with more than two instance variables. This is perhaps the hardest constraint. Bay’s point is that with more than two instance variables, there is almost certainly a reason to subgroup some variables into a separate class.

  8. Use first-class collections. In other words, any class that contains a collection should contain no other member variables. The idea is an extension of primitive obsession. If you need a class that’s a subsumes the collection, then write it that way.

  9. Don’t use setters, getters, or properties. This is a radical approach to enforcing encapsulation. It also requires implementation of dependency injection approaches and adherence to the maxim “tell, don’t ask.”

¡Ja! Dos preguntas: ¿Estas reglas llevan a una mejor orientación a objetos? ¿Qué opinan de seguir estas reglas a rajatabla en “la vida real”?

Yo creo que sí, que indudablemente llevan a una mejor orientación a objetos. En cuanto a la segunda pregunta, mi propia opinión se resume en aquel principio de diseño del BDFL Guido van Rossum:

“Lo pragmático gana a la pureza”.

Y que el ejercicio de aplicarlas estrictamente debería quedarse en eso: un ejercicio acotado a un sistema de más o menos 1000 líneas.

Si programar es como escribir, un sistema es como un libro: hay un argumento central con algunos pasajes magistrales, algunos secundarios que hacen a que la historia sea completa y coherente, y mucho relleno y lugares comunes que siempre –o casi siempre- tienen que estar. La proporción de unos sobre otros determinará la calidad del resultado final, que puede ir del folletín a la obra maestra.

Todo es cuestión de saber dónde y cuándo utilizarlas, porque conllevan cierto esfuerzo adicional. Aplicadas en las funcionalidades críticas del sistema (en aquellas más complejas o indefinidas que se llevarán el grueso de las horas de cambios y mantenimiento) supondrán un ahorro considerable y la diferencia entre el código que resiste las modificaciones (e incluso mejora con ellas) y el que cae sobre sí mismo como un castillo de naipes al viento, convirtiéndose en una masa desordenada de clases. Utilizadas obsesivamente a través de todo el sistema no es más que una pérdida de tiempo.

Las reglas son muy bonitas pero, como decimos a veces en el trabajo “hay que pensar, no queda otra”, todavía no encontramos el método que nos libre de eso… por suerte, porque ese día nos quedamos sin trabajo.

De todas maneras me llamó la atención el libro, habrá que conseguirlo.

6 comentarios:

BlackTigerX dijo...

no creo yo que halla un proyecto "del mundo real" que pueda cumplir esas reglas

no getters/setters?? are you f* kidding me?

AcP dijo...

La verdad es que programando con presiones de tiempo y un objetivo muy claro y concreto a corto plazo es difícil tomarse 30 minutos para ver cómo se implementa un patrón, más teniendo en cuenta la inutilidad de la perfección teórica en requerimientos menores.

Por eso es bueno el ejercicio, porque en la vida real no hay mucho tiempo para practicar, hay que hacer.

fav dijo...

¿Estas reglas llevan a una mejor orientación a objetos?
Si aceptas que la orientación a objetos es sólo un caso particular de programación estructurada, definitivamente. Si no, deberías mirar más bien a los conocidos y probados principios que derivan de, y complementan, el principio abierto-cerrado.

¿Qué opinan de seguir estas reglas a rajatabla en “la vida real”?
"Conoce todas las reglas y luego rompe algunas."

@BlackTigerX Why getter and setter methods are evil.

@AcP "porque en la vida real no hay mucho tiempo para practicar, hay que hacer." eso es un error grave y bien documentado, por ejemplo en el paper de Royce y los puntos 20 y 21 de Classic Mistakes Enumerated. Hacer un prototipo es una forma de "practicar", y, en general, es un error grave utilizarlo luego como base del sistema definitivo. Un prototipo con sanas, e interesantes, restricciones es mejor que un prototipo "total no se va a usar" y mucho mejor que ningún prototipo.

AcP dijo...

@fav: tal vez en mi frase es un poco ambigua la diferencia que hago entre los términos "práctica" y "experiencia", muy propia de la bibliografía de mi facultad y mi carrera... perdón, una deformación profesional, así que amplío un poco.

La "práctica" (tal como la utilicé antes) es la actividad de aprendizaje que consiste en la repetición de la aplicación de un concepto en varias situaciones similares, para internalizarlo y memorizar su estructura.

Así, "práctica" es hacer 100 divisiones en papel, aplicar el patrón Singleton a partir de 10 enunciados diferentes... o utilizar estrictamente esas reglas en un pequeño programa de 1000 líneas. La repetición es un elemento fundamental junto con el objetivo, que debe ser exclusivamente de aprendizaje.

Lo que hacemos en el trabajo con miras a un resultado "laboral" tiene otro objetivo, otras prioridades. Por eso suelo utilizar "experiencia" pero no "práctica".

Resumiendo: es una práctica, un ejercicio. Nos obliga a repetir un montón de patrones un montón de veces en un tiempo acotado.

P.D.: muy buenos links, gracias.

BlackTigerX dijo...

yo solo digo que no creo que un proyecto real pueda cumplir con esas reglas

fav dijo...

@BlackTigerX Si se tradujera el código de Darcs o XMonad a un lenguaje OO ¿qué tan lejos estarían de cumplirlas?
Hmmmm… tal vez el problema es el lenguaje… o el paradigma… =P