Kortsoft

Thursday, February 04, 2010

Código limpio 1

Ahora que estoy leyendo pasajes del libro "Clean Code" de Robert C. Martin me ha surgido la idea de escribir algo sobre código real que he visto estos dias en varios sitios (de varios proyectos distintos de empresas distintas).
En ambos casos la operación que se estaba codificando era:

Obtener A
Modificar A
Actualizar/Guardar A

Bastante sencillo y típico, ¿no? Entonces, ¿por qué es tan fácil encontrar código tan mal hecho?. A las pruebas me remito (he cambiado el nombre de las variables para ocultar el origen del código):

Settings settings = page.getSettings();
settings.setProperty("propertyName", propertyValue);
pageService.updatePageSettings(page.getId(), page.getSettings());

¿Funciona este código? Sí. ¿Es de buena calidad? NO. Y fundamentalmente es porque no sigue la línea de pensamiento que una persona cuerda haría (obtener A, modificar A, guardar A). La lógica de este código anterior dice:

Obtener A
Modificar A
Guardar B

¿¿¿Comorrr??? Sí, eso es lo que dice, lo que pasa es que por artificios del lenguaje (de programación), en este caso A <=> B. (page.getSettings() <=> settings). En este caso, el lector del código (la segunda persona más importante que tiene que entender el código después del señor procesador), rápidamente entiende el error lógico del código y después de preferir un juramento contra el creador del fragmento, puede seguir leyendo, entendiendo o depurando el código. Pero ¿qué pasa si se complica un poco el código? Veamos un ejemplo:

Settings settings = page.getSettings();
settings.setProperty("propertyName", propertyValue);
pageService.updatePageProperties(page.getId(), page.getProperties());

(y el método page.getProperties()):

public Properties getProperties() {
   return this.settings.asProperties();
}

En este caso la confusión es mucho mayor si no conocemos el método page.getProperties() el cual coge nuestro objeto A y lo convierte en B. Efectivamente, el código funciona, porque cuando actualizo el segundo objeto estoy teniendo en cuenta los cambios hechos al primero (pero esta relación no está explícita en el código, sino que tengo que deducirla investigando). La solución de este segundo caso quizás implica una refactorización de varias clases que no obligue a :

  • Trabajar y modificar el objeto A
  • Actualizar el objeto B
Valdría por ejemplo un API que permitiese actualizar objetos de tipo A, y que internamente los transforme a objetos B y luego los actualice.

Al final, lo único que necesitamos es que la trama de nuestro código sea lógica y lineal, y que cualquier lector pueda seguirla. No es necesario hacer tramas tipo Memento aunque en el cine funcionen muy bien.

Labels: