CommunityProgramación y desarrollogithub.com

armandkaufmann/refactor-pass

Encuentra qué necesita ser refactorizado en un repositorio git y qué no, midiendo el historial de cambios, los code smells y el coste de la próxima modificación, para generar una lista de tareas priorizada.

¿Qué es refactor-pass?

Este skill devuelve al desarrollador (sea humano o agente de IA) la intuición perdida sobre qué partes del código necesitan refactorización y cuáles es mejor dejar intactas. En lugar de aplicar cambios a ciegas, el skill produce un análisis en tres partes: 1) un mapa de calor del historial de commits que identifica los puntos calientes (archivos que cambian con frecuencia y son grandes), 2) un catálogo de code smells (como Función Larga, Cirugía con Escopeta, etc.) con su playbook de refactorizaciones reconocidas, y 3) un recorrido simulado del próximo cambio planificado para estimar el coste actual frente al coste tras la refactorización. El resultado es una lista priorizada de elementos (R1, R2… para refactorizaciones, F1… para correcciones, L1… para más adelante, D1… para decisiones del usuario) que se presenta en un checklist HTML interactivo. El skill soporta repositorios git con Python, y puede ejecutarse de forma independiente o mediante subagentes para revisar múltiples áreas en paralelo. Está diseñado para Claude Code, Cursor, Codex y otros agentes que trabajen con código fuente.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/armandkaufmann/refactor-pass/tree/HEAD

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Refactor pass

Antes, la refactorización empezaba con una sensación. El código era difícil de trabajar: una clase que había que recorrer con el scroll para encontrar dónde iba lo nuevo, una función que tenías que mantener en la cabeza para cambiar una rama, una característica que implicaba visitar ocho archivos. Esa misma sensación te decía qué dejar en paz. El código feo que nunca tocabas nunca dolía, así que lo dejabas estar.

Un agente que escribe código no siente nada de eso, y tampoco lo siente un desarrollador que principalmente lee lo que el agente escribió. Así que los code smells se acumulan sin ser notados. Un agente añadirá una trigésima rama a una función sin quejarse. Y cuando se le pide que refactorice, ordena lo que sea que parezca desordenado, incluyendo código que nadie toca. Este skill devuelve ambas mitades de la sensación, como tres cosas que se pueden medir:

  1. Dónde lo sentirías: el mapa de calor. La fricción solo importa donde siguen aterrizando los cambios. Según estudios, el tamaño del archivo y la frecuencia con la que cambia predicen problemas de mantenimiento mejor que cualquier olor individual.
  2. Qué sentirías: los olores. El catálogo establecido de code smells, cada uno traducido a qué contar, cuándo no es un olor, y el playbook de refactorizaciones con nombre que décadas de práctica han construido para él: references/smells.md.
  3. Cuánto lo sentirías: el recorrido. Toma el próximo cambio que se avecina, planeado o probable, y enumera todo lo que tocaría.

Entonces el veredicto combina dónde y qué:

HueleNo huele
Cambia a menudoRefactorizaDi que está bien
Rara vez cambiaDéjalo; como mucho una nota de "Después"Nada

La casilla "Di que está bien" es tan importante como la de "Refactoriza". Es la mitad de la moderación de la intuición, y el informe lo muestra.

Dos tamaños de pregunta. Un pase cubre todo el repositorio: pasos 1 a 7. Una pregunta sobre un área ("¿deberíamos refactorizar X?") ejecuta los mismos pasos solo en esa área. Omite la lista de verificación a menos que haya varios elementos, y su respuesta puede ser "no". De cualquier manera, primero ejecuta el script del paso 1 con --checklists solo: si lista una lista de verificación de un pase anterior, lee Después de un pase anterior primero.

1. Dónde: el mapa de calor

python3 <directorio de este skill>/scripts/heatmap.py -C <repo> <ámbito ...>

<directorio de este skill> es la carpeta que contiene este SKILL.md. Donde python3 no sea el comando, como suele ser en Windows, usa python o py.

  • Ámbito: las carpetas de código fuente y las carpetas de pruebas, como src tests o app, no documentos ni activos. Lee el README del proyecto, un listado de directorios y cualquier instrucción del agente (AGENTS.md, CLAUDE.md) para decidir. Los archivos de prueba, identificados por nombre (Board.spec.ts, test_x.py, XTest.php...) o carpeta, quedan fuera de la tabla y los pares, y se enumeran por separado cuando cambian con varios archivos. Añade --test GLOB para otros nombres de prueba, --not-test GLOB para un archivo que solo se parezca a uno (el mapa de calor nombra cualquiera del que dude), y --ignore GLOB para archivos generados.
  • Ventana: por defecto los últimos 200 commits. --since la establece en su lugar cuando el usuario nombra un punto de partida ("desde v2.0", "desde que añadimos facturación", "los últimos tres meses"): una etiqueta, rama o commit, o una fecha. Los commits de bots, las reformateos masivos que un repositorio lista en .git-blame-ignore-revs y los commits registrados en listas de verificación anteriores se omiten automáticamente. --exclude-commits omite otros que harían que todo lo que tocaron pareciera candente, como una importación de un proveedor.
  • ¿Demasiado fino? Con menos de unos 30 commits en la ventana, los recuentos no pueden distinguir archivos calientes de fríos. Amplía la ventana, o di que el historial es demasiado corto para señalar algo y juzga solo por los olores. Un clon superficial (el mapa de calor lo indica) necesita git fetch --unshallow; pregúntale al usuario.

--help explica cada columna y opción.

Leyéndolo

  • Un punto caliente tiene muchos commits y también es grande, por lo que la lista los pone primero: está ordenada por commits por tamaño. Muchos commits en un archivo pequeño a menudo está bien, como una configuración editada para cada característica. Un archivo grande que nadie toca es barato de dejar en paz.
  • ¿Sigue caliente? recent cuenta sus commits en la mitad más nueva de la ventana (la mitad de los commits, no la mitad del tiempo), y last es la fecha de su último. Lee ambos contra las fechas de la ventana: ocho commits recent, todos en el día en que comienza la mitad más nueva, son un estallido que se ha enfriado. Un archivo que se ha reducido puede que ya se haya solucionado.
  • rel son líneas cambiadas sobre el tamaño del archivo. La rotación relativa predice defectos mucho mejor que la rotación absoluta. Muy por encima de 1 significa que el archivo fue reescrito o creció en la ventana. Léelo con growth: un archivo que solo crece, commit tras commit, es Crecimiento Solo Aditivo. Un archivo nacido en la ventana tiene un crecimiento igual a su tamaño.
  • Pares son archivos que siguen cambiando en los mismos commits. Un grupo son tres o más que todos se emparejan entre sí, contados por los commits que los cambiaron a todos; los grupos que se superponen se listan juntos como un área.
    • Los archivos de diferentes capas que se emparejan fuertemente, o un grupo a través de capas, generalmente significan una característica extendida a través de ellas (Cirugía con Escopeta).
    • Comprueba qué vincula cada par. Una importación, una llamada o un contrato que algo nombra (una ruta, un esquema, el archivo de tipos entre un controlador y su página) es una dependencia visible: una característica a través de un límite. Los archivos que cambian juntos sin tal vínculo, como dos copias de una regla o dos listas mantenidas al paso a mano, tienen una dependencia oculta, el tipo de acoplamiento más fuerte.
    • Un archivo que se empareja con muchos otros es un centro por el que pasa cada cambio.
    • Una prueba listada como cambiando con varios archivos además del suyo está ligada a sus internas y bloqueará la refactorización, a menos que esos archivos sean un grupo que la prueba solo sigue.
    • Si muchos commits eran demasiado grandes para emparejarse (--max-files), como en un repositorio que fusiona squash, súbelo o lee los pares como parciales.
  • Por qué cambia. Lee los mensajes de commit de los archivos principales (--show) y agrúpalos por característica. Muchas razones no relacionadas para cambiar un archivo son Cambio Divergente, y esto se muestra aquí más directamente que en cualquier recuento.

2. Qué: los olores

  • Mide los archivos calientes contra el propio código base, dentro de un lenguaje. python3 <directorio de este skill>/scripts/measure.py -C <repo> <ámbito ...> coloca cada archivo en una banda según los percentiles 70, 80 y 90 de su lenguaje, y --show <archivo> cada una de sus funciones. Grande es la banda del 80 o 90 (las bandas también aplican el piso del catálogo); el 70 merece un vistazo más de cerca. Cuando dice que los percentiles se apoyan en un archivo, juzga también por los puntos de referencia en Medición, que también dice cómo contar el resto (ramas, parámetros, cohesión), o usar el linter del proyecto.
  • Lee los dos o tres archivos principales tú mismo. Los números señalan; la lectura decide.
  • Revisa las otras áreas calientes. Si puedes ejecutar subagentes, dales a dos o tres de ellos un área cada uno (una capa o un directorio, para que cada uno lea un área completa una vez) y ejecútalos en paralelo. Instruye a cada uno desde references/review-brief.md. Sin subagentes, revisa las áreas tú mismo, una a la vez, contra el mismo resumen.
  • Nombra cada olor con su nombre establecido (Función Larga, Cirugía con Escopeta, Switches Repetidos...), y compruébalo contra la entrada "No es un olor cuando" antes de que cuente. El nombre es el índice de su playbook.
  • Busca la idea faltante. Los olores viajan en grupos, y un grupo generalmente apunta a una cosa que el código usa todo el tiempo pero nunca nombró: un estado, la definición de un tipo, una única fuente para una configuración. Consulta Los olores viajan juntos.
  • Comprueba qué pruebas alcanzan el código caliente: consulta Código sin probar.
  • Los errores que notes van a la lista como elementos F, no corregidos ahora. Un error aún no reproducido es una sospecha: titúlalo como tal ("Comprobar: las ediciones omiten la regla de fin de semana"), con la evidencia en su nota. Su primer paso es una prueba que falla; si ninguna falla, se omite, con lo que encontraste.

3. Cuánto: el recorrido

Esto es lo más parecido a la vieja sensación. También es lo que hace que un elemento sea convincente.

  1. Encuentra los próximos cambios. Un cambio planeado supera a uno inferido, así que tómalos primero de lo que el usuario dijo que se avecina ("antes de que empecemos con el chunk 7"), luego del plan o la hoja de ruta del proyecto, si la tiene, luego de los mensajes de commit: los tipos de cambio que ocurren con más frecuencia ("añadir un nuevo tipo de informe", "añadir una configuración", "añadir una pantalla"). Toma los dos o tres tipos más comunes, no solo uno.
  2. Para cada tipo, toma el último commit real del mismo y lista lo que tocó (git show --stat). Si es más antiguo que la ventana, úsalo de todos modos y da su fecha; el recorrido, sobre el código de hoy, muestra lo que se ha movido desde entonces. Si los documentos o las instrucciones del agente del proyecto tienen una receta para ese cambio, cuenta sus pasos. Una receta de cinco pasos para añadir una cosa es una admisión.
  3. Recorre el próximo, sin escribirlo. Lista cada archivo que tendrías que leer, cada lugar que editarías y cada copia que mantendrías al día.
  4. Escribe el recuento de hoy y el recuento después de la refactorización que propondrías: "un nuevo tipo de informe toca 7 archivos y 3 switches hoy, y tocaría 1 archivo después".

Un archivo frío en el que aterrizará el trabajo planificado ya no es frío: ponlo en la fila superior de la tabla, ya que el próximo cambio paga lo que cueste. Si el próximo cambio es barato hoy, el olor cuesta poco, tenga el aspecto que tenga.

4. Comprueba cada hallazgo

Un hallazgo de un revisor es una pista, no un hecho, y lo mismo ocurre con tus propias primeras impresiones. Antes de que algo vaya a la lista, abre las líneas citadas, vuelve a ejecutar los recuentos y descarta o corrige lo que no se sostenga. Di en el informe qué comprobaste. Un elemento incorrecto que envíe al usuario a una refactorización cuesta mucho más que el minuto que se tarda en comprobarlo.

Luego aplica la moderación. Un revisor al que se le pide encontrar problemas siempre encontrará algo, y arreglar cada hallazgo deja capas y pruebas adicionales para casos que no pueden ocurrir. Deja fuera lo que está frío, lo que las líneas "No es un olor cuando" excusan, y lo que el recorrido dice que es barato.

5. Clasifica

Dale a cada elemento un ID estable, porque el usuario nombrará los elementos por él ("empezar R4"), posiblemente en una sesión posterior. Los nombres entre corchetes son los campos del elemento en la lista de verificación (paso 6); los elementos F, L y D dicen los suyos en un note.

  • R1, R2… Refactorizaciones, en el orden sugerido. Para cada una:
    • un título que nombre la idea faltante, como un resultado ("Nombrar los estados de un checkout", no "Refactorizar CheckoutController") (title);
    • los olores por nombre, con números y archivo:línea (smells);
    • el tipo de cambio que facilita, del paso 3 (eases), y el coste de ese cambio (cost: today y after);
    • el plan, como los pasos del playbook (plan);
    • los archivos, tamaño (S, M o L) y riesgo (Bajo, Medio o Alto) (files, size, risk);
    • cómo comprobar que el comportamiento no cambió (verify).
  • F1… Pequeñas correcciones encontradas en el camino, cada una su propio commit.
  • L1… Después: con olor pero frío, o que vale la pena hacer cuando se toque a continuación el código cercano.
  • D1… Decisión del usuario: cambios en cómo trabajan, como una convención de documentación que hace que cada cambio sea costoso. Expón el equilibrio, no una decisión.

Clasifica por beneficio frente a riesgo. El beneficio es cuánto facilita el cambio el trabajo futuro: el mapa de calor y el recorrido son la evidencia. Las prioridades de los olores dicen qué tipos tienden a importar más. El código largo y complejo, y el cambio repartido entre archivos, importan más. Los olores de acoplamiento como Envidia de Característica y Hombre de En medio importan menos, y se arreglan de paso.

Ordena la lista de modo que:

  • los bloqueadores vengan primero: pruebas ligadas a internas que harían que cada paso posterior pareciera que rompió algo, y código que ninguna prueba cubre, cuyo elemento comienza con fijar pruebas o dice claramente que no se puede comprobar (paso 7);
  • los elementos pequeños que eliminan una ruta de copiar y pegar vengan después;
  • los movimientos grandes vengan después, ya que a menudo necesitan primero una costura;
  • cualquier cosa que no puedas verificar tú mismo (cómo suena, se siente o se ve) venga al final, porque el usuario tiene que comprobarlo.

6. Escribe la lista de verificación y el informe

Vuelve a ejecutar el comando del paso 1 con --page .refactor-pass/<YYYY-MM-DD>.html, con la fecha de hoy. Crea la lista de verificación a partir de assets/page.html y escribe el mapa de calor en su bloque heatmap; si lo ejecutas de nuevo, actualiza el mapa de calor y nada más. Tú escribes el bloque pass debajo de él, cuyos project, started, base y updated ya están completados:

  • summary: el estado general en dos o tres frases;
  • items: cada elemento, con los campos del paso 5, un status (todo, doing, waiting en el usuario, done, o skipped con la razón en su outcome), y commits y outcome, vacío para un elemento nuevo; un elemento arrastrado conserva su from. Cada elemento comienza con su ID y estado en una línea, {"id": "R1", "status": "todo",, con sus otros campos después, como muestra el comentario sobre los bloques en su totalidad; no como lo presenta un bonito formateador de JSON, ya que las actualizaciones de estado del paso 7 editan esa única línea;
  • left_alone: cada uno con what y why;
  • checks: las comprobaciones del proyecto, de sus instrucciones, o lo que comprobarás a mano si no tiene ninguna;
  • earlier: después de un pase anterior, su checklist y results, uno por refactorización terminada en él: su id, title, eases y cost, el change real que vino después y lo que actualmente tocó (ambos vacíos si aún no ha llegado ninguno), y un note. En caso contrario, null;
  • log: cada uno con un date y text, el más reciente primero.

Después de cada edición, ejecuta python3 <directorio de este skill>/scripts/check_page.py <página>, que detecta un corchete roto, un campo mal escrito, un ID duplicado o un elemento que no comienza en una línea. Si tu entorno puede publicar o previsualizar páginas HTML, proporciona una previsualización de la página; si no, describe cómo se vería la página basándote en assets/page.html y di dónde está cada elemento.

Reabriendo una lista de verificación existente

Si volvemos a un pase del día fecha, ejecuta el comando del paso 1 con --page .refactor-pass/<fecha>.html, establece el base en el commit de hoy, actualiza updated, y en items cambia a "status": "doing" cualquier cosa que aún no esté done o skipped. Si el proyecto ha cambiado significativamente, considera comenzar de nuevo.

7. Refactoriza, un elemento a la vez

Los elementos están ordenados para que cada uno deje el código listo para el siguiente, pero debes hacer uno a la vez y volver a verificar: la refactorización cambia las mediciones.

  1. Desde la parte superior de la lista, toma el primer elemento que no esté done ni skipped. Si es un elemento L (después), pregúntale al usuario si debe hacerse ahora o dejarse hasta que se toque el código que lo rodea.
  2. Ejecuta las pruebas. Donde la verificación del elemento (paso 5) diga que sus pruebas son fiables, confía en que las pruebas pasan o fallan. Donde diga que las pruebas son lentas, poco fiables o inexistentes, compruébalo a mano o con el método de verificación del elemento. Una prueba que falla o una verificación que muestra un cambio de comportamiento detiene el elemento; no lo arregles de inmediato. Anota el hallazgo como nuevo elemento (probablemente una corrección), vuelve a la comprobación y, a continuación, retrocede el cambio. Si no puedes determinar la causa, el elemento se omite (skipped) con lo que encontraste.
  3. Confirma con un mensaje que nombre el elemento ("R3: Nombrar los estados de un checkout") y el olor que arregla ("Función Larga").
  4. Actualiza el estado del elemento en la página a done, y añade su commit a commits. Opcionalmente, escribe un breve outcome.
  5. Mide de nuevo el mapa de calor y los olores para el elemento siguiente. Ejecuta --page de nuevo para actualizar el mapa de calor, y vuelve a ejecutar la medición. Si la clasificación ya no tiene sentido (se ha vuelto más barato mover un archivo grande ahora que su vecino ha sido extraído, o más arriesgado porque la cobertura de pruebas ha cambiado), ajusta el orden antes de continuar. Los IDs estables permiten que la lista se reordene sin romper las referencias.

Después de un pase anterior

Cuando se lee un --checklists existente, significa que el usuario quiere una nueva pasada sobre un repositorio que ya ha sido refactorizado. Lee el informe anterior. El anterior se ha ido; las decisiones que tomó, buenas o malas, son el estado actual. Los elementos que quedaron L (después) o D (decisión del usuario) pueden o no seguir siendo relevantes. Los elementos R completados pueden haber sido revertidos o mejorados; vuelve a medir cualquier cosa a la que se refiera el usuario o que muestre el mapa de calor. La sección earlier registra lo que sucedió realmente desde entonces; léela.

La respuesta del informe anterior fue una fotografía. La nueva pasada es otra. Si el mismo olor persiste, el elemento anterior puede no haberlo arreglado realmente, o no del todo; el nuevo elemento puede ser una continuación. Ponlo como un nuevo elemento con "from": "R3" si desciende del anterior, o como L si el anterior lo declaró arreglado y ha vuelto.

Skills relacionados