El desarrollo basado en pruebas (TDD) es grande en estos días. A menudo lo veo recomendado como una solución para una amplia gama de problemas aquí en Programmers SE y otros lugares. Me pregunto por qué funciona.
Desde el punto de vista de la ingeniería, me desconcierta por dos razones:
- El enfoque de "prueba de escritura + refactorización hasta pasar" parece increíblemente anti-ingeniería. Si los ingenieros civiles usaran ese enfoque para la construcción de puentes, o los diseñadores de automóviles para sus automóviles, por ejemplo, estarían remodelando sus puentes o automóviles a un costo muy alto, y el resultado sería un desastre reparado sin una arquitectura bien pensada . La directriz "refactorizar hasta pasar" a menudo se toma como un mandato para olvidar el diseño arquitectónico y hacer lo que sea necesario para cumplir con la prueba; en otras palabras, la prueba, en lugar del usuario, establece el requisito. En esta situación, ¿cómo podemos garantizar buenas "ilidades" en los resultados, es decir, un resultado final que no solo sea correcto sino también extensible, robusto, fácil de usar, confiable, seguro, etc. Esto es lo que suele hacer la arquitectura.
- Las pruebas no pueden garantizar que un sistema funcione; solo puede mostrar que no lo hace. En otras palabras, las pruebas pueden mostrarle que un sistema contiene defectos si falla una prueba, pero un sistema que pasa todas las pruebas no es más seguro que un sistema que las falla. La cobertura de la prueba, la calidad de la prueba y otros factores son cruciales aquí. Las falsas sensaciones de seguridad que un resultado "totalmente verde" produce para muchas personas han sido reportadas en las industrias civiles y aeroespaciales como extremadamente peligrosas, porque pueden interpretarse como "el sistema está bien", cuando realmente significa que "el sistema es tan bueno". como nuestra estrategia de prueba ". A menudo, la estrategia de prueba no se verifica. ¿O quién prueba las pruebas?
En resumen, estoy más preocupado por el bit "conducido" en TDD que por el bit "prueba". La prueba está perfectamente bien; lo que no entiendo es conducir el diseño al hacerlo.
Me gustaría ver respuestas que contengan las razones por las cuales TDD en ingeniería de software es una buena práctica, y por qué los problemas que he explicado anteriormente no son relevantes (o no lo suficientemente relevantes) en el caso del software. Gracias.
Respuestas:
Creo que hay una idea falsa aquí. En el diseño de software, el diseño está muy cerca del producto. En ingeniería civil, arquitectura, el diseño se desacopla del producto real: hay planos que contienen el diseño, que luego se materializan en el producto terminado, y estos se separan por una gran cantidad de tiempo y esfuerzo.
TDD está probando el diseño. Pero todos los diseños de automóviles y edificios también se prueban. Primero se calculan las técnicas de construcción, luego se prueban a menor escala, luego se prueban a mayor escala, antes de colocarlas en un edificio real. Cuando inventaron las vigas en H y la carga, por ejemplo, descanse asegurado de que esto se ha intentado e intentado nuevamente antes de que realmente construyan el primer puente con él.
Los diseños de automóviles también se prueban, diseñando prototipos, y sí, ciertamente ajustando cosas que no son exactamente correctas, hasta que cumpla con las expectativas. Sin embargo, parte de este proceso es más lento porque, como dijiste, no puedes perder el tiempo con el producto. Pero cada rediseño de un automóvil se basa en las experiencias aprendidas de los antiguos, y cada edificio tiene alrededor de miles de años de fundamentos detrás de la importancia del espacio, la luz, el aislamiento, la resistencia, etc. Los detalles se cambian y mejoran, tanto en los edificios. y en rediseños para los más nuevos.
Además, se prueban las piezas. Quizás no exactamente en el mismo estilo que el software, pero las partes mecánicas (ruedas, encendedores, cables) generalmente se miden y se someten a estrés para saber que los tamaños son correctos, no se ven anormalidades, etc. Pueden ser radiografiados o láser. medido, golpean los ladrillos para detectar los que están rotos, pueden ser probados en una configuración u otra, o dibujan una representación limitada de un grupo grande para realmente ponerlo a prueba.
Esas son todas las cosas que puede implementar con TDD.
Y de hecho, las pruebas no son garantía. Los programas se bloquean, los autos se descomponen y los edificios comienzan a hacer cosas divertidas cuando sopla el viento. Pero ... 'seguridad' no es una pregunta booleana. Incluso cuando no puede incluir todo, poder cubrir, digamos, el 99% de las eventualidades es mejor que cubrir solo el 50%. No probar y luego descubrir que el acero no se ha asentado bien y es frágil y se rompe al primer golpe de un martillo cuando acaba de levantar su estructura principal es un simple desperdicio de dinero. El hecho de que haya otras inquietudes que aún podrían dañar el edificio no hace que sea menos estúpido permitir que un defecto fácilmente evitable derribe su diseño.
En cuanto a la práctica de TDD, eso es una cuestión de equilibrio. El costo de hacerlo de una manera (por ejemplo, no probar, y luego recoger las piezas más tarde), versus el costo de hacerlo de otra manera. Siempre es un equilibrio. Pero no piense que otros procesos de diseño no tienen pruebas y TDD en su lugar.
fuente
En mi opinión, la mayoría de las historias de éxito de TDD son falsas y solo para fines de marketing. Puede haber muy poco éxito con él, pero solo para aplicaciones pequeñas. Estoy trabajando en una gran aplicación de Silverlight donde se utilizan los principios TDD. La aplicación tiene cientos de pruebas pero aún no es estable. Varias partes de la aplicación no son comprobables debido a las complejas interacciones del usuario. Pruebas resultantes con muchos simulacros y código difícil de entender.
Inicialmente, cuando probamos TDD, todo parece estar bien. Pude escribir muchas pruebas y simular las partes que son difíciles para una prueba unitaria. Una vez que tenga una buena cantidad de código y se requiera un cambio de interfaz, estará jodido. Se deben corregir muchas pruebas y reescribirá más pruebas que el cambio real en el código.
Peter Norvig explica su punto de vista sobre TDD en el libro Coders At Work.
fuente
well, you haven't done TDD right!
Test Driven Design me funciona por las siguientes razones:
Es una forma ejecutable de la especificación.
Esto significa que puede ver en los casos de prueba:
Primero escribes la vista desde afuera.
Con frecuencia, el código se escribe de una manera en la que primero resuelve el problema y luego piensa en cómo debe llamarse el código que acaba de escribir. Con frecuencia, esto proporciona una interfaz incómoda porque con frecuencia es más fácil "simplemente agregar una bandera", etc. Al pensar en "tenemos que hacer ESTO para que las cajas de prueba se vean así" al principio, usted da la vuelta. Esto dará una mejor modularidad, ya que el código se escribirá de acuerdo con la interfaz de llamada, no al revés.
Por lo general, esto también dará como resultado un código más limpio que requiere menos documentación explicativa.
Terminas más rápido
Como tiene la especificación en forma ejecutable, habrá terminado cuando pase el conjunto de pruebas completo. Puede agregar más pruebas a medida que aclara las cosas en un nivel más detallado, pero como principio básico tiene un indicador muy claro y visible del progreso y cuando haya terminado.
Esto significa que puede saber cuándo el trabajo es necesario o no (ayuda a pasar una prueba) y termina necesitando hacer menos.
Para quienes lo consideren útil, les animo a usar TDD para su próxima rutina de biblioteca. Configure lentamente una especificación ejecutable y haga que el código pase las pruebas. Cuando termine, la especificación ejecutable estará disponible para todos los que necesiten ver cómo invocar la biblioteca.
Estudio reciente
"Los resultados de los estudios de caso indican que la densidad de defectos previos al lanzamiento de los cuatro productos disminuyó entre 40% y 90% en relación con proyectos similares que no utilizaron la práctica de TDD. Subjetivamente, los equipos experimentaron un aumento de 15 a 35% en tiempo de desarrollo inicial después de adoptar TDD ". ~ Resultados y experiencias de 4 equipos industriales
fuente
El proceso de creación de software no es el proceso de escribir el código. Ningún proyecto de software debe comenzar sin un plan de "amplio alcance" primero. Al igual que un proyecto de unir dos orillas de un río necesita un plan de este tipo primero.
El enfoque TDD se relaciona (principalmente) con las pruebas unitarias, al menos así es como las personas tienden a pensar en ello, es decir, crear los bits de código de software de más bajo nivel. Cuando todas las características y comportamientos ya se han definido y realmente sabemos lo que queremos lograr.
En ingeniería estructural se parece un poco a esto:
Para probar si el software funciona como un todo, diseñamos otro tipo de pruebas como pruebas de usabilidad, pruebas de integración y pruebas de aceptación. Estos también deben definirse antes de que comience el trabajo real de escritura del código, y se realizan después de que las pruebas unitarias sean verdes.
Ver Modelo V: http://en.wikipedia.org/wiki/V-Model_%28software_development%29
Veamos cómo funcionaría para un puente:
Un gobierno local le dice a una empresa de construcción de puentes: "Necesitamos un puente para conectar estos dos puntos. El puente debe ser capaz de permitir una cantidad n de tráfico por hora y estar listo para el 21 de diciembre de 2012". Esta es una definición de prueba de aceptación. La empresa no obtendrá la cantidad total (o ninguna) de dinero, si no puede pasar esa prueba.
La gestión de la empresa decide el cronograma del proyecto. Establecieron equipos de trabajo y establecieron objetivos para cada equipo. Si los equipos no cumplen con estos objetivos, el puente no se construirá a tiempo. Sin embargo, hay cierto nivel de flexibilidad aquí. Si uno de los equipos tiene algunos problemas, la compañía puede compensarlo cambiando los requisitos, cambiando los subcontratistas, contratando a más personas, etc. para que todo el proyecto cumpla con el objetivo establecido en el punto 1.
Dentro de un equipo responsable de diseñar componentes de puentes particulares, se ve en el ejemplo que he dado anteriormente. A veces, la solución es obvia, porque tenemos un gran conocimiento sobre la construcción de puentes (es como usar una biblioteca bien probada en el desarrollo de software; simplemente asume que funciona como se anuncia). A veces es necesario crear varios diseños y probarlos para elegir el mejor. Aún así, los criterios sobre los cuales se prueba el componente se conocen de antemano.
fuente
En mi opinión, TDD funciona porque
Específicamente en los puntos que planteas
fuente
TL; DR
La programación sigue siendo una actividad de diseño, no es construcción. Escribir pruebas unitarias después del hecho solo confirma que el código hace lo que hace, no que hace algo útil. Las fallas en las pruebas son el valor real porque le permiten detectar errores temprano.
Code Is Design
En el Capítulo 7 de PPP, "Tío Bob" habla sobre este tema directamente. Muy temprano en el capítulo, hace referencia a un excelente artículo de Jack Reeves en el que propone que el código es diseño (el enlace va a una página que recoge los tres artículos sobre el tema).
Lo interesante de este argumento es que señala que, a diferencia de otras disciplinas de ingeniería donde la construcción es una actividad muy costosa, la construcción de software es relativamente gratuita (compila con éxito en tu IDE y tienes tu software integrado). Si ve el código escrito como una actividad de diseño en lugar de una actividad de construcción, entonces el ciclo refactor rojo-verde es básicamente un ejercicio de diseño. Su diseño evoluciona a medida que escribe pruebas, el código para satisfacerlas y refactoriza para integrar el nuevo código en el sistema existente.
TDD como especificación
Las pruebas unitarias que escribe para TDD son una traducción directa de la especificación tal como la comprende. Al escribir código que satisfaga mínimamente su especificación (hace que sus pruebas se vuelvan verdes), todo el código que ha escrito está ahí para un propósito específico. Si se cumple o no ese propósito se valida mediante una prueba repetible.
Escribir pruebas para la funcionalidad
Un error común en las pruebas unitarias ocurre cuando escribe las pruebas después del código, termina probando que el código hace lo que hace. En otras palabras, verás pruebas como esta
Si bien supongo que este código podría ser útil (asegúrese de que alguien no haya hecho algo obsceno con una propiedad simple). No sirve para validar una especificación. Y como dijiste, escribir este tipo de pruebas solo te lleva muy lejos.
Mientras que el verde es bueno, el valor está en el rojo. Tuve mi primer momento verdadero "ajá" en TDD cuando recibí una falla inesperada en la prueba. Tenía un conjunto de pruebas que tenía para un marco que estaba construyendo. Añadiendo una nueva característica, escribí una prueba para ello. Luego escribió el código para hacer pasar la prueba. Compilar, probar ... obtuvo un verde en la nueva prueba. Pero también obtuve un rojo en otra prueba que no esperaba que se pusiera rojo.
Mirando el fracaso, suspiro de alivio porque dudo que hubiera atrapado ese error por bastante tiempo si no hubiera tenido esa prueba en su lugar. Y fue un error MUY desagradable tener. Afortunadamente, tuve la prueba y me dijo exactamente lo que tenía que hacer para corregir el error. Sin la prueba, habría seguido construyendo mi sistema (con el error infectando a otros módulos que dependían de ese código) y para cuando se descubriera el error, habría sido una tarea importante solucionarlo correctamente.
El verdadero beneficio de TDD es que nos permite realizar cambios con abandono imprudente. Es como una red de seguridad para la programación. Piense en lo que sucedería si un trapecista comete un error y cae. Con la red, es un error embarazoso. Sin eso, es una tragedia. En el mismo sentido, TDD le evita convertir los errores descabellados en desastres que matan proyectos.
fuente
No encontrará a nadie que defienda Test Driven Development, o incluso Test Driven Design (son diferentes), que dice que las pruebas prueban las aplicaciones. Así que vamos a llamar a eso un hombre de paja y listo.
No encontrará a nadie a quien no le guste o no esté impresionado por TDD que diga que las pruebas son una pérdida de tiempo y esfuerzo. Aunque las pruebas no prueban las aplicaciones, son bastante útiles para encontrar errores.
Dicho esto, ninguna de las partes está haciendo nada diferente con respecto a la realización de pruebas en el software. Ambos están haciendo pruebas. Ambos confían en las pruebas para encontrar tantos errores como sea posible, y ambos usan pruebas para verificar que un programa de software funciona tan bien como se puede descubrir en ese momento. Nadie con media pista vende software sin probar y nadie con media pista espera que las pruebas vayan a dejar el código que venden completamente sin errores.
Entonces, la diferencia entre TDD y no TDD no es que se estén haciendo pruebas. La diferencia está en cuando se escriben las pruebas. En TDD, las pruebas se escriben ANTES del software. En las pruebas que no son TDD se escriben después o en concierto con el software.
El problema que he visto con respecto a este último es que las pruebas tienden a apuntar al software que se escribe más que el resultado o la especificación deseados. Incluso con el equipo de prueba separado del equipo de desarrollo, el equipo de prueba tiende a mirar el software, jugar con él y escribir pruebas que lo apunten.
Una cosa que han notado una y otra vez los que estudian el éxito del proyecto es la frecuencia con que un cliente diseña lo que quiere, la gente de desarrollo se escapa y escribe algo, y cuando regresa al cliente diciendo "hecho" Resulta ser total y completamente NO lo que el cliente solicitó. "Pero pasa todas las pruebas ..."
El objetivo de TDD es romper este "argumento circular" y proporcionar una base para las pruebas que prueban el software que no es el software en sí. Las pruebas se escriben para apuntar al comportamiento que el "cliente" quiere. El software se escribe para pasar esas pruebas.
Sin embargo, TDD es parte de la solución destinada a abordar este problema. No es el único paso que das. Otras cosas que debe hacer es asegurarse de que haya más comentarios de los clientes y con más frecuencia.
Sin embargo, en mi experiencia, TDD es algo muy difícil de implementar con éxito. Es difícil obtener pruebas escritas antes de que haya un producto porque muchas pruebas automatizadas requieren tener algo con lo que jugar para que el software de automatización funcione correctamente. También es difícil lograr que los desarrolladores que no están acostumbrados a las pruebas unitarias lo hagan. Una y otra vez le he dicho a la gente de mi equipo que escriban las pruebas PRIMERO. Nunca he conseguido uno para hacerlo. Al final, las limitaciones de tiempo y la política destruyeron todos los esfuerzos, por lo que ya ni siquiera hacemos pruebas unitarias. Esto, por supuesto, condujo, inevitablemente, a que el diseño se acoplara accidental y severamente, de modo que incluso si quisiéramos, ahora sería prohibitivamente costoso implementarlo. Evitar ESO es lo que TDD finalmente proporciona a los desarrolladores.
fuente
Diseño primero
TDD no es una excusa para saltear el diseño. He visto muchos saltar en el tren "ágil" porque pensaron que podrían comenzar a codificar de inmediato. Verdaderamente ágil lo llevará a la codificación de estadísticas mucho más rápido que las buenas prácticas de ingeniería (otro campo) que inspiraron el proceso en cascada.
Pero prueba temprano
Cuando uno dice que la prueba está impulsando el diseño, simplemente significa que puede usar las pruebas muy temprano en la fase de diseño, mucho antes de que se complete. Hacer estas pruebas influirá fuertemente en su diseño al desafiar las áreas grises y enfrentarlo con el mundo real mucho antes de que se complete el producto. obligándote a volver al diseño y ajustarlo para tener esto en cuenta.
Prueba y diseño ... uno y lo mismo
En mi opinión, TDD simplemente hace que la prueba sea una parte integral del diseño en lugar de algo que se hace al final para validarlo. A medida que comienzas a usar TDD, cada vez te pones más en la mentalidad de cómo destruir / romper tu sistema a medida que lo diseñas. Personalmente, no siempre hago mis pruebas primero. Claro que hago las pruebas obvias (unitarias) en una interfaz, pero las ganancias reales provienen de las pruebas de integración y especificación que creo cuando pienso en una forma nueva y creativa que este diseño puede romper. Tan pronto como pienso en una forma, codifico una prueba para ver qué sucede. A veces puedo vivir con la consecuencia, en este caso muevo la prueba en un proyecto separado que no es parte de la compilación principal (ya que continuará fallando).
Entonces, ¿quién conduce el espectáculo?
En TDD, conducir aquí simplemente significa que sus pruebas influyen tan fuertemente en su diseño que uno puede sentir que realmente lo están conduciendo. Sin embargo, uno se detiene en eso, y aquí entiendo sus preocupaciones, da un poco de miedo ... ¿quién conduce el espectáculo?
USTED conduce, no las pruebas. Las pruebas están ahí para que, a medida que avanza, gane un buen nivel de confianza en lo que ha creado, lo que le permite construir más sabiendo que se basa en bases sólidas.
sólido siempre y cuando las pruebas sean sólidas
Exactamente , de ahí el impulsado en el TDD. No es tanto que las pruebas conduzcan todo, sino que tendrán una influencia tan profunda sobre cómo se hacen las cosas, sobre cómo diseñar y pensar su sistema que delegará una gran parte de su proceso de pensamiento a las pruebas y, a cambio Tendrán una profunda influencia en su diseño.
Sí, pero si hago eso con mi puente ...
detente ahí mismo ... la ingeniería de software es MUY diferente de cualquier otra práctica de ingeniería por ahí. De hecho, la ingeniería de software tiene mucho más en común con la literatura. Uno puede tomar un libro terminado, extraer 4 capítulos de él y escribir dos nuevos capítulos para reemplazarlos, pegarlos en el libro y aún tiene un buen libro. Con buenas pruebas y software, puede rasgar cualquier parte de su sistema y reemplazarlo por otro, y el costo de hacerlo no es mucho más alto de lo que lo estaba creando en primer lugar. De hecho, si hiciste tus pruebas y permitiste que influyeran en tu diseño lo suficiente, podría ser más barato que crearlo en primer lugar, ya que tendrás un cierto nivel de confianza de que este reemplazo no romperá lo que cubren las pruebas.
Si es tan bueno, ¿cómo es que no siempre funciona?
Porque las pruebas requieren una mentalidad MUY diferente que la construcción. No todos pueden regresar y volver, de hecho, algunas personas no podrán construir pruebas adecuadas simplemente porque no pueden decidir destruir su creación. Esto generará proyectos con muy pocas pruebas o pruebas lo suficiente como para alcanzar una métrica objetivo (me viene a la mente la cobertura del código). Serán felices las pruebas de ruta y las pruebas de excepción, pero se olvidarán de los casos de esquina y las condiciones de contorno.
Otros solo confiarán en las pruebas para el diseño parcial o total. Cada miembro hace lo suyo y luego se integra entre sí. El diseño es ante todo una herramienta de comunicación, apuestas que establecemos en el suelo para decir que aquí es donde voy a estar, bocetos que dicen que aquí es donde estarán las puertas y las ventanas. Sin esto, su software está condenado independientemente de cuántas pruebas ponga en la cosa. La integración y las fusiones siempre serán dolorosas y les faltarán pruebas en los niveles más altos de abstracciones.
Para estos equipos, TDD puede no ser el camino a seguir.
fuente
Con TDD, tiende a no escribir código que no sea fácil o rápido de probar. Esto puede parecer algo pequeño, pero puede tener un profundo efecto en un proyecto ya que afecta lo fácil que es refactorizar, probar, reproducir errores con pruebas y verificar correcciones.
También es más fácil para un nuevo desarrollador en el proyecto ponerse al día cuando tiene un código factorizado mejor respaldado por las pruebas.
fuente
He estado pensando mucho en esto, a pesar de que yo no practico tanto TDD. Parece haber una correlación positiva (¿fuerte?) Entre la calidad del código y el siguiente TDD.
1) Mi primer punto de vista es que, esto no se debe (principalmente) a que TDD agregue "mejor calidad" al código (como tal), es más como que TDD ayuda a eliminar las peores partes y hábitos y, por lo tanto, aumenta indirectamente la calidad.
Incluso recomendaría que no sea la prueba en sí misma, es el proceso de escribir esas pruebas. Es difícil escribir pruebas para un código incorrecto, y viceversa. Y mantener esto en la parte posterior de la cabeza mientras se programa, elimina muchos códigos malos.
2) Otro punto de vista (esto se está volviendo filosófico) es seguir los hábitos mentales del maestro. No aprendes a convertirte en un maestro siguiendo sus "hábitos externos" (por ejemplo, una barba larga es buena), debes aprender sus formas internas de pensar, y esto es difícil. Y de alguna manera los programadores (novatos) siguen TDD, alinean sus formas de pensar más cerca de las de los maestros.
fuente
Parece tener una idea errónea sobre la refactorización y TDD.
Por lo tanto, no puede refactorizar el código hasta que pase.
Y TDD, específicamente las pruebas unitarias (que considero la mejora central, ya que otras pruebas me parecen plausibles), no se trata de rediseñar un componente hasta que funcione. Se trata de diseñar un componente y trabajar en la implementación hasta que el componente funcione como se diseñó.
También es importante comprender realmente que las pruebas unitarias se tratan de probar unidades . Debido a la tendencia a escribir siempre muchas cosas desde cero, es importante probar tales unidades. Un ingeniero civil ya conoce las especificaciones de las unidades que usa (los diferentes materiales) y puede esperar que funcionen. Estas son dos cosas que a menudo no se aplican a los ingenieros de software, y es muy profesional para probar las unidades antes de usarlas, porque significa usar componentes probados y de alta calidad.
Si un ingeniero civil tuvo la idea de usar un nuevo tejido de fibra para hacer un techo para cubrir un estadio, esperaría que lo pruebe como una unidad, es decir, defina las especificaciones necesarias (por ejemplo, peso, permeabilidad, estabilidad, etc.) y luego pruebe y refínelo hasta que los encuentre.
Por eso funciona TDD. Porque si crea software de unidades probadas, es mucho mejor que funcione, cuando las conecta y si no es así, puede esperar que el problema esté en su código de pegamento, suponiendo que sus pruebas tengan una buena cobertura.
editar:
Refactorización significa: sin cambios en la funcionalidad. Un punto de la prueba de la unidad de escritura es asegurarse de que la refactorización no rompa el código. Entonces, TDD tiene la intención de asegurar que la refactorización no tenga efectos secundarios.
La granularidad no es un tema de perspectiva, porque como dije, la unidad prueba las unidades de prueba y no los sistemas, por lo que la granularidad se define exactamente.
TDD fomenta la buena arquitectura. Requiere que defina e implemente especificaciones para todas sus unidades, lo que le obliga a diseñarlas antes de la implementación, lo cual es todo lo contrario de lo que parece pensar. TDD dicta la creación de unidades, que se pueden probar individualmente y, por lo tanto, se desacoplan por completo.
TDD no significa que arroje una prueba de software al código de espagueti y revuelva la pasta hasta que pase.
En contraposición a la ingeniería civil, en ingeniería de software un proyecto generalmente evoluciona constantemente. En ingeniería civil, tiene el requisito de construir un puente en la posición A, que pueda transportar x toneladas y sea lo suficientemente ancho para n vehículos por hora.
En ingeniería de software, el cliente básicamente puede decidir en cualquier momento (posiblemente después de la finalización), quiere un puente de dos pisos, y quiere que esté conectado con la autopista más cercana, y que le gustaría que fuera un puente de elevación, porque su compañía Recientemente comenzó a utilizar veleros.
Los ingenieros de software tienen la tarea de cambiar los diseños. No porque sus diseños sean defectuosos, sino porque ese es el modus operandi. Si el software está bien diseñado, se puede rediseñar a alto nivel, sin tener que reescribir todos los componentes de bajo nivel.
TDD se trata de construir software con componentes altamente desacoplados y probados individualmente. Bien ejecutado, lo ayudará a responder a los cambios en los requisitos significativamente más rápido y seguro que sin él.
TDD agrega requisitos al proceso de desarrollo, pero no prohíbe ningún otro método de garantía de calidad. Por supuesto, TDD no proporciona la misma seguridad que la verificación formal, pero, una vez más, la verificación formal es extremadamente costosa e imposible de usar a nivel de sistema. Y aún así, si quisieras, podrías combinar ambos.
TDD también abarca pruebas distintas de las pruebas unitarias, que se realizan a nivel de sistema. Encuentro esto fácil de explicar pero difícil de ejecutar y difícil de medir. Además, son bastante plausibles. Si bien veo absolutamente su necesidad, realmente no los valoro como ideas.
Al final, ninguna herramienta realmente resuelve un problema. Las herramientas solo facilitan la resolución de un problema. Puedes preguntar: ¿Cómo me ayudará un cincel con una gran arquitectura? Bueno, si planeas hacer paredes rectas, los ladrillos rectos son de ayuda. Y sí, claro, si le das esa herramienta a un idiota, probablemente la golpeará con el pie eventualmente, pero eso no es culpa del cincel, por mucho que no sea un defecto de TDD que da falsa seguridad a los novatos, quienes no escriben buenas pruebas.
Entonces, en el fondo, uno puede decir que TDD funciona mucho mejor que ningún TDD.
fuente
No me gusta que digas 'la prueba, en lugar del usuario, establece el requisito'. Creo que solo está considerando las pruebas unitarias en TDD, mientras que también cubre las pruebas de integración.
Además de probar las bibliotecas que constituyen la base del software, escriba las pruebas que cubren las interacciones que sus usuarios tienen con el software / sitio web / lo que sea. Estos provienen directamente de los usuarios, y las bibliotecas como pepino (http://cukes.info) pueden incluso permitir que sus usuarios escriban las pruebas ellos mismos, en lenguaje natural.
TDD también fomenta la flexibilidad en el código: si pasas una eternidad diseñando la arquitectura de algo, será increíblemente difícil hacer esos cambios más adelante si es necesario. Comience escribiendo un par de pruebas, luego escriba un pequeño código que pase esas pruebas. Agregue más pruebas, agregue más código. Si necesita cambiar radicalmente el código, sus pruebas aún se mantienen.
Y a diferencia de los puentes y los automóviles, una sola pieza de software puede sufrir grandes cambios a lo largo de su vida útil, y realizar una refactorización compleja sin tener que escribir primero las pruebas es solo una cuestión de problemas.
fuente
Creo que te estás acercando al primer punto desde el ángulo equivocado.
Desde un punto de vista teórico, estamos demostrando que algo funciona comprobando los puntos de falla. Ese es el método utilizado. Puede haber muchas otras formas en que puede probar que algo es funcional, pero TDD se ha establecido debido a la simplicidad de su enfoque basado en bits: si no se rompe, funciona.
En la práctica, esto se traduce abiertamente en: ahora podemos pasar al siguiente paso (después de haber aplicado TDD con éxito para satisfacer todos los predicados). Si te acercas a TDD desde esta perspectiva, entonces no se trata de "escribir pruebas + refactorizar hasta pasar", sino más bien de haber completado esto, ahora me estoy enfocando completamente en la siguiente característica como lo más importante .
Piense cómo se aplica esto a la ingeniería civil. Estamos construyendo un estadio que puede albergar una audiencia pública de 150000 personas. Después de demostrar que la integridad estructural del estadio es sólida, primero hemos satisfecho la seguridad . Ahora podemos centrarnos en otros temas que se vuelven inmediatamente importantes, como baños, puestos de comida, asientos, etc., haciendo que la experiencia de la audiencia sea más placentera. Esto es una simplificación excesiva, ya que hay mucho más para TDD, pero el quid es que no obtienes la mejor experiencia de usuario posible si te enfocas en características nuevas y emocionantes y mantienes la integridad al mismo tiempo. Lo obtienes a mitad de camino en ambos casos. Quiero decir, ¿cómo puedes saber exactamente cómoCuántos baños y dónde colocar para 150000 personas? Raramente he visto colapsar estadios en mi propia vida, pero he tenido que esperar en la fila durante el medio tiempo en muchas ocasiones. Eso dice que el problema del baño es posiblemente más complejo y si los ingenieros pueden dedicar menos tiempo a la seguridad, finalmente podrán resolver el problema del baño.
Su segundo punto es irrelevante, porque ya hemos acordado que los absolutos son un esfuerzo tonto y porque Hank Moody dice que no existen (pero parece que no puedo encontrar una referencia para eso).
fuente
TDD en ingeniería de software es una buena práctica, de la misma manera que el manejo de errores en las aplicaciones es una buena práctica, así como el registro y el diagnóstico (aunque es parte del manejo de errores).
TDD no debe usarse como una herramienta para reducir el desarrollo de software en codificación de prueba y error. Pero aún así, la mayoría de los programadores observan los registros de tiempo de ejecución, observan excepciones en el depurador o usan otros signos de falla / éxito durante su fase de desarrollo que consiste en codificar / compilar / ejecutar la aplicación, todo el día.
TDD es solo una forma de formalizar y automatizar esos pasos para que usted como desarrollador sea más productivo.
1) No se puede comparar la ingeniería de software con la construcción de puentes, la flexibilidad en la construcción de puentes no se acerca a la de diseñar un programa de software. Construir el puente es como escribir el mismo programa una y otra vez en una máquina con pérdidas. Los puentes no se pueden duplicar y reutilizar como el software sí. Cada puente es único y tiene que ser fabricado. Lo mismo ocurre con los automóviles y otros diseños.
Lo más difícil en la ingeniería de software es reproducir fallas, cuando un puente falla generalmente es muy fácil determinar qué salió mal y, en teoría, es fácil reproducir la falla. Cuando un programa de computadora falla, puede ser una cadena compleja de eventos que llevó al sistema a un estado defectuoso y puede ser muy difícil determinar dónde está el error. La prueba de unidad y TDD facilita la prueba de la solidez de los componentes de software, bibliotecas y algoritmos.
2) Usar pruebas de unidades débiles y casos de prueba poco profundos que no estresen al sistema para generar un falso sentido de confianza es solo una mala práctica. Ignorar la calidad arquitectónica de un sistema y simplemente cumplir con las pruebas es, por supuesto, tan malo. Pero engañar en el lugar de construcción para un rascacielos o un puente para guardar material y no seguir los planos es tan malo y sucede todo el tiempo ...
fuente
Si acepta que cuanto antes se encuentren los errores, menor será el costo de corregirlos, entonces eso solo hace que TDD valga la pena.
fuente
TDD no se trata realmente de pruebas. Y ciertamente no es un reemplazo para una buena prueba. Lo que le ofrece es un diseño bien pensado, fácil de consumir para el consumidor y fácil de mantener y refactorizar más tarde. Esas cosas a su vez conducen a menos errores y un diseño de software mejor y más adaptable. TDD también lo ayuda a pensar y documentar sus suposiciones, a menudo descubriendo que algunas de ellas eran incorrectas. Lo descubres muy temprano en el proceso.
Y como un buen beneficio adicional, tiene un gran conjunto de pruebas que puede ejecutar para asegurarse de que una refactorización no cambie el comportamiento (entradas y salidas) de su software.
fuente
Te daré una respuesta corta. Por lo general, TDD se ve de la manera incorrecta al igual que las pruebas unitarias. Nunca entendí las pruebas unitarias hasta hace poco después de ver un buen video de tecnología. Esencialmente, TDD solo indica que desea que las siguientes cosas funcionen. DEBEN ser implementados. Luego diseñas el resto del software de la manera que lo harías normalmente.
Es como escribir casos de uso para una biblioteca antes de diseñarla. Excepto que puede cambiar el caso de uso en una biblioteca y es posible que no lo haga para TDD (uso TDD para el diseño de API). También se le recomienda agregar más pruebas y pensar en entradas / usos salvajes que la prueba puede obtener. Me resulta útil al escribir bibliotecas o API donde, si cambia algo, debe saber que rompió algo. En la mayoría del software del día a día no me molesto, ya que ¿por qué necesito un caso de prueba para un usuario que presiona un botón o si quiero aceptar una lista CSV o una lista con una entrada por línea ... Eso realmente no importa? para cambiarlo así no debería / no puedo usar TDD.
fuente
El software es orgánico, cuando la ingeniería estructural es concreta.
Cuando construyas tu puente, seguirá siendo un puente y es poco probable que evolucione a otra cosa en un corto período de tiempo. Se realizarán mejoras durante meses y años, pero no horas y días como en el software.
Cuando prueba de forma aislada, normalmente hay dos tipos de marcos que puede usar. Marco restringido y sin restricciones. Los marcos sin restricciones (en .NET) le permiten probar y sustituir todo, independientemente de los modificadores de acceso. Es decir, puede tropezar y burlarse de componentes privados y protegidos.
La mayoría de los proyectos que he visto utilizan marcos restringidos (RhinoMocks, NSubstitute, Moq). Cuando pruebe con estos marcos, debe diseñar su aplicación de tal manera que pueda inyectar y sustituir dependencias en tiempo de ejecución. Esto implica que debe tener un diseño ligeramente acoplado. El diseño ligeramente acoplado (cuando se hace correctamente) implica una mejor separación de las preocupaciones, lo cual es algo bueno.
Para resumir, creo que pensar detrás de esto es que si su diseño es comprobable, por lo tanto, está acoplado libremente y tiene una buena separación de preocupaciones.
En una nota al margen, he visto aplicaciones que eran realmente comprobables, pero mal escritas desde la perspectiva del diseño orientado a objetos.
fuente
No lo hace.
Aclaración: las pruebas automatizadas son mejores que ninguna prueba. Sin embargo, personalmente creo que la mayoría de las pruebas unitarias son un desperdicio porque generalmente son tautológicas (es decir, dicen cosas obvias del código real bajo prueba) y no se puede probar fácilmente que sean consistentes, no redundantes y cubran todos los casos límite (donde generalmente ocurren errores )
Y lo más importante: el buen diseño de software no se cae mágicamente de las pruebas, como lo anuncian muchos evangelistas ágiles / TDD. Todos los que afirmen lo contrario deben proporcionar enlaces a investigaciones científicas revisadas por pares que prueben esto, o al menos una referencia a algún proyecto de código abierto donde los beneficios de TDD puedan ser potencialmente estudiados por su historial de cambios de código.
fuente