Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/50-loops/90-debug/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
@ test.sh
140 changes: 140 additions & 0 deletions modules/50-loops/90-debug/description.es.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---

name: Depuración
theory: |

Incluso a los desarrolladores más experimentados rara vez les funciona el código a la perfección al primer intento. Cuanto más experimentado es el desarrollador, con más confianza lo **depura**, es decir, analiza los errores y los corrige.

La habilidad de depuración no aparece por sí sola. Hay que desarrollarla, y cuanto antes mejor. A lo largo del aprendizaje realizarás tareas y practicarás, y con el tiempo el análisis de errores se convertirá en un hábito.

## Cómo encontrar un error en el código

Depurar a base de prueba y error lleva mucho tiempo. Es mucho más productivo entender primero qué salió mal y luego corregir la causa. Todo trabajo con errores comienza con la comprensión.

Lo primero es estudiar la **pila de llamadas** (stack trace). Contiene una lista de todas las llamadas a funciones desde el punto del error hasta el inicio del programa. Muestra qué funciones se ejecutaron y dónde surgió el problema. Cada entrada indica un archivo, una línea y la función que se estaba ejecutando.

Imagina que escribiste código en un archivo `users.js` y llamaste a la función `main()`, que internamente llama a una `create()` inexistente:

```javascript
const main = () => {
create();
};

main();
```

Al ejecutarlo verás una salida así:

```bash
ReferenceError: create is not defined
at main (users.js:2:3)
at users.js:5:1
```

La primera línea es el **mensaje de error**. Aquí `ReferenceError: create is not defined` dice que el nombre `create` no está definido. Este error suele significar un error tipográfico en el nombre.

Debajo está la propia pila de llamadas. Se ve que el programa llegó a `main()` (línea 5), dentro de ella llamó a `create()` (línea 2) y aquí se topó con el error. Cada entrada `at ...` indica un archivo y una línea.

## Tipos de errores

Los errores más comprensibles son los **errores de sintaxis**. Surgen cuando el código está mal formateado, por ejemplo, por un paréntesis sin cerrar o comillas que no coinciden. La salida siempre contiene `SyntaxError`:

```bash
console.log("Hello" + 'world);
^^^^^^^^
SyntaxError: Invalid or unexpected token
```

Los más difíciles de corregir son los **errores de programación**. Entre ellos están llamar a una función inexistente, usar una variable no declarada o pasar argumentos de tipo incorrecto. Suelen aparecer en un lugar distinto al de la causa real, lo que dificulta el diagnóstico.

Los más difíciles de combatir son los **errores lógicos**. El programa funciona sin excepciones, pero produce un resultado incorrecto con ciertos datos de entrada. No hay ningún mensaje de error, solo una salida inesperada. Por ejemplo, una función que debería calcular la suma pero calcula la diferencia:

```javascript
// La función debería calcular la suma de los números, pero calcula la diferencia:
const sum = (a, b) => a - b;

// Con esta llamada el error no es evidente, porque
// tanto la suma como la resta dan el mismo resultado
sum(4, 0); // 4
```

## Métodos de depuración

En la base de cualquier método de depuración está la observación de las variables durante la ejecución. Veamos una función concreta.

A continuación, una función que calcula la suma de los números desde `start` hasta `finish`. Con `start=3` y `finish=5` debería calcular `3 + 4 + 5`.

```javascript
const sumOfSeries = (start, finish) => {
let result = 0;
let n = start;
while (n < finish) {
result = result + n;
n = n + 1;
}

return result;
};
```

Las variables clave de esta función son `n` y `result`. Para encontrar el error, hay que ver qué valores toman en cada iteración.

Para ello existen los **depuradores visuales**. Se integran en los editores de código populares y permiten ejecutar el programa paso a paso, observando las variables en tiempo real. Puedes encontrar uno buscando «JavaScript debuggers» en Google.

En el entorno de Hexlet, en lugar de un depurador se usa la **impresión de depuración**. El principio es el mismo, solo que los valores de las variables se imprimen con el habitual `console.log`. Lo que se imprime aparece en la pestaña `OUTPUT`.

```javascript
const sumOfSeries = (start, finish) => {
let result = 0;
let n = start;
while (n < finish) {
console.log('new iteration !!!!');
console.log(n);
result = result + n;
n = n + 1;
console.log(result);
}

return result;
};

sumOfSeries(3, 5);

// new iteration !!!!
// 3
// 3
// new iteration !!!!
// 4
// 7
```

La salida muestra que hay una iteración menos de las necesarias. El cinco (`finish`) no entró en la suma. La condición usa `n < finish` en lugar de `n <= finish`. Hay que reemplazar el signo `<` por `<=`.

Los principiantes a menudo se molestan por los errores y se consideran descuidados. Todos cometen errores, tanto los junior como los senior. La diferencia está en con cuánta seguridad los encuentras.

Los principiantes piensan que un buen desarrollador mira el código y entiende de inmediato qué está mal. Esto rara vez funciona en la práctica. Un fragmento de código sin contexto dice muy poco. **Si quieres pedir consejo a un desarrollador experimentado, lo primero es mostrarle el mensaje de error.**

instructions: |

Implementa la función `compress(str)` que comprime una cadena usando RLE (Run-Length Encoding).

Algoritmo: si un carácter se repite consecutivamente, se reemplaza por el carácter y la cantidad. Los caracteres individuales se escriben sin número.

```javascript
compress('aaabcccc'); // => 'a3bc4'
compress('abcd'); // => 'abcd'
compress('aabbaa'); // => 'a2b2a2'
compress(''); // => ''
```

Este algoritmo se utiliza en formatos reales de compresión de datos, por ejemplo, en antiguos protocolos de fax y archivos BMP.

### Algoritmo

1. Recorrer la cadena contando la cantidad de caracteres idénticos consecutivos.
2. Cuando el carácter cambie, escribir el carácter anterior y el contador (si es mayor que 1).
3. No olvidar procesar el último grupo después de que termine el bucle.

tips: []

definitions: []
18 changes: 18 additions & 0 deletions modules/50-loops/90-debug/en/EXERCISE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Implement the `compress(str)` function that compresses a string using RLE (Run-Length Encoding).

Algorithm: if a character repeats consecutively, replace it with the character and the count. Single characters are written without a number.

```javascript
compress('aaabcccc'); // => 'a3bc4'
compress('abcd'); // => 'abcd'
compress('aabbaa'); // => 'a2b2a2'
compress(''); // => ''
```

This algorithm is used in real compression formats — for example, in old fax protocols and BMP files.

### Algorithm

1. Walk through the string, counting consecutive identical characters.
2. When the character changes — write the previous character and counter (if greater than 1).
3. Don't forget to handle the last group after the loop ends.
110 changes: 110 additions & 0 deletions modules/50-loops/90-debug/en/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
Even experienced developers rarely get their code working perfectly on the first try. The more experienced the developer, the more confidently they **debug** it — that is, analyze errors and fix them.

Debugging skills don't appear on their own. They must be developed, and the sooner you start, the better. During your studies you'll complete assignments and practice, and over time analyzing errors will become a habit.

## How to find a bug in code

Debugging by trial and error takes a lot of time. It's far more productive to first understand what exactly went wrong, and only then fix the cause. Any work with errors starts with understanding.

First, study the **stack trace**. It contains a list of all function calls from the point of the error back to the start of the program. It shows which functions ran and where the problem occurred. Each entry points to a file, a line, and the function being executed.

Imagine you wrote code in a file `users.js` and called the function `main()`, which internally calls a non-existent `create()`:

```javascript
const main = () => {
create();
};

main();
```

When you run it, you'll see output like this:

```bash
ReferenceError: create is not defined
at main (users.js:2:3)
at users.js:5:1
```

The first line is the **error message**. Here `ReferenceError: create is not defined` says that the name `create` is not defined. This error most often means a typo in the name.

Below it is the stack trace itself. You can see that the program reached `main()` (line 5), called `create()` inside it (line 2), and ran into the error here. Each `at ...` entry points to a file and a line.

## Types of errors

The simplest errors are **syntax errors**. They occur when the code is formatted incorrectly, for example because of an unclosed bracket or mismatched quotes. The output always contains `SyntaxError`:

```bash
console.log("Hello" + 'world);

Check notice on line 38 in modules/50-loops/90-debug/en/README.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] modules/50-loops/90-debug/en/README.md#L38

Unpaired symbol: ‘'’ seems to be missing (EN_UNPAIRED_QUOTES) URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US Category: PUNCTUATION
Raw output
modules/50-loops/90-debug/en/README.md:38:20: Unpaired symbol: ‘'’ seems to be missing (EN_UNPAIRED_QUOTES)
 URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses 
 Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US
 Category: PUNCTUATION
^^^^^^^^
SyntaxError: Invalid or unexpected token
```

The hardest to fix are **programming errors**. These include calling a non-existent function, using an undeclared variable, or passing arguments of the wrong type. They usually occur far from where the real cause is, which makes diagnosis harder.

The most difficult are **logic errors**. The program runs without exceptions but produces an incorrect result for certain inputs. There's no error message, only unexpected output. For example, a function that should calculate the sum but calculates the difference:

```javascript
// The function should calculate the sum of numbers, but calculates the difference:
const sum = (a, b) => a - b;

// With this call the error is not obvious, because
// both addition and subtraction give the same result
sum(4, 0); // 4
```

## Debugging methods

At the heart of every debugging method lies observing variables as the code runs. Let's look at a specific function.

Below is a function that calculates the sum of numbers from `start` to `finish`. With `start=3` and `finish=5` it should calculate `3 + 4 + 5`.

```javascript
const sumOfSeries = (start, finish) => {
let result = 0;
let n = start;
while (n < finish) {
result = result + n;
n = n + 1;
}

return result;
};
```

The key variables in this function are `n` and `result`. To find the bug, we need to see what values they take on each iteration.

For this there are **visual debuggers**. They are built into popular code editors and let you run the program step by step, watching variables in real time. You can find one by searching Google for "JavaScript debuggers".

In the Hexlet environment, instead of a debugger we use **print debugging**. The principle is the same, only variable values are printed with the usual `console.log`. What is printed appears in the `OUTPUT` tab.

```javascript
const sumOfSeries = (start, finish) => {
let result = 0;
let n = start;
while (n < finish) {
console.log('new iteration !!!!');
console.log(n);
result = result + n;
n = n + 1;
console.log(result);
}

return result;
};

sumOfSeries(3, 5);

// new iteration !!!!
// 3
// 3
// new iteration !!!!
// 4
// 7
```

The output shows there is one fewer iteration than needed. The five (`finish`) wasn't included in the addition. The condition uses `n < finish` instead of `n <= finish`. We need to replace the `<` sign with `<=`.

Beginners often get upset about errors and think they are inattentive. Everyone makes errors — both juniors and seniors. The difference is how confidently you find them.

Beginners think that a good developer looks at code and immediately understands what's wrong. This rarely works in practice. A snippet of code without context says very little. **If you want to ask an experienced developer for advice, first show them the error message.**
4 changes: 4 additions & 0 deletions modules/50-loops/90-debug/en/data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
name: Debugging
tips: []
definitions: []
18 changes: 18 additions & 0 deletions modules/50-loops/90-debug/es/EXERCISE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Implementa la función `compress(str)` que comprime una cadena usando RLE (Run-Length Encoding).

Algoritmo: si un carácter se repite consecutivamente, se reemplaza por el carácter y la cantidad. Los caracteres individuales se escriben sin número.

```javascript
compress('aaabcccc'); // => 'a3bc4'
compress('abcd'); // => 'abcd'
compress('aabbaa'); // => 'a2b2a2'
compress(''); // => ''
```

Este algoritmo se utiliza en formatos reales de compresión de datos, por ejemplo, en antiguos protocolos de fax y archivos BMP.

### Algoritmo

1. Recorrer la cadena contando la cantidad de caracteres idénticos consecutivos.
2. Cuando el carácter cambie, escribir el carácter anterior y el contador (si es mayor que 1).
3. No olvidar procesar el último grupo después de que termine el bucle.
Loading
Loading