Communitygithub.com

caseycme/skills

Guide le refactoring systématique pour aligner les fonctionnalités sur des motifs établis, éliminer les duplications et améliorer la réutilisation du code. Inclut des directives pour DataGrid/pattern-library, le typage, la pagination des requêtes, view-model vs override-prop, et la disposition MUI avec sx-first (évite les props raccourcies style Box dépréciées). À utiliser lors du refactoring de fonctionnalités, de la consolidation de code dupliqué, de l'extraction d'utilitaires partagés ou de l'alignement de motifs entre des fonctionnalités similaires.

Qu'est-ce que skills ?

Cette compétence de refactoring systématique aide les développeurs à aligner les fonctionnalités sur des motifs établis, éliminer les duplications et améliorer la réutilisation du code. Elle couvre plusieurs plateformes comme Claude Code, Cursor et Codex, et se concentre sur l'analyse pré-refactoring, l'extraction de code partagé, la consolidation de composants, l'alignement des motifs de chargement et de style, ainsi que l'amélioration de la qualité du code. Le processus inclut des étapes pour nettoyer les commentaires inutiles, appliquer des motifs de qualité comme les imports de type uniquement, les assertions de type superflues, et l'extraction de motifs JSX répétés. Des conseils spécifiques sont fournis pour les composants DataGrid, le typage, la pagination des requêtes, et l'utilisation de MUI avec sx plutôt que les props raccourcies dépréciées. L'objectif est de standardiser le code, de réduire la dette technique et d'améliorer la maintenabilité tout en suivant les meilleures pratiques établies.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Compétence de Refactoring

Utilisez cette compétence lors du refactoring de fonctionnalités pour les aligner sur des motifs établis, éliminer les duplications et améliorer la réutilisation du code.

Pour savoir si l'interface utilisateur appartient à la pattern-library ou à une composition locale, utilisez la compétence design-system.

Analyse Pré-Refactoring

1. Identifier les Fonctionnalités Similaires

  • Trouvez des fonctionnalités comparables dans la base de code avec des fonctionnalités similaires
  • Comparez les structures de répertoires, les motifs de composants et l'utilisation des utilitaires
  • Recherchez des fonctionnalités avec des fonctionnalités similaires mais des implémentations différentes
  • Utilisez la recherche sémantique pour trouver des fonctionnalités connexes : "fonctionnalités avec des motifs de tableau/DataGrid similaires"

2. Trouver les Opportunités de Duplication

Recherchez des motifs de code dupliqué :

  • Composants : Cherchez des fichiers de composants similaires entre les fonctionnalités (même nom ou fonctionnalité similaire)
  • Hooks : Vérifiez la logique de hook en double (hooks de tableau, hooks de filtre, hooks d'agrégation)
  • Utilitaires : Trouvez des fonctions utilitaires dupliquées (agrégations, formatteurs, validateurs, transformateurs)
  • Styles : Identifiez des motifs de prop sx en double ou des styles en ligne
  • Constantes : Vérifiez les constantes ou objets de configuration en double
  • Types : Cherchez des définitions de type ou interfaces en double

3. Vérifier les Utilitaires Partagés

Avant de créer de nouveaux utilitaires, vérifiez ceux qui existent :

  • Recherchez dans les répertoires @/util/ pour des utilitaires spécifiques au domaine
  • Vérifiez @/util/dates pour les fonctions de formatage de date
  • Vérifiez @/util/numbers pour les fonctions de formatage de nombre
  • Vérifiez @/components/ pour les composants réutilisables
  • Vérifiez pattern-library pour les composants du système de design
  • Utilisez grep/recherche pour trouver des implémentations existantes avant d'en créer de nouvelles

Processus de Refactoring

Étape 1 : Extraire le Code Partagé

Lorsque vous trouvez des doublons :

  1. Créez des utilitaires partagés dans les répertoires @/util/ appropriés :

    // Exemple : util/[domaine]/[categorie].ts
    export const fonctionPartagee = () => { ... };
    export const constantePartagee = { ... };
    
  2. Mettez à jour toutes les fonctionnalités pour importer depuis l'emplacement partagé :

    // Fichier spécifique à une fonctionnalité - ré-exporter depuis le partagé
    export { fonctionPartagee, constantePartagee } from "@/util/[domaine]/[categorie]";
    
  3. Supprimez les implémentations dupliquées des répertoires de fonctionnalités

  4. Mettez à jour toutes les importations dans toute la base de code

Étape 2 : Consolider les Composants

Lorsque vous trouvez des composants dupliqués :

  1. Identifiez la version la plus complète/riche en fonctionnalités (vérifiez les props, la fonctionnalité, les tests)
  2. Extrayez vers un emplacement partagé (@/components/ ou emplacement indépendant de la fonctionnalité)
  3. Rendez les props flexibles pour prendre en charge tous les cas d'utilisation (utilisez des types unions, des props optionnelles ou des génériques)
  4. Mettez à jour les importations dans toutes les fonctionnalités utilisant le composant
  5. Supprimez les fichiers de composants dupliqués
  6. Vérifiez que toutes les utilisations fonctionnent toujours correctement

Étape 3 : Aligner les Motifs de Chargement

Pour les états de chargement :

  1. Vérifiez les fichiers loading.tsx - doivent être des squelettes simples, pas des mises en page complètes
  2. Supprimez les chargeurs squelettes au niveau des composants - reposez-vous sur loading.tsx au niveau de la page pour le chargement initial
  3. Lors des rechargements : Affichez les données existantes, pas les squelettes (sauf si explicitement nécessaire pour l'UX)
  4. Correspondance des motifs avec des fonctionnalités similaires dans la base de code
  5. Utilisez les conventions App Router de Next.js - loading.tsx gère le chargement initial, les composants gèrent les états de rechargement

Étape 4 : Consolider les Styles

Pour le style :

  1. Extrayez les motifs de style réutilisables vers des composants partagés ou des utilitaires de style
  2. Supprimez les props sx en ligne lorsqu'un composant partagé existe
  3. Utilisez les composants du système de design de pattern-library au lieu de styles personnalisés
  4. Vérifiez les objets de style en double qui pourraient être des utilitaires partagés ou des extensions de thème
  5. Suivez les motifs Material-UI - utilisez les valeurs du thème, évitez les nombres magiques

Étape 5 : Vérifier l'Alignement des Motifs

Assurez la cohérence avec les fonctionnalités établies :

  1. Comparez les structures de répertoires - doivent suivre des motifs similaires (_components/, _hooks/, _utils/)
  2. Vérifiez les motifs de hooks - des hooks plus simples sont acceptables si les exigences de la fonctionnalité diffèrent
  3. Vérifiez le flux de données - doit correspondre aux fonctionnalités similaires dans la mesure du possible
  4. Examinez la composition des composants - doit utiliser des motifs similaires (wrappers, composition, etc.)
  5. Vérifiez les conventions de nommage - suivez les motifs établis (PascalCase pour les composants, camelCase pour les hooks)

Étape 6 : Consolidation des Fonctions Utilitaires

Pour les fonctions utilitaires :

  1. Vérifiez si la fonction existe dans les utilitaires partagés d'abord (recherchez dans la base de code)
  2. Comparez les implémentations - utilisez la version la plus complète/robuste
  3. Consolidez les doublons - déplacez vers un emplacement partagé, mettez à jour toutes les importations
  4. Documentez les différences - si les implémentations diffèrent intentionnellement, documentez pourquoi
  5. Préservez la fonctionnalité - assurez-vous que la version consolidée gère tous les cas d'utilisation

Étape 7 : Nettoyer les Commentaires

Après le refactoring, supprimez les commentaires inutiles :

  1. Supprimez les notes de migration - Commentaires expliquant d'où vient le code (par exemple, "isCollecting est maintenant exporté depuis Table/utils.ts")
  2. Supprimez les commentaires évidents - Commentaires qui ne font que reformuler ce que fait le code (par exemple, "// Ré-exporter les agrégations partagées" quand le code montre clairement des ré-exportations)
  3. Conservez les commentaires explicatifs - Commentaires qui expliquent POURQUOI quelque chose est fait (par exemple, "// Utiliser setTimeout pour s'assurer que l'état du formulaire est mis à jour")
  4. Conservez les commentaires de logique complexe - Commentaires qui expliquent une logique métier non évidente ou des cas limites
  5. Supprimez les commentaires TODO/FIXME - Sauf s'il s'agit d'éléments de travail futurs légitimes

Exemples de commentaires inutiles :

// ❌ Inutile - évident d'après le code
// Ré-exporter les agrégations partagées depuis util
export { latest, totalRange } from "@/util/keywords/gridAggregations";

// ❌ Inutile - note de migration, plus nécessaire
// isCollecting est maintenant exporté depuis Table/utils.ts pour éviter la duplication
// Importez-le depuis là-bas : import { isCollecting } from "../KeywordListDetail/Table/utils";

Exemples de bons commentaires :

// ✅ Bon - explique POURQUOI
// Utiliser setTimeout pour s'assurer que l'état du formulaire est mis à jour après le traitement CSV
setTimeout(() => {
  void handleSubmit(onSubmit)();
}, 100);

// ✅ Bon - explique une logique complexe
// Un mot-clé est mis à jour si :
// 1. Sa valeur lastUpdated a changé (indicateur le plus fiable), OU
// 2. Il n'est plus en état de collecte ET nous avons assez interrogé (solution de repli)

Étape 8 : Améliorations de la Qualité du Code

Appliquez des motifs de qualité de code cohérents dans tout le code refactoré :

Vérifications Null/Undefined

Simplifiez les vérifications null et undefined en utilisant l'égalité lâche :

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

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

Remarque : Utilisez != null (égalité lâche) pour vérifier à la fois null et undefined en une seule vérification. C'est idiomatique en TypeScript/JavaScript et plus concis.

Imports Uniquement de Type

Utilisez import type pour les imports uniquement de type afin d'améliorer les performances de construction et de clarifier l'intention :

// ❌ Import d'exécution pour une utilisation uniquement de type
import { SomeType } from "app-api/types/domain";

// ✅ Import uniquement de type
import type { SomeType } from "app-api/types/domain";

Appliquez à :

  • Définitions de type depuis app-api
  • Imports d'interface
  • Types utilitaires uniquement de type
  • Tout import utilisé uniquement dans les annotations de type

Supprimer les Assertions de Type Inutiles

Supprimez les assertions de type lorsque TypeScript peut inférer le type correctement :

// ❌ Assertion inutile
const items = data.map((item) => item as SomeType);

// ✅ Laissez TypeScript inférer
const items = data.map((item) => item);

Quand garder les assertions : Uniquement lorsque TypeScript ne peut vraiment pas inférer le type, ou lors du rétrécissement de types d'une manière que TypeScript ne peut pas vérifier.

Supprimer la Fusion Nullish Inutile

Supprimez ?? null lorsque la valeur est déjà nullable ou que TypeScript infère le type correct :

// ❌ Inutile - valueGetter retourne déjà nullable
valueGetter: (value, row) => {
  return row.someField ?? null;
};

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

Quand garder : Lors de la conversion explicite de undefined en null pour la compatibilité API ou lorsque le système de types l'exige.

Supprimer les Props Inutilisées

Supprimez les props des interfaces de composants et des implémentations lorsqu'elles ne sont pas utilisées :

// ❌ Prop inutilisée
interface ComponentProps {
  item: Item;
  unusedField: string; // Jamais utilisé dans le composant
}

// ✅ Interface propre
interface ComponentProps {
  item: Item;
}

Ajouter des Types Explicites aux Callbacks

Ajoutez des annotations de type explicites aux paramètres de callback lorsque TypeScript ne peut pas les inférer :

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

// ✅ Type explicite
const items = ids.map((id: string | number) => { ... });

Appliquez à : Méthodes de tableau (map, filter, forEach), gestionnaires d'événements et autres callbacks où les types ne sont pas clairs d'après le contexte.

Extraire les Motifs JSX Répétés

Extrayez les motifs JSX répétés dans des composants réutilisables :

// ❌ Motif répété
{
  isAggregation ? (
    <Typography
      variant="body2"
      fontWeight="medium"
      fontStyle="italic"
      color="text.secondary"
    >
      {formattedValue}
    </Typography>
  ) : (
    <Typography variant="body2" fontWeight="medium">
      {formattedValue}
    </Typography>
  );
}

// ✅ Composant extrait
<AggregationTypography
  formattedValue={formattedValue}
  isAggregation={isAggregation}
/>;

Utiliser des Fonctions d'Usine pour des Implémentations Variées

Lorsque la logique est similaire mais doit gérer différentes structures de données, utilisez des fonctions d'usine :

// ✅ Motif de fonction d'usine
export const createIntentOperators = <T extends { intent?: Intent | Intent[] }>(
  normalizeToArray: (value: T) => Intent[]
) => {
  return {
    // Opérateurs qui fonctionnent avec un tableau normalisé
  };
};

// Utilisation dans différentes fonctionnalités
const operators1 = createIntentOperators<Feature1Type>((item) => [item.intent]);
const operators2 = createIntentOperators<Feature2Type>(
  (item) => item.intents || []
);

Avantages : Réutilise la logique centrale tout en permettant de gérer correctement différentes structures de données.

Renforcement de la Revue de Code (retour récurrent)

Appliquez ces conseils lors du refactoring touchant les grilles, tableaux de bord, requêtes ou formes partagées "ligne + métriques" (s'aligne avec les retours récurrents des PR de l'interface utilisateur Moz Pro).

DataGrid : bascule du panneau de détail

  • Préférez DetailPanelToggle de pattern-library pour l'expansion/réduction sur une colonne de panneau de détail au lieu d'un IconButton + @mui/icons ad hoc dans une cellule personnalisée.
  • Câblez l'accessibilité : passez buttonTabIndex={0} lorsque la cellule doit être accessible au focus via tabulation (voir app/(default)/competitive-research/top-competing-content/_module/components/Table/columns.tsx, SerpFeaturesCell).
  • Disposition / centrage : utilisez sx sur Box/Stack (ou la direction / spacing de Stack lorsque c'est le motif établi). Ne remplacez pas sx par les props système de style héritées de MUI sur Box (par exemple display, alignItems comme props de premier niveau)—MUI déprécie cette approche au profit de sx.

Typage : éviter les formes de ligne object / anonymes

  • Ne faites pas circuler readonly object[] pour brand_definitions, fragments de ligne ou listes adjacentes à l'API lorsqu'un type structurel existe ou peut être défini une fois.
  • Définissez une interface "like" partagée (par exemple BrandDefinitionLike) dans le module utils de la fonctionnalité ; exportez-la ainsi qu'un seul helper d'affichage (par exemple getBrandDefinitionDisplayLine) au lieu de dupliquer getBrandName avec des casts dans les cellules.
  • Supprimez les casts redondants (as BrandDefinitionLike[]) après avoir typé les paramètres.
  • Réutilisez les helpers de domaine depuis *_module/utils/dataHelpers lorsque la forme est un véritable BrandDefinition ; utilisez le helper plus lâche uniquement lorsque les charges utiles du prompt-row diffèrent.

Typography vs Box (pattern-library)

  • Pour le texte (états vides, "—" en ligne, spans accentuées), préférez Typography de pattern-library avec component="span" lorsque c'est approprié—pas de Box faisant office de copie.
  • API Typography : utilisez variant, color, fontWeight, component là où ils expriment la sémantique (ce ne sont pas dépréciés).
  • Wrappers Box / disposition : préférez sx pour l'espacement, la disposition flex, le dimensionnement et les valeurs du thème. Évitez les refactors de passage qui déplacent le style de sx vers les props raccourcies "style" de Box ; cela entre en conflit avec les directives actuelles de MUI.

Frontières des composants : props vs état interne

  • Dérivez les booléens des data à l'intérieur du composant lorsque le parent n'en a pas besoin pour la disposition ou l'état d'URL (par exemple "a des termes de marque" à partir de brand_terms de la marque principale).
  • Gardez les bascules d'interface utilisateur internes (par exemple passer d'un mode de graphique à un autre dans une seule carte) sauf si un autre frère ou une route doit piloter le même état—alors documentez pourquoi le remontée est nécessaire.

Flux de contrôle et JSX

  • Préférez un return précoce pour les branches de chargement/vide au lieu d'un grand ternaire assigné à une variable immédiatement avant un seul return, sauf si la mémorisation nécessite vraiment une expression unique.
  • Comparateurs de tri : ne codez jamais en dur un sentinelle magique (par exemple 5) lié à un maximum de domaine supposé ; utilisez Number.POSITIVE_INFINITY / un "trier en dernier" explicite pour les valeurs null/undefined afin que le comportement reste correct si les limites changent.

Requêtes et pagination

  • Évitez un limit fixe et petit (par exemple 100) pour les listes à l'échelle du tableau de bord lorsque le backend est paginé et que les projets peuvent dépasser une page.
  • Bouclez avec une taille de page stable jusqu'à ce qu'une page retourne moins de lignes que la limite ou zéro ligne, ou suivez le contrat documenté de l'action (voir la documentation de l'action moz-pro-service / Bruno pour la limit maximale).
  • Affichez total ou des totaux dérivés de manière cohérente si les appelants ont besoin de comptes.

Individual skills in this repo

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

Skills associés