Explorar, corregir, refactorizar y usar Git
Aquí Task Notes se convierte en una pequeña codebase. Aprenderás a orientarte sin leerlo todo, a distinguir una corrección de una refactorización y a usar Git como herramienta de comprensión y recuperación.
Qué trabajarás, paso a paso
Construir un mapa antes de modificar
Ante una codebase nueva, leerlo todo casi siempre es la forma más lenta de entenderla. Necesitas un mapa del recorrido relevante: dónde entra el dato, dónde se transforma, dónde se conserva y dónde aparece.
Explorar no significa abrir cada archivo. Empieza por la estructura, identifica el punto de entrada, sigue los datos desde el límite de entrada hasta la salida y encuentra los tests que describen el comportamiento. Este mapa reduce el contexto y limita las suposiciones.
Pide al agente que cite archivos y símbolos que sostienen su explicación. Si el bug aparece en la interfaz pero nace en el parser, modificar la vista oculta el síntoma sin corregir la causa.
En el CSV la prioridad es `alta`, pero Task Notes la muestra como `normal`.
- Empiezas por el comando de importación e identificas `import_csv()` como entrada, sin abrir todavía todo el proyecto.
- Sigues el valor en `parser.py`: la columna se lee correctamente y se pasa al validador.
- En el validador encuentras una lista que acepta solo valores en inglés; `alta` cae por tanto en el valor predeterminado antes de llegar al store.
- Comparas los tests y la documentación del formato para entender si el contrato prevé italiano, inglés o ambos antes de proponer el parche.
Resultado: La vista no se toca: has localizado el primer punto en el que el dato cambia y además has identificado la decisión de producto que hay que aclarar.
Del síntoma a la hipótesis
El síntoma es lo que observas; la hipótesis es tu explicación provisional. Mantenerlos separados es fundamental: puedes estar seguro del síntoma y aun así equivocarte sobre la causa.
Una buena reproducción contiene entrada, acción y resultado observado. Conviértela en un test que falla antes del parche cuando sea práctico: el test impide que la solución persiga una idea abstracta y se convierte en una protección futura.
Formula una sola hipótesis principal y describe qué debería observar el test si fuera verdadera. Si el experimento la desmiente, actualiza el mapa; no amplíes enseguida el cambio.
- Reproduce.
- Localiza el límite responsable.
- Escribe la hipótesis.
- Haz fallar un test dirigido.
- Aplica el parche mínimo y vuelve a ejecutar.
Un usuario informa de que, al hacer doble clic en «Guardar», a veces aparecen dos tareas idénticas.
- Describes el caso mínimo: título `Pagar factura`, dos clics rápidos, dos registros observados en lugar de uno.
- Formulas la hipótesis de que el botón sigue activo mientras la primera solicitud está en curso; por tanto, prevés dos solicitudes casi simultáneas en el log.
- El test de interacción reproduce los dos clics y falla mostrando dos llamadas. En este punto ya no estás adivinando: el test muestra el comportamiento que habías previsto.
- Deshabilitas el botón durante el guardado, vuelves a ejecutar el mismo test y compruebas además que un error vuelva a habilitar el control para un nuevo intento. Si un duplicado tuviera consecuencias graves, añade también una protección en el servidor: la misma solicitud no debe crear dos registros en caso de retry de red.
Resultado: El test protege tanto la ausencia del duplicado como la posibilidad de volver a intentarlo. El parche responde al comportamiento observado, no a una conjetura genérica sobre la red.
Corregir bugs y refactorizar no son sinónimos
Una corrección y un refactoring pueden tocar la misma función, pero responden a preguntas distintas. La corrección cambia un comportamiento erróneo; el refactoring cambia la estructura sin cambiar el comportamiento protegido.
La corrección de bugs cambia intencionadamente un comportamiento incorrecto. La refactorización mejora la estructura manteniendo el comportamiento verificado. Separarlas hace legible el diff y permite atribuir un posible fallo al cambio correcto.
Si una función es difícil de corregir, aplica primero el parche mínimo. Después de que los tests pasen, evalúa un segundo cambio estructural con tests invariantes. Dos commits cuentan mejor dos intenciones.
`total(100, 20)` devuelve `99.8` porque la función resta `20 / 100` en vez de aplicar el 20 por ciento al precio. Aquí aislamos la fórmula; en una app real, para el dinero usaríamos céntimos enteros o un tipo decimal adecuado.
- Añades el test `total(100, 20) == 80` y lo ejecutas en la versión actual: falla con el valor observado.
- En el primer cambio sustituyes solo la fórmula por `precio * (1 - descuento / 100)` y vuelves a ejecutar los casos existentes.
- Compruebas y registras un diff mínimo que contiene test y fórmula, sin mover la función ni renombrar todo el módulo.
- En un segundo cambio introduces nombres como `porcentaje_descuento` y separas la validación, manteniendo intactos los mismos resultados probados.
Resultado: Puedes publicar o deshacer la corrección independientemente de la limpieza estructural, y cada revisión tiene una pregunta concreta que responder.
Git como red de seguridad legible
Git es útil cuando cuenta una historia comprensible: qué había antes, qué has cambiado y por qué. No es una licencia para borrar a ciegas, sobre todo cuando en la misma carpeta existe trabajo que no pertenece a tu misión.
`status` muestra el estado del trabajo, `diff` cuenta el cambio y un commit atómico conserva un punto comprensible. Antes de restaurar algo, comprueba si existen cambios del usuario que no pertenezcan a la tarea.
Prefiere operaciones recuperables. Un revert añade una corrección a la historia compartida; reescribir o borrar la historia solo puede ser apropiado en un contexto controlado y con autoridad clara.
Has corregido `parser.py`, pero `git status` muestra también cambios en `theme.css` y un archivo nuevo `notes-private.txt` que no has creado.
- No restauras ni añades todo. Examinas el diff de `parser.py` y confirmas que contiene solo el parche y el test acordados.
- No sabes de dónde vienen `theme.css` y el archivo sin seguimiento: los tratas como trabajo ajeno, los dejas intactos y señalas que ya estaban presentes.
- Preparas explícitamente solo los archivos de la corrección y compruebas `git diff --staged` antes del commit.
- Ejecutas el test pertinente y creas un mensaje que describa el comportamiento corregido, no una fórmula vaga como «actualizaciones varias».
Resultado: El commit contiene una sola intención y el trabajo externo permanece en el working tree. La red de seguridad no se convierte en una fuente de pérdida de datos.
Un descuento aplicado incorrectamente
El total de una actividad de pago usa el porcentaje como valor absoluto.
# Error
def total(precio, descuento):
return precio - descuento / 100
# Parche mínimo
def total(precio, descuento):
return precio * (1 - descuento / 100)