Communitygithub.com

caseycme/skills

Guía la refactorización sistemática para alinear funcionalidades con patrones establecidos, eliminar duplicaciones y mejorar la reutilización de código. Incluye orientación sobre DataGrid/pattern-library, tipado, paginación de fetch, view-model vs override-prop, y diseño MUI sx-first (evitar props shorthand de estilo obsoletas de Box). Úsalo al refactorizar funcionalidades, consolidar código duplicado, extraer utilidades compartidas o alinear patrones entre funcionalidades similares.

¿Qué es skills?

Este skill está diseñado para guiar a un agente de IA (como Claude Code) en el proceso de refactorización sistemática de una base de código, asegurando la alineación con patrones establecidos, eliminando duplicación y mejorando la reutilización del código. Es útil para desarrolladores que trabajan con proyectos React, TypeScript y Material-UI (MUI), especialmente aquellos que utilizan Next.js App Router y una librería de diseño o 'pattern-library'. El skill detalla un proceso paso a paso que incluye: análisis previo para identificar características similares y oportunidades de duplicación, extracción de código compartido a directorios de utilidades, consolidación de componentes, alineación de patrones de carga y estilos, y verificación de la consistencia general. También incluye una sección de 'code review hardening' con pautas muy específicas para evitar regresiones comunes, como el uso de `DetailPanelToggle` de pattern-library en DataGrids, la definición de interfaces compartidas para evitar tipos anónimos, la preferencia por `Typography` sobre `Box` para texto, y la implementación correcta de la paginación en fetches. El skill está pensado para plataformas como Cursor, Codex o Claude Code, y su contenido se basa en un archivo SKILL.md que contiene las reglas detalladas.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/caseycme/skills/tree/HEAD/skills/engineering/refactoring

Preguntar en tu IA favorita

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

Documentación

Skill de Refactorización

Usa este skill al refactorizar funcionalidades para alinearlas con patrones establecidos, eliminar duplicación y mejorar la reutilización de código.

Para saber si una UI pertenece a pattern-library o a una composición local, usa el skill design-system.

Análisis Previo a la Refactorización

1. Identificar Funcionalidades Similares

  • Encuentra funcionalidades comparables en la base de código con funcionalidad similar
  • Compara estructuras de directorios, patrones de componentes y uso de utilidades
  • Busca funcionalidades con funcionalidad similar pero implementaciones diferentes
  • Usa búsqueda semántica para encontrar funcionalidades relacionadas: "funcionalidades con patrones de tabla/cuadrícula de datos similares"

2. Encontrar Oportunidades de Duplicación

Busca patrones de código duplicado:

  • Componentes: Busca archivos de componentes similares entre funcionalidades (mismo nombre o funcionalidad similar)
  • Hooks: Verifica lógica duplicada de hooks (hooks de tabla, hooks de filtro, hooks de agregación)
  • Utilidades: Encuentra funciones de utilidad duplicadas (agregaciones, formateadores, validadores, transformadores)
  • Estilos: Identifica patrones de prop sx duplicados o estilos en línea
  • Constantes: Verifica constantes u objetos de configuración duplicados
  • Tipos: Busca definiciones de tipos o interfaces duplicadas

3. Verificar Utilidades Compartidas

Antes de crear nuevas utilidades, verifica las existentes:

  • Busca en directorios @/util/ utilidades específicas de dominio
  • Revisa @/util/dates para funciones de formato de fechas
  • Revisa @/util/numbers para funciones de formato de números
  • Revisa @/components/ para componentes reutilizables
  • Revisa pattern-library para componentes del sistema de diseño
  • Usa grep/búsqueda para encontrar implementaciones existentes antes de crear nuevas

Proceso de Refactorización

Paso 1: Extraer Código Compartido

Al encontrar duplicados:

  1. Crea utilidades compartidas en los directorios @/util/ apropiados:

    // Ejemplo: util/[domain]/[category].ts
    export const sharedFunction = () => { ... };
    export const sharedConstant = { ... };
    
  2. Actualiza todas las funcionalidades para importar desde la ubicación compartida:

    // Archivo específico de funcionalidad - reexportar compartido
    export { sharedFunction, sharedConstant } from "@/util/[domain]/[category]";
    
  3. Elimina implementaciones duplicadas de los directorios de funcionalidades

  4. Actualiza todas las importaciones en la base de código

Paso 2: Consolidar Componentes

Al encontrar componentes duplicados:

  1. Identifica la versión más completa/rica en funcionalidades (verifica props, funcionalidad, pruebas)
  2. Extrae a una ubicación compartida (@/components/ o ubicación independiente de funcionalidad)
  3. Haz las props flexibles para soportar todos los casos de uso (usa tipos unión, props opcionales o genéricos)
  4. Actualiza importaciones en todas las funcionalidades que usan el componente
  5. Elimina archivos de componentes duplicados
  6. Verifica que todos los usos sigan funcionando correctamente

Paso 3: Alinear Patrones de Carga

Para estados de carga:

  1. Verifica archivos loading.tsx - deben ser esqueletos simples, no diseños de página completos
  2. Elimina cargadores de esqueleto a nivel de componente - confía en loading.tsx a nivel de página para la carga inicial
  3. Durante recargas (refetches): Muestra datos existentes, no esqueletos (a menos que sea explícitamente necesario para UX)
  4. Coincide con patrones de funcionalidades similares en la base de código
  5. Usa las convenciones de Next.js App Router - loading.tsx maneja la carga inicial, los componentes manejan estados de recarga

Paso 4: Consolidar Estilos

Para estilos:

  1. Extrae patrones de estilo reutilizables a componentes compartidos o utilidades de estilo
  2. Elimina props sx en línea cuando exista un componente compartido
  3. Usa componentes del sistema de diseño de pattern-library en lugar de estilos personalizados
  4. Verifica objetos de estilo duplicados que podrían ser utilidades compartidas o extensiones de tema
  5. Sigue patrones de Material-UI - usa valores del tema, evita números mágicos

Paso 5: Verificar Alineación de Patrones

Asegura la consistencia con funcionalidades establecidas:

  1. Compara estructuras de directorios - deben seguir patrones similares (_components/, _hooks/, _utils/)
  2. Verifica patrones de hooks - hooks más simples están bien si los requisitos de la funcionalidad difieren
  3. Verifica el flujo de datos - debe coincidir con funcionalidades similares cuando sea posible
  4. Revisa la composición de componentes - debe usar patrones similares (wrappers, composición, etc.)
  5. Verifica convenciones de nomenclatura - sigue patrones establecidos (PascalCase para componentes, camelCase para hooks)

Paso 6: Consolidación de Funciones de Utilidad

Para funciones de utilidad:

  1. Verifica si la función existe primero en utilidades compartidas (busca en la base de código)
  2. Compara implementaciones - usa la versión más completa/robusta
  3. Consolida duplicados - mueve a una ubicación compartida, actualiza todas las importaciones
  4. Documenta diferencias - si las implementaciones difieren intencionalmente, documenta por qué
  5. Preserva la funcionalidad - asegura que la versión consolidada maneje todos los casos de uso

Paso 7: Limpiar Comentarios

Después de la refactorización, elimina comentarios innecesarios:

  1. Elimina notas de migración - Comentarios que explican de dónde se movió el código (ej., "isCollecting ahora se exporta desde Table/utils.ts")
  2. Elimina comentarios obvios - Comentarios que solo repiten lo que hace el código (ej., "// Reexportar agregaciones compartidas" cuando el código muestra claramente las reexportaciones)
  3. Mantén comentarios explicativos - Comentarios que explican POR QUÉ se hace algo (ej., "// Usar setTimeout para asegurar que el estado del formulario se actualice")
  4. Mantén comentarios de lógica compleja - Comentarios que explican lógica de negocio no obvia o casos límite
  5. Elimina comentarios TODO/FIXME - A menos que sean elementos de trabajo futuro legítimos

Ejemplos de comentarios innecesarios:

// ❌ Innecesario - obvio por el código
// Reexportar agregaciones compartidas desde util
export { latest, totalRange } from "@/util/keywords/gridAggregations";

// ❌ Innecesario - nota de migración, ya no es necesaria
// isCollecting ahora se exporta desde Table/utils.ts para evitar duplicación
// Impórtalo desde allí: import { isCollecting } from "../KeywordListDetail/Table/utils";

Ejemplos de buenos comentarios:

// ✅ Bueno - explica POR QUÉ
// Usar setTimeout para asegurar que el estado del formulario se actualice después del procesamiento CSV
setTimeout(() => {
  void handleSubmit(onSubmit)();
}, 100);

// ✅ Bueno - explica lógica compleja
// Una palabra clave se actualiza si:
// 1. Su valor lastUpdated cambió (el indicador más fiable), O
// 2. Ya no está en estado de recolección Y hemos sondeado suficientes veces (fallback)

Paso 8: Mejoras de Calidad de Código

Aplica patrones de calidad de código consistentes en todo el código refactorizado:

Comprobaciones de Null/Undefined

Simplifica las comprobaciones de null y undefined usando igualdad débil:

// ❌ Verboso
if (value !== undefined && value !== null) { ... }
if (value !== undefined && value !== null && value !== "") { ... }

// ✅ Simplificado
if (value != null) { ... }
if (value != null && value !== "") { ... }

Nota: Usa != null (igualdad débil) para comprobar tanto null como undefined en una sola comprobación. Esto es idiomático en TypeScript/JavaScript y más conciso.

Importaciones Solo de Tipo

Usa import type para importaciones solo de tipo para mejorar el rendimiento de compilación y hacer la intención clara:

// ❌ Importación en tiempo de ejecución para uso solo de tipo
import { SomeType } from "app-api/types/domain";

// ✅ Importación solo de tipo
import type { SomeType } from "app-api/types/domain";

Aplica a:

  • Definiciones de tipo de app-api
  • Importaciones de interfaces
  • Tipos de utilidad solo de tipo
  • Cualquier importación usada solo en anotaciones de tipo

Eliminar Aserciones de Tipo Innecesarias

Elimina aserciones de tipo cuando TypeScript pueda inferir el tipo correctamente:

// ❌ Aserción innecesaria
const items = data.map((item) => item as SomeType);

// ✅ Deja que TypeScript infiera
const items = data.map((item) => item);

Cuándo mantener aserciones: Solo cuando TypeScript genuinamente no pueda inferir el tipo, o al estrechar tipos de una manera que TypeScript no pueda verificar.

Eliminar Coalescencia Nula Innecesaria

Elimina ?? null cuando el valor ya sea nullable o TypeScript infiera el tipo correcto:

// ❌ Innecesario - valueGetter ya devuelve nullable
valueGetter: (value, row) => {
  return row.someField ?? null;
};

// ✅ Simplificado
valueGetter: (value, row) => {
  return row.someField;
};

Cuándo mantener: Cuando se convierta explícitamente undefined a null para compatibilidad con API o cuando el sistema de tipos lo requiera.

Eliminar Props No Usadas

Elimina props de interfaces de componentes e implementaciones cuando no se usen:

// ❌ Prop no usada
interface ComponentProps {
  item: Item;
  unusedField: string; // Nunca se usa en el componente
}

// ✅ Interfaz limpia
interface ComponentProps {
  item: Item;
}

Agregar Tipos Explícitos a Callbacks

Agrega anotaciones de tipo explícitas a parámetros de callback cuando TypeScript no pueda inferirlos:

// ❌ any implícito
const items = ids.map((id) => { ... });

// ✅ Tipo explícito
const items = ids.map((id: string | number) => { ... });

Aplica a: Métodos de array (map, filter, forEach), manejadores de eventos y otros callbacks donde los tipos no sean claros por contexto.

Extraer Patrones JSX Repetidos

Extrae patrones JSX repetidos en componentes reutilizables:

// ❌ Patrón repetido
{
  isAggregation ? (
    <Typography
      variant="body2"
      fontWeight="medium"
      fontStyle="italic"
      color="text.secondary"
    >
      {formattedValue}
    </Typography>
  ) : (
    <Typography variant="body2" fontWeight="medium">
      {formattedValue}
    </Typography>
  );
}

// ✅ Componente extraído
<AggregationTypography
  formattedValue={formattedValue}
  isAggregation={isAggregation}
/>;

Usar Funciones Fábrica para Implementaciones Variadas

Cuando la lógica es similar pero necesita manejar diferentes estructuras de datos, usa funciones fábrica:

// ✅ Patrón de función fábrica
export const createIntentOperators = <T extends { intent?: Intent | Intent[] }>(
  normalizeToArray: (value: T) => Intent[]
) => {
  return {
    // Operadores que trabajan con array normalizado
  };
};

// Uso en diferentes funcionalidades
const operators1 = createIntentOperators<Feature1Type>((item) => [item.intent]);
const operators2 = createIntentOperators<Feature2Type>(
  (item) => item.intents || []
);

Beneficios: Reutiliza la lógica central mientras permite que diferentes estructuras de datos se manejen adecuadamente.

Refuerzo de Revisión de Código (comentarios recurrentes)

Aplica estos cuando la refactorización toque cuadrículas (grids), paneles (dashboards), fetches o formas compartidas de "fila + métricas" (se alinea con comentarios repetidos en PR de Moz Pro UI).

DataGrid: alternancia de panel de detalle

  • Prefiere DetailPanelToggle de pattern-library para expandir/colapsar en una columna de panel de detalle en lugar de un IconButton + @mui/icons ad hoc en una celda personalizada.
  • Conecta accesibilidad: pasa buttonTabIndex={0} cuando la celda deba poder recibir foco mediante tabulación (ver app/(default)/competitive-research/top-competing-content/_module/components/Table/columns.tsx, SerpFeaturesCell).
  • Diseño / centrado: usa sx en Box/Stack (o direction / spacing de Stack cuando ese sea el patrón establecido). No reemplaces sx con props de estilo de sistema heredadas de MUI en Box (ej., display, alignItems como props de nivel superior)—MUI está deprecando ese enfoque en favor de sx.

Tipado: evita formas de fila object / anónimas

  • No uses readonly object[] para brand_definitions, fragmentos de fila o listas adyacentes a API cuando exista un tipo estructural o se pueda definir una vez.
  • Define una interfaz "como" compartida (ej., BrandDefinitionLike) en el módulo utils de la funcionalidad; expórtala y un helper de línea de visualización único (ej., getBrandDefinitionDisplayLine) en lugar de duplicar getBrandName con casts dentro de celdas.
  • Elimina casts redundantes (as BrandDefinitionLike[]) después de tipar los parámetros.
  • Reutiliza helpers de dominio de *_module/utils/dataHelpers cuando la forma sea un BrandDefinition real; usa el helper más flexible solo donde las cargas útiles de fila de prompt difieran.

Typography vs Box (pattern-library)

  • Para texto (estados vacíos, "—" en línea, tramos enfatizados), prefiere Typography de pattern-library con component="span" cuando sea apropiado—no Box fingiendo ser copia.
  • API de Typography: usa variant, color, fontWeight, component donde expresen semántica (estos no están deprecados).
  • Box / wrappers de diseño: prefiere sx para espaciado, diseño flexible, dimensionamiento y valores de tema. Evita refactorizaciones que muevan estilos de sx a props shorthand de estilo de Box; eso entra en conflicto con la guía actual de MUI.

Límites de componentes: props vs estado interno

  • Deriva booleanos de data dentro del componente cuando el padre no los necesite para diseño o estado de URL (ej., "tiene términos de marca" de brand_terms de la marca principal).
  • Mantén alternancias solo de UI internas (ej., cambiar entre dos modos de gráfico en una tarjeta) a menos que otro hermano o ruta deba manejar el mismo estado—entonces documenta por qué es necesario elevarlo.

Flujo de control y JSX

  • Prefiere return temprano para ramas de carga/vacío en lugar de un gran ternario asignado a una variable inmediatamente antes de un solo return, a menos que la memoización requiera genuinamente una expresión.
  • Comparadores de ordenación: nunca codifiques un centinela mágico (ej., 5) vinculado a un máximo de dominio asumido; usa Number.POSITIVE_INFINITY / explícito "ordenar al final" para null/undefined para que el comportamiento se mantenga correcto si los límites cambian.

Fetches y paginación

  • Evita un limit pequeño fijo (ej., 100) para listas a escala de panel cuando el backend esté paginado y los proyectos puedan exceder una página.
  • Itera con un tamaño de página estable hasta que una página devuelva menos filas que el límite o cero filas, o sigue el contrato documentado de la acción (ver docs de acción moz-pro-service / Bruno para el limit máximo).
  • Expone total o totales derivados de manera consistente si los llamadores necesitan conteos.

Envoltorios de presentación: no repitas lo obvio

  • Elimina campos de estado alternativo redundantes cuando la Card padre ya establezca el título visible (ej., evita duplicar cardContentTitle que coincida con el título de la tarjeta).
  • Comprobaciones de null: si una prop está tipada como string, no hagas una comprobación de null en ella; si puede ser null, el tipo debería reflejarlo.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados