Depuración para principiantes sin experiencia

Sin excepción, el código que escriben los desarrolladores de software no siempre hace lo que se espera. A veces hace algo completamente diferente. Cuando ocurre lo inesperado, la siguiente tarea consiste en averiguar por qué y, aunque quedarnos mirando fijamente el código durante horas es muy tentador, es más fácil y eficaz usar un depurador o una herramienta de depuración.

Un depurador, lamentablemente, no puede revelar todos los problemas o “errores” en nuestro código mágicamente. Depurar significa ejecutar el código paso a paso en una herramienta de depuración como Visual Studio, para buscar el punto exacto donde ha cometido un error de programación. Entonces sabrá qué correcciones debe realizar en el código; las herramientas de depuración suelen permitir realizar cambios temporales para que pueda continuar la ejecución del programa.

Usar un depurador de forma eficaz también es una habilidad que lleva tiempo y práctica desarrollar, pero en última instancia es una tarea fundamental para los desarrolladores de software. En este artículo se presentan los principios básicos de la depuración y se proporcionan sugerencias para ayudarle a comenzar.

Aclarar el problema haciéndose las preguntas adecuadas

Resultará útil aclarar el problema que surgió antes de intentar corregirlo. Se supone que ya haya tenido algún problema con el código porque, en caso contrario, no debería estar intentando averiguar cómo depurarlo. Por lo tanto, antes de iniciar la depuración, asegúrese de que ha identificado el problema que está intentando resolver:

  • ¿Qué esperaba que hiciese el código?

  • ¿Qué pasó en su lugar?

    Si se ha producido un error (excepción) durante la ejecución de la aplicación, podría resultar positivo. Una excepción es un evento inesperado al ejecutar código, normalmente un error de algún tipo. Una herramienta de depuración puede llevarle hasta el lugar exacto en el código donde se produjo la excepción y puede ayudarle a investigar las posibles soluciones.

    Si ha sucedido otra cosa, ¿cuál es el síntoma del problema? ¿Ya sospecha que este problema se produjo en el código? Por ejemplo, si el código muestra algo de texto, pero el texto es incorrecto, sabe que los datos son incorrectos o el código que establece el texto para mostrar tiene algún tipo de error. Al pasar el código por un depurador, puede examinar cada uno de los cambios en las variables para descubrir exactamente cuándo y cómo se asignaron valores incorrectos.

Examinar sus suposiciones

Antes de investigar un error, piense en las suposiciones que le llevaron a esperar un resultado determinado. Las suposiciones ocultas o desconocidas pueden interferir a la hora de identificar un problema, incluso cuando la causa del problema está justo delante de sus ojos en un depurador. Es posible que tenga una larga lista de suposiciones posibles. Estas son algunas preguntas con las que puede cuestionar sus suposiciones.

  • ¿Está usando la API adecuada (es decir, el objeto, función, método o propiedad adecuado)? Una API que esté usando podría no hacer lo que piensa que hace. (Después de examinar la llamada API en el depurador, para corregirla puede ser necesario consultar la documentación para ayudar a identificar la API correcta).

  • ¿Está utilizando una API correctamente? Tal vez ha usado la API correcta pero no la usó de la forma adecuada.

  • ¿El código contiene errores al escribir? Algunos errores tipográficos, como un error al escribir un nombre de variable, pueden ser difíciles de ver, especialmente cuando se trabaja con idiomas que no requieren que se declaren las variables antes de usarse.

  • ¿Ha realizado un cambio en el código y supone que no está relacionado con el problema que está viendo?

  • ¿Esperaba que un objeto o una variable contuviese un valor determinado (o un determinado tipo de valor) que es diferente de lo que realmente sucedió?

  • ¿Conoce la intención del código? A menudo resulta más difícil depurar el código de otra persona. Si no es su propio código, es posible que deba dedicar tiempo a conocer qué hace exactamente el código antes de poder depurarlo de forma eficaz.

    Sugerencia

    Al escribir código, empiece poco a poco y con código que funcione. (Un buen código de ejemplo puede ser útil aquí). A veces, resulta más fácil de corregir un conjunto grande o complejo de código empezando con un pequeño fragmento de código que muestra la tarea principal que está intentando lograr. Después, puede modificar o agregar código de forma incremental, haciendo pruebas en cada punto en busca de errores.

Al cuestionar sus suposiciones, puede reducir el tiempo necesario para encontrar un problema en el código. También puede reducir el tiempo necesario para corregir un problema.

Recorrer el código en modo de depuración para buscar dónde se produjo el problema

Al ejecutar una aplicación con normalidad, verá errores y resultados incorrectos solo después de que se haya ejecutado el código. Un programa también puede finalizarse inesperadamente sin que se indique por qué.

Al ejecutar una aplicación dentro de un depurador, también denominado modo de depuración, el depurador supervisa activamente todo lo que sucede durante la ejecución del programa. También permite pausar la aplicación en cualquier momento para examinar su estado y después recorrer el código línea por línea para ver todos los detalles a medida que se producen.

En Visual Studio puede entrar en el modo de depuración mediante F5 (o el comando de menú Depuración>Iniciar depuración o el botón Iniciar depuraciónIcon showing Start Debugging button. de la barra de herramientas Depuración). Si se produce alguna excepción, el Asistente de excepciones de Visual Studio le lleva al punto exacto donde ocurrió y proporciona información útil adicional. Para más información sobre cómo controlar las excepciones en el código, vea Técnicas y herramientas de depuración.

Si no se ha iniciado una excepción, probablemente pueda hacerse una idea de dónde buscar el problema en el código. Este paso es donde usará puntos de interrupción con el depurador para examinar más detenidamente el código. Los puntos de interrupción son la característica más básica y esencial para una depuración confiable. Un punto de interrupción indica el lugar en el que Visual Studio debe pausar la ejecución de código para poder echar un vistazo a los valores de las variables o al comportamiento de la memoria en la secuencia de código que se ejecuta.

En Visual Studio, puede configurar rápidamente un punto de interrupción haciendo clic en el margen izquierdo junto a una línea de código. También puede colocar el cursor en una línea y presionar F9.

Para ayudar a ilustrar estos conceptos, le llevaremos por código de ejemplo que ya tiene varios errores. Estamos usando C#, pero las características de depuración se aplican a Visual Basic, C++, JavaScript, Python y otros lenguajes compatibles. También se proporciona un código de ejemplo para Visual Basic, pero las capturas de pantalla están en C#.

Crear una aplicación de ejemplo (con algunos errores)

Ahora, creará una aplicación que tiene algunos errores.

  1. Debe tener instalados Visual Studio y la carga de trabajo Desarrollo de escritorio de .NET.

    Si todavía no ha instalado Visual Studio, vaya a la página de descargas de Visual Studio para instalarlo de forma gratuita.

    Si tiene que instalar la carga de trabajo pero ya tiene Visual Studio, seleccione Herramientas>Obtener herramientas y características. Se iniciará el Instalador de Visual Studio. Elija la carga de trabajo Desarrollo de escritorio de .NET y, luego, seleccione Modificar.

  2. Abra Visual Studio.

    En la ventana de inicio, elija Crear un proyecto nuevo. Escriba consola en el cuadro de búsqueda, seleccione C# o Visual Basic como lenguaje y elija Aplicación de consola para .NET. Elija Siguiente. Escriba un nombre de proyecto como, por ejemplo, ConsoleApp_FirstApp y seleccione Siguiente.

    Seleccione la plataforma de destino recomendada o .NET 8 y, después, elija Crear.

    Si no ve la plantilla de proyecto Aplicación de consola para .NET, vaya a Herramientas>Obtener herramientas y características y se abrirá el Instalador de Visual Studio. Elija la carga de trabajo Desarrollo de escritorio de .NET y, luego, seleccione Modificar.

    Visual Studio crea el proyecto de consola, que aparece en el panel derecho del Explorador de soluciones.

  3. En Program.cs (o Program.vb), reemplace todo el código predeterminado con el siguiente. (Seleccione primero la pestaña de lenguaje correcto, ya sea C# o Visual Basic).

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    Nuestra intención para este código es mostrar la información del nombre de la galaxia, la distancia a la galaxia y el tipo de galaxia en una lista. Para depurar, es importante comprender la intención del código. Este es el formato de una línea en la lista que se va a mostrar en la salida:

    nombre de la galaxia, distancia, tipo de galaxia.

Ejecutar la aplicación

Presione F5 o el botón Iniciar depuraciónIcon showing Start Debugging button. en la barra de herramientas Depuración, que se encuentra situada encima del editor de código.

La aplicación se inicia y el depurador no nos muestra ninguna excepción. Pero, el resultado que se ve en la ventana de consola no es el esperado. Este es el resultado esperado:

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

Sin embargo, verá esta salida en su lugar:

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

Si nos fijamos en el resultado y en nuestro código, sabemos que GType es el nombre de la clase que almacena el tipo de galaxia. Pero, estamos intentando mostrar el tipo de galaxia real (por ejemplo, "espiral"), no el nombre de clase.

Depurar la aplicación

  1. Con la aplicación en ejecución, inserte un punto de interrupción.

    Haga clic con el botón derecho junto al método Console.WriteLine para obtener el menú contextual y seleccione Punto de interrupción>Insertar punto de interrupción en el menú desplegable.

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    Cuando establece el punto de interrupción, aparece un punto rojo en el margen izquierdo.

    Dado que detecta un problema en la salida, comience la depuración examinando el código anterior que establece la salida en el depurador.

  2. Seleccione el botón ReiniciarIcon showing RestartApp button in Debug toolbar. en la barra de herramientas de depuración (Ctrl + Mayús + F5).

    La aplicación se detiene en el punto de interrupción que definió. El resaltado amarillo indica que el depurador está en pausa (la línea amarilla de código aún no se ha ejecutado).

  3. Mantenga el mouse sobre la variable GalaxyType a la derecha y después, a la izquierda del icono de llave inglesa, expanda theGalaxy.GalaxyType. Verá que GalaxyType contiene una propiedad MyGType y el valor de propiedad se establece en Spiral.

    Screenshot of the Visual Studio Debugger with a line of code in yellow and a menu open below the Galaxy GalaxyType property.

    “Espiral” es realmente el valor correcto que se esperaba que se imprimiese en la consola. Por lo tanto, es un buen punto de partida que pueda tener acceso al valor en este código mientras se ejecuta la aplicación. En este escenario, estamos usando la API incorrecta. Veremos si puede corregir esto mientras se ejecuta código en el depurador.

  4. En el mismo código, mientras todavía se depura, coloque el cursor al final de theGalaxy.GalaxyType y cámbielo a theGalaxy.GalaxyType.MyGType. Aunque puede realizar el cambio, el editor de código muestra un error que indica que no puede compilar este código. (En Visual Basic, el error no se muestra y esta sección del código funciona).

  5. Presione F11 (Depurar>Paso a paso por instrucciones o el botón Paso a paso por instrucciones en la barra de herramientas Depurar) para ejecutar la línea de código actual.

    F11 hace avanzar el depurador (y ejecuta código) en una instrucción cada vez. F10 (Saltar) es un comando similar y ambos son útiles para aprender a usar el depurador.

    Aparece el cuadro de diálogo Editar y continuar, lo que indica que no se pueden compilar las modificaciones.

    Screenshot of the Visual Studio Debugger with a line of code highlighted in red and a message box with the Edit option selected.

    Nota:

    Para depurar el código de ejemplo de Visual Basic, omita los pasos siguientes hasta que se le indique que haga clic en el botón ReiniciarIcon showing Restart app button in Debug toolbar..

  6. Seleccione Editar en el cuadro de mensaje Editar y continuar. Ahora verá un mensaje de error en la ventana Lista de errores. El error indica que el 'object' no contiene una definición para MyGType.

    Screenshot of the Visual Studio Debugger with a line of code highlighted in red and an Error List window with two errors listed.

    Aunque se establezca cada galaxia con un objeto de tipo GType (que tiene la propiedad MyGType), el depurador no reconoce el objeto theGalaxy como un objeto de tipo GType. ¿Qué sucede? Desea buscar cualquier código que establece el tipo de galaxia. Al hacerlo, verá que la clase GType definitivamente tiene una propiedad de MyGType, pero algo no es correcto. El mensaje de error sobre object resulta ser la pista; para el intérprete de lenguaje, el tipo parece ser un objeto de tipo object en lugar de un objeto de tipo GType.

  7. Al examinar el código relacionado con la configuración del tipo galaxia, descubre que la propiedad GalaxyType de la clase Galaxy está especificada como object en lugar de GType.

    public object GalaxyType { get; set; }
    
  8. Cambie el código anterior de la siguiente manera:

    public GType GalaxyType { get; set; }
    
  9. Seleccione el botón ReiniciarIcon showing Restart app button in Debug toolbar. de la barra de herramientas Depurar (Ctrl + Mayús + F5) para volver a compilar el código y reiniciar.

    Ahora, cuando el depurador se detiene en Console.WriteLine, puede mantener el puntero sobre theGalaxy.GalaxyType.MyGType y ver que el valor se estableció correctamente.

  10. Quite el punto de interrupción haciendo clic en el círculo de punto de interrupción en el margen izquierdo (o haga clic con el botón derecho y elija Punto de interrupción>Eliminar punto de interrupción) y después presione F5 para continuar.

    La aplicación se ejecuta y muestra el resultado. Ahora tiene bastante buen aspecto, pero tenga en cuenta una cosa. Esperaba que la galaxia Pequeña Nube de Magallanes apareciese como una galaxia irregular en la salida de consola, pero no muestra ningún tipo de galaxia en absoluto.

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. Establezca un punto de interrupción en esta línea de código antes de la instrucción switch(antes de la instrucción Select en Visual Basic).

    public GType(char type)
    

    Este código es donde se establece el tipo de galaxia, por lo que queremos analizarlo en detalle.

  12. Haga clic en el botón ReiniciarIcon showing Restart app button in Debug toolbar. en la barra de herramientas de depuración (Ctrl + Mayús + F5) para reiniciar.

    El depurador se detiene en la línea de código en la que estableció el punto de interrupción.

  13. Mantenga el mouse sobre la variable type. Ve un valor de S (siguiendo el código de carácter). Le interesa un valor de I, puesto que sabe que es un tipo de galaxia irregular.

  14. Presione F5 y mantenga de nuevo el mouse sobre la variable type. Repita este paso hasta que vea un valor de I en la variable type.

    Screenshot of the Visual Studio Debugger with a line of code in yellow and a window with the type variable value of 73 I.

  15. Ahora, presione F11 (o Depurar>Depurar paso a paso por instrucciones).

  16. Presione F11 hasta que se detenga en la línea de código en la instrucción switch para un valor de “I” (instrucción Select en Visual Basic). En este caso, verá un problema claro causado por un error de escritura. Esperaba que el código avanzase a donde se establece MyGType como un tipo de galaxia irregular, pero en su lugar el depurador omite completamente este código y se detiene en la sección default de la instrucción switch (instrucción Else en Visual Basic).

    Screenshot showing the typo error.

    Examinando el código, ve un error de escritura en la instrucción case 'l'. Debería ser case 'I'.

  17. Seleccione el código para case 'l' y reemplácelo por case 'I'.

  18. Quite el punto de interrupción y después seleccione el botón Reiniciar para reiniciar la aplicación.

    Ahora están corregidos los errores y verá la salida esperada.

    Presione cualquier tecla para finalizar la aplicación.

Resumen

Cuando vea un problema, utilice el depurador y los comandos de paso como F10 y F11 para buscar la región de código con el problema.

Nota

Si es difícil identificar la región de código donde se produce el problema, establezca un punto de interrupción en código que se ejecuta antes de que se produce el problema y después use los comandos de paso hasta que vea el problema manifiesto. También puede usar puntos de seguimiento para registrar mensajes en la ventana Salida. Al mirar los mensajes registrados (y observar los mensajes que aún no se registraron), a menudo puede aislar la región de código con el problema. Es posible que deba repetir este proceso varias veces para delimitarla.

Cuando encuentre la región de código con el problema, utilice el depurador para investigar. Para averiguar la causa de un problema, inspeccione el código del problema mientras se ejecuta la aplicación en el depurador:

  • Inspeccione variables y compruebe si contienen el tipo de valores que deben contener. Si encuentra un valor incorrecto, averigüe dónde se estableció el valor no válido (para buscar dónde se estableció el valor, es posible que deba reiniciar el depurador, examinar la pila de llamadas o realizar ambas acciones).

  • Compruebe si la aplicación está ejecutando el código que espera. (Por ejemplo, en la aplicación de ejemplo, se esperaba que el código de la instrucción switch estableciese el tipo de galaxia en irregular, pero la aplicación ha omitido el código debido al error de escritura).

Sugerencia

Use un depurador para ayudarle a encontrar errores. Una herramienta de depuración puede encontrar errores automáticamente solo si conoce la intención del código. Una herramienta solo puede saber la intención del código si usted, la persona que desarrolla, expresa dicha intención. Puede hacerlo escribiendo pruebas unitarias.

Pasos siguientes

En este artículo, ha aprendido algunos conceptos generales de depuración. A continuación, puede empezar a aprender más sobre el depurador.