Skip to content

Latest commit

 

History

History
259 lines (190 loc) · 11.5 KB

File metadata and controls

259 lines (190 loc) · 11.5 KB

Refactoring-Dokumentation

Diese Dokumentation beschreibt die durchgeführten Refactoring-Maßnahmen zur Verbesserung der Performance und Wartbarkeit des Flow UI Toolkits.

Überblick

Das Refactoring konzentrierte sich auf folgende Hauptbereiche:

  1. Aufspaltung des monolithischen PropertyEditors in kleinere, spezialisierte Komponenten
  2. Implementierung eines SubflowManager-Utilities zur Reduzierung von redundantem Code
  3. Optimierung der Visibility-Condition-Auswertung durch Memoization und Abhängigkeitsverfolgung
  4. Verbesserung der TypeScript-Typen und Implementierung von Discriminated Unions
  5. Optimierung des State-Managements durch modulare Struktur
  6. Verbesserung der Pfadnavigation und -auflösung für tiefe Verschachtelungen
  7. Implementierung einer intelligenten Containertyp-Erkennung und -Anzeige
  8. Entwicklung von Strukturnormalisierungs- und Validierungsfunktionen für komplexe JSON-Strukturen

1. PropertyEditor-Refactoring

Probleme des ursprünglichen Designs

  • Monolithische Komponente mit über 3000 Zeilen Code
  • Zahlreiche verschachtelte Switch-Statements
  • Redundante Update-Muster für verschiedene Elementtypen
  • Schwer zu warten und zu erweitern

Implementierte Lösung

  • Komponentenstruktur:

    • CommonPropertiesEditor: Bearbeitung gemeinsamer Eigenschaften aller Elemente
    • ElementEditorFactory: Factory-Pattern zur Instanziierung des passenden Editors
    • Spezialisierte Editoren für verschiedene Elementtypen (z.B. TextElementEditor, BooleanElementEditor)
    • VisibilityConditionEditor: Eigenständige Komponente für die Bearbeitung von Visibility-Bedingungen
  • Wiederverwendbare UI-Komponenten:

    • TranslatableField: Für mehrsprachige Textfelder
    • SectionTitle: Für Abschnittstitel im PropertyEditor
  • Vorteile:

    • Bessere Wartbarkeit durch kleinere, fokussierte Komponenten
    • Einfachere Erweiterbarkeit für neue Elementtypen
    • Reduzierte Komplexität und verbesserte Lesbarkeit
    • Weniger Fehleranfälligkeit durch spezialisierte Komponenten

2. SubflowManager-Utility

Probleme des ursprünglichen Designs

  • Redundanter Code für die Verwaltung von Subflows
  • Komplexe und fehleranfällige Update-Logik
  • Inkonsistente Implementierung über verschiedene Komponenten hinweg

Implementierte Lösung

  • Utility-Funktionen:

    • updateSubflowElement: Aktualisiert ein Element innerhalb eines Subflows
    • updateSubflowElementProperty: Aktualisiert eine bestimmte Eigenschaft eines Elements
    • removeSubflowElementProperty: Entfernt eine Eigenschaft eines Elements
    • findSubflowByType: Findet einen Subflow nach seinem Typ
    • filterSubflows: Filtert Subflows nach ihren Typen
  • Vorteile:

    • Reduzierung von Code-Duplikation
    • Konsistente Implementierung von Subflow-Operationen
    • Verbesserte Testbarkeit durch isolierte Funktionen
    • Einfachere Fehlerbehebung durch zentralisierte Logik

3. Optimierte Visibility-Condition-Auswertung

Probleme des ursprünglichen Designs

  • Ineffiziente Auswertung von Visibility-Bedingungen
  • Wiederholte Berechnungen für unveränderte Bedingungen
  • Fehlende Abhängigkeitsverfolgung für betroffene Elemente

Implementierte Lösung

  • Optimierungsstrategien:

    • Memoization für die Evaluierungsfunktion mit Lodash
    • Extraktion relevanter Felder aus Bedingungen für effiziente Cache-Schlüssel
    • Erstellung einer Abhängigkeitskarte für betroffene Elemente
    • Selektive Neuauswertung nur bei Änderung relevanter Feldwerte
  • Neue Funktionen:

    • extractRelevantFields: Extrahiert alle Feldnamen aus einer Visibility-Bedingung
    • createDependencyMap: Erstellt eine Abhängigkeitskarte für alle Elemente
    • getElementsToReevaluate: Findet Elemente, die bei Feldänderungen neu evaluiert werden müssen
  • Vorteile:

    • Verbesserte Performance durch Vermeidung redundanter Berechnungen
    • Effizientere Aktualisierung der UI bei Feldwertänderungen
    • Skalierbarkeit für komplexe Formulare mit vielen Visibility-Bedingungen

4. Verbesserte TypeScript-Typen

Probleme des ursprünglichen Designs

  • Inkonsistente Verwendung von TypeScript-Typen
  • Fehlende Discriminated Unions für bessere Typsicherheit
  • Unzureichende Null-Checks

Implementierte Lösung

  • Typverbesserungen:

    • Konsistente Benennung von Eigenschaften (z.B. fieldName statt field_name)
    • Strikte Null-Checks in kritischen Funktionen
    • Verbesserte Typgards für UI-Elemente
  • Vorteile:

    • Reduzierte TypeScript-Fehler
    • Verbesserte Entwicklererfahrung durch bessere Typinferenz
    • Frühzeitige Fehlererkennung während der Entwicklung

5. Optimiertes State-Management

Probleme des ursprünglichen Designs

  • Tiefe Objektmutationen führen zu unnötigen Re-Renders
  • Ineffiziente Zustandsaktualisierungen
  • Fehlende Memoization für rechenintensive Operationen

Implementierte Lösung

  • Optimierungsstrategien:

    • Modulare Struktur für gezielte Zustandsaktualisierungen
    • Immutable Update-Patterns für Zustandsänderungen
    • Memoization für rechenintensive Operationen
  • Vorteile:

    • Reduzierte Re-Renders und verbesserte UI-Performance
    • Bessere Nachvollziehbarkeit von Zustandsänderungen
    • Effizientere Speichernutzung

6. Verbesserte Pfadnavigation

Probleme des ursprünglichen Designs

  • Begrenzte Unterstützung für tiefe Verschachtelungen
  • Inkonsistente Pfadauflösung bei komplexen Strukturen
  • Schwierigkeiten bei der Navigation durch verschachtelte Elemente
  • Probleme beim Hinzufügen von Elementen in tiefen Ebenen

Implementierte Lösung

  • Verbesserte Funktionen:

    • getElementByPath: Robuste Funktion zur Auflösung von Elementpfaden
    • getPathContext: Ermittelt den Kontext eines Pfads (übergeordnete Elemente, Containertyp)
    • Optimierte Breadcrumb-Navigation mit Pfadkontext
    • Verbesserte handleAddElement-Funktion mit Pfadkontext-Berücksichtigung
  • Vorteile:

    • Unterstützung für bis zu 6 Verschachtelungsebenen
    • Konsistente Pfadauflösung auch bei komplexen Strukturen
    • Verbesserte Benutzerführung durch kontextbezogene Navigation
    • Zuverlässiges Hinzufügen von Elementen in tiefen Ebenen

7. Containertyp-Erkennung

Probleme des ursprünglichen Designs

  • Fehlende einheitliche Erkennung von Containertypen
  • Inkonsistente Behandlung verschiedener Container (Gruppe, Array, ChipGroup, etc.)
  • Unzureichende visuelle Unterscheidung von Containertypen
  • Schwierigkeiten bei der Bearbeitung von Unterelementen

Implementierte Lösung

  • Neue Funktionen:

    • getContainerType: Ermittelt den Containertyp eines Elements (group, array, chipgroup, custom, subflow)
    • getSubElements: Einheitliche Funktion zum Abrufen von Unterelementen
    • Verbesserte visuelle Darstellung von Containertypen in der UI
    • Containertyp-spezifische Aktionen und Bearbeitungsmöglichkeiten
  • Vorteile:

    • Einheitliche Behandlung verschiedener Containertypen
    • Verbesserte Benutzerführung durch visuelle Unterscheidung
    • Optimierte Bearbeitung von Unterelementen
    • Unterstützung für komplexe Containerstrukturen wie CustomUIElement mit sub_flows

8. Strukturnormalisierung

Probleme des ursprünglichen Designs

  • Inkonsistente JSON-Strukturen bei Import/Export
  • Fehlende Validierung von Strukturen
  • Probleme bei der Verarbeitung komplexer JSON-Dateien wie doorbit_original.json
  • Inkonsistente Einwicklung von Elementen in PatternLibraryElement-Objekte

Implementierte Lösung

  • Neue Funktionen:

    • normalizeElementTypes: Normalisiert Elementtypen und Eigenschaften
    • normalizeVisibilityCondition: Normalisiert Visibility-Bedingungen
    • validateFlowStructure: Validiert die Struktur eines Flows
    • enforcePatternLibraryElementWrapping: Erzwingt die Einwicklung von Elementen
    • normalizeComplexStructure: Spezielle Normalisierung für komplexe Strukturen
  • Vorteile:

    • Konsistente JSON-Strukturen bei Import/Export
    • Frühzeitige Erkennung von Strukturfehlern
    • Verbesserte Unterstützung für komplexe JSON-Dateien
    • Zuverlässige Verarbeitung von doorbit_original.json und ähnlichen Strukturen

9. Trennung von UUIDs und Field-IDs

Ausgangsproblem

  • Importierte Referenz-Flows (z.B. doorbit_esg (2).json) enthielten fachliche Feldnamen in field_id.field_name.
  • Die ursprüngliche Implementierung von uuidUtils.ensureUUIDs hat bei Elementen ohne "-" im Feldnamen UUID-Suffixe an field_id.field_name angehängt.
  • Visibility-Bedingungen und andere Referenzen (z.B. KeyValue-Listen) blieben jedoch auf die ursprünglichen Feldnamen gerichtet.
  • Dadurch entstanden Divergenzen zwischen Felddefinitionen und Referenzen sowie falsche Export-Strukturen.

Implementierte Lösung

  • Klare Trennung von internen und externen IDs:
    • uuid wird als rein interne ID für Seiten, Subflows, Elemente, Optionen, Chips und Visibility-Bedingungen verwendet.
    • field_id.field_name bleibt fachlich/external und wird beim Import nie automatisch verändert.
  • Anpassungen in uuidUtils.ts:
    • ensureElementUUID normalisiert field_id nur noch von String → Objekt, ohne den field_name inhaltlich zu ändern.
    • ChipGroup-Chips und other_user_value.text_ui_element erhalten UUIDs, ihre field_id.field_name-Werte bleiben jedoch unverändert (nur String → Objekt-Konvertierung, falls nötig).
    • Neue Hilfsfunktion stripUUIDFromVisibilityCondition entfernt rekursiv alle uuid-Felder aus Visibility-Bedingungen und normalisiert ggf. field_id von String → Objekt.
    • transformElementForExport nutzt stripUUIDFromVisibilityCondition und entfernt zusätzlich alle uuid-Felder aus verschachtelten Elementen, Chips, Items und Optionen.
    • Neue Funktion transformFlowForExport erzeugt aus einem internen ListingFlow einen exportfertigen Flow ohne uuid-Felder, inklusive Bereinigung von Seiten- und Subflow-UUIDs sowie deren Visibility-Bedingungen.
  • Anpassungen in App.tsx und JsonPreview.tsx:
    • handleSave verwendet nun transformFlowForExport(state.currentFlow), bevor der JSON-Download erzeugt wird.
    • JsonPreview zeigt die gleiche exportbereite Struktur an, indem es transformFlowForExport(data) verwendet.

Vorteile

  • Importierte Referenzdateien wie doorbit_esg (2).json) können verlustfrei importiert, im Editor bearbeitet und wieder exportiert werden, ohne dass sich field_id.field_name oder die Struktur ändern.
  • Alle internen UUIDs bleiben auf den Editor beschränkt und tauchen im Export nicht mehr auf.
  • Visibility-Bedingungen behalten stabile Feldreferenzen, da field_id.field_name nicht mehr nachträglich verändert wird.
  • JSON-Preview und tatsächlicher Export verwenden dieselbe Transformationslogik und sind damit konsistent.

Testergebnisse

Die implementierten Refactoring-Maßnahmen wurden mit automatisierten Tests validiert:

  • SubflowManager: Alle Tests erfolgreich
  • optimizedVisibilityUtils: Alle Tests erfolgreich
  • Bestehende Tests: Keine Regressionen in bestehender Funktionalität

Nächste Schritte

Für zukünftige Verbesserungen werden folgende Maßnahmen empfohlen:

  1. Integration der neuen Komponenten:

    • Schrittweise Migration vom alten PropertyEditor zum neuen RefactoredPropertyEditor
    • Implementierung weiterer spezialisierter Editoren für andere Elementtypen
  2. Weitere Optimierungen:

    • Implementierung von Immer für unveränderliche Updates
    • Erweiterung der Memoization auf weitere rechenintensive Operationen
    • Implementierung von React.memo für kritische Komponenten
  3. Erweiterte Tests:

    • Performance-Tests für Visibility-Condition-Auswertung
    • Integrationstests für die neuen Editor-Komponenten
    • Stress-Tests für komplexe Formulare mit vielen Elementen