La depuración de código es una parte fundamental del proceso de desarrollo de software. A menudo, los errores pueden ser tan simples como un error tipográfico o tan complejos como un desbordamiento de memoria. A lo largo de los años, se han desarrollado diversas técnicas y herramientas para facilitar esta tarea, permitiendo a los desarrolladores identificar y corregir problemas de manera eficiente. Una de estas herramientas, especialmente útil en entornos de desarrollo integrados como Visual Studio, es la característica "Just My Code".

La Importancia de "Just My Code" en la Depuración
"Just My Code" es una característica de depuración de Visual Studio diseñada para simplificar el proceso al omitir automáticamente las llamadas a código externo, como el sistema operativo, frameworks o librerías de terceros. Durante una sesión de depuración, la ventana "Módulos" en Visual Studio muestra qué partes del código son tratadas por el depurador como "Mi Código" (código de usuario) y su estado de carga de símbolos. Esto permite a los desarrolladores centrarse en su propio código sin perderse en la complejidad de las capas inferiores de la aplicación.
Para interactuar con estas ventanas de depuración, como "Módulos" o "Pila de llamadas", es necesario estar activo en una sesión de depuración. Si se desea examinar el código que ha sido contraído como [Código externo], se puede hacer clic derecho en la ventana "Pila de llamadas" o "Tarea" y seleccionar "Mostrar código externo" en el menú contextual. Al hacer doble clic en una línea de código externo expandida en la ventana "Pila de llamadas", la línea de código que realizó la llamada se resaltará en verde en el código fuente, facilitando la identificación del punto de origen.
En proyectos .NET, "Just My Code" se apoya en archivos de símbolos (.pdb) y optimizaciones de programa para distinguir entre código de usuario y no usuario. Si el depurador se detiene en código que no es de usuario, por ejemplo, al usar "Depurar > Interrumpir todo" y la pausa ocurre en código externo, aparecerá la ventana "Sin Origen". Sin embargo, si las excepciones de primera oportunidad están habilitadas para esa excepción, la línea de código del usuario que realizó la llamada se resaltará en verde en el código fuente, proporcionando una pista valiosa.
A partir de la versión 15.8 de Visual Studio 2017, la funcionalidad "Just My Code" también se extiende a la ejecución paso a paso del código. Esta característica requiere el uso de la opción del compilador /JMC (Just My Code). Este modificador está habilitado por defecto en proyectos de C++. Para que la ejecución paso a paso funcione correctamente con "Just My Code" en C++, el código debe ser compilado con los compiladores de MSVC en Visual Studio 15.8 Preview 3 o posterior, y el modificador /JMC debe estar habilitado (lo cual ocurre por defecto). Para obtener información más detallada, se puede consultar la personalización de la pila de llamadas de C++ y el comportamiento paso a paso del código, así como entradas de blog específicas sobre el tema.
Para código compilado con compiladores anteriores, los archivos .natstepfilter son la única forma de personalizar la ejecución paso a paso del código, operando de manera independiente a "Just My Code". Durante la depuración de C++, el código que no es de usuario se omite por defecto. Si el depurador alcanza una excepción, se detendrá en ella, ya sea en código de usuario o no usuario.
You are debugging a Release build of .dll. Using Just My Code with Release builds using compiler
Personalización Avanzada de la Depuración en C++
En proyectos de C++, es posible especificar qué módulos, archivos de código fuente y funciones deben ser tratados por la ventana "Pila de llamadas" como código que no es de usuario, mediante la configuración en archivos *.natjmc. Estos archivos son obligatorios y permiten una granularidad fina en la depuración.
La estructura de un archivo *.natjmc incluye:
- Ruta del Módulo: La ruta completa del módulo o módulos a considerar como código externo. Se pueden utilizar los caracteres comodín de Windows
?(un solo carácter) y*(cero o más caracteres). - Nombre de la Empresa (Opcional): El nombre de la empresa que publica el módulo, incrustado en el archivo ejecutable.
- Ruta del Archivo de Origen: La ruta de acceso completa al archivo de origen o archivos que se tratarán como código externo. Los caracteres comodín
?y*son aplicables aquí. - Nombre Completo de la Función: El nombre completo de la función que se tratará como código externo. Los caracteres comodín
?y*también son válidos. - Nombre o Ruta del Módulo (Opcional): El nombre o la ruta de acceso completa al módulo que contiene la función.
Además, para proyectos de C++, se pueden especificar funciones para omitir durante la ejecución paso a paso enumerándolas como NoStepInto en archivos *.natstepfilter. Las funciones listadas en estos archivos no dependen de la configuración de "Just My Code". Una función marcada como NoStepInto instruye al depurador a recorrerla sin entrar en su código, incluso si llama a otras funciones o a código de usuario.
La definición de NoStepInto en *.natstepfilter es obligatoria y se basa en expresiones regulares con formato ECMA-262 para especificar el nombre completo de la función que debe coincidir. Por ejemplo, <Name>MyNS::MyClass::.*</Name> indica al depurador que todos los métodos de MyNS::MyClass deben considerarse código que no es de usuario. Opcionalmente, se puede especificar una expresión regular ECMA-262 para la ruta completa del módulo que contiene la función.
Es importante destacar que, a diferencia de los archivos .natvis, los archivos .natstepfilter y .natjmc no se recargan en caliente.
Depuración en Entornos Modernos y Aplicaciones Web
Para proyectos .esproj en Visual Studio 2022, Visual Studio Code utiliza un archivo launch.json para configurar y personalizar el depurador. Visual Studio asocia el depurador únicamente al código de usuario. En el caso de proyectos .esproj, la configuración de "Mi Código" (es decir, "Just My Code") en Visual Studio se realiza a través de la configuración skipFiles en launch.json, que funciona de manera similar a la configuración en VS Code.
La depuración de aplicaciones web, especialmente aquellas que han sido comprometidas por hackers, requiere un enfoque distinto. Una recomendación inicial es desactivar completamente el sitio web y permitir el acceso solo desde direcciones IP propias durante el proceso de limpieza. Esto ayuda a poner el sitio en cuarentena, impidiendo el acceso de atacantes y evitando que los visitantes accedan a contenido infectado. Además, esta medida puede prevenir que motores de búsqueda como Google o MSN bloqueen el sitio.
La forma más sencilla de poner en cuarentena un sitio es editar el archivo .htaccess y configurar el acceso para permitirlo únicamente desde la dirección IP del usuario. Al reemplazar IP_Address con la IP propia, el sitio aparecerá inaccesible para los visitantes.
Para iniciar la limpieza de un sitio web infectado, se deben descargar todos los archivos del sitio al ordenador local mediante FTP y escanearlos con un programa antivirus. El código infectado a menudo es fácil de detectar debido a su ofuscación (cifrado), a diferencia del código limpio y ordenado de aplicaciones de código abierto, que suele incluir comentarios explicativos. Es crucial asegurarse de tener una conexión a Internet segura, preferiblemente WPA2 para conexiones inalámbricas. En casos de malware en WordPress, se puede solicitar ayuda experta a través del Centro de Ayuda en el Área de Usuario del proveedor de hosting.

Estrategias Generales para la Depuración de Código
Independientemente del entorno o lenguaje, la depuración es a menudo descrita como el doble de difícil que escribir el código en primer lugar. Los desarrolladores junior, en particular, buscan soluciones efectivas para abordar errores. Una estrategia útil es clasificar los errores en "tipos" para poder preparar estrategias específicas para cada grupo. Los errores de renderizado en frameworks de componentes, por ejemplo, implican tratar con el DOM y el renderizado de React, y requieren enfoques distintos a otros tipos de problemas.
Las arquitecturas de backend más complejas, con código asíncrono, herramientas basadas en la nube y microservicios, presentan desafíos de depuración incrementales a medida que la aplicación crece. Por esta razón, es imperativo ejecutar el código con frecuencia, idealmente después de cada pequeño cambio (recarga rápida), en lugar de esperar a acumular muchos cambios.
Una pregunta clave durante la depuración es: "¿Cuál fue la última línea de código que actualicé?". Si esta actualización se realizó en el frontend y no se tiene claro cuándo apareció el error, es probable que se hayan realizado muchos cambios desde la última ejecución exitosa.

Interpretación de Códigos de Error
Los códigos de estado HTTP proporcionan información valiosa sobre la naturaleza de los errores en aplicaciones web:
- 400 (Bad Request): Indica un problema del lado del cliente; el servidor esperaba un formato o valores de datos diferentes.
- 401 (Unauthorized): También un problema del lado del cliente, indicando que se está intentando solicitar algo para lo que no se tiene permiso. Podría deberse a la falta de credenciales en la solicitud.
- 403 (Forbidden): Probablemente del lado del cliente, donde las credenciales se incluyen pero podrían ser incorrectas.
Cuando se trabaja con servidores web (como Express, Flask, Django, etc.), es esencial revisar el registro de solicitudes. Estos registros permiten ver cada solicitud realizada al servidor por cualquier cliente, ordenadas por hora exacta, lo que ayuda a identificar patrones o solicitudes problemáticas.
Si los pasos anteriores han sido seguidos correctamente, se debería tener una idea clara de a qué parte del código está relacionado el error. Mantener el enfoque y utilizar la información recopilada es crucial.
Errores de Sintaxis vs. TypeErrors
Los errores de sintaxis generalmente indican la línea exacta donde se encuentra el problema. Por otro lado, los TypeErrors sugieren un problema con el tipo de datos que se está utilizando.
Si la pestaña de red muestra códigos de estado 4xx, indica problemas del lado del cliente. Si muestra códigos 5xx, los problemas residen en el lado del servidor.
Un signo positivo durante la depuración es cuando, al intentar arreglar un error modificando el código, aparece un nuevo error. Esto a menudo significa que se está avanzando en la resolución del problema y se debe confiar en la información recopilada para mantener el enfoque.
El Concepto de "Código Limpio"
Escribir "código limpio" es un objetivo fundamental en el desarrollo de software. Se refiere a código que es fácil de leer, entender y mantener. El código limpio se escribe de manera simple, concisa y expresiva, siguiendo un conjunto de convenciones, estándares y prácticas que facilitan su seguimiento.
El código limpio está libre de complejidad innecesaria, redundancias y otros "code smells" o anti-patrones que pueden dificultar su mantenimiento, depuración y modificación. La importancia del código limpio radica en que, al ser fácil de leer y comprender, los desarrolladores pueden trabajar de manera más eficiente en la base de código, lo que se traduce en una mayor productividad y una reducción de errores. Además, un código fácil de mantener asegura que la base de código pueda ser mejorada y actualizada a lo largo del tiempo, algo esencial para proyectos a largo plazo.
Evaluación de una Base de Código Limpia
Evaluar la limpieza de una base de código se puede hacer de varias maneras. Una buena documentación, un formato consistente y una estructura bien organizada son indicadores de código limpio. Las revisiones de código también son valiosas para identificar problemas potenciales y asegurar que el código siga las mejores prácticas. El testing es otro pilar del código limpio, ya que ayuda a verificar que el código funcione como se espera y a detectar errores tempranamente.
Existen numerosas herramientas, prácticas y convenciones que se pueden implementar para asegurar una base de código limpia. Sin embargo, es importante recordar que existe una subjetividad inherente a este tema, y las opiniones pueden variar. Lo que parece limpio para una persona o proyecto podría no serlo para otro. Aun así, existen convenciones generales que ayudan a lograr un código más limpio.
Principios y Convenciones para Escribir Código Limpio
Eficacia, Eficiencia y Simplicidad: Al implementar nuevas características o resolver problemas, se debe priorizar la eficacia (que el código resuelva el problema), la eficiencia (que lo haga utilizando recursos razonables) y la simplicidad (que sea fácil de entender). La complejidad algorítmica es clave para evaluar la eficiencia.
Formato y Sintaxis Consistentes: Utilizar un formato y sintaxis uniformes en toda la base de código mejora la legibilidad y la comprensión. Herramientas como linters y formateadores de código automatizan estas convenciones. La elección de convenciones de mayúsculas y minúsculas también debe ser consistente.
Denominación Clara y Descriptiva: Nombrar variables y funciones de manera que reflejen claramente sus responsabilidades mejora la legibilidad y mantenibilidad. Por ejemplo, calcularTotalConImpuesto(precio, porcentajeImpuesto) es más descriptivo que calc(a, b).
Concisión vs. Claridad: Es fundamental encontrar un equilibrio. Si bien el código conciso puede mejorar la legibilidad, es igualmente importante que sea claro y fácil de entender. El uso de nombres descriptivos, formateo legible y comentarios ayuda a lograr este equilibrio.
Reusabilidad: La capacidad de reutilizar código sin modificación mejora la eficiencia y productividad del desarrollo, reduce la cantidad de código a escribir y probar, y minimiza el riesgo de errores. En lugar de funciones separadas para cada cálculo de área, una función genérica calcularArea(forma, ...argumentos) es más reutilizable.
Flujo Claro de Ejecución: Un flujo de ejecución claro hace que el código sea más fácil de leer, entender y mantener. Se debe evitar el "código espagueti", que es complejo y difícil de seguir.
Principio de Responsabilidad Única (PRU): Cada clase o módulo debe tener una única razón para cambiar, es decir, una única responsabilidad. Esto facilita la comprensión, el mantenimiento, la prueba y la refactorización del código. Dividir una función procesarPedido en clases separadas como ProcesadorDePedidos y GuardarPedido ejemplifica este principio.
Tener una "Fuente Única de la Verdad": Solo debe existir un lugar donde se almacene un dato o configuración particular. Esto asegura la consistencia de la información y evita duplicaciones y contradicciones. Por ejemplo, una clave API debe almacenarse en un único archivo y ser exportada para su uso.
Exponer y Consumir Solo los Datos Necesarios: Exponer y consumir únicamente la información requerida para una tarea específica reduce la complejidad, aumenta la eficiencia y previene errores derivados del uso de información innecesaria.
Compilación y Limpieza de Proyectos
Visual Studio ofrece funcionalidades para compilar, recompilar o limpiar proyectos o elementos de proyecto dentro de una solución. Se pueden compilar soluciones completas o proyectos específicos, y la ventana "Salida" muestra el progreso y los resultados. La herramienta subyacente es MSBuild. Los comandos como "Compilar solución" o "Compilar proyecto" compilan la configuración actual.
Para proyectos C++, los comandos de compilación, recompilación y limpieza se aplican al proyecto seleccionado, sin afectar directamente a sus dependencias o archivos de solución. Si los archivos tienen dependencias, se compilan en orden. La operación de compilación fallará si los archivos requieren un encabezado precompilado que no está disponible.
La interfaz de usuario de Visual Studio puede variar según la configuración activa, pero los principios generales de compilación, recompilación y limpieza permanecen. La opción "Compilar solo proyectos de inicio y dependencias" al ejecutar, limita la compilación al proyecto de inicio actual y sus dependencias.
En resumen, la depuración efectiva implica una combinación de herramientas especializadas como "Just My Code", técnicas de personalización avanzadas, una comprensión sólida de los principios del código limpio y la aplicación de metodologías de depuración probadas. Dominar estas áreas permite a los desarrolladores abordar desafíos complejos y construir software más robusto y mantenible.