Communitygithub.com

caseycme/skills

Führt systematisches Refactoring durch, um Features mit etablierten Mustern in Einklang zu bringen, Duplikate zu entfernen und die Code-Wiederverwendung zu verbessern. Enthält Richtlinien für DataGrid/pattern-library, Typisierung, Fetch-Paginierung, view-model vs. override-prop sowie MUI sx-First-Layout (Vermeidung veralteter Box-Stil-Kurzschreibweisen). Verwenden Sie dies beim Refactoring von Features, Konsolidieren von doppeltem Code, Extrahieren gemeinsamer Hilfsprogramme oder Angleichen von Mustern in ähnlichen Features.

Was ist skills?

Die Refactoring-Skill ist ein umfassender Leitfaden für Entwickler, die React/TypeScript- und MUI-Codebasis systematisch verbessern möchten. Sie bietet eine strukturierte Schritt-für-Schritt-Anleitung, die mit der Identifikation ähnlicher Features und doppelter Code-Muster beginnt und dann durch Extraktion gemeinsam genutzter Komponenten, Konsolidierung von Hilfsfunktionen und Vereinheitlichung von Styling und Ladezuständen führt. Die Skill ist plattformunabhängig, aber besonders nützlich für Entwickler, die mit Next.js, MUI (Material-UI) und einem pattern-library-Designsystem arbeiten. Sie enthält spezifische Regeln für Code-Review-Best Practices wie die Verwendung von `DetailPanelToggle` aus der pattern-library, das Vermeiden von veralteten MUI-Stil-Props zugunsten von `sx`, die Definition gemeinsam genutzter 'like'-Schnittstellen für API-Daten und die konsistente Behandlung von Paginierung in Dashboard-Skalierungen. Die Skill betont die Einhaltung von TypeScript-Best Practices wie `import type` für typenreine Importe, Vereinfachung von Null-Prüfungen und Entfernen unnötiger Typ-Assertions. Wichtig ist, dass sie auch die Bereinigung von Kommentaren nach dem Refactoring abdeckt und unnötige Migrationsnotizen und offensichtliche Kommentare entfernt, während erklärende Kommentare und komplexe Logik-Kommentare erhalten bleiben. Zusammenfassend hilft diese Skill Entwicklern, Codequalität, Konsistenz und Wartbarkeit in großen Codebasen zu verbessern.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Refactoring-Skill

Verwenden Sie diese Skill beim Refactoring von Features, um sie an etablierte Muster anzupassen, Duplikate zu entfernen und die Code-Wiederverwendung zu verbessern.

Für die Frage, ob UI zur pattern-library oder zur lokalen Komposition gehört, verwenden Sie die design-system-Skill.

Analyse vor dem Refactoring

1. Ähnliche Features identifizieren

  • Finden Sie vergleichbare Features in der Codebasis mit ähnlicher Funktionalität
  • Vergleichen Sie Verzeichnisstrukturen, Komponentenmuster und die Nutzung von Hilfsprogrammen
  • Suchen Sie nach Features mit ähnlicher Funktionalität, aber unterschiedlichen Implementierungen
  • Verwenden Sie semantische Suche, um verwandte Features zu finden: "features with similar table/data grid patterns"

2. Gelegenheiten für Duplikate finden

Suchen Sie nach doppelten Code-Mustern:

  • Komponenten: Suchen Sie nach ähnlichen Komponentendateien in verschiedenen Features (gleicher Name oder ähnliche Funktionalität)
  • Hooks: Überprüfen Sie auf doppelte Hook-Logik (Tabellen-Hooks, Filter-Hooks, Aggregations-Hooks)
  • Hilfsfunktionen: Finden Sie doppelte Hilfsfunktionen (Aggregationen, Formatierer, Validierer, Transformer)
  • Styles: Identifizieren Sie doppelte sx-Prop-Muster oder Inline-Styles
  • Konstanten: Überprüfen Sie auf doppelte Konstanten oder Konfigurationsobjekte
  • Typen: Suchen Sie nach doppelten Typdefinitionen oder Interfaces

3. Gemeinsame Hilfsfunktionen prüfen

Bevor Sie neue Hilfsfunktionen erstellen, überprüfen Sie vorhandene:

  • Suchen Sie in @/util/-Verzeichnissen nach domänenspezifischen Hilfsfunktionen
  • Überprüfen Sie @/util/dates auf Datumsformatierungsfunktionen
  • Überprüfen Sie @/util/numbers auf Zahlenformatierungsfunktionen
  • Überprüfen Sie @/components/ auf wiederverwendbare Komponenten
  • Überprüfen Sie pattern-library auf Design-System-Komponenten
  • Verwenden Sie grep/search, um vorhandene Implementierungen zu finden, bevor Sie neue erstellen

Refactoring-Prozess

Schritt 1: Gemeinsamen Code extrahieren

Wenn Duplikate gefunden werden:

  1. Erstellen Sie gemeinsame Hilfsfunktionen in den entsprechenden @/util/-Verzeichnissen:

    // Beispiel: util/[domain]/[category].ts
    export const sharedFunction = () => { ... };
    export const sharedConstant = { ... };
    
  2. Aktualisieren Sie alle Features, um aus dem gemeinsamen Speicherort zu importieren:

    // Feature-spezifische Datei - re-exportieren aus gemeinsamem Speicherort
    export { sharedFunction, sharedConstant } from "@/util/[domain]/[category]";
    
  3. Entfernen Sie doppelte Implementierungen aus den Feature-Verzeichnissen

  4. Aktualisieren Sie alle Imports in der gesamten Codebasis

Schritt 2: Komponenten konsolidieren

Wenn doppelte Komponenten gefunden werden:

  1. Identifizieren Sie die vollständigste/feature-reichste Version (überprüfen Sie Props, Funktionalität, Tests)
  2. Extrahieren Sie sie an einen gemeinsamen Speicherort (@/components/ oder feature-agnostischer Speicherort)
  3. Machen Sie Props flexibel, um alle Anwendungsfälle zu unterstützen (verwenden Sie Union-Typen, optionale Props oder Generics)
  4. Aktualisieren Sie Imports in allen Features, die die Komponente verwenden
  5. Löschen Sie doppelte Komponentendateien
  6. Überprüfen Sie, ob alle Verwendungen noch korrekt funktionieren

Schritt 3: Ladepatterns angleichen

Für Ladezustände:

  1. Überprüfen Sie loading.tsx-Dateien - sollten einfache Skelette sein, keine vollständigen Seitenlayouts
  2. Entfernen Sie komponenteninterne Skelett-Loader - verlassen Sie sich für das anfängliche Laden auf das seitenweite loading.tsx
  3. Während erneuter Abrufe: Zeigen Sie vorhandene Daten an, keine Skelette (es sei denn, UX erfordert explizit etwas anderes)
  4. Passen Sie sich Mustern aus ähnlichen Features in der Codebasis an
  5. Verwenden Sie Next.js App Router-Konventionen - loading.tsx übernimmt das anfängliche Laden, Komponenten übernehmen erneute Abrufzustände

Schritt 4: Styles konsolidieren

Für Styling:

  1. Extrahieren Sie wiederverwendbare Stilmuster in gemeinsame Komponenten oder Stil-Hilfsfunktionen
  2. Entfernen Sie Inline-sx-Props, wenn eine gemeinsame Komponente existiert
  3. Verwenden Sie Design-System-Komponenten aus pattern-library anstelle von benutzerdefinierten Styles
  4. Überprüfen Sie auf doppelte Stilobjekte, die gemeinsame Hilfsfunktionen oder Theme-Erweiterungen sein könnten
  5. Folgen Sie Material-UI-Mustern - verwenden Sie Theme-Werte, vermeiden Sie magische Zahlen

Schritt 5: Musterangleichung überprüfen

Stellen Sie Konsistenz mit etablierten Features sicher:

  1. Vergleichen Sie Verzeichnisstrukturen - sollten ähnlichen Mustern folgen (_components/, _hooks/, _utils/)
  2. Überprüfen Sie Hook-Muster - einfachere Hooks sind in Ordnung, wenn sich die Feature-Anforderungen unterscheiden
  3. Überprüfen Sie den Datenfluss - sollte nach Möglichkeit ähnlichen Features entsprechen
  4. Überprüfen Sie die Komponentenzusammensetzung - sollte ähnliche Muster verwenden (Wrapper, Komposition usw.)
  5. Überprüfen Sie Namenskonventionen - folgen Sie etablierten Mustern (PascalCase für Komponenten, camelCase für Hooks)

Schritt 6: Konsolidierung von Hilfsfunktionen

Für Hilfsfunktionen:

  1. Überprüfen Sie, ob die Funktion existiert zuerst in gemeinsamen Hilfsfunktionen (Codebase durchsuchen)
  2. Vergleichen Sie Implementierungen - verwenden Sie die vollständigere/robustere Version
  3. Konsolidieren Sie Duplikate - verschieben Sie sie an einen gemeinsamen Speicherort, aktualisieren Sie alle Imports
  4. Dokumentieren Sie Unterschiede - wenn sich Implementierungen absichtlich unterscheiden, dokumentieren Sie warum
  5. Erhalten Sie die Funktionalität - stellen Sie sicher, dass die konsolidierte Version alle Anwendungsfälle abdeckt

Schritt 7: Kommentare bereinigen

Nach dem Refactoring entfernen Sie unnötige Kommentare:

  1. Entfernen Sie Migrationsnotizen - Kommentare, die erklären, woher der Code verschoben wurde (z. B. "isCollecting is now exported from Table/utils.ts")
  2. Entfernen Sie offensichtliche Kommentare - Kommentare, die nur wiederholen, was der Code tut (z. B. "// Re-export shared aggregations" wenn der Code eindeutig Re-Exports zeigt)
  3. Behalten Sie erklärende Kommentare - Kommentare, die erklären, WARUM etwas getan wird (z. B. "// Use setTimeout to ensure form state is updated")
  4. Behalten Sie Kommentare zu komplexer Logik - Kommentare, die nicht offensichtliche Geschäftslogik oder Randfälle erklären
  5. Entfernen Sie TODO/FIXME-Kommentare - es sei denn, es handelt sich um legitime zukünftige Arbeiten

Beispiele für unnötige Kommentare:

// ❌ Unnötig - offensichtlich aus dem Code
// Re-export shared aggregations from util
export { latest, totalRange } from "@/util/keywords/gridAggregations";

// ❌ Unnötig - Migrationsnotiz, nicht mehr benötigt
// isCollecting is now exported from Table/utils.ts to avoid duplication
// Import it from there: import { isCollecting } from "../KeywordListDetail/Table/utils";

Beispiele für gute Kommentare:

// ✅ Gut - erklärt WARUM
// Use setTimeout to ensure form state is updated after CSV processing
setTimeout(() => {
  void handleSubmit(onSubmit)();
}, 100);

// ✅ Gut - erklärt komplexe Logik
// A keyword is updated if:
// 1. Its lastUpdated value changed (most reliable indicator), OR
// 2. It's no longer in collecting state AND we've polled enough times (fallback)

Schritt 8: Verbesserung der Codequalität

Wenden Sie konsistente Codequalitätsmuster im gesamten refaktorierten Code an:

Null/Undefined-Prüfungen

Vereinfachen Sie Null- und Undefined-Prüfungen mit loser Gleichheit:

// ❌ Ausführlich
if (value !== undefined && value !== null) { ... }
if (value !== undefined && value !== null && value !== "") { ... }

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

Hinweis: Verwenden Sie != null (lose Gleichheit), um sowohl auf null als auch auf undefined in einer einzigen Prüfung zu testen. Dies ist idiomatisches TypeScript/JavaScript und prägnanter.

Typ-Only-Imports

Verwenden Sie import type für typenreine Imports, um die Build-Leistung zu verbessern und die Absicht klar zu machen:

// ❌ Runtime-Import für typenreine Verwendung
import { SomeType } from "app-api/types/domain";

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

Anwenden auf:

  • Typdefinitionen aus app-api
  • Interface-Imports
  • Typenreine Hilfstypen
  • Jeden Import, der nur in Typannotationen verwendet wird

Entfernen unnötiger Typ-Assertions

Entfernen Sie Typ-Assertions, wenn TypeScript den Typ korrekt ableiten kann:

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

// ✅ TypeScript ableiten lassen
const items = data.map((item) => item);

Wann Assertions behalten werden sollten: Nur wenn TypeScript den Typ nicht wirklich ableiten kann oder wenn Typen auf eine Weise eingeengt werden, die TypeScript nicht überprüfen kann.

Entfernen unnötiger Nullish Coalescing

Entfernen Sie ?? null, wenn der Wert bereits nullable ist oder TypeScript den korrekten Typ ableitet:

// ❌ Unnötig - valueGetter gibt bereits nullable zurück
valueGetter: (value, row) => {
  return row.someField ?? null;
};

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

Wann behalten werden sollte: Wenn explizit undefined in null für die API-Kompatibilität umgewandelt wird oder wenn das Typsystem es erfordert.

Entfernen ungenutzter Props

Entfernen Sie Props aus Komponenten-Schnittstellen und Implementierungen, wenn sie nicht verwendet werden:

// ❌ Ungenutztes Prop
interface ComponentProps {
  item: Item;
  unusedField: string; // Wird nie in der Komponente verwendet
}

// ✅ Saubere Schnittstelle
interface ComponentProps {
  item: Item;
}

Explizite Typen zu Callbacks hinzufügen

Fügen Sie explizite Typannotationen zu Callback-Parametern hinzu, wenn TypeScript sie nicht ableiten kann:

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

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

Anwenden auf: Array-Methoden (map, filter, forEach), Event-Handler und andere Callbacks, bei denen Typen nicht aus dem Kontext klar sind.

Wiederholte JSX-Muster extrahieren

Extrahieren Sie wiederholte JSX-Muster in wiederverwendbare Komponenten:

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

// ✅ Extrahierte Komponente
<AggregationTypography
  formattedValue={formattedValue}
  isAggregation={isAggregation}
/>;

Factory-Funktionen für variierte Implementierungen verwenden

Wenn die Logik ähnlich ist, aber mit unterschiedlichen Datenstrukturen umgehen muss, verwenden Sie Factory-Funktionen:

// ✅ Factory-Funktionsmuster
export const createIntentOperators = <T extends { intent?: Intent | Intent[] }>(
  normalizeToArray: (value: T) => Intent[]
) => {
  return {
    // Operatoren, die mit normalisiertem Array arbeiten
  };
};

// Verwendung in verschiedenen Features
const operators1 = createIntentOperators<Feature1Type>((item) => [item.intent]);
const operators2 = createIntentOperators<Feature2Type>(
  (item) => item.intents || []
);

Vorteile: Wiederverwendung der Kernlogik bei gleichzeitiger angemessener Handhabung verschiedener Datenstrukturen.

Code-Review-Härtung (wiederkehrendes Feedback)

Wenden Sie dies an, wenn das Refactoring Grids, Dashboards, Abrufe oder gemeinsame "Zeilen- + Metrik-"Formen berührt (entspricht wiederholtem Moz Pro UI PR-Feedback).

DataGrid: Detail-Panel-Umschalter

  • Bevorzugen Sie DetailPanelToggle aus pattern-library zum Auf-/Zuklappen einer Detail-Panel-Spalte anstelle eines ad-hoc IconButton + @mui/icons in einer benutzerdefinierten Zelle.
  • Accessibility verdrahten: übergeben Sie buttonTabIndex={0}, wenn die Zelle tab-fokussierbar sein soll (siehe app/(default)/competitive-research/top-competing-content/_module/components/Table/columns.tsx, SerpFeaturesCell).
  • Layout / Zentrierung: Verwenden Sie sx auf Box/Stack (oder Stacks direction/spacing, wenn dies das etablierte Muster ist). Ersetzen Sie nicht sx durch veraltete MUI System-Style-Props auf Box (z. B. display, alignItems als Top-Level-Props) – MUI veraltet diesen Ansatz zugunsten von sx.

Typisierung: object / anonyme Zeilenformen vermeiden

  • Verwenden Sie nicht readonly object[] für brand_definitions, Zeilenfragmente oder API-nahe Listen, wenn ein struktureller Typ existiert oder einmal definiert werden kann.
  • Definieren Sie eine gemeinsame "like"-Schnittstelle (z. B. BrandDefinitionLike) im Feature-utils-Modul; exportieren Sie sie und einen einzigen display-line-Helfer (z. B. getBrandDefinitionDisplayLine), anstatt getBrandName mit Casts in Zellen zu duplizieren.
  • Entfernen Sie redundante Casts (as BrandDefinitionLike[]), nachdem Parameter typisiert sind.
  • Wiederverwenden Sie Domain-Helfer aus *_module/utils/dataHelpers, wenn die Form eine echte BrandDefinition ist; verwenden Sie den lockereren Helfer nur, wo sich Prompt-Zeilen-Payloads unterscheiden.

Typography vs. Box (pattern-library)

  • Für Text (Leerzustände, Inline-"—", hervorgehobene Spans) bevorzugen Sie Typography aus pattern-library mit component="span", wenn angemessen – nicht Box, das sich als Text ausgibt.
  • Typography-API: Verwenden Sie variant, color, fontWeight, component, wo sie Semantik ausdrücken (diese sind nicht veraltet).
  • Box / Layout-Wrapper: Bevorzugen Sie sx für Abstände, Flex-Layout, Größen- und Theme-Werte. Vermeiden Sie beiläufige Refactorings, die Styling von sx zu Box "style"-Kurzschreibweisen verschieben; dies widerspricht der aktuellen MUI-Empfehlung.

Komponentengrenzen: Props vs. interner Zustand

  • Leiten Sie Booleans aus data ab innerhalb der Komponente, wenn das übergeordnete Element sie nicht für Layout oder URL-Status benötigt (z. B. "hat Markenbegriffe" aus den brand_terms der Primärmarke).
  • Halten Sie UI-only-Toggles intern (z. B. Umschalten zwischen zwei Diagrammmodi in einer Karte), es sei denn, ein anderes Geschwister oder eine Route muss denselben Status steuern – dann dokumentieren Sie, warum das Anheben erforderlich ist.

Kontrollfluss und JSX

  • Bevorzugen Sie eine frühe return-Anweisung für Lade-/Leerzweige anstelle eines großen ternären Operators, der einer Variablen unmittelbar vor einem einzelnen return zugewiesen wird, es sei denn, die Memoisierung erfordert wirklich einen Ausdruck.
  • Sortiervergleicher: Härten Sie niemals eine magische Sentinel-Zahl (z. B. 5) ein, die an ein angenommenes Domänenmaximum gebunden ist; verwenden Sie Number.POSITIVE_INFINITY / explizites "sort last" für null/undefined, damit das Verhalten korrekt bleibt, falls sich Limits ändern.

Abrufe und Paginierung

  • Vermeiden Sie ein festes kleines limit (z. B. 100) für Dashboard-Listen, wenn das Backend paginiert ist und Projekte eine Seite überschreiten können.
  • Durchlaufen Sie mit einer stabilen Seitengröße, bis eine Seite weniger Zeilen als das Limit oder null Zeilen zurückgibt, oder folgen Sie dem dokumentierten Vertrag der Aktion (siehe moz-pro-service-Aktionsdokumentation / Bruno für max limit).
  • Geben Sie total oder abgeleitete Summen konsistent an, wenn Aufrufer Zählungen benötigen.

Präsentations-Wrapper: nicht das Offensichtliche wiederholen

  • Entfernen Sie redundante Alt-Status-Felder, wenn die übergeordnete Card bereits den sichtbaren Titel setzt (z. B. vermeiden Sie die Duplizierung von cardContentTitle, das mit dem Kartentitel übereinstimmt).
  • Null-Prüfungen: Wenn ein Prop als string typisiert ist, führen Sie keine Prüfung auf null durch, es sei denn, es gibt einen Laufzeitpfad, der null setzt (selten in typisiertem React-Code).
  • Props sortieren: Halten Sie Props in JSX in einer konsistenten Reihenfolge (erforderliche Props zuerst, gefolgt von optionalen Props, dann Event-Handler).

Datenabruf-Zustandsmaschine

  • Verwenden Sie eine Zustandsmaschine mit drei Zuständen für jeden Datenabruf: loading, error, success. Vermeiden Sie es, Fehler als impliziten "leeren Zustand" zu behandeln.
  • Behandeln Sie Fehler explizit mit einer UI-Fehlermeldung oder einem erneuten Abruf-Button (siehe app/(default)/competitive-research/_module/components/ErrorState.tsx).
  • Zeigen Sie leere Zustände nur an, wenn der Abruf erfolgreich war, aber keine Daten zurückgegeben wurden. Verwechseln Sie dies nicht mit Lade- oder Fehlerzuständen.

Fazit

Diese Refactoring-Skill bietet einen umfassenden Rahmen zum systematischen Verbessern der Codequalität, Reduzieren von Duplikaten und Sicherstellen der Konsistenz in einer großen React/TypeScript-Codebase. Durch Befolgen dieser Schritte können Entwickler wartbareren, wiederverwendbareren und robusteren Code erstellen.

Schlüsselerkenntnisse:

  1. Analysieren Sie vor dem Refactoring – identifizieren Sie ähnliche Features und Duplikate, bevor Sie Änderungen vornehmen.
  2. Extrahieren Sie in gemeinsame Speicherorte – Konsolidieren Sie Code in @/components/, @/util/ oder pattern-library.
  3. Gleichen Sie Muster an – stellen Sie sicher, dass Features denselben Strukturen, Konventionen und Datenflüssen folgen.
  4. Bereinigen Sie nach dem Refactoring – entfernen Sie unnötige Kommentare und wenden Sie Verbesserungen der Codequalität an.
  5. Befolgen Sie Code-Review-Best-Practices – wenden Sie konsistente Muster für DataGrid, Typisierung, Styling und Datenabruf an.

Individual skills in this repo

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

Verwandte Skills