En mi proyecto actual (un juego, en C ++), decidí que usaría Test Driven Development 100% durante el desarrollo.
En términos de calidad del código, esto ha sido excelente. Mi código nunca ha sido tan bien diseñado o tan libre de errores. No me avergüenzo al ver el código que escribí hace un año al comienzo del proyecto, y he adquirido una idea mucho mejor de cómo estructurar las cosas, no solo para ser más fácilmente comprobable, sino para ser más simple de implementar y usar .
Sin embargo ... ha pasado un año desde que comencé el proyecto. De acuerdo, solo puedo trabajar en ello en mi tiempo libre, pero TDD todavía me está frenando 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 he estado en esto durante un año y todavía estoy trabajando a paso de tortuga.
Cada vez que pienso en el siguiente paso que necesita trabajo, tengo que parar cada vez y pensar en cómo escribiría una prueba para poder escribir el código real. A veces me quedo atascado durante horas, sabiendo exactamente qué código quiero escribir, pero sin saber cómo desglosarlo lo suficientemente fino como para cubrirlo completamente con pruebas. Otras veces, pensaré rápidamente en una docena de pruebas y pasaré una hora escribiendo pruebas para cubrir un pequeño fragmento de código real que de otro modo me hubiera llevado unos minutos escribir.
O, después de terminar la prueba número 50 para cubrir una entidad en particular en el juego y todos los aspectos de su creación y uso, miro mi lista de tareas y veo la próxima entidad que se codifica, y me horrorizo ante la idea de escribir otras 50 pruebas similares para implementarlo.
Llegué al punto de que, mirando el progreso del año pasado, estoy considerando abandonar TDD por "terminar el maldito proyecto". Sin embargo, renunciar a la calidad del código que viene con él no es algo que esté esperando. Me temo que si dejo de escribir pruebas, dejaré el hábito de hacer que el código sea tan modular y comprobable.
¿Acaso 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 prueba? ¿Cómo sobreviven otras personas al TDD sin matar toda la productividad y la motivación?
fuente
Respuestas:
Permítame comenzar agradeciéndole que comparta su experiencia y expresando sus inquietudes ... lo que tengo que decir que no son infrecuentes.
Y eso me lleva a la consulta final: ¿Cómo puedo mejorar? Mi (o una) respuesta es Leer, reflexionar y practicar.
Por ejemplo, últimamente, mantengo pestañas en
fuente
No necesita una cobertura de prueba del 100%. Se pragmático.
fuente
a = x + y
y aunque todas las líneas en el código se ejecutaron en las pruebas, las pruebas solo se probaron para el caso donde y = 0, por lo que el error (debería haber sidoa = x - y
) nunca se encontró en las pruebas.Eso es realmente falso.
Sin TDD, pasa algunas semanas escribiendo código que funciona principalmente y pasa el próximo año "probando" y reparando muchos (pero no todos) los errores.
Con TDD, pasas un año escribiendo código que realmente funciona. Luego, realiza las pruebas de integración final durante algunas semanas.
El tiempo transcurrido probablemente será el mismo. El software TDD tendrá una calidad sustancialmente mejor.
fuente
Esto me hace preguntarme cuánto estás siguiendo el paso "Refactor" de TDD.
Cuando pasan todas las pruebas, es hora de refactorizar el código y eliminar la duplicación. Si bien las personas generalmente recuerdan esto, a veces olvidan que también es el momento de refactorizar sus pruebas , para eliminar la duplicación y simplificar las cosas.
Si tiene dos entidades que se fusionan en una para permitir la reutilización del código, considere fusionar sus pruebas también. Realmente solo necesita probar las diferencias incrementales en su código. Si no realiza regularmente mantenimiento en sus pruebas, pueden volverse difíciles de manejar rápidamente.
Un par de puntos filosóficos sobre TDD que podrían ser útiles:
EDITAR: sobre el tema de la filosofía de las pruebas unitarias, creo que esto podría ser interesante para usted: The Way of Testivus
Y un punto más práctico, si no necesariamente muy útil,:
fuente
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 muy mal candidato para TDD. No puede probar si OpenGL / DirectX dibuja el 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 voltea después de la transformación del sombreador. Tampoco puede probar problemas de recorte en versiones de controladores con diferentes precisiones, etc. El comportamiento de dibujo indefinido debido a llamadas incorrectas también se puede probar solo con una revisión precisa del código y un SDK a mano. El sonido también es un mal candidato. El subprocesamiento múltiple, que de nuevo es bastante importante para los juegos, es prácticamente inútil para la prueba unitaria. Entonces es duro.
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 clases de carga de modelos, clases de carga de texturas, bibliotecas de matrices y algo así, que no es mucho código y, muy a menudo, no es muy reutilizable, si es solo su primer proyecto. Además, están empaquetados en formatos propietarios, por lo que no es muy probable que la entrada de terceros pueda diferir mucho, a menos que publique herramientas de modificación, etc.
Por otra parte, no soy gurú o evangelista de TDD, así que tómalo con un grano de sal.
Probablemente escribiría algunas pruebas para los componentes principales del núcleo (por ejemplo, biblioteca matricial, biblioteca de imágenes). Agregue un montón de
abort()
entradas inesperadas en cada función. Y lo más importante, concéntrese en un código resistente / resistente que no se rompa fácilmente.Con respecto a los errores uno, el uso inteligente de C ++, RAII y un buen diseño ayuda mucho a evitarlos.
Básicamente, tienes mucho que hacer solo para cubrir los conceptos básicos si quieres lanzar el juego. No estoy seguro si TDD ayudará.
fuente
Estoy de acuerdo con las otras respuestas, pero también quiero agregar un punto muy importante: ¡Refactorización de costos!
Con pruebas unitarias bien escritas, puede reescribir de forma segura su código. Primero, las pruebas unitarias bien escritas proporcionan una excelente documentación de la intención de su código. Segundo, 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 antiguo código también son ciertas para su nuevo código.
fuente
Esto es completamente diferente de mis experiencias. Usted es increíblemente inteligente y escribe código sin errores (por ejemplo, por errores) o no se da cuenta de que su código tiene errores que impiden que su programa funcione, por lo que en realidad no están terminados.
TDD se trata de tener la humildad de saber que usted (¡y yo!) Cometemos errores.
Para mí, el tiempo de escribir pruebas unitarias está más que guardado en un tiempo de depuración reducido para proyectos que se realizan utilizando TDD desde el principio.
Si no comete errores, ¡tal vez TDD no sea tan importante para usted como para mí!
fuente
Solo tengo algunas observaciones:
Parece que estás intentando probar todo . Probablemente no debería, solo los casos de alto riesgo y límite de una pieza de código / método en particular. Estoy bastante seguro de que la regla 80/20 se aplica aquí: gasta el 80% escribiendo pruebas para el último 20% de su código o casos que no están cubiertos.
Priorizar Ingrese al desarrollo ágil de software y haga una lista de lo que realmente realmente necesita hacer para lanzar en un mes. Luego suelte, así como así. Esto te hará pensar en la prioridad de las funciones. Sí, sería genial si tu personaje pudiera hacer un backflip, pero ¿tiene valor comercial ?
TDD es bueno, pero solo si no buscas una cobertura de prueba del 100%, y no si te impide producir valor comercial real (es decir, características, cosas que agregan algo a tu juego).
fuente
Sí, escribir pruebas y código puede llevar más tiempo que escribir código, pero escribir código y pruebas unitarias 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, posiblemente más rápido.
Refactorización constante: es imposible realizar una refactorización seria sin un conjunto completo de pruebas unitarias. La forma más eficiente de construir esa red de seguridad basada en pruebas unitarias es durante la TDD. El código bien refactorizado mejora significativamente la productividad general del diseñador / equipo que mantiene el código.
fuente
Considere reducir el alcance de su juego y obtenerlo donde alguien pueda jugarlo o usted 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.
fuente