A las 7:15 a.m. Nuestro soporte t茅cnico est谩 inundado de trabajo. Good Morning America acaba de hablar de nosotros y muchos de los que visitan nuestro sitio por primera vez han encontrado errores.
Tenemos mucha prisa. Nosotros, ahora mismo, antes de perder la oportunidad de convertir a los visitantes del recurso en nuevos usuarios, vamos a implementar el fixpack. Uno de los desarrolladores prepar贸 algo. 脡l piensa que esto ayudar谩 a hacer frente al problema. Colocamos un enlace a la versi贸n actualizada del programa, que a煤n no ha entrado en producci贸n, al chat de la empresa, y pedimos a todos que lo prueben. Funciona!
Nuestros heroicos ingenieros ejecutan scripts para implementar los sistemas y despu茅s de unos minutos la actualizaci贸n entra en batalla. De repente, el n煤mero de llamadas de soporte t茅cnico se duplica. Nuestra soluci贸n urgente rompi贸 algo, los desarrolladores se llevaron la culpa y los ingenieros hicieron retroceder el sistema a su estado anterior en ese momento.

El autor del material, cuya traducci贸n publicamos hoy, cree que todo esto podr铆a haberse evitado gracias a TDD.
驴Por qu茅 estoy usando TDD?
No he estado en situaciones como esta durante mucho tiempo. Y no es que los desarrolladores hayan dejado de cometer errores. El hecho es que durante muchos a帽os, en todos los equipos que dirig铆 e influ铆, se aplic贸 la metodolog铆a TDD. Los errores, por supuesto, a煤n ocurren, pero la penetraci贸n en la producci贸n de problemas que pueden "derribar" el proyecto ha disminuido a casi cero, a pesar de que la frecuencia de las actualizaciones de software y el n煤mero de tareas que deben resolverse durante la actualizaci贸n han crecido exponencialmente desde entonces. cuando sucedi贸 algo de lo que habl茅 al principio.
Cuando alguien me pregunta por qu茅 deber铆a ponerse en contacto con TDD, le cuento esta historia y puedo recordar una docena m谩s de casos similares. Una de las razones m谩s importantes por las que cambi茅 a TDD es que esta metodolog铆a
mejora la cobertura de las pruebas con c贸digo, lo que conduce a un
40-80% menos de errores en la producci贸n. Esto es lo que m谩s me gusta de TDD. Esto quita una monta帽a de problemas de los hombros de los desarrolladores.
Adem谩s, vale la pena se帽alar que TDD salva a los desarrolladores del temor de realizar cambios en el c贸digo.
En los proyectos en los que participo, conjuntos de m贸dulos autom谩ticos y pruebas funcionales casi a diario evitan que el c贸digo entre en producci贸n, lo que puede interrumpir seriamente el trabajo de estos proyectos. Por ejemplo, ahora estoy mirando 10 actualizaciones autom谩ticas de la biblioteca realizadas la semana pasada, de modo que antes de lanzarlas sin usar TDD, me temo que podr铆an arruinar algo.
Todas estas actualizaciones se integraron autom谩ticamente en el c贸digo y ya se usan en producci贸n. No revis茅 ninguno de ellos manualmente, y no me preocup茅 en absoluto de que pudieran tener un efecto negativo en el proyecto. Al mismo tiempo, para dar este ejemplo, no tuve que pensar mucho. Acabo de abrir GitHub, mir茅 fusiones recientes y vi de lo que estaba hablando. La tarea que anteriormente se resolvi贸 manualmente (o, lo que es peor, el problema que se ignor贸) ahora es un proceso en segundo plano automatizado. Puede intentar hacer algo similar sin una buena cobertura de c贸digo con las pruebas, pero no recomendar铆a hacerlo.
驴Qu茅 es TDD?
TDD son las siglas de Test Driven Development. El proceso implementado al aplicar esta metodolog铆a es muy simple:
Las pruebas detectan errores, las pruebas se completan con 茅xito, se realiza la refactorizaci贸nEstos son los principios b谩sicos para usar TDD:
- Antes de escribir un c贸digo de implementaci贸n para alguna caracter铆stica, escriben una prueba que le permite verificar si este futuro c贸digo de implementaci贸n funciona o no. Antes de continuar con el siguiente paso, se inicia la prueba y est谩 convencido de que arroja un error. Gracias a esto, puede estar seguro de que la prueba no produce resultados falsos positivos, es un tipo de prueba de las pruebas mismas.
- Crean una implementaci贸n de la oportunidad y aseguran que pase la prueba con 茅xito.
- Realice, si es necesario, la refactorizaci贸n de c贸digo. La refactorizaci贸n, en presencia de una prueba que puede indicarle al desarrollador si el sistema est谩 funcionando correcta o incorrectamente, le da confianza al desarrollador en sus acciones.
驴C贸mo puede TDD ayudar a ahorrar el tiempo necesario para desarrollar programas?
A primera vista, podr铆a parecer que escribir pruebas significa un aumento significativo en la cantidad de c贸digo del proyecto, y que todo esto lleva a los desarrolladores mucho tiempo extra. En mi caso, al principio, todo era solo eso, y trat茅 de comprender c贸mo, en principio, es posible escribir c贸digo comprobable y c贸mo agregar pruebas al c贸digo que ya se ha escrito.
TDD se caracteriza por una cierta curva de aprendizaje, y mientras un principiante sube por esta curva, el tiempo requerido para el desarrollo puede aumentar en un
15-35% . A menudo esto es exactamente lo que sucede. Pero en alg煤n lugar unos 2 a帽os despu茅s del inicio del uso de TDD, algo incre铆ble comienza a suceder. A saber, por ejemplo, comenc茅, con la redacci贸n preliminar de pruebas unitarias, programando m谩s r谩pido que antes cuando no se usaba TDD.
Hace unos a帽os, implement茅, en el sistema del cliente, la capacidad de trabajar con fragmentos de un videoclip. Es decir, el punto era que ser铆a posible permitir al usuario indicar el comienzo y el final del fragmento de grabaci贸n, y recibir un enlace al mismo, lo que permitir铆a referirse a un lugar espec铆fico en el clip, y no a todo este clip.
No trabaj茅 El jugador lleg贸 al final del fragmento y continu贸 jugando, pero no ten铆a idea de por qu茅 era as铆.
Pens茅 que el problema estaba conectando incorrectamente los oyentes de eventos. Mi c贸digo se parec铆a a esto:
video.addEventListener('timeupdate', () => { if (video.currentTime >= clip.stopTime) { video.pause(); } });
El proceso para encontrar el problema se ve铆a as铆: hacer cambios, compilar, reiniciar, hacer clic, esperar ... Esta secuencia de acciones se repiti贸 una y otra vez.
Para verificar cada uno de los cambios introducidos en el proyecto, me llev贸 casi un minuto gastarlo, y experiment茅 una incre铆ble cantidad de opciones para resolver el problema (la mayor铆a de ellos 2-3 veces).
驴Tal vez comet铆 un error en la palabra clave
timeupdate
? 驴Entend铆 las caracter铆sticas de trabajar con la API correctamente? 驴La llamada
video.pause()
? Realic茅 cambios en el c贸digo, agregu茅
console.log()
, volv铆 al navegador, hice clic en el bot贸n
, hice clic en la posici贸n ubicada al final del fragmento seleccionado y luego esper茅 pacientemente hasta que el clip se reproduzca por completo. Iniciar sesi贸n dentro de la construcci贸n
if
no condujo a nada. Parec铆a una pista sobre un posible problema. Copi茅 la palabra
timeupdate
de la documentaci贸n de la API para estar absolutamente seguro de que no comet铆 un error al ingresarla. Vuelvo a cargar la p谩gina, hago clic de nuevo, espero de nuevo. Y nuevamente, el programa se niega a funcionar correctamente.
Finalmente puse
console.log()
fuera del bloque
if
. "No ayudar谩", pens茅. Al final, la
if
era tan simple que simplemente no ten铆a idea de c贸mo escribirla incorrectamente. Pero iniciar sesi贸n en este caso funcion贸. Me atragant茅 con el caf茅. "驴Qu茅 demonios es eso?" Pens茅
Ley de depuraci贸n de Murphy. El lugar del programa que nunca prob贸, ya que cre铆a firmemente que no pod铆a contener errores, ser谩 exactamente el lugar donde encontrar谩 un error despu茅s de que, una vez agotado, realice cambios en este lugar solo porque que ya han intentado todo lo que se les ocurri贸.
Establec铆 un punto de interrupci贸n en el programa para entender lo que est谩 sucediendo.
clip.stopTime
el significado de
clip.stopTime
. Para mi sorpresa, no estaba
undefined
. Por qu茅 Mir茅 el c贸digo nuevamente. Cuando el usuario selecciona la hora de finalizaci贸n del fragmento, el programa coloca el marcador para el final del fragmento en el lugar correcto, pero no establece el valor de
clip.stopTime
. "Soy un idiota incre铆ble", pens茅, "no se me debe permitir entrar a las computadoras hasta el final de mi vida".
No me olvid茅 de esto y a帽os despu茅s. Y todo, gracias a la sensaci贸n que experiment茅, a煤n encontrando un error. Probablemente sabes de lo que estoy hablando. Con todo esto sucedi贸. Y, tal vez, todos podr谩n reconocerse en este meme.
As铆 es como me veo cuando programoSi escribiera ese programa hoy, comenzar铆a a trabajar de esta manera:
describe('clipReducer/setClipStopTime', async assert => { const stopTime = 5; const clipState = { startTime: 2, stopTime: Infinity }; assert({ given: 'clip stop time', should: 'set clip stop time in state', actual: clipReducer(clipState, setClipStopTime(stopTime)), expected: { ...clipState, stopTime } }); });
Existe la sensaci贸n de que hay mucho m谩s c贸digo que en esta l铆nea:
clip.stopTime = video.currentTime
Pero ese es el punto. Este c贸digo act煤a como una especificaci贸n. Esto es documentaci贸n y prueba de que el c贸digo funciona como lo requiere esta documentaci贸n. Y, dado que esta documentaci贸n existe, si cambio el orden de trabajo con el marcador por el tiempo de finalizaci贸n de un fragmento, no tengo que preocuparme si durante la introducci贸n de estos cambios viol茅 la operaci贸n correcta con el tiempo de finalizaci贸n del clip.
Aqu铆 , por cierto, hay material 煤til para escribir pruebas unitarias, el mismo que acabamos de ver.
El punto no es cu谩nto tiempo lleva ingresar este c贸digo. El punto es cu谩nto tiempo lleva depurar si algo sale mal. Si el c贸digo es incorrecto, la prueba dar谩 un excelente informe de error. Inmediatamente sabr茅 que el problema no es el controlador de eventos.
setClipStopTime()
que es en
setClipStopTime()
o en
clipReducer()
, donde se implementa un cambio de estado. Gracias a la prueba, sabr铆a qu茅 funciones realiza el c贸digo, qu茅 muestra realmente y qu茅 se espera de 茅l. Y, lo que es m谩s importante, mi colega tendr谩 el mismo conocimiento, quien, seis meses despu茅s de que escrib铆 el c贸digo, introducir谩 nuevas caracter铆sticas en 茅l.
Al comenzar un nuevo proyecto, yo, como una de las primeras cosas, configuro un
script de observaci贸n que ejecuta autom谩ticamente pruebas unitarias cada vez que se cambia un determinado archivo. A menudo programo usando dos monitores. En uno de ellos, se abre la consola del desarrollador, en la que se muestran los resultados de dicho script, en el otro, se muestra la interfaz del entorno en el que escribo el c贸digo. Cuando realizo un cambio en el c贸digo, generalmente, en 3 segundos, averiguo si el cambio funcion贸 o no.
Para m铆, TDD es mucho m谩s que un seguro. Esta es la capacidad de recibir de manera constante y r谩pida, en tiempo real, informaci贸n sobre el estado de mi c贸digo. Recompensa instant谩nea en forma de pruebas aprobadas o un informe instant谩neo de errores en caso de que haya hecho algo mal.
驴C贸mo me ense帽贸 la metodolog铆a TDD a escribir mejor c贸digo?
Me gustar铆a hacer una admisi贸n, incluso admitir que es vergonzoso: no ten铆a idea de c贸mo crear aplicaciones antes de aprender TDD y pruebas unitarias. No puedo imaginar c贸mo me contrataron, pero despu茅s de entrevistar a cientos de desarrolladores, puedo decir con confianza que muchos programadores se encuentran en una situaci贸n similar. La metodolog铆a TDD me ha ense帽ado casi todo lo que s茅 sobre la descomposici贸n eficiente y la composici贸n de componentes de software (me refiero a m贸dulos, funciones, objetos, componentes de interfaz de usuario, etc.).
La raz贸n de esto es que las pruebas unitarias obligan al programador a probar componentes aislados uno del otro y de los subsistemas de E / S. Si el m贸dulo se proporciona con algunos datos de entrada, debe proporcionar ciertos datos de salida previamente conocidos. Si no lo hace, la prueba falla. Si lo hace, la prueba tiene 茅xito. El punto aqu铆 es que el m贸dulo deber铆a funcionar independientemente del resto de la aplicaci贸n. Si est谩 probando la l贸gica del estado, deber铆a poder hacerlo sin mostrar nada en la pantalla o guardar nada en la base de datos. Si est谩 probando la formaci贸n de la interfaz de usuario, deber铆a poder probarla sin tener que cargar la p谩gina en un navegador o acceder a los recursos de la red.
Entre otras cosas, la metodolog铆a TDD me ense帽贸 que la vida se vuelve mucho m谩s f谩cil si se lucha por el minimalismo al desarrollar componentes de interfaz de usuario. Adem谩s, la l贸gica empresarial y los efectos secundarios deben aislarse de la interfaz de usuario. Desde un punto de vista pr谩ctico, esto significa que si usa un marco de interfaz de usuario basado en componentes como
React o Angular, puede ser aconsejable crear componentes de presentaci贸n que sean responsables de mostrar algo en la pantalla y componentes del contenedor que no est谩n conectados entre s铆 son mixtos
Un componente de presentaci贸n que recibe ciertas propiedades siempre genera el mismo resultado. Dichos componentes se pueden verificar f谩cilmente mediante pruebas unitarias. Esto le permite averiguar si el componente funciona correctamente con las propiedades y si cierta l贸gica condicional utilizada en la formaci贸n de la interfaz es correcta. Por ejemplo, es posible que el componente que forma la lista no muestre nada m谩s que una invitaci贸n para agregar un nuevo elemento a la lista si la lista est谩 vac铆a.
Conoc铆a el principio de separaci贸n de responsabilidades mucho antes de dominar TDD, pero no sab铆a c贸mo compartir la responsabilidad entre diferentes entidades.
Las pruebas unitarias me permitieron estudiar el uso de mokas para probar algo, y luego descubr铆 que burlarse es una se帽al de que
algo podr铆a estar mal con el c贸digo . Me sorprendi贸 y cambi贸 por completo mi enfoque de la composici贸n del software.
Todo el desarrollo de software es una composici贸n: el proceso de dividir problemas grandes en muchos problemas peque帽os y f谩ciles de resolver, y luego crear soluciones para estos problemas que forman la aplicaci贸n. Tuxing por el bien de las pruebas unitarias indica que las unidades at贸micas de la composici贸n no son, de hecho, at贸micas. Estudiar c贸mo deshacerse de mok sin afectar la cobertura del c贸digo mediante pruebas me permiti贸 aprender a identificar las innumerables razones ocultas de la fuerte conexi贸n de las entidades.
Esto me permiti贸, como desarrollador, crecer profesionalmente. Esto me ense帽贸 a escribir c贸digo mucho m谩s simple que es m谩s f谩cil de extender, mantener y escalar. Esto se aplica a la complejidad del c贸digo en s铆 y a la organizaci贸n de su trabajo en grandes sistemas distribuidos, como las infraestructuras de la nube.
驴C贸mo TDD ahorra tiempo al equipo?
Ya he dicho que TDD, en primer lugar, conduce a una
mejor cobertura del c贸digo con las pruebas. La raz贸n de esto es que no comenzamos a escribir c贸digo para implementar alguna caracter铆stica hasta que escribimos una prueba que verifica el funcionamiento correcto de este c贸digo futuro. Primero escribimos una prueba. Luego permitimos que termine con un error. Luego escribimos el c贸digo para implementar la oportunidad. Estamos probando el c贸digo, recibimos un mensaje de error, logramos la aprobaci贸n correcta de las pruebas, realizamos la refactorizaci贸n y repetimos este proceso.
Este proceso le permite crear una "cerca" a trav茅s de la cual solo unos pocos errores pueden "saltar". Esta protecci贸n contra errores tiene un efecto sorprendente en todo el equipo de desarrollo. Alivia el miedo al equipo de fusi贸n.
El alto nivel de cobertura del c贸digo con pruebas permite al equipo deshacerse del deseo de controlar manualmente cualquier cambio, incluso peque帽o, en la base del c贸digo. Los cambios de c贸digo se convierten en una parte natural del flujo de trabajo.
Deshacerse del miedo a hacer cambios en el c贸digo se asemeja al desenfoque de cierta m谩quina. Si esto no se hace, la m谩quina finalmente se detendr谩, hasta que se lubrique y se reinicie.
Sin este temor, el proceso de trabajar en programas es mucho m谩s tranquilo que antes. Las solicitudes de extracci贸n no se retrasan hasta el final. El sistema CI / CD ejecutar谩 las pruebas y, si las pruebas fallan, detendr谩 el proceso de realizar cambios en el c贸digo del proyecto. Al mismo tiempo, los mensajes de error y la informaci贸n sobre exactamente d贸nde ocurrieron ser谩n muy dif铆ciles de no notar.
Este es todo el punto.
Estimados lectores! 驴Utiliza TDD cuando trabaja en sus proyectos?
