Diseñar es imaginar, diseñar es pensar. El objetivo del diseño del software es imaginar, pensar, esbozar la implementación de los componentes y el software especificados en el análisis condicionado por las decisiones arquitectónicas tomadas.
El objetivo del diseño del código es imaginar la implementación de los componentes y el software especificados en el análisis condicionado por las decisiones arquitectónicas tomadas. De este modo, en el paradigma de la programación orientada a objetos, el resultado del Diseño será la definición de clases y flujos de colaboración entre ellas. Estas definiciones sustentarán la actividad de codificación.
Diferentes productos pueden hacer uso de una misma Arquitectura de Desarrollo, por ejemplo 2 niveles y 3 capas; de una misma Arquitectura de Presentación, por ejemplo, patrón MVP; y de una misma Arquitectura de Integración, por ejemplo, servicios web como interfaces de comunicación. Todos estos productos comparten una misma “Arquitectura”.
Sin embargo, aunque estos productos compartan arquitectura, deberán necesariamente de dotarse de su propio diseño de código. Por ejemplo, un producto software cuyo propósito sea gestionar planes de salud pública de cribado poblacional de cáncer se sustentará en clases como “Cáncer”, “Citación”, “Carta”, “Kit”, etc.. El diseño de otro producto software cuyo propósito sea gestionar la farmacia hospitalario se sustentará en clases como “Prescripción”, “Fármaco”, “ReaccionAdversa”, etc. Ambos productos pueden compartir un mismo diseño de arquitectura, pero su diseño del código es diferente.
En las metodologías predictivas es habitual que los roles de diseñador y codificador sean interpretados por personas diferentes. Por lo tanto, es necesario que el diseñador comunique al codificador los conceptos, ideas y bocetos que fundamentan la implementación del código. Para ello este tipo de metodologías hacen uso de diagramas UML como elemento básico de comunicación. Los diagramas UML trasladan las clases imaginadas en la mente del diseñador al papel.
En las metodologías adaptativas es habitual que los roles de diseñador, codificador y tester sean interpretados por una misma persona. Además, las actividades de diseño, codificación y pruebas suelen solaparse, realizándose en paralelo. Por lo tanto, no es necesario “documentar” el diseño para ser comunicado. Este tipo de metodologías no suelen hacer uso de diagramas UML.
Existen técnicas y patrones que ayudan a diseñar buenas soluciones:
Los Principios de Diseño son soluciones recurrentes a problemas similares. Los Principios de Diseño son útiles para imaginar en la mente del diseñador las clases, estructuras y componentes necesarios. En el paradigma Orientado a Objetos existen Principios de Diseño que ayudan al programador o diseñador a reflexionar sobre la estructura de las clases y sus relaciones. Seguir los principios de diseño permiten generar código mantenible, extensible y testable, no seguirlos genera código difícil de entender y modificar. Estos principios guían a los diseñadores a “descubrir” las clases y componentes necesarios.
Los Diagramas UML permiten materializar en una representación gráfica los diseños que emergen en la mente del diseñador. Son un vehículo de comunicación entre los miembros del equipo de desarrollo. A la hora de plasmar en un documento el diseño de las clases es habitual recurrir a la utilización de diagramas UML.
El Desarrollo Guiado por Pruebas obliga a poner a prueba los diseños detallados directamente en código. Las pruebas “ejercitan” el código, permitiendo al programador refinar y mejorar sus diseños iniciales. Poner a prueba el diseño permite recoger un rápido feedback al diseñador-codificador, certificando si el diseño es adecuado o no.
A pesar de que los paradigmas de programación han evolucionado enormemente desde entonces, los fundamentos que debe cumplir el “buen” código no han cambiado: alta cohesión y bajo acoplamiento. Estos fundamentos perduran y son aplicables al paradigma estructurado, al funcional o al orientado a objetos. Además, si el código ofrece una alta cohesión y un bajo acoplamiento, entonces posee un importante valor añadido: el código es fácilmente testable.
Los En 1975, Larry Constantine y Edward Yourdon publicaron “Structured Design”. En él mencionan la importancia de la alta cohesión y del bajo acoplamiento a la hora de diseñar código mantenible (fácil de corregir) y extensible (fácil de ampliar).
Bajo Acoplamiento. El acoplamiento se refiere al grado de interdependencia que tienen dos unidades de software entre sí, entendiendo por unidades de software: clases, métodos, módulos, etc. Por ejemplo, si una función del módulo A invoca a una función del módulo B, entonces un cambio en el código de la función de B podría afectar a la función de A. Decimos entonces que el módulo A está acoplado al módulo B. Un buen diseño debe minimizar las dependencias entre módulos.
Alta Cohesión. La cohesión de software es el grado en que elementos diferentes de un sistema permanecen unidos para alcanzar un mejor resultado que si trabajaran por separado. Por ejemplo, si dos funciones deben trabajar en sintonía para alcanzar un objetivo, entonces un buen diseño debería encapsular estas funciones en la misma clase. Por el contrario, si dos segmentos de código realizan trabajos diferentes, deberían encapsularse en distintas funciones.
🔎 La cohesión consiste en juntar bien cerca las cosas parecidas y alejar bien lejos las cosas diferentes
Una forma de entender el valor que la alta cohesión y el bajo acoplamiento da a un sistema, es mostrar los problemas que la baja cohesión y el alto acoplamiento ocasionan. El siguiente “sistema” ejemplifica el exceso de complejidad y dificultad de mantenimiento y extensión que una baja cohesión y un alto acoplamiento provocan.
🔎 El diseño de la rueda trasera de esta bicicleta está profundamente equivocado. ¡A la rueda trasera le falta cohesión y le sobra acoplamiento! Alto acoplamiento porque el movimiento de las dos piezas que forman la rueda trasera es muy dependiente el uno del otro. Baja cohesión porque las dos piezas que forman la rueda trasera implementan una única funcionalidad, pero sin embargo están separadas.
En el paradigma de programación orientada a objetos, existen una serie de principios de diseño que, a modo de brújula, ofrecen guías y pautas que ayudan al programador a diseñar sin perder el rumbo hacia la alta cohesión y el bajo acoplamiento. Estos principios de diseño ayudan a hacer emerger en la mente del diseñador las clases y sus relaciones.
Algunos principios de diseño son:
Las Cuatro Reglas el Diseño Simple
Principios SOLID
Patrones de Diseño
Inversión del Control
Kent Beck propuso las Cuatro Reglas del Diseño Simple mientras desarrollaba la metodología XP a finales de los 90s:
El código debe “pasar” los tests. En primer lugar, por supuesto, la aplicación debe hacer lo que se espera que haga. Para verificar que el código funciona es imprescindible cubrirlo con tests automatizados.
El código debe revelar su intención. A continuación, el código debe ser fácil de entender. Hacer uso de un buen naming es fundamental.
El código debe evitar duplicaciones. Cada pieza de código debe tener una única, no ambigua y representativa identidad dentro del sistema. Esta regla es también conocida como DRY (Don’t Repeat Yourself).
El código debe tener el menor número de elementos posible. Por último, todo lo que no cumpla con las tres reglas anteriores debe eliminarse. Esta regla pretende simplificar los diseños, eliminando todas las abstracciones innecesarias. Si con únicamente dos clases, el código pasa las pruebas, revela su intención y evita las repeticiones, entonces esta solución es preferible a otra que haga uso de tres clases para obtener lo mismo.
Las reglas se describen por orden de prioridad, por lo que "pasa las pruebas" tiene prioridad sobre "revela la intención".
La primera regla se estudiará con más detalle durante la actividad “pruebas”. La segunda y tercera reglas se indagarán en la actividad “codificación”. La última regla es más propia de la actividad de “diseño”. Las cuatro reglas de diseño simple de Kent Beck muestran de manera muy clara como las actividades de diseño, codificación y pruebas se solapan, las fronteras se difuminan. Beck propone realizar estas actividades a la vez. No existen los roles “diseñador”, “codificador” y “tester” sino que existe una única actividad de diseño de software que incluye todas estas actividades. Este enfoque será explicado con más detalle en el apartado “4.3.4 Desarrollo guiado por pruebas”.
SOLID es un acrónimo que acuñó Michael Feathers, basándose en los principios de la programación orientada a objetos que Robert C. Martin había recopilado en el año 2000 en su artículo “Design Principles and Design Patterns”.
Los cinco principios SOLID de diseño de aplicaciones de software, que favorecen una alta cohesión y un bajo acoplamiento, son:
Single responsibility principle o Principio de responsabilidad única. Solo debe existir un motivo para modificar una clase, o dicho de otra forma, una clase solo debe ser responsable de una funcionalidad.
Open/closed principle o Principio de abierto (a la extensión) / cerrado (a la modificación). Establece que las entidades (clases y módulos) deben estar abiertos para su extensión, pero cerrados para su modificación. En lugar de modificar el método de una clase añadiendo una nueva condición puede resultar preferible crear una nueva clase que extienda la anterior sobrescribiendo el método con el nuevo comportamiento. Para cambiar el comportamiento del software es preferible escribir nuevo código a modificar el ya existente.
Liskov substitution principle o Principio de sustitución de Liskov (Barbara Liskov, ganadora del premio Turing en 2008). Las clases derivadas no pueden conocer a las clases base.
Interface segregation principle o Principio de segregación del interface. Los clientes no deberían verse forzados a depender de interfaces que no usan. En lugar de añadir un nuevo método a una clase o interfaz, puede resultar más adecuado crear una nueva clase o interface.
Dependency inversion principle o Principio de inversión de dependencia. Las clases deben depender de abstracciones no de implementaciones. Se debe programar contra interfaces, no contra implementaciones. Esto permite sustituir componentes en el diseño de forma sencilla.
🔎 En los últimos años, los principios SOLID han recibido importantes críticas. Dan North impulsor de la técnica de diseño BDD (Behaviour Driven Development) plantea en su lugar las propiedades CUPID. Recientemente David Copeland ha publicado una dura (y divertida) crítica en forma de ensayo SOLID is not SOLID. El autor propone evitar “contar responsabilidades”. En lugar de “aforismos reduccionistas” que no tienen en cuenta el contexto, propone reflexionar específicamente cada caso atendiendo a los principios fundamentales: la cohesión y el acoplamiento.
Los patrones de diseño son soluciones habituales a problemas recurrentes en el desarrollo del software. Normalmente constan de una serie de pautas a seguir para resolver un problema concreto. Estas “recetas” han sido probadas intensamente y documentadas por la comunidad de desarrolladores de software.
Los principales patrones de diseño en el software fueron recopilados en 1994 en el libro “‘Design Patterns” escrito por el grupo Gang of Four (GoF) compuesto por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. En él se recogen los 23 patrones de diseño más comunes en el desarrollo de software.
Los patrones proponen soluciones mantenibles y extensibles a problemas concretos. Se basan en principios (SOLID, separation of concerns, ley de Demeter, etc.) que favorecen el código limpio, de esta manera, buscan maximizar la cohesión y minimizar el acoplamiento.
🔎 “Design Patterns” es un libro escrito en un lenguaje académico muy formal repleto de diagramas UML. Exige del lector una gran capacidad de comprensión y abstracción. En 2004, 10 años después de “Design Patterns”, Eric Freeman y Kathy Sierra publican “Head First Design Patterns” en el que tratan los 23 patrones de “Design Patterns” de forma más amena e informal. Rápidamente se convirtió en un “best seller”. “Head First Design Patterns” popularizó los patrones de diseño haciéndolos accesibles a todos los programadores.
En la programación “tradicional”, la interacción entre clases y funciones se hace de forma imperativa, es decir, de forma explícita, en el código de un método de una clase se crea un objeto de otra clase. La inversión de control es un principio que delega en un tercero (un framework o contenedor) el control del flujo de un programa para la creación de un objeto.
La inversión de control está basada en el principio de Hollywood. En la “meca del cine” era muy habitual la frase que decían los directores a los aspirantes: “No nos llames; nosotros te llamaremos”.
Existen distintas formas de implementar la inversión de control. Las formas más conocidas de este principio son el patrón “Service Locator” y el patrón “Inyección de Dependencias”. La diferencia fundamental entre ambas es que con el Service Locator las dependencias se solicitan explícitamente desde la clase dependiente al proveedor de servicios (Service Locator), mientras que, con la inyección de dependencias, un agente externo (Contenedor IoC) se encarga de proveer las mismas, sin mediar acoplamiento entre la dependencia y su proveedor. minimizar el acoplamiento.
🔎 Una bicicleta de competición es el resultado de ensamblar cientos de piezas. Cada una de esas piezas viene definida por una especificación que debe cumplir. Además, el plano de montaje señala la dependencia que cada pieza tiene con las demás. De esta forma es posible sustituir por ejemplo un sillín de paseo por uno de competición, siempre que el sillón de competición cumpla las especificaciones de los sillines exigidos en el diseño de la bicicleta. Un mecánico podrá montar toda la bicicleta o solo una parte de ella siguiendo los planos. Por ejemplo, si el mecánico desea probar que los discos funcionan, puede montar en el banco de pruebas toda la bicicleta excepto las ruedas para evitar que al dar pedales comience a moverse.
En esta metáfora la bicicleta representa al producto de software, las piezas representan a las clases (cada pieza es una clase), la dependencia con otras piezas puede aflorar en el constructor de cada clase señalando los objetos de otras clases que necesitará el objeto para funcionar, el mecánico es el contenedor IoC, el banco de pruebas es el framework de testing.
La técnica de aportar los objetos requeridos por una clase en el constructor, en lugar de permitir que los propios objetos instancien las dependencias dentro de sus métodos, se llama “Inyección de Dependencias”. Cuando el código depende de abstracciones (contratos) en lugar de implementaciones, implementa el principio de “Inversión de Dependencias”, la “D” de SOLID. La capacidad del código de extender su comportamiento modificando únicamente la clase ejecutora del arranque del software, ensamblando diferentes “sabores” de las dependencias, se llama “Inversión de Control”. De esta manera, la Inyección de Dependencias hace uso del principio de “inversión de dependencias” para lograr la Inversión de Control.
UML ofrece un estándar para describir un sistema (modelo), incluyendo aspectos conceptuales como procesos y aspectos concretos como expresiones de lenguajes de programación o esquemas de bases de datos.
Este estándar proporciona un conjunto de notaciones (recuadros y líneas) para describir modelos. Por ejemplo, el diagrama de clases. También proporciona un conjunto estándar de tipos de diagramas para combinar modelos que ayuden a implementar un caso de uso. Por ejemplo, el diagrama de secuencia.
Fue definido en los años 90 por Grady Booch, Ivar Jacobson y James Rumbaugh. Adoptado por el Object Management Group (OMG) en 1997 y de esta forma integrado en UP (Proceso Unificado).
Este lenguaje de modelado incluye un conjunto de notaciones gráficas que permiten crear modelos visuales de sistemas. Combina diagramas utilizados en el análisis como los diagramas E-R o los diagramas de flujo (workflows) con diagramas para representar clases derivadas de la Programación Orientada a Objetos, sus atributos y su comportamiento.
UML admite hasta 14 tipos de diagramas.
Martin Fowler, firmante del Manifiesto Ágil y autor de UML Distilled (1997), propone tres formas diferentes de hacer uso de las diagramas UML:
Diagramas UML usados como lenguaje de programación. Si el diagrama es muy riguroso y detallado, herramientas informáticas pueden transformar estos diagramas en código ejecutable. A pesar de los intentos de la industria en el desarrollo de lenguajes gráficos de programación, estos no terminan de implantarse de forma generalizada.
Diagramas UML usados como los planos del código. Disponer de planos del software permitiría a la industria la especialización de roles en diferentes equipos de personas, el grupo de diseñadores entrega los planos del software que el grupo de codificadores se encarga de transformar en código. Para ello es necesario el desarrollo de diagramas suficientemente rigurosos y detallados. El diseño debe incluir todas las decisiones de diseño, para que la programación sea una actividad sencilla que requiere poca reflexión. Los planos tienen como objetivo transmitir información detallada sobre el código, ya sea en documentos en papel o como un navegador gráfico interactivo. Los planos pueden mostrar todos los detalles de una clase en una forma gráfica que sea más fácil de entender para los desarrolladores. Un ejemplo de este tipo de uso son algunas herramientas middle CASE como por ejemplo Visual Paradigm.
Diagramas UML usados como un boceto. Los desarrolladores usan UML para ayudar a comunicar algunos aspectos de un sistema. En frente del boceto el equipo de desarrollo resuelve algunos problemas del código que están a punto de escribir. El boceto ayuda a dirigir el debate y ayuda a comunicar los diferentes puntos de vista. El diagrama UML utilizado como boceto no pretende especificar cada línea del código que se desarrollará. Estos diagramas no son rigurosos y suelen evitar “enfangarse” en los detalles de la implementación.
La tendencia de la industria por las metodologías adaptativas ha alentado el uso de los diagramas UML como bocetos. Destacados ingenieros de software, con mucho reconocimiento en la comunidad del desarrollo de software se han posicionado en este sentido. En los últimos años incluso los propios creadores del UML se han mostrado partidarios de su uso, no como planos o lenguaje de programación, sino como bocetos.
💬 [...] Así que aquí está mi consejo para usar bien los diagramas. Primero, tenga en cuenta para qué está dibujando los diagramas. El valor principal es la comunicación. La comunicación eficaz significa seleccionar cosas importantes y descuidar las menos importantes. Esta elección es la clave para usar bien el UML. No dibujes todas las clases, solo las importantes. Para cada clase, no muestre todos los atributos y operaciones, solo los importantes. No dibujes diagramas de secuencia para todos los casos de uso y escenarios, solo ... te haces una idea. Un problema común con el uso común de diagramas es que la gente trata de hacerlos completos. [...] Recuerde que el código es el depósito de información detallada, los diagramas actúan para resumir y resaltar cuestiones importantes. [...]
Martin Fowler, ¿Ha muerto el diseño? 2004
💬 UML debería usarse para razonar y discutir sobre alternativas. Crea algunos diagramas del sistema. Comprueba como de bien responden a los casos de uso que deberían cumplir. Después tira los diagramas y escribe el código que corresponde al mejor diseño
💬 Deberías usar una notación gráfica para aquellos aspectos sobre los que no se puede discutir fácilmente mirando el código
Grady Booch, “padre” de UML
Los diagramas UML vivieron su esplendor en los 90 y comienzos del 2000. Actualmente apenas son utilizados. Una buena prueba de ello, es la eliminación por parte de Microsoft de la característica de Visual Studio 2015 que permitía dibujar diagramas UML debido a su poco uso. Los principales factores que han provocado el poco uso de los diagramas UML es la percepción que tiene gran parte de la industria de su poca utilidad unido a su enorme complejidad.
💬 UML es, de hecho, tan complejo como un lenguaje de programación grande y críptico, con un uso generoso de “$” y “#” y “–” y “triángulos sólidos sin cola” y rectángulos y diamantes y líneas sólidas y líneas punteadas y elipses sólidas y elipses punteadas y flechas de todo tipo y palabras reservadas tomo “const” y “sorted” (no confundir con “ordered”) y semánticas distintas para una clase dependiendo si su nombre aparece en letra “romana” o “itálica”. ¡Pero al menos un lenguaje de programación, incluso el peor de ellos, es ejecutable! Aquí hay que aprender toda esa complejidad monstruosa para construir diagramas de un posible sistema futuro.
Bertrand Meyer, creador del lenguaje Eiffel. UML: The positive spin, 1997
Si el principal uso de los diagramas UML es bocetar el código, entonces no es necesario dotar al lenguaje de modelado de una gran rigurosidad formal. Los detalles de implementación serán resueltos durante la codificación, no durante el diseño. Las tarjetas CRC y el modelado C4 son algunas alternativas a los diagramas UML.
🔎 El Lenguaje de Modelado Galáctico fue una propuesta de Kent Beck que, en serio o en broma, tuvo algo de recorrido. El GML prescribe únicamente tres elementos para realizar diagramas: Cajas, Líneas y Etiquetas. El GML no contempla ni tipos de flecha (composición, agregación, etc.) ni la definición de atributos y métodos que UML exige. De esta manera apenas se requiere al lector o receptor del diagrama conocimientos previos sobre modelado de sistemas.
Como una alternativa al complejísimo modelado UML, Kent Beck y Brad Cunningham propusieron en el artículo A Laboratory For Teaching Object-Oriented Thinking las tarjetas Clase-Responsabilidad-Colaborador. Las tarjetas CRC ayudan a los programadores a conceptualizar los objetos de la solución. La técnica consiste en dibujar una tarjeta por cada clase u objeto, y dividirla en tres zonas: en la parte superior, el nombre de la clase; debajo, a la izquierda, las responsabilidades de la clase (objetivos a alto nivel); debajo, a la derecha, los colaboradores de la clase (otras clases necesarias para cumplir sus objetivos). Las tarjetas CRC ayudan a “bocetar” el diseño de forma mucho menos prescriptiva y detallada que los diagramas UML de clases.
Por otro lado, Simon Brown propone el modelado C4. Este lenguaje de modelado basado en sencillas cajas y flechas ofrece una jerarquía de cuatro niveles:
Contexto. Diagrama de muy alto nivel que muestra un sistema como una caja en el centro, rodeado por otras cajas que representan a usuarios u otros sistemas. Los detalles no son importantes. El enfoque debe estar en las personas (actores, roles, personas, etc.) y sistemas de software en lugar de tecnologías, protocolos y otros detalles de bajo nivel. Es el tipo de diagrama que se podría mostrar a personas sin conocimientos técnicos.
Contenedor. Diagrama de alto nivel que muestra las opciones tecnologías (servidores web, bases de datos, etc.) junto con las relaciones e interacciones.
Componente. Diagrama de bajo nivel que muestra los componentes de cada contenedor.
Clase. Diagrama de muy bajo nivel que describe la implementación de clases o patrones. En este nivel es habitual utilizar bocetos de diagramas UML.
💬 El Big Design Up Front es tonto, no diseñar nada en absoluto antes de codificar es incluso aún más tonto
Simon Brown, autor del modelado C4
El desarrollo guiado por pruebas, habitualmente utilizada en las metodologías adaptativas, permite prescindir de los “planos” del software, en su lugar el diseño queda documentado en los tests. Además, poner a prueba el código facilita la mejora del diseño.
De esta forma, los “planos” o el “ADN” del software no son los diagramas UML sino el propio código (Code As Design, Jack Reeves, 1992). El diseño de los sistemas está documentado principalmente por el código fuente, los diagramas que representan el código fuente son accesorios. El código es el diseño detallado del software, no los diagramas. Así, los programadores no son los encargados de transformar los diagramas en código, es el compilador el encargado de transformar el diseño (el propio código fuente) en binarios (ensamblados o ejecutables). Los codificadores diseñan el software, asumiendo el rol de diseñadores-codificadores.
El Desarrollo Guiado por Pruebas (Test Driven Development) evita hacer uso de los diagramas UML como si de “planos” se tratasen a la hora de diseñar las clases. El desarrollo guiado por pruebas hace “emerger” el diseño del software a partir de las pruebas. Las pruebas deben ser lo suficientemente rigurosas como para representar claramente las especificaciones indicadas en el análisis o en los requisitos.
Antes de continuar conviene aclarar qué es una prueba de código. Cuando un desarrollador escribe un segmento de código necesita probar que el código implementado funciona adecuadamente. Para ello el propio desarrollador escribe los tests que el código debe superar. El test define un conjunto de casos de prueba (test case). Un caso de prueba arroja un valor positivo si ante una determinada entrada el código objeto de pruebas devuelve el resultado esperado y un valor negativo si el resultado obtenido es distinto al esperado. En los tests automatizados, el codificador escribe código que tiene por objeto probar a su vez el código del programa.
El diseñador de código, en lugar de “dibujar” haciendo uso de cajas y flechas, escribe directamente el código de la clase y las pruebas necesarias. Al poner a prueba su diseño, el desarrollador obtiene un rápido “feedback” sobre lo adecuado del mismo. Los tests exigen al desarrollador reflexionar sobre el diseño de clases propuesto. Es el propio diseñador el que va a sufrir (o disfrutar) del diseño implementado al obligarse a sí mismo a utilizar las clases por él mismo planteadas. De esta manera, los tests hacen emerger el diseño en la mente del codificador-diseñador.
El desarrollo guiado por pruebas no solo hace emerger el diseño de clases, además ofrece importantes ventajas:
Documenta el código. Los tests reflejan el funcionamiento del código. Es además una documentación que no caduca, es suficiente con ejecutar los tests para asegurar que el código hace exactamente lo que indican las pruebas.
Facilita la refactorización del código. Refactorizar un código consiste en reescribir un código, haciendo más fácil de entender y extender, sin modificar su comportamiento. El código seguirá pasando los mismos casos de prueba, el código seguirá devolviendo los mismos resultados ante las mismas condiciones de entrada.
Previene las regresiones del código (bugs). En ocasiones es necesario modificar un segmento de código modificando su comportamiento, añadiendo por ejemplo alguna funcionalidad. Los tests ya escritos serán utilizados por el diseñador/desarrollador para confirmar que la modificación del código no ha roto ninguna de las funcionalidades ya existentes.
Todas estas características mejoran mucho la mantenibilidad y extensibilidad del producto software, claves en la visión adaptativa del desarrollo.
Existen diferentes tipos de desarrollo guiado por pruebas:
Test Driven Development (TDD). No aclara cómo de detalladas deben ser las pruebas.
Behaviour Driven Development (BDD). Cada regla de negocio debe ser probada.
Acceptance Test Driven Development (ATDD). Cada requisito debe ser probado.
Referencias:
• Métrica-3 Técnicas. Administración Electrónica del Gobierno de España.
• K.Beck; "Extreme Programming Explained", Addison-Wesley Professional, 1999
• M.Fowler; "UML Distilled. A Brief Guide to the Standard Object Modeling"
• R.C. Martin "Código Limpio", Anaya, 2009
• S.McConnell "Code Complete", Microsoft, 1993
• Autentia. Software Design: Principios y patrones del desarrollo de software
• Martin Fowler, ¿Ha muerto el diseño? 2004
• Jack Reeves, Code As Design, 1992