TDD vs. Productividad

129

En mi proyecto actual (un juego, en C ++), decidí que usaría Test Driven Development 100% durante el desarrollo.

En términos de calidad de código, esto ha sido genial. Mi código nunca ha sido tan bien diseñado o tan libre de errores. No me estremezco al ver el código que escribí hace un año al inicio del proyecto, y he adquirido un mejor sentido de cómo estructurar las cosas, no solo para que sea más fácil de probar, sino para que sea más sencillo de implementar y usar. .

Sin embargo ... hace un año que empecé el proyecto. Por supuesto, solo puedo trabajar en ello en mi tiempo libre, pero TDD todavía me está ralentizando considerablemente en comparación con lo que estoy acostumbrado. Leí que la velocidad de desarrollo más lenta mejora con el tiempo, y definitivamente creo que las pruebas son mucho más fáciles de lo que solía hacerlo, pero llevo un año trabajando en ello y todavía estoy trabajando a toda velocidad.

Cada vez que pienso en el siguiente paso que necesita trabajo, tengo que detenerme cada vez y pensar cómo escribiría una prueba para poder escribir el código real. A veces me quedo estancado durante horas, sabiendo exactamente qué código quiero escribir, pero sin saber cómo dividirlo lo suficiente como para cubrirlo completamente con pruebas. Otras veces, rápidamente me haré una docena de pruebas y pasaré una hora escribiendo pruebas para cubrir una pequeña pieza de código real que de otra forma habría tomado unos minutos para escribir.

O, después de terminar la prueba 50 para cubrir una entidad particular en el juego y todos los aspectos de su creación y uso, miro mi lista de tareas pendientes y veo la siguiente entidad que se codificará, y me estremezco de horror ante la Pensé en escribir otras 50 pruebas similares para implementarlo.

Llegué al punto en que, al analizar el progreso del año pasado, estoy considerando abandonar el TDD por "terminar el maldito proyecto". Sin embargo, renunciar a la calidad del código que lo acompaña no es algo que estoy deseando. Me temo que si dejo de escribir pruebas, perderé el hábito de hacer que el código sea tan modular y comprobable.

¿Quizás estoy haciendo algo mal para ser tan lento en esto? ¿Existen alternativas que aceleren la productividad sin perder por completo los beneficios? TAD? Menos cobertura de la prueba? ¿Cómo sobreviven otras personas a TDD sin matar toda productividad y motivación?

    
pregunta Nairou 22.06.2011 - 03:55
fuente

10 respuestas

75

Permítanme comenzar agradeciéndoles que compartan su experiencia y expresen sus inquietudes ... que, como tengo que decir, no son infrecuentes.

  • Tiempo / Productividad: Escribir pruebas es más lento que no escribirlas. Si se aplica a eso, estoy de acuerdo. Sin embargo, si ejecuta un esfuerzo paralelo en el que aplica un enfoque que no sea TDD, es probable que el tiempo que dedique al código existente de detección de errores, corrección y corrección lo ponga en el negativo neto. Para mí, TDD es lo más rápido que puedo ir sin comprometer mi código de confianza. Si encuentra cosas en su método que no agregan valor, elimínelas.
  • Número de pruebas: si codificas N cosas, necesitas probar N cosas. parafraseando una de las líneas de Kent Beck " Prueba solo si quieres que funcione. "
  • Quedarme atascado durante horas: yo también (a veces y no > 20 minutos antes de detener la línea). Es solo su código que le indica que el diseño necesita algo de trabajo. Una prueba es solo otro cliente para su clase SUT. Si a una prueba le resulta difícil usar su tipo, es probable que también lo hagan sus clientes de producción.
  • Pruebas similares tedio: Esto necesita un poco más de contexto para que pueda redactar un contraargumento. Dicho esto, detente y piensa en la similitud. ¿Puede realizar la prueba de datos de esas pruebas de alguna manera? ¿Es posible escribir pruebas contra un tipo base? Entonces solo necesita ejecutar el mismo conjunto de pruebas contra cada derivación. Escucha tus pruebas. Sea el tipo de perezoso correcto y vea si puede encontrar una manera de evitar el tedio.
  • Detenerte a pensar en lo que debes hacer a continuación (la prueba / especificación) no es algo malo. Por el contrario, se recomienda para que construyas "lo correcto". Generalmente, si no puedo pensar en cómo probarlo, tampoco puedo pensar en la implementación. Es una buena idea dejar en blanco las ideas de implementación hasta que llegue allí ... tal vez una solución más simple se vea opacada por un diseño preventivo YAGNI-ish.

Y eso me lleva a la consulta final: ¿Cómo puedo mejorar? Mi (o An) respuesta es Leer, reflexionar y practicar.

por ejemplo Últimamente, estoy al tanto de

  • si mi ritmo refleja RG [Ref] RG [Ref] RG [Ref] o es RRRRGRRef.
  • % de tiempo empleado en el estado de error de compilación / rojo.
  • ¿Estoy atrapado en un estado de compilación Rojo / Roto?
respondido por el Gishu 22.06.2011 - 07:09
fuente
31

No necesitas una cobertura de prueba del 100%. Sea pragmático.

    
respondido por el Alistair 24.06.2011 - 02:48
fuente
22
  

TDD todavía me está ralentizando considerablemente

Eso es realmente falso.

Sin TDD, pasas unas semanas escribiendo un código que en su mayoría funciona y pasas el siguiente año "probando" y solucionando muchos (pero no todos) los errores.

Con TDD, pasas un año escribiendo un código que realmente funciona. Luego haces pruebas de integración final durante unas semanas.

El tiempo transcurrido probablemente será el mismo. El software TDD será sustancialmente de mejor calidad.

    
respondido por el S.Lott 22.06.2011 - 04:01
fuente
20
  

O, después de terminar la prueba 50 para cubrir una entidad particular en el juego y todos los aspectos de su creación y uso, miro mi lista de tareas pendientes y veo la siguiente entidad que se codificará, y me estremezco de horror ante la Pensé en escribir otras 50 pruebas similares para implementarlo.

Esto me hace preguntarme cuánto estás siguiendo el paso "Refactor" de TDD.

Cuando todas sus pruebas están pasando, este es el momento para que usted refactorice el código y elimine la duplicación. Mientras que la gente suele recordar esto, a veces olvidan que también es hora de refactorizar sus pruebas también, para eliminar la duplicación y simplificar las cosas.

Si tiene dos entidades que se fusionan en una para habilitar la reutilización del código, considere también fusionar sus pruebas. Realmente solo necesitas probar diferencias incrementales en tu código. Si no realiza un mantenimiento regular en sus pruebas, pueden volverse difíciles de manejar rápidamente.

Un par de puntos filosóficos sobre TDD que podrían ser útiles:

  • Cuando no puedes descubrir cómo escribir una prueba, a pesar de la amplia experiencia en escribir pruebas, eso definitivamente es un olor de código . De alguna manera, su código carece de modularidad, lo que dificulta la escritura de pruebas pequeñas y sencillas.
  • Escoger un poco de código es perfectamente aceptable cuando se usa TDD. Escriba el código que desea, para tener una idea de cómo se ve, luego elimine el código y comience con las pruebas.
  • Veo la práctica de TDD extremadamente estricta como una forma de ejercicio. Cuando empieces por primera vez, definitivamente escribe una prueba primero cada vez, y escribe el código más simple para hacer que la prueba pase antes de continuar. Sin embargo, esto no es necesario una vez que se sienta más cómodo con la práctica. No tengo una prueba de unidad para cada ruta de código posible que escribo, pero a través de la experiencia, puedo elegir qué se necesita probar con una prueba de unidad y qué se puede cubrir con pruebas funcionales o de integración. . Si has estado practicando TDD de manera estricta durante un año, me imagino que también estás cerca de este punto.

EDITAR: Sobre el tema de la filosofía de las pruebas unitarias, creo que podría ser interesante para usted leer: El Camino de Testivus

Y un punto más práctico, si no necesariamente muy útil:

  • Mencionas C ++ como tu lenguaje de desarrollo. He practicado TDD extensivamente en Java, usando excelentes bibliotecas como JUnit y Mockito. Sin embargo, he encontrado que TDD en C ++ es muy frustrante debido a la falta de bibliotecas (en particular, marcos de simulacros) disponibles. Si bien este punto no te ayuda mucho en tu situación actual, espero que lo tengas en cuenta antes de deshacerte de TDD por completo.
respondido por el jaustin 24.06.2011 - 02:35
fuente
8

Pregunta muy interesante.

Lo que es importante tener en cuenta, es que C ++ no es fácilmente comprobable, y los juegos, en general, también son un candidato muy malo para TDD. No puede probar si OpenGL / DirectX dibuja un triángulo rojo con el controlador X y amarillo con el controlador Y fácilmente. Si el vector normal del mapa de relieve no se invierte después de las transformaciones del sombreado. Tampoco puede probar problemas de clipping sobre versiones de controlador con diferentes precisiones, y así sucesivamente. El comportamiento de dibujo indefinido debido a llamadas incorrectas también se puede probar solo con la revisión precisa del código y el SDK a la mano. El sonido también es un mal candidato. El multihilo, que a su vez es bastante importante para los juegos, es bastante inútil para la prueba unitaria. Así que es difícil.

Básicamente, los juegos son una gran cantidad de GUI, sonido e hilos. La GUI, incluso con componentes estándar a los que puede enviar WM_, es difícil de probar por unidad.

Entonces, lo que puede probar es el modelo de clases de carga, las clases de carga de texturas, las bibliotecas de matriz y algunas de esas características, que no es mucho código y, a menudo, no son muy reutilizables, si es solo su primer proyecto. Además, están empaquetados en formatos propietarios, por lo que no es muy probable que las entradas de terceros puedan diferir mucho, a menos que libere herramientas de modding, etc.

Otra vez, no soy un gurú o evangelista de TDD, así que toma todo eso con un grano de sal.

Probablemente escribiría algunas pruebas para los componentes principales principales (por ejemplo, biblioteca de matriz, biblioteca de imágenes). Agregue un montón de abort() en entradas inesperadas en cada función. Y lo más importante, concéntrate en un código resistente / resistente que no se rompa fácilmente.

En lo que respecta a los errores, el uso inteligente de C ++, RAII y un buen diseño ayudan a prevenirlos.

Básicamente, tienes mucho que hacer solo para cubrir lo básico si quieres lanzar el juego. No estoy seguro de si TDD ayudará.

    
respondido por el Coder 28.06.2011 - 15:39
fuente
6

Estoy de acuerdo con las otras respuestas, pero también quiero agregar un punto muy importante: ¡¡¡Refactorizar los costos !!

Con pruebas de unidad bien escritas, puede volver a escribir su código de manera segura. Primero, las pruebas de unidad bien escritas proporcionan una excelente documentación de la intención de su código. En segundo lugar, cualquier efecto secundario desafortunado de su refactorización quedará atrapado en el conjunto de pruebas existente. Por lo tanto, ha garantizado que las suposiciones de su código anterior también son ciertas para su nuevo código.

    
respondido por el Morten 23.06.2011 - 14:00
fuente
4
  

¿Cómo sobreviven otras personas TDD?   sin matar toda la productividad y   motivación?

Esto es completamente diferente de mis experiencias. O eres increíblemente inteligente y escribes código sin errores (por ejemplo, desactivado por un error) o no te das cuenta de que tu código tiene errores que impiden que tu programa funcione, y por lo tanto no están terminados.

TDD se trata de tener la humildad de saber que tú (y yo!) cometemos errores.

Para mí, el tiempo en que escribe unittests es más que guardado en un tiempo de depuración reducido para proyectos que se realizan utilizando TDD desde el principio.

Si no cometes errores, ¡quizás el TDD no sea tan importante para ti como lo es para mí!

    
respondido por el Tom 24.06.2011 - 18:21
fuente
3

Tengo solo algunos comentarios:

  1. Parece que estás intentando probar todo . Probablemente no deberías, solo los casos de alto riesgo y borde de una determinada pieza de código / método. Estoy bastante seguro de que la regla 80/20 se aplica aquí: gasta el 80% de las pruebas de escritura para el último 20% de su código o casos que no están cubiertos.

  2. Prioriza. Ingrese al desarrollo ágil de software y haga una lista de lo que realmente necesita hacer para lanzar en un mes. Luego suelte, así como así. Esto te hará pensar en la prioridad de las características. Sí, sería genial si tu personaje pudiera hacer un backflip, pero ¿tiene valor comercial ?

TDD es bueno, pero solo si no apunta al 100% de cobertura de prueba, y no lo es si le impide generar valor comercial real (es decir, características, cosas que agregan algo a su juego).

    
respondido por el Cthulhu 28.06.2011 - 17:06
fuente
1

Sí, escribir pruebas y código puede tomar más tiempo que escribir código, pero escribir código y pruebas de unidad asociadas (usando TDD) es mucho más predecible que escribir código y luego depurarlo.

La depuración casi se elimina cuando se usa TDD, lo que hace que todo el proceso de desarrollo sea mucho más predecible y, al final, más rápido.

Refactorización constante: es imposible realizar una refactorización seria sin un conjunto completo de pruebas de unidad. La forma más eficiente de construir esa red de seguridad basada en pruebas unitarias es durante TDD. El código bien refaccionado mejora significativamente la productividad general del diseñador / equipo que mantiene el código.

    
respondido por el ratkok 28.06.2011 - 05:24
fuente
0

Considere reducir el alcance de su juego y consígalo donde alguien pueda jugarlo o lo libere. Mantener sus estándares de prueba sin tener que esperar demasiado para lanzar su juego podría ser un término medio para mantenerlo motivado. Los comentarios de sus usuarios pueden proporcionar beneficios a largo plazo y sus pruebas le permiten sentirse cómodo con las adiciones y los cambios.

    
respondido por el JeffO 08.07.2011 - 02:17
fuente

Lea otras preguntas en las etiquetas