Jeder Entwickler hat diesen einen Ordner. Den, der utils oder helpers heißt und den man von Repo zu Repo kopiert. Man fügt ihn ein, verbringt zwanzig Minuten damit, Verweise auf alte Datenbank-Schemata zu löschen, Auth-Checks herauszureißen, die nicht anwendbar sind, und Variablen umzubenennen, damit der neue Linter aufhört zu meckern. Ich habe das früher mit einem Theming-System gemacht, das ich selbst gebaut hatte: dem Dynamic Theme Kit. Es begann als Feature innerhalb einer Anwendung, und monatelang behandelte ich es wie ein portables Werkzeug. Ich habe mich geirrt. Code zu kopieren ist keine Wiederverwendung. Es ist Duplizierung mit zusätzlichen Schritten.

Die Falle des Single-Project-Mindsets

Wenn man ein Feature innerhalb eines Projekts baut, trifft man hunderte unsichtbare Annahmen. Die Farbpalette setzt vielleicht ein bestimmtes CSS-in-JS-Setup voraus. Die Abstandsskala bezieht sich möglicherweise auf einen Design-Token aus dem Brand Guide des Unternehmens. Das Umschalten zwischen Light- und Dark-Mode ruft eventuell einen Endpoint für Benutzereinstellungen auf, der einzigartig für das Backend dieser App ist. Diese Abhängigkeiten fühlen sich harmlos an, weil sie innerhalb des Projekts harmlos sind. Sie gehören dorthin.

Das Problem beginnt, wenn man versucht, diesen Code auszulagern. Man stellt fest, dass die „wiederverwendbare“ Komponente in Wirklichkeit ein Geflecht aus versteckten Strings ist, die sie mit dieser einen Codebasis verbinden. Das habe ich mit DTK gelernt. Es generierte zwar Theme-Variablen, ja. Aber es erwartete auch eine spezifische Ordnerstruktur. Es importierte eine Typdefinition aus irgendeinem tiefen Verzeichnis des ursprünglichen App-Typenverzeichnisses. Es setzte die Existenz eines globalen Konfigurationsobjekts voraus, das nur in diesem einen Repository existierte. Das war mir nie aufgefallen, weil innerhalb dieses Projekts alles immer vorhanden war.

DTK in ein eigenständiges Paket zu verwandeln, bedeutete Chirurgie, keine Erweiterung. Ich brauchte keine weiteren Features. Ich brauchte weniger Verbindungen.

Die Extraktion des Dynamic Theme Kit

Die härteste Arbeit bestand darin, sich vor den Code zu setzen und für jede Funktion und jeden Export zu fragen: Dient dies der Theming-Logik oder dient es dem Projekt? Ich habe Styling-Presets entfernt. Ich habe die Annahme entfernt, dass der Konsument eine React-Anwendung sein würde. Ich habe die Standard-Farbpaletten komplett gelöscht. Das ursprüngliche Projekt hatte eine navy- und schiefergraue Corporate-Ästhetik in den Defaults fest eingebaut. Das musste weg. Ein Paket kann nicht eure Markenfarben mitliefern.

Das neue Kit würde genau eine Sache tun. Es nimmt ein Konfigurationsobjekt entgegen – einige Farbwerte, einige Abstände, einige Typografie-Skalen – und generiert CSS Custom Properties. Das ist alles. Es wendet sie nicht an. Es entscheidet nicht, wo sie in deinem DOM landen. Es ist egal, ob du Tailwind, Styled Components oder einfaches HTML verwendest. Es liefert deiner Anwendung die Variablen, und dein Projekt entscheidet, wie es sie nutzt.

Diese Einschränkung fühlte sich anfangs limitierend an. Sie stellte sich als befreiend heraus.

Was kaputtgeht, wenn man es tatsächlich wiederverwenden will

Bevor ich irgendetwas veröffentlichte, brauchte ich einen Beweis, dass die Abstraktion tatsächlich hielt, was sie versprach. Ich nahm drei kleine persönliche Projekte aus meinem Archiv: ein Markdown-Vorschau-Tool, einen Habit-Tracker und eine Landingpage für ein Event. Keines davon teilte sich ein Framework oder eine Ordnerstruktur. Ich installierte DTK lokal in jedem einzelnen und versuchte, sie zu themen.

Der erste Versuch scheiterte sofort. Die von DTK generierten Variablennamen waren zu spezifisch. Es gab Tokens wie --primary-action und --background-overlay aus, die ein bestimmtes UI-Layout implizierten. Im Markdown-Vorschau-Tool ergaben diese Namen keinen Sinn. Es gab keinen Action-Button. Es gab kein Overlay. Ich habe die Generierungslogik so umgeschrieben, dass sie neutrale, strukturelle Namen erzeugt, die den Wert beschreiben, anstatt das Widget.

Ich stellte auch fest, dass meine Standardwerte zu aggressiv waren. Wenn ein Benutzer eine unvollständige Konfiguration übergab, füllte DTK die Lücken mit Werten auf, die in einem dichten Dashboard gut aussah, aber auf einer minimalistischen Landingpage alles zerschoss. Ich wechselte zu transparenten Standardwerten, bei denen fehlende Token einfach nicht gerendert wurden, sodass das konsumierende Projekt seine eigenen Fallbacks definieren konnte.

Dann war da noch die Dokumentation. Was für mich offensichtlich schien – „übergib einfach ein Konfigurationsobjekt“ – war für jemanden, der die README um Mitternacht liest, vage. Ich schrieb sie mit echten Objekten, echten Dateipfaden und klaren Erklärungen um, was passiert, wenn man die Funktion aufruft, im Gegensatz zu dem, was die Anwendung danach tun muss.

Diese kleinen persönlichen Projekte dienten als Testumgebungen. Es stand wenig auf dem Spiel, aber sie deckten echte Mängel auf, die mir beim bloßen Starren auf den isolierten Quellcode nicht aufgefallen wären.

Der echte Test: Produktion bei Web Weavers World

Persönliche Projekte sind Sandkästen. Sie haben keine Deadlines, Stakeholder oder veraltetes CSS, das älter ist als dein Paket. Der wahre Test kam, als ich DTK in Web Weavers World, meine Geschäftswebsite, integrierte. Dies war eine Live-Seite mit bestehenden Styles, Kundenerwartungen und zu berücksichtigenden Analysen. Wenn das Paket etwas kaputt gemacht hätte, hätte ich nicht einfach das Repo löschen und von vorne anfangen können.

Ich fügte DTK der Build-Pipeline hinzu, wies es einer neuen Farbkonfiguration zu und ließ es einen frischen Satz CSS-Variablen generieren. Die Integration dauerte einen Nachmittag, keine Woche. Das war das Signal. Zuvor bedeutete das Hinzufügen eines neuen Themes, neues CSS zu schreiben, hartcodierte Hex-Werte in zwanzig Dateien aufzuspüren und zu hoffen, dass ich keinen Edge Case übersehen hatte. Jetzt füge ich eine Palette zur Konfigurationsdatei hinzu, DTK generiert die Variablen und der Rest der Website nutzt sie. Die Theme-Logik entwickelte sich von einem fragilen, manuellen Prozess zu etwas, dem ich genug vertraue, um es an Mitwirkende zu übergeben.

Drei Fragen, die meine Arbeitsweise verändert haben

Dieser Prozess zwang mich dazu, eine mentale Checkliste zu formalisieren, die ich nun verwende, bevor ich irgendetwas abstrahiere:

  • Ist diese Variable wirklich generisch? Wenn der Name oder die Logik auf ein Domänenkonzept des ursprünglichen Projekts verweist, bleibt es zurück.
  • Gehört das in das Paket oder in die Anwendung? Geschäftsregeln, Markenidentitäten und Layout-Annahmen gehören in die App. Die Infrastruktur, die standardisierte Ausgaben generiert, gehört in das Paket.
  • Löse ich ein wiederverwendbares Problem oder ein projektspezifisches? Dies ist am schwersten ehrlich zu beantworten. Wir neigen dazu zu glauben, dass unsere Lösungen universell sind. Meistens sind sie lokal.

Die Beantwortung dieser Fragen zwang mich dazu, mein Design zu vereinfachen, oft indem ich Code entfernte, anstatt ihn hinzuzufügen. DTK hat mich gelehrt, dass Wiederverwendbarkeit kein Geschenk ist, das man sich selbst macht. Es ist eine Disziplin, die man ausübt, indem man Nein zur Bequemlichkeit sagt.

Eine andere Art, über Refactoring nachzudenken

Früher habe ich Refactorings daran gemessen, wie viel kürzer sie den Code machten. Weniger Zeilen fühlten sich nach Fortschritt an. Jetzt messe ich sie daran, wie viele Türen sie öffnen. Das Dynamic Theme Kit ist nicht elegant, weil es prägnant ist. Es ist nützlich, weil es drei nicht zusammenhängende persönliche Projekte und eine produktive Geschäftswebsite überstanden hat, ohne dass sein Inneres geändert werden musste.

Das ist die Kennzahl, auf die es ankommt. Code, der nur einmal funktioniert, ist ein Kostenfaktor. Code, der wiederholt funktioniert, ist ein Vermögenswert. Bevor ich jetzt mit einem neuen Feature beginne, halte ich inne. Ich frage mich, ob ich etwas baue, das ich wieder brauchen werde. Wenn die Antwort ja lautet, baue ich es von der ersten Zeile an anders. Ich isoliere die Inputs. Ich definiere die Outputs. Ich entferne die Annahmen.

Das beste Refactoring macht deinen Code nicht kürzer. Es sorgt dafür, dass dein Code an Orten funktioniert, die du dir noch gar nicht vorgestellt hast.