viernes, junio 06, 2008

Ejercicios calisténicos para objetos (III)

La introducción a esta entrada puedes verla aquí. El segundo capítulo, aquí.

2. No utilices la palabra clave else

No utilices la palabra clave else. Si la condición no se cumple, debes salir del método. Esto evitará el famoso código sinusoidal al no permitirse cadenas de elses.

No... no acabo de captar el sentido de este ejercicio. Vamos a ver. "No utilices else". Hmmmm. "Si la condición no se cumple, debes salir del método"... "Salir del método..." ¿Y si no quiero salir? ¿Qué pasa si con el else tengo asociado cierto comportamiento no trivial? Creo que el tema del else tiene que ver más con la implementación de guardias (al estilo del DIseño por Contrato á lá Bertrand Meyer) Aquí sí que creo que se han columpiado. ¿No será mejor decir que tienes que evitar aumentar irresponsablemente la complejidad de tu código? ¿Que con cada if (¡de hecho con cada punto de decisión!) haces más difícil entender tu código?

3. Esconde las cadenas y los tipos primitivos en clases.

Esconde las cadenas y los tipos primitivos en clases. Esto se conoce como "obsesión por las primitivas". Si quieres usar un entero, antes debes crear una clase (incluso una clase interna) para identificar su auténtico papel. Con ello conseguirás código mucho más claro y verificable.

¡Abstrae, maj@, abstrae! Crea un nuevo lenguaje, por encima de C++, C#, Visual Basic.NET, Eiffel, Haskel, Caml, o ensamblador (especialmente en ensamblador ;-). Deja de hablar de cadenas, de listas doblemente enlazadas, de árboles equilibrados. Las cadenas de conexión a la base de datos ya no existe, la base de datos ya no existe. La web no existe, ni un servicio web, ni la memoria RAM. El lenguaje en el que debes expresarte y el que antes debes construir, que eso es programar, ¡es el del dominio de tu problema! Si tu problema es financiero (¿y el de quién no, en estos tiempos de crisis?), tu lenguaje permite crear una Accion, invocar el método Accion.Comprar(cuantas). Si tu problema es de logística, tendrás clases como Ruta (.Calcular(), .Llegada(), .Salida()...), Camion, Mercancia...

Más aún, ¿de qué tipo declararías una variable que va a guardar un código postal? ¿un número entero? ¿una cadena de caracteres? Nopes, la solución es crear un tipo CodigoPostal para poder hablar en términos del dominio (por ejemplo, CodigoPostal.Provincia(), y así evitarás tener que invocar mil veces en tu código el método Substring(1, 2) sobre la cadena codigoPostal...). Otra cosa es que internamente sea una cadena, o un número. Eso es decisión tuya y secreto que debe guardar el nuevo tipo.

Dos observaciones. Primero, la obsesión por abstraer puede llevarte a modelizar todo el MundoReal™, (y rediseñar Matrix), y a tu jefe puede que no le mole demasiado. Segundo, abstraer no significa necesariamente ser ambiguo. De hecho, una buena abstracción es extraordinariamente precisa.

Seguiremos informando.

3 comentarios:

Jorge Alonso dijo...

Sobre el primer comentario.
Sí y no. Estoy d'acuerdo con lo que dice el hombrecillo ese. Pero en el siguiente sentido. Si tu tienes una condición de la forma:

if (condition) {
doSomething1();
doSomething2();
doSomething3();
}

transformalo a:

if (!condition) {
return;
}
doSomething1();
doSomething2();
doSomething3();

El else NO se puede quitar en muchos casos. Pero si se puede utilizar las lógica negativa (tb más oscura) para que no tengamos tango código barriga :D

Sobre las abstracción... Me quedo con el KIS (kept it simple). I mean, pon un int y si se te queda pequeño abstraelo. Pero no por definición y en la primera iteración del código.

Intro-spectre dijo...

Jorge, en el caso particular que presentas, yo evitaría la segunda opción (!condition). Como dices, la logica negada lo hace más complicado, sobre todo si condition es algo así del tipo (!found && index <= top). Lo evitaría igualmente si 'condition' están relacionado directamente con los doSomething. Sí creo que tiene todo el sentido cuando tienen que ver con el control de entradas, al estilo de pre-condiciones. El inclumplimiento de cualquiera de ellas evitaría la ejecución del código. En lo que sí estamos de acuerdo es que la legibilidad del código es también un factor muy importante.

Respecto del tema de la abstracción, es verdad que no hay que pasarse, y se debe empezar por lo sencillo, y en esa línea iba mi comentario acerca de "modelizar el resto del MundoReal" ;-) Lo que también es especialmente doloroso es ver que la abtracción no se usa cuando es necesaria. Entiendo también que el problema de la abstracción es también más problema en sistemas más grandes, donde la mantenibilidad es una cualidad imprescindible.

Intro-spectre dijo...

Por cierto, ¿para cuando un Grupo de Estudio de Diseño Software al estilo de DPSG de Nueva York? ;-)