Grado azul

Índice

Principios

El diseño y la aplicación no se solapan

El diseño y la aplicación no se solapan

¿Por qué?
Los documentos de planificación que no tienen nada en común con la aplicación hacen más mal que bien. Por tanto, no renuncie a la planificación, pero minimice las posibilidades de incoherencia.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

Uno de los problemas fundamentales del desarrollo de software son las implementaciones que ya no muestran signos de planificación previa. Hay diagramas de diseño colgados en la pared que apenas tienen nada que ver con la realidad del código. La razón es la violación del principio fundamental DRY: diseño e implementación son repeticiones de lo mismo, la estructura de un software. Dado que la implementación sigue al diseño y representa la mayor parte del trabajo, ambos se desfasan rápidamente si los cambios estructurales no se incorporan repetidamente al diseño durante la implementación. De lo contrario, los diagramas de diseño pronto no valdrán nada una vez iniciada la implementación.

¿Cómo puede mejorarse la situación? ¿Acaso debería prescindirse del diseño si la "verdad estructural" reside en última instancia en la aplicación? No, desde luego que no. El diseño es imprescindible. Sin planificación no hay objetivo. Pero el diseño y la aplicación deben cumplir el principio DRY. Por eso, diseño e implementación deben solaparse lo menos posible. Su interfaz debe ser delgada. Si es así, ya no son repeticiones, sino que describen cosas diferentes. Esto significa: al diseño/arquitectura no le importa la implementación y a la implementación no le importa la arquitectura.

¿Y por dónde pasa esta línea divisoria? En los llamados componentes (ver Prácticas más abajo). A los arquitectos no les preocupa la estructura interna de los componentes. Para ellos, son cajas negras cuya estructura de clases no es relevante para la arquitectura. A la inversa, la arquitectura es irrelevante para un implementador de componentes. Lo que tiene que implementar resulta de los contratos de componentes que su componente importa y exporta. No necesita conocer un contexto más amplio.

La tarea de la arquitectura es, por tanto, descomponer el software en componentes, definir sus dependencias y describir los servicios en contratos. Los arquitectos son los únicos encargados de mantener estas estructuras. Y la tarea de la implementación es hacer realidad los componentes definidos por la arquitectura. Cómo lo hacen no es relevante para la arquitectura. Su estructura interna es invisible para la arquitectura.

La aplicación refleja el diseño

La aplicación refleja el diseño

¿Por qué?
Una realización que puede desviarse de la planificación a voluntad conduce directamente a la imposibilidad de mantenimiento. Por tanto, la realización requiere un marco físico definido por la planificación.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

La arquitectura y la implementación no deben solaparse para no violar el principio DRY. Así se evitan las incoherencias que pueden surgir si se cambia algo en una parte sin que este cambio se implemente en la otra.

No obstante, la arquitectura hace declaraciones sobre la aplicación. No sus detalles, sino su forma básica. La arquitectura define los elementos estructurales y sus relaciones dentro de un sistema de código. Por lo tanto, la implementación no existe independientemente de la arquitectura, incluso en ausencia de solapamientos, sino dentro de ella, por así decirlo.

Sin embargo, esto también debe expresarse en la implementación. Esto facilita su comprensión y garantiza que la implementación se ajuste realmente a la arquitectura. Por lo tanto, los elementos estructurales definidos por la arquitectura en diferentes niveles de abstracción no deberían "mezclarse" en una gran "olla de código" (por ejemplo, una gran solución de Visual Studio). Es mucho mejor, también en términos de alta productividad y facilidad de comprobación, manifestar las estructuras lógicas de la arquitectura tan físicamente como sea posible.

  1. Las estructuras previstas por la arquitectura a distintos niveles de abstracción deben reflejarse en la medida de lo posible en la organización del código. Por un lado, esto significa que la arquitectura utiliza principalmente unidades físicas de código como elementos estructurales. Por otro lado, estos elementos estructurales también deben ser claramente visibles en el código fuente o en la organización del código en el repositorio.
  2. Cuando se trabaja en la implementación de elementos estructurales y, especialmente, dentro de componentes, debe ser imposible realizar cambios arquitectónicos "sobre la marcha". Quien trabaje en o sobre un elemento estructural, es decir, una parte, no debe poder modificar ad hoc la estructura circundante, es decir, el conjunto. Sólo si esto se garantiza, la entropía de un software no crecerá sin control. Esto es importante porque el principal objetivo de la arquitectura es minimizar la entropía y, por tanto, la complejidad del software.

La planificación es imprescindible. La aplicación no debe torpedear la planificación. (Aunque, por supuesto, los resultados de la aplicación pueden influir en la planificación). Por lo tanto, la planificación y la aplicación deben estar disociadas. Y cuando esto no sea posible, la planificación debe trabajar con los medios de ejecución y la ejecución debe reflejar físicamente la planificación.

No lo vas a necesitar (YAGNI)

No lo vas a necesitar (YAGNI)

¿Por qué?
Las cosas que nadie necesita no tienen valor. Así que no pierdas el tiempo con ellas.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

El principio YAGNI (No lo vas a necesitar) es uno de los principios más sencillos del desarrollo de software y, sin embargo, probablemente el que se viola con más frecuencia después del principio DRY. Por eso YAGNI no sólo está al principio del grados rojospero también aquí hacia el final del camino a través del Sistema de valores.

El principio YAGNI se debe a la especial relación entre la precisión de los requisitos y la materialidad del producto en el desarrollo de software. Los requisitos son notoriamente imprecisos o cambiantes y el producto en el que deben materializarse es inmaterial. En comparación con la ingeniería mecánica o la construcción de edificios, el material es por tanto infinitamente flexible y puede, en principio, adaptarse a prácticamente cualquier requisito con comparativamente poco esfuerzo. Por tanto, una gran volatilidad o imprecisión se une a una gran flexibilidad. En principio, esto parece ideal.

Sin embargo, la práctica demuestra que es precisamente en esta relación donde está el germen del fracaso de muchos proyectos. A corto plazo, los proyectos intentan hacer lo correcto haciendo lo obvio:

  • Los requisitos imprecisos suelen compensarse con productos que intentan suplir la imprecisión. La inmaterialidad del software se aprovecha para aplicarlo de forma tan amplia y flexible que incluso los requisitos desconocidos o imprecisos se cumplen por anticipado.
  • Los requisitos, que cambian constantemente, se actualizan en el producto con la mayor rapidez posible, ya que esto es posible gracias a su inmaterialidad.

A largo plazo, sin embargo, este comportamiento es contraproducente:

  • La obediencia anticipada conduce a una amplitud y flexibilidad que no son realmente necesarias. Realiza prestaciones que no se utilizan.
  • Las rápidas modificaciones del software debidas a la evolución de los requisitos provocan una erosión de la calidad del código. Aunque el software es inmaterial y flexible, no toda estructura de software es evolucionable ni siquiera comprensible.

Las situaciones de requisitos poco claros y cambiantes en el contexto de la gran flexibilidad fundamental del software conducen rápidamente a gastos innecesarios y a un código frágil. Un gran número de proyectos que han superado sus límites presupuestarios y un número aún mayor de proyectos que se han vuelto imposibles de mantener al cabo de pocos años son testimonio elocuente de ello.

Los CCD, como desarrolladores profesionales de software, consideran su deber contrarrestar a diario estos avances. Dada la innegable naturaleza del software -es y sigue siendo inmaterial-, el planteamiento consiste en hacer frente a los requisitos. Este es el origen del principio YAGNI.

El principio YAGNI es como un cuchillo afilado: si lo utilizas, cortas un problema en pequeños cubos de lo inmediatamente necesario. Según el principio YAGNI, sólo se aplica lo que es incuestionable e inmediatamente útil. Todo lo demás... bueno, eso viene después. En este sentido, el YAGNI va de la mano de la regla "decidir lo más tarde posible" del Desarrollo ajustado de software.

El principio YAGNI es pertinente en todos los niveles de desarrollo de software y en todas las fases. Siempre que te preguntes: "¿Debería hacer este esfuerzo?" o "¿Realmente lo necesitamos?", aunque sea de forma tímida y silenciosa, estarás aplicando el principio YAGNI. Dice: "En caso de duda, decide no hacer el esfuerzo".

Parece fácil, pero es difícil. De ahí las frecuentes infracciones. Hay muchas fuerzas que contradicen la decisión de no esforzarse. "Oh, no es tanto esfuerzo" o "Si no miramos ahora hacia adelante, no podremos hacer nada más en el futuro" son dos justificaciones obvias del esfuerzo, aunque existan dudas sobre sus beneficios. Esto se aplica a las decisiones arquitectónicas (por ejemplo, ¿deberíamos empezar ya con una arquitectura distribuida, aunque la carga actual aún no la necesite?) y a las decisiones locales (por ejemplo, ¿debería optimizarse el algoritmo ahora, aunque actualmente no esté causando ningún problema de rendimiento?)

El cliente sólo paga por los beneficios directos. Lo que hoy no puede especificar con claridad no le sirve de nada. Por tanto, intentar anticiparlo en la fase de ejecución supone invertir esfuerzos sin generar beneficios. Cuando más adelante el cliente sepa exactamente lo que quiere, entonces -¡y no antes! - es el momento de satisfacer sus deseos. Sin embargo, siempre que un proyecto intenta anticiparse a esta voluntad, corre el riesgo de verse contradicho por la realidad de la voluntad del cliente mañana. Una prestación -funcional o no funcional- que se implanta hoy sin un requisito claro puede dejar de interesar al cliente mañana. O puede que ya no sea tan importante para ellos como otra característica.

Esto significa para el desarrollo de software:

  • Aplique únicamente requisitos claros.
  • El cliente prioriza sus requisitos claros.
  • Aplique los requisitos claros en el orden en que se han priorizado.
  • Establecer el proceso de desarrollo y la estructura del código a gran y pequeña escala de tal forma que no haya miedo a darse cuenta de los cambios y los nuevos requisitos.

Como desarrolladores profesionales, CCD comunica claramente este enfoque al cliente. Esto hace que:

  • dispuestos a prestar el servicio, porque no tienen que rechazar al cliente una solicitud clara
  • Responsables, porque sólo utilizan el presupuesto para prestaciones claramente formuladas
  • protectoras hacia el código, porque lo protegen de ser sobrecargado con lo que a fin de cuentas es innecesario.

Por tanto, YAGNI no es sólo un principio que deba seguir todo desarrollador, sino también un principio para proyectos y equipos, es decir, a nivel organizativo. YAGNI debe tenerse siempre en cuenta, al igual que DRY. En caso de duda, aplaza la decisión si es posible. En caso contrario, decida en contra del esfuerzo. Esto relaja y agiliza y conduce más rápidamente al éxito.

Prácticas

Diseño antes de la aplicación

Diseño antes de la aplicación

¿Por qué?
Hay que diseñar una solución antes de aplicarla. De lo contrario, no habrá una reflexión coherente sobre la solución.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

La tarea de un desarrollador es traducir los requisitos en código. Para ello, es necesario desarrollar una solución para los requisitos. Hay que pensar en ello. Pero, ¿cómo hacerlo bien si los desarrolladores se lanzan directamente a codificar?

En casos triviales, puede ser posible escribir código directamente. Sin embargo, también se piensa en la solución cuando se salta inmediatamente a la codificación. Sin embargo, esto suele ocurrir de forma inconsciente, y sobre todo mientras que la implementación. El desarrollador piensa un poco, codifica, piensa, codifica, etc. Falta una reflexión coherente sobre la solución, separada de la aplicación.

A más tardar, si un grupo de desarrolladores quiere trabajar en equipo, el diseño debe realizarse por separado de la implementación. De lo contrario, no es posible una división fluida del trabajo.

El diseño permite al equipo o a un desarrollador individual pensar en principios importantes incluso antes de codificar. Por ejemplo, los métodos o clases con múltiples responsabilidades no se crean en primer lugar, ya que el diseño ya está pensado a nivel de diseño. Principio de Responsabilidad Única (PRU) puede tenerse en cuenta. Esto ahorra al equipo el esfuerzo de refactorización que surge al codificar "sobre la marcha".

Ver también https://flow-design.info.

Entrega continua (CD)

Entrega continua (CD)

¿Por qué?
Como desarrollador de código limpio, quiero estar seguro de que una configuración instala el producto correctamente. Si solo lo descubro en las instalaciones del cliente, ya es demasiado tarde.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

En el grado verde hemos puesto en marcha el proceso de integración continua para la compilación y las pruebas. El proceso de integración continua garantiza que los errores se detecten rápidamente durante la fase de compilación y prueba. Si, por ejemplo, un cambio en el código significa que otro componente ya no se puede compilar, el proceso de integración continua señala el error poco después de que se haya confirmado el cambio. Sin embargo, si al final se produce un programa de instalación que no puede instalarse debido a errores, aún no hemos logrado nuestro objetivo: un software que funcione y pueda instalarse en nuestros clientes.

Por consiguiente, también tenemos que automatizar las fases de instalación y despliegue para que puedan llevarse a cabo con sólo pulsar un botón. Sólo así podemos estar seguros de que producimos un software instalable. Y la automatización garantiza que nadie olvide un paso importante que haya que realizar "a pie". Esto significa que todos los miembros del equipo pueden producir e instalar la versión actual del producto lista para su instalación en cualquier momento.

Véase también Herramientas.

El libro más importante en este contexto es probablemente Acelerar ser.

Desarrollo iterativo

Desarrollo iterativo

¿Por qué?
Parafraseando a von Clausewitz: Ningún diseño, ninguna implementación sobrevive al contacto con el cliente. Por eso, el desarrollo de software hace bien en corregir el rumbo.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

Por supuesto, el desarrollo de software siempre avanza desde la planificación a la implantación y la prueba por parte del cliente. Sin embargo, es erróneo suponer que un proyecto puede funcionar con una fase de planificación, una de implantación y una de prueba por parte del cliente. Esto sólo funciona -si es que funciona- en escenarios triviales en los que todos los requisitos se conocen en la fase de planificación. Sin embargo, en los proyectos reales, cada fase aporta información a las anteriores. La prueba con el cliente siempre tiene consecuencias para la planificación y la ejecución.

Sin embargo, estas conclusiones sólo pueden influir en un proyecto si el planteamiento no es lineal. Si no hay vuelta atrás de una fase posterior a una anterior, la retroalimentación es inútil.

Para poder incorporar comentarios a un producto de software, el proceso de desarrollo debe contener bucles. El bucle desde la fase de prueba del cliente hasta la planificación es siempre necesario. Esto significa que el desarrollo de software sólo puede tener lugar de forma iterativa, es decir, en varias iteraciones, basadas en el catálogo de requisitos del cliente. Cualquiera que intente entregar "todo de una vez" (big bang) está actuando en contra de esta constatación. Por el contrario, el proceso de desarrollo de software debe planificarse de tal manera que "muerda" los requisitos en pequeños trozos. Cada uno de estos trozos no debe ser mayor que el tiempo que se tarda en pasar de la planificación a las pruebas con el cliente, es decir, más de 2-4 semanas. Sólo así la reacción del cliente será lo suficientemente frecuente como para no perderse en el proceso de implantación durante demasiado tiempo.

El desarrollo de software es, por tanto, un proceso de aprendizaje. En el transcurso de este proceso, el equipo del proyecto aprende algo sobre los requisitos del cliente. Escucha, planifica, implementa y entrega una versión del software que refleja su comprensión de lo que ha oído. A continuación, el equipo vuelve a escuchar, planifica de nuevo en función de los últimos hallazgos, etc., y así sucesivamente, siempre en círculo. Iteración tras iteración. A veces se perfecciona algo de una iteración anterior, a veces se añade algo nuevo.

Pero no sólo el desarrollo de software es un proceso de aprendizaje. El aprendizaje también debe tener lugar a nivel organizativo. El equipo no sólo debe aprender algo sobre el cliente, sino también sobre sí mismo. Por eso siempre debe haber "puntos de parada" en los que el equipo reflexione sobre su enfoque. Los resultados de estas retrospectivas se incorporan a la siguiente iteración del desarrollo organizativo. En este caso, el nivel azul es la continuación del nivel rojo, que incluye la reflexión personal diaria.

Por supuesto, toda iteración debe tener también un final. Y para saber si se ha terminado, hay que definir claramente de antemano lo que se quiere conseguir en la iteración. La posibilidad de alcanzar los objetivos sólo puede estimarse, y la reflexión ayuda a mejorar gradualmente las estimaciones para que sean lo suficientemente precisas para la planificación. Pero, ¿cuándo se alcanza el objetivo previamente definido? ¿Qué se hace? Nuestro principal objetivo es entregar a nuestros clientes un software funcional. Por consiguiente, este objetivo sólo puede alcanzarse cuando hemos producido software listo para entregar. En concreto, esto significa que el software se ha probado y puede instalarse mediante configuración. Nos aseguramos de ello continuamente mediante la integración continua. En ningún caso decidimos poco antes del final de una iteración que se ha alcanzado un objetivo, aunque no se hayan completado todas las pruebas.

Véase también Herramientas.

Desarrollo gradual

Desarrollo gradual

¿Por qué?
Trabajar sólo por incrementos permite al propietario del producto proporcionar información.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

Un incremento representa una sección vertical a través de los diversos aspectos de un sistema de software. Un incremento es, por tanto, una pieza de software ejecutable. El incremento puede ponerse a disposición del propietario del producto en una máquina de pruebas para obtener comentarios.

La retroalimentación periódica a intervalos cortos, al final de cada iteración, es la definición de agilidad.

Si, por el contrario, el enfoque es horizontal en lugar de vertical, se crean módulos que no pueden ejecutarse de forma independiente. Un propietario de producto no puede dar su opinión sobre dichos módulos. Esto significa que no es posible un enfoque verdaderamente ágil.

Orientación de los componentes

Orientación de los componentes

¿Por qué?
El software necesita componentes de caja negra que puedan desarrollarse y probarse en paralelo. Esto favorece la capacidad de cambio, la productividad y la corrección.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Equipo

Los principios de la Sistema de valores CCD hasta ahora se han referido sobre todo a fragmentos de código más pequeños. ¿Qué debe estar en un método, qué debe distribuirse en varios? ¿Qué métodos debe publicar una clase? ¿De dónde debe salir un objeto cliente para un objeto servicio? Hasta ahora, se ha tratado de principios para el desarrollo de software a pequeña escala.

Pero, ¿no tiene nada que decir el sistema de valores del CCD sobre estructuras más amplias, sobre el desarrollo de software en general? ¿Qué pasa con la arquitectura del software? Aquí es exactamente donde entra en juego el principio de orientación a componentes. Hasta ahora también hemos utilizado la palabra "componente", pero en un sentido más bien laxo y coloquial. Sin embargo, a partir de ahora Componente describen algo muy específico que consideramos fundamental para el software evolucionable.

Mientras sigamos pensando que el software se compone únicamente de clases con métodos, estaremos intentando describir los ordenadores a nivel de transistores, por así decirlo. En última instancia, sin embargo, esto no funciona porque nos ahogamos en la riqueza de detalles. Ni siquiera resumir las clases en capas sirve de mucho. En su lugar, necesitamos un medio para describir estructuras de software más amplias. Pero no sólo eso: el medio de descripción también debe ser un medio de implementación -al igual que las clases- para que el modelo, el plan, la descripción se refleje en el código.

Aunque los procesos del sistema operativo son un medio arquitectónico de este tipo, en última instancia son demasiado grandes. Mientras el EXE de un proceso de aplicación conste de varios cientos o miles de clases, no ganamos nada.

Sin embargo, el principio de orientación a componentes proporciona ayuda. Éste establece que un proceso de aplicación consta inicialmente de componentes y no de clases. Sólo los bloques de construcción de los componentes son entonces clases. ¿Y qué es un componente? Existen varias definiciones de componentes, de las que dos criterios básicos parecen inquebrantables:

  • Los componentes son unidades funcionales binarias. (Una clase, en cambio, es una unidad funcional a nivel de código fuente).
  • El rendimiento de los componentes se describe en un contrato independiente. (La descripción del rendimiento de una clase, por otro lado, se encuentra dentro de ella. Es la suma de las firmas de sus métodos).

A la hora de diseñar software, tras definir los procesos, un CCD busca primero los componentes que deben constituirlos. Se pregunta qué "bloques de servicio" componen la aplicación. Y el CCD ve estos bloques como cajas negras en cuanto a su estructura de clases. Estos bloques son conjuntos con un servicio bien definido pero una estructura desconocida.

Por tanto, un componente cliente C no sabe nada sobre la estructura de clases de su componente de servicio S. C sólo conoce el contrato de S, que es independiente de la implementación de S. En este sentido, los contratos son para los componentes lo que las interfaces son para las clases. No es casualidad que los contratos consistan en gran medida, o incluso totalmente, en interfaces.

Los componentes son, por tanto, elementos tanto de planificación como de ejecución. Para enfatizar esto, los componentes se implementan físicamente de forma independiente unos de otros; una forma probada de hacerlo es Bancos de trabajo de componenteses decir, soluciones de Visual Studio independientes para cada implementación de componente. Esto no sólo favorece la concentración en una tarea, ya que sólo se ve el código de un componente mientras se trabaja en él en el IDE. También favorece la realización de pruebas unitarias coherentes utilizando maquetas, ya que el código fuente de otros componentes no es visible. Además, esta organización del código aumenta la productividad porque los componentes pueden implementarse en paralelo gracias a sus contratos separados. Por último, el aislamiento físico contrarresta el aumento progresivo de la entropía en el código. Cuando los vínculos entre componentes sólo pueden establecerse mediante contratos, el acoplamiento es flexible y controlado.

Por lo tanto, la orientación a los componentes no sólo incluye unidades binarias de código más grandes con contratos separados, sino también el desarrollo de los contratos antes de su aplicación (Diseñar primero el contrato). Una vez definidos los contratos que importa y exporta un componente, se puede empezar a trabajar en él independientemente de todos los demás.

Véase también Herramientas.

Para el término componente, véase también Entrada de blog sobre la jerarquía de módulos.

Pruebe primero

Pruebe primero

¿Por qué?
El cliente es el rey y determina la forma de un servicio. Por tanto, las implantaciones de servicios solo se personalizan si las impulsa un cliente.
Cambiabilidad  
Corrección  
Eficacia de la producción  
Mejora continua  
Desarrollador único

Si la orientación a los componentes exige que los contratos de los componentes se definan independientemente de su ejecución, se plantea la cuestión de cómo hacerlo. ¿A través de mesas redondas? Sin duda, es una forma de hacerlo. Sin embargo, una forma mejor no es pasar mucho tiempo redactando contratos en una pizarra, sino verterlos inmediatamente en el código. Los contratos de componentes -o, más en general, toda interfaz de código- sirven en última instancia de API para otro código. Por tanto, es lógico y eficaz especificar interfaces basadas en este código.

Esta es la preocupación de Pruebe primero. Test first se basa en la idea de que las unidades funcionales (métodos, clases, etc.) se caracterizan por relaciones cliente-servicio. Estas relaciones giran en torno a la interfaz entre cliente y servicio. Y esta interfaz debe ser determinada por el cliente. Como cliente del servicio, el cliente es el rey. El servicio debe servirle y, por tanto, la interfaz del servicio debe estar orientada hacia él.

Por esta razón, las interfaces de las unidades de código de un software se definen de fuera hacia dentro. En el exterior, en la interfaz de usuario, está el cliente final, el usuario. Éste define la interfaz visual/háptica de las unidades de código de la interfaz de usuario. Éstas, a su vez, son los clientes de las capas de código subyacentes. Éstas son a su vez clientes de capas más profundas, y así sucesivamente. Por tanto, el rendimiento y las interfaces de las capas de código más profundas sólo pueden determinarse si ya se han determinado las de las capas superiores, y así sucesivamente.

Esto contradice el enfoque frecuente de definición ascendente de las unidades de código. A los proyectos les gusta empezar por definir e implantar una capa de acceso a los datos. Esto es comprensible, porque esa funcionalidad fundamental es aparentemente el requisito previo para todo lo demás. Pero este enfoque es problemático, como demuestran muchos proyectos fallidos:

  • Quien especifica y aplica de abajo arriba, de dentro afuera, sólo ofrece valor al cliente en una fase muy tardía. Esto es, como mínimo, frustrante, cuando no contraproducente.
  • Si se procede de abajo arriba en la especificación, se especifica sin conocer los requisitos exactos del cliente final, el usuario. Así que lo que especifiquen corre el riesgo de ser demasiado general y, por tanto, poco manejable al final - o simplemente de no utilizarse (una violación del principio YAGNI, véase más arriba y en el grado rojo).
  • Si se implementa de abajo arriba, se corre el riesgo de no desacoplar realmente. Porque si se requieren capas más profundas para implementar capas superiores, entonces es probable que no se utilicen pruebas unitarias verdaderamente aisladas con maniquíes y tampoco inversión de control.

Sin embargo, los desarrolladores de código limpio evitan estos problemas. Especifican las interfaces no sólo antes de las implementaciones (contract-first, véase la orientación a componentes más arriba), sino también desde fuera hacia dentro y de forma muy práctica a través de la codificación. Con los medios de pruebas automatizadas, es muy fácil definir interfaces en pequeños pasos en forma de pruebas.

Test first añade así una vertiente semántica a los contratos sintácticos (por ejemplo, las interfaces). A falta de otros métodos formales para especificar la semántica, las pruebas son la única manera de formalizar los requisitos. Si se quiere asignar un componente a un desarrollador para su implementación, conviene no sólo especificar sintácticamente su "interfaz" (API), sino también el comportamiento deseado en forma de pruebas.

Esto tiene muchas ventajas:

  • La forma de una interfaz depende directamente del cliente y, por tanto, tiene la máxima relevancia. YAGNI no tiene ninguna posibilidad.
  • Las pruebas no son sólo pruebas, sino también documentación de especificaciones. Los usuarios de una interfaz y los implementadores pueden estudiarlas por igual. La documentación separada es en gran medida superflua. Así se cumple el principio DRY.
  • Las especificaciones no son meros textos pasivos, sino código ejecutable. Una vez que se dispone de una aplicación, puede comprobarse con estas pruebas. Por tanto, la especificación y las pruebas no son fases sucesivas que requieran mucho tiempo. Esto aumenta la productividad. De este modo, la garantía de calidad es previa a la aplicación.

Véase también Herramientas.

Continúe con el grado blanco

es_ESEspañol