Está en la página 1de 22

19: Análisis y Diseño

El paradigma de la orientación a objetos es una filosofía de programación


nueva y diferente.

Al principio mucha gente tiene problemas para saber cómo aproximarse a los
proyectos de POO. Ahora que ya entiendes el concepto de objeto, y según
vayas aprendiendo a pensar más y más en un estilo orientado-a-objetos,
puedes empezar a crear “buenos” diseños que aprovechen todos los beneficios
que la POO puede ofrecer. Este capítulo introduce las ideas de análisis, diseño
y algunas formas de aproximación a los problemas que aparecen al desarrollar
programas orientados-a-objetos buenos en un período de tiempo razonable.

Metodología
Una metodología (llamada a veces simplemente método) es un conjunto de
procesos y heurísticas que se utilizan para romper la complejidad de un
problema de programación. Muchas metodologías de POO han sido formuladas
desde el amanecer de la programación

La me todología, especialmente en el caso de la POO, es un campo de múltiple


experimentación, así que es importante entender que problema está
intentando resolver dicha metodología antes de considerar su adopción. Esto
es particularmente cierto en Java, donde el lenguaje de programación pretende
reducir la complejidad (comparado con C) que existe al escribir un programa.
De hecho, esto puede hacer menos necesario la adopción de metodologías que
se hacen cada vez más complejas. En su lugar, puede ser suficiente recurrir a
metodologías simples para un rango mucho mayor de problemas del que
podrías gestionar utilizando metodologías simples con lenguajes procedurales.

También es importante darse cuenta de que el término “metodología” a


menudo es demasiado pretencioso y promete demasiado. Sea lo que sea que
haces ahora cuando diseñas y escribes un programa es una metodología.
Puede que sea tu propia metodología, y puede que no seas consciente de que
la estás utilizando, pero es un proceso que sigues mientras creas. Si es un
proceso eficaz, puede que sólo sea necesario un pequeño ajuste para que sirva
para Java. Si no estás satisfecho con tu productividad y la forma en la que se
desarrollan tus programas puede que quieras considerar la adopción de una
metodología formal, o tomar elementos de las varias metodologías formales
existentes.

Durante el proceso de desarrollo, la cuestión más importante es la siguiente:


No perderse. Es fácil. La mayoría de las metodologías de análisis y diseño
pretenden resolver el problema más complejo. Recuerda que la mayoría de los
proyectos no encajan en esta categoría, así que normalmente puedes obtener
un buen análisis y diseño con un subconjunto relativamente pequeño de las
recomendaciones de una metodología. [1] Pero por lo general, algún tipo de
proceso, no importa cuan pequeño o limitado, te guiará de una forma mucho
mejor que limitars e codificar desde el principio.

[1] Un ejemplo excelente de esto es el libro de Martin Fowler UML Distilled , 2nd
edition (Addison-Wesley 2000), que reduce el a veces inabarcable proceso UML
a un subconjunto manejable.

También es fácil atascarse, caer en la “paralización por la investigación,” en la


que te sientes como si no pudieras avanzar porque no has asegurado cada
pequeño detalle de la fase actual. Recuerda, no importa cuanto análisis hagas,
hay elementos del sistema que no se revelarán hasta la fase de diseño, y más
cosas aún que no se revelarán hasta que has empezado a codificar, o incluso
no lo harán hasta que el programa esté en funcionamiento. Debido a esto, es
crucial moverse rápidamente por el análisis y el diseño, e implantar una
prueba de concepto del sistema propuesto.

Este punto es digno de mención. Debido a la experiencia que tenemos con los
lenguajes procedurales, es encomiable que un equip o quiera proceder con
cautela y entender cada detalle por pequeño que sea antes de pasar al diseño
y la construcción del sistema. Sin duda, cuando se trata de crear un Sistema
de Gestión de Bases de Datos (SGBD), merece la pena entender
completamente las necesidades del cliente. Pero un SGBD es un tipo de
problema que está muy bien planteado y es bien comprendido; en muchos
programas semejantes, la estructura de la base de datos es el problema a
sortear. El tipo de problemas que se discuten en este capítulo es de la variedad
“comodín” (expresión mía), en la que la solución no es una simple
reformulación de una solución bien conocida, sino que implica a uno o más
“factores comodín”—elementos para los que previamente no existe una
solución bien comprendida, para los que es necesario trabajo de
investigación.[2] El intento de analizar completamente un problema comodín
antes de pasar al diseño y la construcción resultan en la paralización por
investigación porque no se tiene suficiente información para resolver este tipo
de problemas durante la fase de análisis. Resolver semejante problema
necesita la iteración de todo el ciclo, y requiere de un comportamiento de
aceptación de riesgos (que tiene sentido, porque estás intentando hacer algo
nuevo y los beneficios potenciales son mayores). Podría parecer que aceptar el
riesgo implica “precipitarse” en una construcción preliminar, pero por contra,
éste hecho puede reducir el riesgo que se da en un proyecto comodín porque
de esta manera se puede averiguar en una etapa temprana si una
aproximación concreta a un problema es viable. El desarrollo de productos es
gestión de riesgos.

[2] La regla de estimación a groso modo que utilizo para dichos proyectos es:
Si hay más de un comodín, ni siquiera trates de planificar cuánto se va a
tardar o cuánto va a costar hasta que hayas creado un prototipo. Hay
demasiados grados de libertad.

A menudo se propone “construir uno para tirar.” Con la POO podrías seguir
tirando parte del mismo, pero debido a que el código está encapsulado en
clases, durante la primera iteración inevitablemente producirás algunos
diseños de clase que son útiles y desarrollarás algunas ideas valiosas sobre el
diseño del sistema que no es necesario tirar. Así, un rápido primer repaso del
problema no sólo produce n i formación crítica para los siguientes pasos de
análisis, diseño y construcción, también crea una base de código.

Dicho esto, si miras una metodología que contiene mucho detalle y sugiere
muchos pasos y documentos, sigue siendo difícil saber cuándo parar. Mantén
presente lo que intentas descubrir:

1. ¿Qué objetos hay? (¿Cómo divides tu proyecto en sus partes


componentes?)
2. ¿Cuáles son sus inferfaces? (¿Qué mensajes necesitas enviar a cada
objeto?)

Aunque no obtengas más que los objetos y sus interfaces ya puedes escribir un
programa. Puede que, por diversas razones, necesites más descripciones y
documentos, pero no podrás proceder con menos.

El proceso puede realizarse en cinco fases, y una Fase 0 que es simplemente el


compromiso inicial para utilizar algún tipo de estructura.

Fase 0: planificar
Primero debes decidir qué pasos vas a tener que dar en tu proceso. Parece
sencillo (de hecho todo esto parece sencillo), y sin embargo a menudo la gente
no toma esta decisión antes de empezar a codificar. Si tu plan es “dejémonos
de preliminares y empecemos a codificar,” bien. (A veces, cuando tienes un
problema que comprendes bien es lo adecuado.) Al menos admite que este es
el plan.

También podrías decidir en esta fase que es necesario tener alguna estructura
de proceso, pero no las nueve yardas al completo. Es comprensible que
algunos programadores les gusta trabajar en “modo vacacional,” en el que no
se impone ninguna estructura en el proceso de desarrollo de su trabajo;
“terminaré cuando todo haya terminado.” Esto puede ser atractivo durante un
tiempo, pero he llegado a la conclusión de que unos cuantos hitos en el camino
ayudan a focalizar y motivar tus esfuerzos sobre esos hitos en lugar de
atascarte en la única meta de “terminar el proyecto.” Además, esto div ide el
proyecto en trozos más manejables y lo hace parecer menos amenazador (sin
contar con que los hitos ofrecen más oportunidades para celebrar el progreso).

Cuando comencé a estudiar estructura narrativa (por si quería escribir algún


día una novela) al principio era reluctante a la idea de estructura, sentía que
podía escribir mejor cuando me limitaba a dejar la narración fluir en la página.
Pero luego me di cuenta de que cuando escribo sobre ordenadores la
estructura me es lo suficientemente clara como para no tener que pensar en
ella mucho. Sigo estructurando mi trabajo, aunque sólo de forma
semiconsciente en mi cabeza. Incluso si piensas que tu plan es simplemente
empezar a codificar, todavía tienes que pasar por las fases siguientes
haciéndote ciertas preguntas y contestando a las mismas.

La declaración de la misión
Cualquier sistema que construyas, no importa lo complicado que sea, tiene un
propósito fundamental—el negocio en el que se sitúa, la necesidad básica que
satisface. Si eres capaz de mira r más allá de la interfaz de usuario, los detalles
específicos del hardware o del sistema, los algoritmos de codificación y los
problemas de eficiencia, con el tiempo encontrarás el corazón de su ser—
simple y directo. Es como lo que llaman concepto principal de una película de
Hollywood, puedes describirlo en una o dos frases. Esta pura descripción es el
punto de partida.

El concepto principal es muy importante porque fija la orientación de tu


proyecto; es una declaración de la misión. No conseguirás que sea
completamente acertada desde el principio (puede que estés en una fase
posterior del proyecto antes de que esté completamente clara), pero sigue
intentándolo hasta que parezca adecuada. Por ejemplo, en un sistema de
control de tráfico aéreo puedes comenzar con un concepto principal enfocado
en el sistema que estás construyendo: “El programa de la torre supervisa la
posición de las aeronaves.” Pero considera lo que ocurre cuando tu sistema es
el de un aeródromo muy pequeño; quizás sólo hay un controlador humano, o
ninguno. Un modo más útil no tendrá en cuenta la solución que estás
definiendo sino que describirá el problema: “Las aeronaves llegan, descargan,
se abastecen y recargan, luego se van.”

Fase 1: ¿Qué estamos haciendo?


En la generación anterior de diseño de programas (llamada diseño procedural),
esto se denominaba “creación del análisis de requisitos y especificación del
sistema.” Por supuesto, estos eras lugares en los que era fácil perderse;
documentos con nombres intimidatorios que podrían llegar a ser grandes
proyectos en si mismos. No obstante, su intención era buena. El análisis de
requisitos dice “haz una lista de las líneas guía que seguiremos para saber
cuando hemos terminado el trabajo y el cliente está satisfecho.” [3] La
especificación del sistema dice “Aquí tienes una descripción de lo que el
programa debe hacer (no del cómo) para satisfacer los requisitos.” El análisis
de requisitos es un verdadero contrato entre tú y el cliente (incluso si el cliente
está en tu propia empresa, o si se trata de otro objeto o sistema). La
especificación de sistemas es una exploración de alto nivel del problema y en
cierto sentido se trata de descubrir si se puede hacer y cuánto tiempo llevará.
Dado que ambas cosas requieren de consenso entre las personas (y debido a
que éstas habitualmente cambian con el tiempo), creo que lo mejor es
mantenerlas tan simples como sea posible—idealmente, reducidas a listas y
diagramas básicos—para ahorrar tiempo (esto está en línea con la
Programación Extrema, que aboga por una documentación muy reducida,
aunque sólo vale para proyectos pequeños a medianos). Podrías tener otras
restricciones que requiriesen una explicación en más detalle en documentos
más extensos, pero si mantienes el documento inicial pequeño y conciso,
podrás crearlo en unas pocas sesiones de trabajo en grupo utilizando técnicas
de tormenta de ideas y un líder que de forma dinámica realiza la descripción.
Estas técnicas no sólo piden a todo el mundo ofrezca ideas, también favorece
una involucración y un acuerdo iniciales por parte de todos los miembros del
grupo. Y quizás lo más importante, puede lanzar un proyecto con mucho
entusiasmo.

[3] Un recurso excelente para el análisis de requisitos es el libre de Gaue y


Weinberg Exploring Requirements: Quality Before Design (Dorset House 1989).

Es necesario mantener el foco en el corazón de lo que se intenta conseguir en


esta fase: Determinar lo que se supone que el sistema debe hacer. La
herramienta más valiosa para conseguirlo es una colección de lo que se
denominan “casos de uso,” o en Programación Extrema, “historias del usuario.”
Los casos de uso identifican las características clave del sistema que revelarán
algunas de las clases fundamentales que se utilizarán. Se trata esencialmente
de respuestas decriptivas a preguntas como: [4]

• “¿Quién utilizará el sistema?”


• “¿Qué pueden esos actores hacer son el sistema?”
• “¿Cómo hace este actor eso con este sistema?”
• “¿De qué otra forma podría funcionar si alguien estuviese haciendo esto
otro, o si el mismo actor tuviese un objetivo diferente?” (para descubrir
variantes)
• “¿Qué problemas podrían ocurrir mientras se está haciendo esto con el
sistema?” (para descubrir excepciones)

[4] Gracias a la ayuda de James H Jarrett.

Si, por ejemplo, estás diseñando un cajero automático, el caso de uso para un
aspecto concreto de la funcionalidad del sistema es tratar de describir lo que el
cajero automático hace en cada situación posible. Cada una de estas
“situaciones” se denomina escenarios, y un caso de uso puede ser considera do
como una colección de escenarios. Puedes pensar en un escenario como una
pregunta que comienza de la siguiente manera: “¿Qué hace el sistema si......?”
Por ejemplo, “¿Qué hace el cajero automático si un cliente acaba de depositar
un cheque en las últimas 24 horas y no hay saldo suficiente en la cuenta sin
que el cheque haya sido confirmado para realizar una retirada de fondos que el
cliente ha solicitado?”

Los diagramas de caso de uso son intencionadamente sencillos para evitar que
te enfangues en los detalles de construcción del sistema de forma prematura:
Cada persona palo representa un “actor,” que es típicamente un humano o
algún otro tipo de agente de comportamiento libre. (Estos pueden ser incluso
otros sistemas informáticos, como es el caso del “ATM.”) La caja representa los
límites de tu sistema. Las elipses representan los casos de uso, que son
descripciones de trabajo de valor añadido que se puede realizar con el sistema.
Las líneas entre los actores y los casos de uso representan las interacciones.

No importa cómo está el sistema realmente construido, siempre que se


comporte con el usuario de la manera determinada.

Un caso de uso no tiene que ser necesariamente horriblemente complejo,


aunque el sistema subyacente lo sea. La intención es únicamente mostrar el
sistema como aparece ante el usuario. Por ejemplo:

Los casos de uso producen las especificaciones de requisitos al determinar


todas las interacciones que el usuario puede tener con el sistema. Intenta
descubrir un co njunto completo de casos de uso para tu sistema, y una vez
que lo hayas hecho tendrás el núcleo de lo que se supone que el sistema debe
hacer. Lo bueno de enfocarse en los casos de uso es que siempre te traen de
vuelta a lo esencial y evitan que derives hacia asuntos que no son críticos para
terminar el trabajo. Esto es, si tienes un conjunto de casos de uso completo,
puedes describir tu sistema y pasar a la siguiente fase. Probablemente no
conseguirás que todo se perfile perfectamente en el primer intento, pero eso
está bien. Todos los detalles aparecerán a su debido momento, si pretendes
obtener una especificación perfecta del sistema en este punto, te atascarás.
Si te atascas de verdad, puedes darle un empujón a esta fase utilizando una
herramienta de aproximación de alto nivel: Describe el sistema en unos pocos
párrafos y busca nombres y verbos. Los nombres pueden sugerir actores,
contextos de los casos de uso (p.e., “grupos de interesados”, o artefactos que
se manipulan en el caso de uso. Los verbos pueden sugerir interacciones entre
los actores y el caso de uso, y especificar pasos dentro del caso de uso.
También descubrirás que los nombres y los verbos producen objetos y
mensajes durante la fase de diseño (y ten en cuenta que los casos de uso
describen interacciones entre subsistemas, de forma que la técnica de “los
nombres y los verbos” sólo puede ser considerada como una herramienta para
las tormentas de ideas porque no generan casos de uso). [5]

[5] Se puede encontrar más información sobre los casos de uso en el libro de
Rosenberg Use Case Driven Object Modeling with UML (Addison-Wesley 1999).
Y una buena visión preliminar de las historias de usuario se puede leer en el
libro de Beck y Fowler Planning Extreme Programming (Addison-Wesley 2001).

La frontera entre un caso de uso y un actor puede indicar la existencia de un


interfaz de usuario, pero no define dicha interfaz. Si quieres profundizar en el
proceso de definición y creación de interfaces de usuario, mira en el libro de
Larry Constantine y Lucy Lockwood Software for Use, (Addison-Wesley
Longman, 1999) o busca en la web en www.ForUse.com.

Aunque se trate de magia negra, en este punto es importante recurrir algún


tipo de técnica de planificación de tareas. Ya tienes una percepción de lo que
vas a construir, así que probablemente podrás hacerte una idea de cuánto
tiempo te llevará hacerlo. Muchos factores entran aquí a jugar un papel. Si
estimas un plan largo, puede que la empresa decida no construirlo (y utilizar
así sus recursos en algo más razonable—esto es algo bueno). También puede
que un directivo haya decidido de antemano cuánto debería llevar el proyecto
y trate de influir en tu estimación. Pero lo mejor es tener un calendario
honesto desde el principio y tratar con las decisiones difíciles al principio. Ha
habido muchos intentos de conseguir técnicas de planificación temporal
ajustadas (tantas como ha técnicas de predicción en el mercado de valores),
pero probablemente la mejor aproximación es confiar en tu experiencia e
intuición. Utiliza tus instintos para estimar la duración del proyecto y luego
dobla la cantidad y añade un 10 por ciento. Tus instintos probablemente sean
correctos; puede que consigas algo que funcione en ese tiempo. “Doblar” la
cantidad convertirá el producto en algo decente, y el 10 por ciento permitirá el
pulido y los detalles finales. [6] Por mucho que quieras explicarlo, y a pesar de
las quejas y manipulaciones que se dan cuando das un calendario como ese,
simplemente parece que la cosa funciona así. [7]

[6] Últimamente, mi regla personal para éste tema ha cambiado. Doblar y


añadir un 10 por ciento te da una estimación razonablemente ajustada
(asumiendo que no haya demasiados factores comodín), pero todavía tendrás
que trabajar de forma muy diligente para terminar en ese plazo. Si quieres
tener tiempo para hacerlo realmente elegante y para disfrutar durante el
proceso, creo que el factor correcto es más del orden de tres o cuatro veces tu
instinto inicial. Si quieres ver un estudio sobre el efecto de los calendarios en la
productividad y una refutación de la “Ley de Parkinson” busca en el libro de
DeMarco y Lister PeopleWare (Dorset House 1999).

[7] Planning Extreme Programming (ibid.) tiene algunas percepciones valiosas


sobre el tema de la planificación y la estimación temporal.

Fase 2: ¿Cómo lo vamos a construir?


En esta fase debes obtener un diseño que describa qué aspecto tienen las
clases y la forma en la que interactúan. Una técnica excelente para determinar
las clases e interacciones existentes es la de las tarjetas Clase-
Responsabilidad-Colaboración (CRC). Parte del valor de esta herramienta es
que no tiene asociada una tecnología espacial: Comienzas con una pila de
tarjetas 3 x 5 en blanco, y escribes sobre ellas. Cada tarjeta representa una
única clase, y en la tarjeta escribes:

1. El nombre de la clase. Es importante de que este nombre captura la


esencia de lo que la clase hace, para que tenga sentido a primera vista.
2. Las “responsabilidades” de la clase: que debería hacer. Esto se puede
resumir normalmente mediante una lista de los nombres de los métodos
(dado que dichos nombres deberían ser descriptivos en un buen diseño),
pero no excluye la utilización de otras anotaciones. Si necesitas sembrar
el proceso, estudia el problema desde la perspectiva de un programador
perezoso: ¿Qué objetos te gustaría que mágicamente aparecieran para
resolver tu problema?
3. Las “colaboraciones” de la clase: ¿Con qué otras clases interactúa?
“Interactuar” es un término intencionadamente ambiguo; podría indicar
una agregación o simplemente la existencia de algún otro objeto que
realizase los servicios para un objeto de esa clase. Las colaboraciones
deberían también considerar la audiencia de la clase actual. Por ejemplo,
si creas una clase FuegoDeArtificio , ¿quién va a observarlo, un
Pirotécnico o un Expectador? El primero estará interesado en conocer
los componentes químicos de los que está compuesto, el segundo
responderá a los colores y la forma que toma cuando explota.

Puede que pienses que las tarjetas deberían ser más grandes debido a la
información que te gustaría tener en ellas. Sin embargo, se han dejado así de
pequeñas de forma intencionada, no sólo para mantener pequeñas tus clases,
sino también para evitar que entres en demasiado detalle demasiado pronto.
Si no puedes encajar todo lo que necesitas sabes sobre una clase en un
pequeña tarjeta, entonces la clase es demasiado compleja (o estás entrando
en demasiado detalle o deberías crear más de una clase). La clase ideal
debería ser entendida en un vistazo. La idea de las tarjetas CRC es ayudarte a
obtener un primer corte del diseño de forma que puedas ver el dibujo completo
y luego refinar tu diseño.
Uno de los mayores beneficios de las tarjetas CRC está en la comunicación.
Ésta se realiza mejor en tiempo real, en un grupo, sin ordenadores. Cada
persona se hace responsable de varias clases (que al principio no tienen
nombres ni ninguna otra información). Realizas una simulación en vivo
representando un escenario cada vez, diciendo que mensajes se envían a los
diferentes objeto s para resolver cada escenario. Según se avanza en este
proceso, vas descubriendo las clases que necesitas y sus responsabilidades y
colaboraciones, y vas rellenando las tarjetas. Cuando has cubierto todos los
casos de uso, deberías tener un primer corte bastante completo de tu diseño.

Antes de empezar a utilizar tarjetas CRC, las experiencias que había tenido con
mayor éxito en obtención de un diseño inicial implicaban ponerme delante de
un equipo —que no había realizado antes ningún proyecto de POO—y dibujado
objetos en una pizarra. Comentábamos cómo se suponía que los objetos
debían comunicarse entre sí, borrábamos algunos y los reemplazábamos con
otros. En la práctica estaba gestionando todas las “tarjetas CRC” en la pizarra.
El equipo (cuyos miembros sa bían lo que se suponía que el producto debía
hacer) en realidad creaban el diseño, eran sus “propietarios”, en lugar de
dárselo hecho. Todo lo que yo me limitaba a hacer era guiar el proceso
haciendo las preguntas adecuadas, extrayendo las premisas y recib iendo la
realimentación del equipo para modificar dichas premisas. Lo verdaderamente
bello del proceso fue que el equipo no aprendió como conseguir un diseño
orientado a objetos mediante la revisión de ejemplos abstractos, sino
trabajando en el diseño en el que más interés tenían en ese momento: el suyo.

Una vez que has obtenido un conjunto de tarjetas CRC, puede que quieras
crear una descripción más formal de tu diseño utilizando UML. [8] No
necesitas utilizar UML, pero puede ser útil, especialmente si qu ieres colocar un
diagrama en la pared para que todo el mundo medite sobre él, lo que es una
buena idea (hay una plétora de herramientas de diagramación para UML
disponibles). Una alternativa a UML es la descripción textual de los objetos y
sus interfaces o, dependiendo de tu lenguaje de programación, el propio
código. [9]

[8] Para los principiantes recomiendo el anteriormente mencionado UML


Distilled , 2nd edición.

[9] Python (www.Python.org) se utiliza a menudo como “pseudocódigo


ejecutable.”

UML también ofrece una notación de diagramas adicional que permite describir
el modelo dinámico de tu sistema. Esto es útil en aquellas situaciones en las
que la transición entre estado de un sistema o subsistema son lo
suficientemente importantes como para necesitar sus propios diagramas (como
por ejemplo en un sistema de control). Puede que también necesites describir
las estructuras de datos para los sistemas o subsistemas en los que los datos
son el factor dominante (como los de una base de datos).
Sabrás que has terminado con la Fase 2 cuando hayas descritos los objetos y
sus interfaces. Bueno, la mayoría de ellos—suele haber unos cuantos que se
deslizan por las grietas y no se dan a conocer hasta la Fase 3. Pero eso está
bien. Lo que es importante es que con el tiempo descubrirás todos tus objetos.
Es agradable descubrirlos todos en una etapa temprana del proceso, pero la
POO ofrece suficiente estructura como para que no sea tan negativo si los
descubres más tarde. De hecho, el diseño de un objeto tiende a ocurrir en
cinco etapas, a lo largo del proceso de desarrollo del programa.

Las cinco etapas del diseño de objetos


El ciclo de vida del diseño de un objeto no está limitado al período en el que
escribes el programa. En vez de esto, el diseño de un objeto aparece durante
una secuencia de etapas. Es útil tener esta perspectiva porque dejas de
esperar la perfección desde el principio; en lugar de ello, te das cuenta de que
comprender lo que hace un objeto y cómo debería evolucionar con el tiempo.
Esta visión también se aplica al diseño de diversos tipos de programa; el
patrón para un tipo particular de programa emerge de la lucha continua con
ese problema (cuya crónica es relatada en el libro Pensando sobre Patrones
(con Java) disponible en www.BruceEckel.com). Los objetos, también, tienen
sus patrones y emergen mediante la comprensión, la utilización y la
reutilización.

1. Descubrimiento de los objetos. Esta etapa ocurre durante el análisis


inicial de un programa. Se puede descubrir a los objetos mirando los facto res
externos y los límites, la duplicación de elementos en el sistema, y las
unidades conceptuales más pequeñas. Algunos objetos son obvios si ya tienes
un conjunto de bibliotecas de clases. Los puntos en común entre las clases que
sugieren las clases básicas y la herencia pueden aparecer desde el principio, o
más avanzado el proceso de diseño.

2. Ensamblado de objetos. Según vas construyendo un objeto descubrirás la


necesidad de nuevos miembros que no aparecieron durante la fase de
descubrimiento. Las necesidades internas del objeto pueden hacer necesarias
otras clases que den soporte a dicho objeto.

3. Construcción del sistema. Una vez más, puede que en esta fase
aparezcan más requisitos del objeto. Según vas aprendiendo, tus objetos
evolucionan. La necesidad de comunicación e interconexión con otros objetos
del sistema puede hacer cambiar las tus clases o hacer necesarias nuevas
clases. Por ejemplo, puede que descubras la necesidad de clases de facilidades
o apoyo, tales como una lista enlazada, que contienen poca o ninguna
información y sirven sólo para dar servicio a la funcionalidad de otras clases.

4. Extensión del sistema. Según vas añadiendo nuevas características al


sistema puede que descubras que tu diseño anterior no facilita una extensión
fácil del sistema. Con esta nueva información, puedes reestructurar partes del
sistema, posiblemente añadiendo nuevas clases o nuevas jerarquías de clase.
Este es también un buen momento para considerar la retirada de
funcionalidades del proyecto.

5. Reutilización de objetos. Esta es la verdadera prueba de fuego de una


clase. Si alguien intenta reutilizar la clase en una situación completamente
nueva, probablemente encontrará defectos. Según la vayas adaptando a más
programas nuevos, los principios generales de la clase se harán más claros, y
así será hasta que tengas un tipo verdaderamente reutilizable. Sin embargo,
no esperes que la mayoría de los objetos del sistema sean reutilizables—es
perfectamente normal que el grueso de tus objetos sean específicos del
sistema. Los tipos reutilizables tienden a ser menos habituales y deben
resolver problemas más generales si quieren ser reutilizables.

Guías para el desarrollo de objetos


Estas etapas sugieren algunas líneas de guía cuando se trata de pensar en las
clases que estás desarrollando:

1. Crea una clase para un problema específico y luego deja que la clase
madure y se desarrolle para solucionar otros problemas.
2. Recuerda que descubrir las clases que necesitas (y sus interfaces)
supone la mayor parte del diseño del sistema. Si ya tenías dichas clases,
éste debería ser un proyecto fácil.
3. No te esfuerces por conocerlo todo desde el principio. Aprende según
vayas avanzando. De todos modos será así.
4. Empieza a programar. Consigue algo que funcione de forma que puedas
aprobar o rechazar tu diseño. No temas terminar con un código
espagueti de tipo procedural—las clases dividen el problema y ayudan a
controlar la anarquía y la entropía. Las clases problemáticas no afectarán
a las buenas.
5. Mantén la simplicidad. Los objetos pequeños y limpios con una utilidad
obvia son mejores que las interfaces grandes y complicadas. Cuando
llegue el momento de decidir, utiliza una aproximación del tipo Navaja de
Ocán [10]: Considera las alternativas y selecciona la que sea más
sencilla, po rque las clases simples son casi siempre las mejores.
Comienza haciéndolo pequeño y sencillo, y podrás ampliar el interfaz de
la clase cuando lo entiendas mejor. Es fácil añadir métodos, pero según
pasa el tiempo, es difícil eliminar métodos de una clase.

[10] “Lo que puede hacerse con menos... en vano se hace con más... la
mente no debería multiplicar las cosas sin necesidad.” Guillermo de Ockham,
1290-1349.

Fase 3: Construir el núcleo


Esta fase supone la conversión inicial del diseño aproximado en un cue rpo de
código compilable y ejecutable que puede ser probado y, especialmente, te
servirá para aprobar o refutar tu arquitectura. Este no es un proceso de un
sólo paso, sino el comienzo de una serie de pasos que construirán el sistema
de forma iterativa, como verás en la Fase 4.

Tu meta es encontrar el núcleo de la arquitectura de tu sistema, el núcleo que


necesita ser construido para generar un sistema que funcione, sin importar lo
incompleto que sea ese sistema en su primera pasada. Estás creando una
infraestructura sobre la que puedes construir en iteraciones posteriores.
Además estás realizando la primera de las muchas integraciones y pruebas que
harás, y ofreciendo a los accionistas una idea de cómo va a ser su sistema y
cómo va progresando. De manera d i eal revelarás algunos de los riesgos más
críticos. Probablemente descubrirás los cambios y mejoras que puedes hacerle
a la arquitectura original—cosas que no habrías descubierto sin construir el
sistema.

Parte de la construcción del sistema es el contraste con la realidad que se


obtiene al comprobar con el análisis de requisitos y especificación del sistema
(sea la que sea la forma que tenga). Asegúrate de que las pruebas verifican los
requisitos y los casos de uso. Cuando el núcleo del sistema sea estable, estás
listo para progresar y añadir más funcionalidad.

Fase 4: Iterar para cada caso de uso


Una vez que la infraestructura básica está funcionando, cada conjunto de
características que añadas es en si misma un pequeño proyecto. Añades un
conjunto de características durante cada iteración, un período de tiempo de
desarrollo razonablemente corto.

¿Cómo de larga es una iteración? De forma ideal, cada iteración dura entre una
a tres semanas (esta duración puede variar dependiendo del lenguaje de
programación). Al final de ese período, tienes un sistema integrado y probado
con más funcionalidad de la que tenía antes. Pero lo que es particularmente
interesante es la base de la iteración: un único caso de uso. Cada caso de uso
es un paquete de funcionalidad relacionada que incluyes en el sistema de una
vez, durante el curso de una iteración. Esto, no sólo te da una mejor idea del
ámbito que el caso de uso debería tener, sino que también ofrece mayor
validación a la idea del caso de uso, puesto que el concepto no lo descartamos
después del análisis y el diseño, es una unidad fundamental de desarrollo a lo
largo de todo el proceso de construcción del software.

Terminas las iteraciones cuando alcanzas la funcionalidad objetivo o se alcanza


una fecha límite impuesta desde el exterior y el cliente se considera satisfecho
con la versión actual. (Recuerda que el software es un negocio de suscripción.)
Dado que el proceso es iterativo, tienes muchas oportunidades de entregar un
producto en lugar de tener un único punto final; los proyectos de fuente
abierta funcionan exclusivamente en un entorno iterativo, de mucha
realimentación y es eso precisamente lo que los convierte en un éxito.

Un proceso de desarrollo iterativo es valioso por muchas razones. Puedes


descubrir y resolver los riesgos críticos antes, los clientes tienen muchas
oportunidades de cambiar de idea, la satisfacción del programador es mayor, y
el proyecto puede dirigirse con mayor precisión. Pero hay un beneficio
adicional importante y es la realimentación que llega a los accionistas, los
cuales pueden ver cómo van las cosas por el estado actual del producto. Esto
puede reducir o eliminar la necesidad de las embotadoras reuniones de estado
e incrementar la confianza y el apoyo de los accionistas.

Fase 5: Evolución
Este es el punto del ciclo de desarrollo que tradicionalmente se denomina
“mantenimiento,” un término globalizador que puede significar cualquier cosa
desde “hacer que funcione realmente de la forma que se suponía debía hacerlo
desde el principio ” a “añadir características que el cliente olvidó mencionar” a
la más tradicional “arreglar los errores que aparezcan” y “añadir nuevas
características según vaya siendo necesario.” Se ha utilizado tantas veces el
término “mantenimiento” de forma equivocada que lo que conlleva es cierto
halo de calidad decepcionante, en parte porque sugiere que tu objetivo era
construir un programa perfecto y que todo tenías que hacer en adelante era
cambiar partes del mismo, engrasarlo y evitar que se oxidara. Quizás existe
una palabra mejor para describir lo que realmente ocurre.

Yo utilizaré la palabra evolución. [11] Esto es, “No lo vas a hacer bien la
primera vez, así que déjate a ti mismo el espacio necesario para aprender y
volver atrás para hacer cambios.” Puede que necesites hacer muchos cambios
según vayas aprendiendo y entendiendo el problema mejor. La elegancia que
obtendrás si evolucionas hasta conseguirlo compensará tanto a corto como a
largo plazo. La evolución es la forma en la que tu programa pasa de ser bue no
a ser mejor, y es la forma en la que las cuestiones que no comprendiste bien la
primera vez se clarifican. También es la forma en las que tus clases pueden
pasar de ser utilizadas en un único proyecto a ser recursos reutilizables.

[11] En el libro de Martin Fowler Refactoring: Improving the Design of Existing


Code (Addison-Wesley 1999), que sólo utiliza ejemplos en Java, se cubre al
menos un aspecto de la evolución de la que estamos hablando.

Lo que implica “hacerlo bien” no es sólo que el programa funcione según los
requisitos y los casos de uso. También quiere decir que la estructura interna
del código tiene sentido para ti y que parece encajar en su conjunto, sin
sintaxis extraña, objetos demasiado grandes, o trozos de código expuestos
torpemente. Además, debes tener la sensación de que la estructura del
programa sobrevivirá a los cambios que inevitablemente tendrá que sufrir a lo
largo de su vida, y que dichos cambios se podrán realizar de forma sencilla y
limpia. Este no es un objetivo pequeño. No só lo debes entender lo que estás
construyendo, sino que también deberás entender cómo evoluciona el
programa (lo que yo denomino el vector de cambio). Afortunadamente, los
lenguajes de programación orientados a objetos permiten particularmente bien
este tipo de modificación continua—los límites que los objetos definen son los
que tienden a proteger del colapso a la estructura. También te permiten hacer
cambios—ésos que parecerían drásticos en un programa procedural—sin
provocar terremotos por todo tu código. De hecho, las facilidades que ofrece
para la evolución del sistema podría ser el beneficio más importante de la POO.

Con el mecanismo de la evolución, creas algo que más o menos se aproxima a


lo que piensas que estás construyendo, y luego frenas, lo comparas con tus
requisitos y ves en qué se queda corto. Luego puedes volver atrás y arreglarlo,
rediseñando y rehaciendo las partes de tu programa que no funcionaron
correctamente. [12] En realidad, puede que hayas resuelto el problema, o un
aspecto del proble ma, muchas veces antes de que des con la solución
adecuada. (Aquí te puede ser de ayuda estudiar Patrones de diseño. Puedes
encontrar información sobre éste tema en Pensando sobre patrones (con Java)
disponible en www.BruceEckel.com.)

[12] Esto es parecido al “prototipado rápido,” en el cúal se suponía que debías


realizar una versión rápida y sucia que te permitiera aprender sobre el
sistema, para luego tirar el prototipo y hacerlo bien. El problema con el
prototipado rápido es que la gente no tiraba el prototipo, sino que construía
sobre él. Esto, combinado con la falta de estructura de la programación
procedural, conducía a menudo a sistemas enrevesados que eran costosos de
mantener.

También se observa evolución cuando tras la realización del sistema, observas


si se amolda a tus requisitos, y descubres que en realidad no es lo que querías.
Cuando ves un sistema funcionando, puedes darte cuenta de que en realidad
querías resolver un problema diferente. Si crees que este tipo de evolución
puede darse, entonces deberías construir tu primera versión tan rápido como
sea posible para averiguar si realmente es lo que quieres.

Quizás, lo más importante que has de recordar es que por defecto —por
definición, en realidad—si modificas una clase, sus superclases y subclases
seguirán funcionando. No tienes por qué temer la modificación (especialmente
si tienes un conjunto integrado de unidades de prueba que verifiquen la
corrección de tus modificaciones). Una modificación no tiene necesariamente
que estropear el programa, y cualquier cambio en el resultado se limitará a las
subclases y/o colaboradores específicos de la clase que has cambiado.

Los planos son valiosos


Por supuesto que no construirías una casa sin unos planos cuidadosamente
delineados. Si estás construyendo una cubierta o una caseta para el perro los
planos no serán tan elaborados, pero probablemente no empezarías sin algún
tipo de diagrama que te sirva de guía. El desarrollo de software ha llevado esto
al extremo. Durante mucho tiempo, la gente no incorporaba mucha estructura
en su desarrollo, pero entonces comenzaron a fallar los grandes proyectos.
Debido a esto, terminamos con metodologías que tenían una cantidad
intimidatorio de estructura y detalle, fundamentalmente dirigida a esos
grandes proyectos. El uso de estas metodologías era tan espeluznante —
parecía como si tuvieras que emplear todo tu tiempo en escribir documentos y
no dedicarle nada a la programación. (Este era a menudo el caso.) Espero que
lo que te he enseñado hasta el momento te sugiera que hay un término
medio —una escala con situaciones intermedias. Utiliza una aproximación que
se ajuste a tus necesidades (y a tu personalidad). No importa lo mínimo que
sea el plan que escojas, un plan de algún tipo supondrá una gran mejora en tu
proyecto, si se contrapone a no tener ningún plan en absoluto. Recuerda que,
la mayoría de las estimaciones dicen que ás del 50 por ciento de los proyectos
terminan mal (algunas estimaciones elevan esa cantidad al ¡70 por ciento!).

Al seguir un plan—preferiblemente uno que sea sencillo y breve—y obtener


una estructura de diseño antes de empezar a codificar, descubrirás que las
cosas encajan de forma mucho más fácil de la que lo harían si te lanzas de
cabeza a machete. También conseguirás mayor satisfacción. Mi experiencia es
que obtener una solución elegante es satisfactorio a un nivel completamente
diferente; te sientes más cerca del arte que de la tecnología. Además, la
elegancia siempre merece la pena; no es un objetivo frívolo. No sólo
conseguirás un programa más fácil de realizar y depurar, también será más
fácil de entender y mantener, y es ahí donde reside el valor financiero del
conjunto.

Programación Extrema
He estudiado técnicas de análisis y diseño, una y otra vez, desde que estaba
en el instituto. Y el co ncepto de Programación Extrema (XP) es el más radical y
delicioso que he visto hasta ahora. puedes leer su crónica en el libro de Kent
Beck Extreme Programming Explained (Addison-Wesley, 2000) y en la Web en
www.xprogramming.com. También parece ser que Addison-Wesley va a sacar
un nuevo libro de la serie XP cada uno o dos meses; el objetivo parece ser
mover a la conversión casi religiosa de todo el mundo por el sólo peso de los
libros (aunque generalmente estos libros son pequeños y agradables de leer).

XP es tanto una filosofía sobre la programación como un conjunto de guías


para programar. Algunas de estas líneas de guía están presentes en otras
metodologías recientes, pero, en mi opinión, las dos contribuciones más
importantes y singulares, son la de “escribir primero las pruebas” y la
“programación en parejas.” Aunque Beck defiende con ahínco el uso del
proceso completo, también señala que si sólo adoptases estas dos prácticas
mejorarías enormemente tu productividad y fiabilidad.

Escribe primero las pruebas


Tradicionalmente las pruebas se relegan a la última etapa de un proyecto,
después de que “todo funciona, y sólo para asegurarse de ello.” Implícitamente
tienen una prioridad baja, y a la gente que se especializa en ellas no se les da
mucho estatus y a menudo se les retiene en un sótano, lejos de los
“verdaderos programadores.” Los equipos de pruebas han respondido en
consonancia, llegando a llevar ropaje negro y carcajeándose con júbilo cuando
rompen algo (para ser honesto, yo mismo me he sentido así cuando he roto
algún compilador).

XP ha revolucionado completamente el concepto de la prueba al darle una


prioridad equivalente a (o incluso mayor que) la codificación. De hecho, debes
escribir las pruebas antes de escribir el código que deberá ser probado, y las
pruebas permanecen con el código para siempre. Las pruebas deben
ejecutarse con éxito cada vez que recompilas y montas el proyecto (lo que se
hace a menudo, a veces más de una vez al día).

Escribir primero las pruebas tiene dos efectos extremadamente importantes.

Primero, obliga a tener una definición clara de la interfaz de la clase. A menudo


sugiero que la gente “imagine una clase perfecta para resolver un problema
particular” como herramienta cuando tratan de diseñar el sistema. La
estrategia de pruebas de XP va más allá—especifica exactamente cuál debe ser
el aspecto de la clase para el consumidor de dicha clase y exactamente cómo
debe comportarse. Sin términos inciertos. Puedes escribir toda la prosa o crear
todos los diagramas que quieras que describan cómo se debería comportar una
clase y qué aspecto debe tener, pero no hay nada como un conjunto de
pruebas reales. Lo primero es una carta a los reyes magos, pero las pruebas
son un contrato que se mantiene en vigor gracias al compilador y la
infraestructura de pruebas. Es difícil imaginar una descripción más concreta de
una clase que las pruebas.

Mientras creas las pruebas, te fuerzas as repensar completamente sobre la


clase y a menudo descubrirás funcionalidad necesaria que había pasado
desapercibida a pesar de los experimentos mentales que conllevan los
diagramas UML, las tarjetas CRC, los casos de uso, etc.

El segundo efecto importante de escribir primero las pruebas viene del hecho
de que las pruebas se ejecutan cada vez que se reconstruye el software. Esta
actividad te ofrece la parte del testeo que no te da el compilador. Si observas
la evolución de los lenguajes de programación desde estas perspectivas, verás
que los verdaderos avances tecnológicos en realidad han venido del lado de la
prueba. El lenguaje ensamblador sólo comprobaba la sintaxis, pero C impuso
algunas restricciones semánticas, y dichas restricciones evitaban que
cometieras ciertos tipos de error. Los lenguajes de POO impusieron aún más
restricciones semánticas, lo que, si lo piensas, en realidad son
comprobaciones. “¿Se utiliza este tipo de datos de la forma adecuada?” y “¿Se
invoca a este método de la forma adecuada?” son los tipos de comprobaciones
que o el compilador o el sistema de ejecución realizan. Hemos visto los
resultados de tener incorporados estas comprobaciones al lenguaje: la gente
es capaz de escribir sistemas más complejos, y hacerlos funcionar, en mucho
menos tiempo y con mucho menos esfuerzo. Me he devanado los sesos
pensando en el porqué de esto, pero ahora me doy cuenta de que son las
pruebas: haces algo mal, y la red de seguridad que te ofrecen las
comprobaciones integradas te dicen que hay un problema y te señalan dónde
está.
Pero las comprobaciones integradas que el diseño del lenguaje permite no
pueden ir más allá. En un cierto punto, tú debes incorporarte al proceso y
añadir el resto de las pruebas que producen un conjunto completo (en
cooperación con el compilador y el sistema de ejecución) que verifique todo tu
programa. Y, así como tienes un compilador que vigila por encima de tu
hombro, ¿no querrías que estas pruebas te ayudasen desde el principio? Esa es
la razón por la que escribes las pruebas primero, y las ejecutas
automáticamente con cada construcción del sistema. Tus pruebas constituyen
una extensión de la red de seguridad que ofrece el lenguaje.

Una de las cosas que he descubierto con el uso de lenguajes de programación


cada vez más potentes es que me atrevo a probar con experimentos más
descarados, porque se que el lenguaje evita que pierda tiempo buscando
errores. El esquema de pruebas de XP hace esto mismo por tu proyecto al
completo. Porque sabes que tus pruebas interceptarán los problemas que
introduzcas (y regularmente añades nuevas pruebas según vayas pensando en
ellas), puedes hacer grandes cambios cuando lo necesites sin preocuparte de
sacar todo el proyecto de su línea. Esto es increíblemente potente.

En esta tercera edición de éste libro, me he dado cuenta de que las pruebas
son tan importantes que deberían aplicarse también a los ejemplos del libro.
Con ayuda de los Internos del Verano 2002 de Crested Butte, desarrollamos el
sistema de pruebas que verás que hemos utilizado a lo largo de este libro. El
código y la descripción están en el Capítulo 15. Este sistema ha mejorada la
robustez de los ejemplos de código de este libro de forma inconmensurable.

Programación en parejas
La programación en parejas pretende luchar contra el exacerbado
individualismo en el que hemos sido adoctrinados desde el principio, desde la
escuela (donde aprobamos o suspendemos por nosotros mismos, y el trabajo
con nuestros vecinos se considera “hacer trampa”), hasta los medios de
comunicación, especialmente en las películas de Hollywood en las que el héroe
habitualmente lucha contra la conformidad sin sentido. [13] También los
programadores son considerados ejemplos de individualidad—los
“codificadores vaqueros,” como Larry Constantine suele llamarlos. XP por
contra, lo cual supone una batalla contra el pensamiento convencional, dice
que el código debería escribirse con dos personas por estación de trabajo. Y
que debería hacerse en un área con un grupo de estaciones de trabajo que no
tenga las barreras a las que la gente que diseña las instalaciones es tan
aficionada. De hecho, Beck dice que la primera tarea para convertirse al XP es
llegar al trabajo con destornilladores y llaves Allen y apartar todo lo que esté
en medio. [14] (Esto requiere un jefe que pueda desviar las iras del
departamento de instalaciones.)

[13] Aunque puede que sea una perspectiva norteamericana no compartida,


las historias de Hollywood llegan a todas partes.
[14] Esto incluye (especialmente) el sistema megafonía. En una ocasión
trabajé en una empresa que insistía en emitir por megafonía cada llamada
entrante que recibía cada ejecutivo, lo que constantemente interrumpía
nuestra concentración (pero los responsables no podían ni siquiera concebir la
supresión de un servicio tan importante como la megafonía). Al final, cuando
nadie miraba empecé a desconectar a escondidas los cables de los altavoces.

El valor de la programación en parejas reside en que una persona es la que en


realidad realiza la codificación mientras que la otra está pensando sobre ello.
La que piensa mantiene en su mente la imagen de la totalidad de lo que se
hace—no sólo la imagen del problema que tienen entre manos, sino las líneas
guía de XP. Por ejemplo, si dos personas están trabajando juntas, es menos
probable que una de ellas se desvíe del proceso y diga, “no quiero escribir
primero las pruebas.” Y si el codificador se atasca, pueden intercambiarse el
puesto. Si los dos se atascan, puede que alguien más del área de trabajo
escuche sus dudas pueden, alguien que pueda hacer alguna contribución. La
programación en parejas mantiene las cosas fluidas y bajo control. Lo que es
probablemente más importante, hace la programación más social y divertida.

He empezado a usar la programación en parejas durante los ejercicios de


algunos de mis seminarios y parece mejorar significativamente la experiencia
de todo el mundo.

Estrategias para el cambio


Si ya te has decidido por la POO, tu próxima pregunta probablemente será,
“¿Cómo puede hacer que mi jefe/mi equipo/mi departamento/mis compañeros
empiecen a utilizar objetos?” Piensa en cómo tú—un programador
independiente —empezaría a aprender a utilizar un nuevo lenguaje y un nuevo
paradigma de programación. Ya lo has hecho antes. Primero viene la formación
y los ejemplos; luego viene un proyecto de prueba que te permita entender lo
básico sin confundirte demasiado. Luego viene un proyecto “del mundo real”
que haga algo realmente útil. Durante tus primeros proyectos sigues
educándote por la lectura, haciendo preguntas a los expertos e intercambiando
ideas con los amigos. Esta es la aproximación que sugieren muchos
programadores experimentados para cambiar a Java. Por supuesto que
cambiar a toda una empresa introduce cierta dinámica de grupos, pero en cada
paso ayudará recordar cómo lo haría una sola persona.

Guías
A continuación se dan algunas líneas de guía que conviene considerar cuando
se hace la transición a la POO y a Java:

1. Formación

El primer paso es algún tipo de formación. Recuerda la inversión que la


empresa ha hecho en código, y no intentes desarreglar las cosas durante seis o
nueve meses, el tiempo que tarda la gente en resolver los problemas que
aparecen con las características menos familiares. Escoge a un pequeño grupo
para adoctrinarlos, preferiblemente uno compuesto por personas que sean
curiosas, trabajen bien juntas y puedan funcionar como una red de
autosoporte mientras aprenden Java.

Una aproximación alternativa es la educación de todos los niveles de la


empresa a la vez, incluyendo cursos de introducción para los niveles de
jefatura estratégica y cursos de diseño y programación para los equipos de
proyectos. Esta aproximación es especialmente buena para las empresas más
pequeñas que van a cambiar de manera fundamental la forma en la que hacen
las cosas, o en un nivel de división para las empresas más grandes. Sin
embargo, y dado que el coste es mayor, algunos pue den que empiecen
eligiendo formar a un equipo de proyecto, hacer un proyecto piloto
(posible mente con un mentor externo), y dejar que el equipo se convierta en
los que formen al resto de la empresa.

2. Un proyecto de bajo riesgo

Intenta primero abordar un proyecto de bajo riesgo y deja que aparezcan los
errores. Una vez que hayas ganado alguna experiencia, puede utilizar los
miembros del equipo como semillas para otros proyectos o utilizarlos como
personal de soporte técnico de POO. Este primer proyecto puede que no
funcione bien la primera vez, así que no debería ser un proyecto crítico para la
misión de la empresa. Debería ser simple, sin relación con otros proyectos e
instructivo; esto implica que debería implicar la creación de clases que tengan
sentid o para el resto de programadores de la empresa cuando les llegue el
turno de aprender Java.

3. Modela desde el éxito

Busca ejemplos de buen diseño orientado a objetos en vez de empezar desde


cero. Hay buenas probabilidades de que alguien más haya resuelto ya tu
problema, y si no lo han resuelto exactamente puedes probablemente aplicar
lo que has aprendido sobre la abstracción para modificar un diseño existente
para que se ajuste a tus necesidades. Este el concepto general que está detrás
de los patrones de diseño, que se cubre en Pensando sobre patrones (con
Java) disponible en www.BruceEckel.com.

4. Utiliza las bibliotecas de clase existentes

Una motivación económica importante para cambiar a la POO es la facilidad


con la que se puede utilizar el código existente en forma de bibliotecas de
clase (en particular, las bibliotecas estándar de Java que se cubren en este
libro). Obtendrás el más corto de los ciclos de desarrollo sólo cuando puedas
crear y utilizar objetos de biblioteca no adaptados. Sin embargo, algunos
programadores nuevos no entienden esto, no son conscientes de las
bibliotecas de clase existentes o, debido a la fascinación que ejerce el lenguaje
sobre ellos, desean escribir clases que muy bien pueden ya existir. Tu éxito
con la POO y Java se rá óptimo si puedes hacer el esfuerzo de buscar y
reutilizar el código de otros que hayan realizado antes el proceso de transición.

5. No reescribas código existente en Java

Coger código existente y funcional y reescribirlo en Java no suele ser la mejor


forma de emplear tu tiempo. Si vas a cambiar a la orientación a objetos
puedes acceder al código C o C++ utilizando el interfaz de Java para Código
Nativo o el Lenguaje de Marcado Extensible (XML). Hay en ello beneficios
marginales, especialmente si se ha anunciado que el código será reutilizable.
Pero hay pocas oportunidades de que vayas a ver mejoras dramáticas de la
productividad que esperas de tus primeros proyectos a menos que sean
completamente nuevos. Java y la POO brillan mejor cuando se lleva un
proyecto al completo, desde su concepción hasta la realidad.

Problemas de gestión
Si eres un gestor, tu trabajo es conseguir recursos para tu equipo, quitar
barreras que están en el camino del éxito para tu equipo, y en general tratar
de ofrecer el entorno más productivo y divertido, de forma que tu equipo tenga
más oportunidades de realizar los milagros que siempre os piden. El cambio a
Java cae en esas tres categorías, y además podría ser maravilloso si no te
costase nada. Aunque cambiar a Java puede ser más barato —dependiendo de
tus restricciones—que las alternativas en POO para un equipo de
programadores C (y probablemente para programadores de otros lenguajes
procedurales), no será gratis, y hay obstáculos de los que deberías ser
consciente antes de intentar vender el cambio a Java en tu empresa y de
embarcarte en el mismo.

Costes de establecimiento

El coste de la transición a Java no se sólo el de la adquisición de los


compiladores para Java (el compilador para Java de Sun Java es gratuito, así
que este apenas supone un obstáculo). Los costes a medio y largo plazo se
minimizarán si inviertes en formación (y si es posible un mentor par tu primer
proyecto) y también si identificas y compras una biblioteca de clases que
resuelva tu problema en vez de tratar de construir dichas bibliotecas por ti
mismo. Esto tiene un coste alto que debe factorizarse en una propuesta
realista. Además, existen costes ocultos por la pérdida de productividad que se
produce mientras se aprende un nuevo lenguaje y posiblemente un nuevo
entorno de programación. La formación y la presencia de un mentor
seguramente pueden minimizarlos, pero los miembros del equipo deben
superar sus propios problemas para entender la nueva tecnología. Durante
este proceso cometerán más errores (esta es algo positivo, ya que los errores
que se reconocen son el camino más rápido con el que aprender) y ser menos
productivos. Incluso entonces, con algunos problemas de programación típicos,
las clases adecuadas y el entorno de desarrollo adecuado, es posible ser más
productivos durante el aprendizaje de Java (incluso aunque se considere que
cometes más errores y escribes menos líneas de código al día) que si hubieses
seguido con C.

Consideraciones de rendimiento

Una pregunta habitual es, “¿No hará la POO a utomáticamente a mis programas
más voluminosos y lentos?” La respuesta es, “Depende.” Las características
adicionales de seguridad de Java tradicionalmente han supuesto una
penalización frente a los que usan un lenguaje com C++. Las tecnologías como
“hotspot” y otras tecnologías de compilación han mejorado significativamente
la velocidad de ejecución en la mayoría de los casos, y se siguen haciendo
esfuerzos para mejorar el rendimiento.

Cuando tu foco es el prototipado rápido, puedes unir componentes tan rápido


como puedas ignorando cuestiones de eficiencia. Si utilizas bibliotecas de otros
proveedores, generalmente están optimizadas por sus fabricantes; en
cualquier caso no es para ti un punto a tratar mientras estés en el modo de
prototipado rápido. Cuando tienes el sistema que quieres, si es suficientemente
pequeño y rápido, ya has terminado. En caso contrario, empiezas a ajustarlo
con un perfilador, buscando primero las mejoras de rendimiento que se pueden
obtener reescribiendo pequeñas partes del código. Si eso no ayuda, busca
modificaciones que se puedan hacer en la parte oculta de la implementación de
forma que el código que utiliza una clase particular deba modificarse. Si el
rendimiento es tan crítico en esa parte del diseño, debe ser parte de tu criterio
de diseño. Así que te has beneficiado al averiguar este hecho en una etapa
temprana al utilizar técnicas de desarrollo rápido.

El capítulo 15 introduce el tema de los perfiladores, los cuales pueden ayudarte


a descubrir cuellos de botella en tus sistema de forma que puedas optimizar
esa parte de tu código (desde el lanzamiento de las tecnologías hotspot, Sun
ha dejado de recomendar el uso de métodos nativos para optimizar el
rendimiento). También hay disponibles otras herramientas de optimización.

Errores de diseño típicos

Cuando tu equipo empieza a utiliza la POO y Java, los programadores suelen


cometer una serie de errores típicos. A menudo, esto ocurre debido a una
realimentación insuficiente por parte de los expertos durante las etapas de
diseño y construcción de los primeros proyectos, porque no se han
desarrollado expertos en el seno de la empresa y porque puede haber
resistencia a mantener consultores por mucho tiempo. Es fácil creerse que
entiendes la POO demasiado pronto en el ciclo y salirse por la tangente. Algo
que es obvio para alguien experto en el lenguaje puede ser una cuestión de
debate para un novato. Gran parte de estos traumas pueden evitarse
utilizando un experto externo con suficiente experiencia en la formación como
mentor.

Resumen
La intención de este capítulo sólo era ofrecerte conceptos de las metodologías
de POO y las clases de preguntas que te encontrarás cuando lleves tu empresa
hacia la POO y Java. Puedes encontrar más información sobre el diseño de
Objetos en el seminario de MindView “Diseño de Objetos y Sistemas” (busca
en “Seminars” en el sitio www.MindView.net).

También podría gustarte