Pasar demasiado tiempo depurando

24

Ayer, lancé una versión v1.0 de un proyecto web en el que pasé unas 6 semanas trabajando (de vez en cuando, claro). No he hecho ningún registro exacto de mi tiempo, pero de acuerdo con mis experiencias, estimaría que de todo el tiempo que pasé programando, la mitad se dedicó a la depuración. Calculo que se trata de una buena depuración de 15-20 horas, lo que para mí es un tiempo precioso que podría haberse gastado mejor escribiendo un nuevo código o terminando el proyecto antes. Tampoco ayuda especialmente que sea un estudiante de primer año en la universidad en 5 semanas.

La cosa es que me siento mal por pasar todo ese tiempo depurando. Todo el tiempo dedicado a la depuración me hace darme cuenta de que cometí algunos errores bastante estúpidos mientras desarrollaba mi proyecto, errores que me costaron una gran cantidad de tiempo para solucionarlos.

¿Cómo puedo evitar que esto suceda en el futuro? No quiero pasar el 50% de mi tiempo depurando, prefiero pasar el 10% de depuración y el resto escribiendo código nuevo. ¿Cuáles son algunas técnicas que puedo tratar de ayudarme a alcanzar este objetivo?

Ryan
fuente
22
Cuando era estudiante de primer año, yo también era un programador lento. Solo dale 20 años.
Trabajo
27
uhh sí, buena suerte con eso. "Si la depuración es el proceso de eliminar errores. Entonces la programación debe ser el proceso de ponerlos". -Edsger Dijkstra
Matt
77
¿Aprendiste algo de esos errores? Si lo hizo, no los hará la próxima vez y esto reducirá su tiempo de depuración.
Craig T
55
Esto se llama "experiencia" y lo ayudará en su próximo proyecto.
44
Hablando de finales de la década de 1940, Maurice Wilkes escribió: "Tan pronto como comenzamos a programar, nos sorprendió que no fuera tan fácil hacer los programas correctamente como habíamos pensado. La depuración tuvo que ser descubierta. Fue en uno de En mis viajes entre la sala de EDSAC y el equipo de perforación que 'dudaba en los ángulos de las escaleras', me di cuenta con toda la fuerza de que una buena parte del resto de mi vida iba a pasarla encontrando errores en mis propios programas ".
Trevor Powell

Respuestas:

35

Estás pidiendo el Santo Grial de la ingeniería de software, y nadie tiene "la" respuesta a esta pregunta todavía.

Lo esencial es hacer un seguimiento de los tipos de errores que está cometiendo y luego hacer un análisis de esos errores para determinar si hay una tendencia común. El análisis de causa raíz es el nombre formal para este tipo de introspección, y hay mucho material en la web al respecto.

Los profesionales usan un sistema de seguimiento de errores para que puedan (1) saber lo que necesita ser arreglado, pero también (2) analizar lo que tuvo que arreglarse después del hecho. No es necesario que sea tan formal, solo llevar una cuenta en un cuaderno puede estar bien para usted.

Defectos de la etapa de diseño

Si descubre que la mayoría de sus errores provienen de un malentendido de la declaración del problema, o si sigue encontrando que ha elegido el algoritmo o el camino incorrecto a seguir para resolver sus problemas, tiene problemas en la etapa de diseño.

Le convendría tomarse más tiempo al comienzo del proyecto y escribir exactamente lo que debe hacerse y cómo debe hacerlo. Revise este trabajo cuidadosamente y revise el problema original y determine si realmente lo está abordando de la manera correcta. Una hora o tres adicionales al comienzo pueden ahorrarle muchas horas más adelante.

Errores de codificación

Si su diseño es sólido, pero constantemente está luchando contra el lenguaje con el que está codificando, consiga algunas herramientas que analizarán su código por usted y le advertirán temprano y, a menudo, que está cometiendo errores.

Si está programando en C, active todas las advertencias del compilador, use un verificador semántico como linty use una herramienta como valgrindpara detectar problemas comunes relacionados con la memoria dinámica.

Si estás programación Perl, encienda stricty warningsy hacer caso de lo que dice.

No importa qué idioma esté usando, probablemente existan muchas herramientas para ayudar a detectar errores comunes mucho antes de llegar a la etapa de depuración.

Defectos de la etapa de integración

A medida que desarrolla su código siguiendo buenas prácticas de modularidad, debe comenzar a pegar las piezas separadas. Por ejemplo, las diferentes secciones de su código pueden tener que ver con la entrada del usuario, la interacción de la base de datos, la visualización de datos, los algoritmos / lógica, y cada uno de ellos está construido de manera relativamente independiente el uno del otro (es decir, tiende a concentrarse en la sección en cuestión) en lugar de preocuparse por la integración con todo lo demás).

Aquí es donde el desarrollo impulsado por pruebas (TDD) es muy útil. Cada módulo de su código puede tener pruebas que verifiquen que funcionan de acuerdo a cómo fueron diseñadas. Estas pruebas deben escribirse primero o muy temprano en el proceso para que pueda tener un conjunto de "ayudantes" que lo mantengan honesto. Cuando comience a hacer que todo funcione en conjunto, y descubra que tiene que cambiar la forma en que esto o aquello se implementa o interactúa con otro subsistema, puede recurrir a sus pruebas para asegurarse de que lo que ha hecho para hacer todo funciona en conjunto no rompe la exactitud del código.

Y así...

Elija algunos libros sobre ingeniería de software y técnicas prácticas de codificación, y aprenderá muchas formas diferentes de hacer que el desarrollo sea menos caótico y más confiable. También descubrirá que la experiencia simplemente antigua, obtener un título de la escuela de golpes duros, también lo pondrá en forma.

Lo que casi todo se reduce a eso es que un poco de tiempo y trabajo por adelantado vale la pena en grandes dividendos más adelante en el proceso de desarrollo / lanzamiento.

El hecho de que hayas notado estos problemas tan temprano en tu carrera habla bien para tu futuro, y te deseo la mejor de las suertes.

poco pitón
fuente
1
Esta es una gran respuesta, pero en mi humilde opinión a una pregunta un poco diferente. El OP dice que pasé 6 semanas encendido / apagado escribiendo algo y tuve que pasar mucho tiempo depurando. Todavía no sabemos nada de, por ejemplo, la calidad, el mantenimiento y la escalabilidad de su producto. Si asumimos TDD, buen diseño, seguimiento de errores, todavía queda la cuestión de cómo escribimos el código (incluido el código de prueba que también debe ser depurado) con menos defectos. Activar advertencias, usar pelusa, etc. son buenas sugerencias. ¿Más de los de la escuela de golpes duros? :-)
Guy Sirton
1
@Guy - Sí ... la pregunta del OP fue un poco vaga, es por eso que hice énfasis en el análisis de la causa raíz. No sabes lo que está mal hasta que sabes lo que está mal. La razón por la que realicé la encuesta de áreas problemáticas es porque quería que él fuera consciente de muchas trampas potenciales y que cada etapa del proceso merece su propio examen. Por lo que sé, puede ser el próximo Tony Hoare, pero uno con las habilidades de tipeo de un elefante ciego: diferentes soluciones para diferentes causas.
antipático
37

Escribir pruebas unitarias

Escribir pruebas unitarias para su código lo obligará a pensar en su arquitectura y lo alentará a escribir su código en piezas pequeñas, cuidadosamente controladas y comprobables. Esto reducirá en gran medida su esfuerzo de depuración, y la pequeña cantidad de depuración que realice se limitará a pequeños fragmentos de código bien enfocados.

Además, las pruebas que escriba "cubrirán" su código; podrá saber cuándo un cambio que realiza en el código rompe algo, porque una o más de sus pruebas existentes fallarán. Esto reduce la complejidad general de su esfuerzo de depuración y aumenta su confianza en que el código funciona.

El problema, por supuesto, es que el tiempo dedicado a la depuración ahora se dedica a escribir pruebas. Pero solo tiene que escribirlos una vez, y se pueden ejecutar tantas veces como sea necesario después de escribirlos.

Robert Harvey
fuente
+1 para pruebas unitarias: cuanto antes en el proceso de desarrollo se detectan los errores, más baratos y fáciles de solucionar.
Paul R
26

El 50% para la depuración (en un sentido amplio) no es tan malo. Por lo general, las personas pasan mucho más tiempo diseñando, probando, reparando errores, refactorizando y escribiendo pruebas unitarias que usted escribiendo el código real. Es parte del trabajo.

Y para ser honesto, es mucho peor en la programación de mantenimiento: con bastante frecuencia, pasaba una hora averiguando qué funciona mal, luego cinco minutos escribiendo el código para solucionarlo, y luego media hora probando todo. Eso es un poco más del 5% de codificación frente a casi el 95% de no codificación.

Sin embargo, hay algunas cosas que puede hacer para reducir el tiempo de depuración:

  • Escribir código depurable . Esto significa: manejo adecuado de errores (con un poco de reflexión), estructurando su código para que sea fácil de seguir, utilizando afirmaciones, seguimientos y cualquier otra cosa que pueda facilitar la vida del depurador. Evitar líneas complicadas; una línea que hace más de una cosa debe dividirse para que pueda recorrerlas individualmente.
  • Escribe código comprobable . Divida su código en funciones simples (o cualquier otra cosa que admita su idioma de elección); evite los efectos secundarios, ya que son difíciles de capturar en pruebas unitarias. Diseñe sus funciones para que puedan ejecutarse de forma aislada. Evita las funciones multipropósito. Evitar casos extremos. Documente lo que se supone que deben hacer sus funciones.
  • Escribe exámenes . Tener pruebas unitarias significa que sabe que sus funciones funcionan al menos para un subconjunto de sus entradas; también significa que tiene un control de cordura para confirmar que sus cambios no rompan nada. Asegúrese de comprender los conceptos de cobertura de código y cobertura de entrada, así como las limitaciones de las pruebas unitarias.
  • Configure un 'banco de trabajo' . Cómo exactamente hace esto depende del idioma en cuestión. Algunos lenguajes, como Python o Haskell, vienen con un intérprete interactivo y puedes cargar tu código existente para jugar con él. Esto es perfecto, ya que puede llamar a sus funciones en cualquier contexto que desee, con un esfuerzo mínimo, una herramienta invaluable para encontrar y aislar errores. Otros idiomas no tienen este lujo, y tendrá que recurrir a escribir pequeños programas de prueba interactivos.
  • Escribe código legible . Acostúmbrese a escribir su código para expresar sus intenciones con la mayor claridad posible. Documente todo lo que no sea perfectamente obvio.
  • Escribe un código simple . Si su propio cerebro tiene problemas para entender toda la base de código, entonces no es simple, y es muy poco probable que alguien más pueda entenderlo completamente. No puede depurar el código de manera efectiva a menos que entienda lo que se supone que debe hacer.
  • Sea fácil con el botón 'Eliminar' . Cualquier código que no necesite ahora pertenece a la papelera. Si lo necesita más tarde, revívalo desde el control de origen (la experiencia muestra que esto es extremadamente raro). Cuanto más código deseche, más pequeña será su superficie de depuración.
  • Refactorizar temprano y con frecuencia. Sin refactorizar, no puede mantener su código en un estado depurable mientras agrega nuevas funciones.
tdammers
fuente
1
Además, el mundo puede comportarse de manera diferente de lo esperado en caso de problemas. Esto puede causar errores muy sutiles.
2
+1. Diría que solo gastar el 50% en los esfuerzos de depuración es bastante bajo, especialmente pero no solo en una base de código establecida. Si se me asigna un error, a menos que requiera una reescritura completa de las partes relevantes del código (poco probable), podría pasar mucho más tiempo que esa fracción del tiempo total solo para descubrir qué está sucediendo y luego probar la solución. La solución en sí es a menudo rápida, a menudo representa solo una o unas pocas líneas de código modificado.
un CVn
@ ThorbjørnRavnAndersen Hell sí, especialmente con proyectos web como el OP menciona. Nos estamos
divirtiendo
5

Más planificación

Es inevitable que pases una buena parte del tiempo depurando, el 10% es un objetivo bastante ambicioso. Aunque una de las mejores formas de reducir el tiempo dedicado a la depuración y el desarrollo es pasar más tiempo en la fase de planificación.

Esto puede variar desde diagramas hasta pseudocódigo en una plataforma de planificación. De cualquier manera, tendrá más tiempo para mordisquear lo que planea hacer en lugar de cometer esos errores durante el desarrollo.

Bryan Harrington
fuente
1
+1 porque esto es lo que hago para reducir mi tiempo de depuración. Cuando comienzo un nuevo proyecto, escribo todo lo que voy a hacer en los comentarios, luego vuelvo y reemplazo los comentarios con el código
CamelBlues
Hago lo mismo con los comentarios, más aún para evitar que me olvide de dónde lo dejé. Pero me gusta dibujar diagramas de clases en papel y sus dependencias. Esto me da una buena idea de lo que estoy pensando en ese momento.
Bryan Harrington
5

Trabajar con más cuidado

Este es el equivalente de software de "medir dos veces cortar una vez":

  • No codifique si se siente distraído o cansado.
  • Dedique suficiente tiempo a pensar en el problema de modo que tenga una solución limpia y elegante. Las soluciones simples tienen menos probabilidades de tener problemas.
  • Presta toda tu atención a la tarea. Atención.
  • Lea su código rápidamente después de la codificación para intentar buscar errores. Auto revisión de código.
  • No espere demasiado entre codificación y prueba. La retroalimentación inmediata es importante para mejorar.
  • Evite hacer cosas que comúnmente conducen a errores. Leer en código olores .
  • Elija las herramientas adecuadas para el trabajo.

Dicho todo esto, nada eliminará por completo los defectos. Necesitas aceptar esto como un hecho de la vida. Dado este hecho, planifique defectos, p. Ej. Prueba unitaria. Tampoco tome esto como "tomar para siempre" (también conocido como análisis-parálisis). Se trata de encontrar el equilibrio.

Guy Sirton
fuente
4

Otras respuestas ya han cubierto la mayor parte de lo que quiero decir, pero de todos modos quiero darle mi opinión (brutalmente honesta):

Básicamente, para el trabajo de software no trivial, espere pasar la gran mayoría de su tiempo en mantenimiento y depuración. Si está trabajando en un sistema de software de producción maduro y está gastando menos del 80-90% de su tiempo en mantenimiento y depuración, ¡lo está haciendo bien!

Ahora, obviamente, la distinción entre "mantenimiento" y "depuración" es un poco subjetiva. ¿Considera que los "errores" son problemas con el código que se encuentra después de su lanzamiento y los usuarios se han quejado de ellos? ¿O es cada pequeña cosa que sale mal con su código una vez que ha agregado algo (que se encuentra en sus propias fases de prueba de prelanzamiento)? En un sistema de software no trivial (dependiendo de los patrones de uso) uno puede ser mucho más grande que el otro. Pero, en cualquier caso, esto es lo que requiere la programación de algo más grande que un programa "Hello world" de juguete: mucho mantenimiento y depuración. Algunas personas incluso dicen algo así como "se debe esperar que todo después de la primera línea de código sea 'modo de mantenimiento',

TL; DR: Simplemente me parece que puede tener una imagen poco realista de lo que se trata la programación de sistemas de software no triviales. La gran mayoría del esfuerzo consiste en afinar, mantener, refactorizar, corregir errores y, en general, hacer cosas que estarían bajo "depuración" (mantenimiento), al menos en un sentido muy general, en lugar de hacer un trabajo nuevo y totalmente nuevo. escribiendo nuevo código nuevo.

Mesas Bobby
fuente
2

Es difícil dar técnicas específicas sin detalles específicos sobre lo que está haciendo y qué tecnologías está utilizando. Pero incluso los codificadores realmente buenos pasan mucho tiempo probando y depurando.

Mucho escribir buen código sin muchos errores es experiencia. Cometes errores, luego los corriges, luego recuerdas cuáles fueron los errores y lo que tenías que hacer para corregirlos, y no cometes el mismo error la próxima vez. Y si aún no estás en la universidad y ya estás empezando a pensar seriamente en formas de cometer menos errores, diría que definitivamente estás por delante del juego.

Mason Wheeler
fuente
1
Me sorprende la gente que veo que no aprenden de sus errores (o se molestan en recordar lo que aprendieron). Y justo después de que algo les explota en la cara a lo grande, se dan la vuelta y hacen exactamente lo mismo en el próximo proyecto.
HLGEM
2

INTEGRACIÓN CONTINUA (CI) es la respuesta.

Integración continua = Sistema de gestión de configuración (a saber, Git, Mercurial, SVN, etc.) + Herramienta CI + Pruebas unitarias + Pruebas de humo

Esa fórmula debería impulsarlo a leer más sobre Integración Continua (CI). A continuación se presentan algunos recursos en esta área:

karthiks
fuente
1

Realmente, para reducir la depuración, puede realizar una carga frontal planificando con mayor profundidad. ¿Aún no has ido a la universidad? Creo que verá en sus clases universitarias de mediados a finales que cubrirá detalles del ciclo de vida de desarrollo de software que muy bien pueden arrojar algo de luz sobre sus locuras.

Mientras trato de explicarles a mis empleadores, la mejor manera de reducir el mantenimiento del código y el soporte técnico es pasar el tiempo para planificar su código de manera integral por adelantado.

Aparejo
fuente
1

El desarrollo basado en pruebas puede ayudar a reducir el tiempo de depuración al:

  • tener muchas pruebas pequeñas y enfocadas significa que si una falla, solo hay una pequeña cantidad de código que podría haber causado el problema.
  • trabajar en pequeños pasos (al escribir una prueba reprobatoria y luego aprobarla) significa que puede concentrarse en una tarea a la vez. Es decir, hacer pasar la prueba actual.
  • La refactorización después de pasar una prueba lo alienta a mantener su código claro y comprensible, lo que facilita su seguimiento en caso de que surjan problemas.

Incluso si usa TDD, aún tendrá momentos en los que necesite usar el depurador. Cuando esto sucede, debe intentar escribir una prueba unitaria para reproducir el escenario que causó la sesión de depuración. Esto asegurará que si ese problema vuelve a ocurrir, se detectará rápidamente cuando la prueba falle, y la prueba actuará como un marcador para el área de código que causó el problema, reduciendo la necesidad de depuración.

Jason
fuente
1

La depuración es inevitable en la programación, pero la clave aquí es, ¿es su código fácil de depurar o no? Si necesita pasar horas solo para depurar algo simple, entonces debe haber algo realmente mal con su arquitectura de código.

Debería acostumbrarse a escribir código limpio y eliminar los malos hábitos como copiar el código de pegado y escribir métodos largos, etc.

Además, debe refactorizar su código de vez en cuando. Le sugiero que lea el libro de Martin Fowler: Refactorización: Mejora del diseño de código existente

Dresde
fuente
1

Otros han mencionado pruebas y revisión de código. Ambos son extremadamente útiles pero tienen una diferencia clave: cuándo es mejor realizarlos. La prueba se realiza mejor cerca de escribir el código originalmente, para que pueda recordar más fácilmente por qué hizo las cosas de cierta manera y pueda localizar el problema más rápidamente cuando falla la prueba. La revisión del código, por otro lado, se hace mejor un poco más adelante. Desea tener que mirar el código sin un recuerdo perfecto para no pasar por alto detalles en los que recuerda haber pensado pero que no ingresó. Desea darse cuenta de los lugares donde su código no está claro. Desea el pequeño esfuerzo adicional de tener que descubrir qué está haciendo el código. Desea poder aplicar cualquier conocimiento nuevo que haya adquirido sobre el problema o las interacciones con otro código o nuevas técnicas. Básicamente,

Sin embargo, todo esto sigue siendo tangente a su pregunta. Para pasar menos tiempo depurando, debe comprender por qué tuvo que depurar en primer lugar. El malentendido del problema, el conocimiento imperfecto de sus herramientas y tecnologías, y el simple hecho de que "los datos reales no coinciden con los datos de muestra", todos los tipos de problemas se manifestarán de diferentes maneras y necesitarán diferentes técnicas y tipos de práctica para evitar en el futuro.

El último punto que haré es la experiencia. No hay una manera fácil de obtener esto, solo tiene que dedicarle tiempo. A medida que gane experiencia, pasará menos tiempo depurando porque comenzará a escribir un código mejor, notará problemas antes y desarrollará una mejor intuición de cuál podría ser la fuente de un problema. Sigue así y crecerás constantemente a lo largo de tu carrera.

CPhelps
fuente
0

Grandes respuestas anteriores, pero nadie mencionó directamente (aunque la mayoría insinuó esto):

LEER LEER LEER LEER et en nauseam ...

Cuanto más sabes, menos no sabes. Un poco cliché, pero sigue siendo la verdad básica.

Una vez que haya seguido los consejos anteriores y haya documentado analíticamente los errores, intente clasificarlos y luego lea la literatura pertinente.

¿Fue un problema de decisión de diseño? Lea sobre Patrones de diseño.

¿Fue una falta de conocimiento del marco o el lenguaje? ¡Hágase con eso!

etc.

Hay dos cosas que un desarrollador (en vivo) nunca puede escapar: el cambio (la única constante en TI) y RTFMing ...

Martin S. Stoller
fuente
0

Pruebas unitarias y afirma

Siempre que sea posible, factorice su código en piezas pequeñas que se puedan probar de forma aislada. Sin embargo, esto no siempre es práctico. Algunas piezas de funcionalidad dependen de entradas extremadamente complicadas. Algunos hacen algo que no se puede verificar fácilmente de una manera automatizada, como dibujar cosas en la pantalla. A veces está involucrado el no determinismo, etc.

Cuando no puede escribir buenas pruebas unitarias, la siguiente mejor opción es la afirmación. Mientras que las pruebas unitarias verifican si obtiene la respuesta correcta en alguna entrada predeterminada, afirma verificar la cordura de los pasos intermedios en las entradas del mundo real. Si su código tiene errores, fallará rápidamente, cerca de la raíz del problema y con un mensaje de error claro, en lugar de estar lejos del problema con un mensaje de error ambiguo. Además, afirma suposiciones de documentos y hace que su código sea más legible.

dsimcha
fuente
0

Cuando comienza un proyecto, ¿cuántos enfoques alternativos identifica?

¿Tiene de dos a cuatro enfoques diferentes, con pros y contras para cada uno? ¿Entonces haces una selección razonada de entre ellos?

Entonces, lo más importante, ¿considera que la simplicidad es tan importante?

La razón por la que pregunto es, en mi experiencia, el volumen de código, y por lo tanto la cantidad de errores (sin mencionar el rendimiento), puede variar en más de un orden de magnitud entre un enfoque de diseño y otro. Lo que veo a personas con mucha experiencia haciendo es realizar trabajos sin más código del necesario.

Son completamente competentes y conocen todos los algoritmos de estructura de datos, características de lenguajes orientados a objetos, etc., pero su código parece no serlo , porque usan esas cosas con moderación , o no lo hacen, si el problema persiste. No los requiero.

Mike Dunlavey
fuente
0

Cada vez que arregles un error, debes evitar cometer el mismo error nuevamente. Para hacerlo, puede hacer lo siguiente:

  • Anótelo en un registro de registro de defectos , que incluye:

    • tipo de defecto
    • fase en la que se inyectó el defecto
    • fase en la que se eliminó
    • fijar tiempo
    • una descripción del problema y solución
  • Adopta una guía de estilo para normalizar el estilo del código que escribes

  • Integre reglas de codificación seguras en su proceso de revisión de código

  • Visualice el flujo de control y los datos.

Referencias

Paul Sweatte
fuente