Einheitenumrechner

Prev Next

Um den Einheitenumrechner „Masse“ herunterzuladen, besuchen Sie: [tulip](https://<span translate=).co/library/apps/unit-converter--mass">Library

Um den Einheitenumrechner „Volumen“ herunterzuladen, besuchen Sie: [tulip.co/library/apps/unit-converter--volume">Library](https://<span translate=)

In diesem Artikel erläutert Tamás, einer unserer Bibliotheksentwickler, die Entwicklungsentscheidungen hinter der in der Bibliothek verfügbaren Baustein-App „Einheitenumrechner“.

Warum ich eine Objektliste anstelle einer Tabelle verwendet habe

Hallo, ich bin Tamás von Tulip.

Als ich diese Komponente für den Einheitenumrechner entwickelte, war eine meiner ersten architektonischen Entscheidungen, keine Tabelle zu verwenden. Stattdessen entschied ich mich dafür, alles in Objektlisten zu speichern, die als Standardkomponentenvariablen initialisiert wurden.

Der Grund dafür war einfach: Die Einheitenumrechnung verhält sich in diesem Kontext wie eine mathematische Konstante und nicht wie operative Daten. Die Beziehungen sind rein multiplikativ, ändern sich selten und erfordern keine Bearbeitung zur Laufzeit, keine Aggregation, keine Filterung und keine relationalen Abfragen. Die Einführung einer Tabelle hätte Folgendes bedeutet: * das Erstellen und Pflegen zusätzlicher Infrastruktur, * das Konfigurieren von Abfragen und aggregations, * das Hinzufügen einer weiteren Abhängigkeitsschicht zu jeder App, die die Komponente nutzt.

Das hätte die Komplexität erhöht, ohne die Funktionalität zu verbessern.

Stattdessen habe ich die Datensätze direkt in die Komponente eingebettet:* Kanonische Basisdatensätze: * _lengthToBaseDefaults * _massToBaseDefaults * _volumeToBaseDefaults

  • Synonymwörterbücher:
    • _lengthUnitAliases
    • _massUnitAliases
    • _volumeUnitAliases

Beide dienen als Standardwerte für Variablen. Dadurch bleibt die Komponente:* Portabel* In sich geschlossen* Deterministisch* Einfach zwischen Apps kopierbar

Wenn sich der Datensatz wie eine Konstante verhält, ziehe ich es vor, ihn innerhalb der Komponente zu schützen, anstatt ihn zu externalisieren.

Warum keine Tabelle?

Eine tabellenbasierte Lösung würde eine strukturelle Abhängigkeit mit sich bringen, die dieses Problem nicht rechtfertigt.

Einheitsdefinitionen sind keine transaktionalen Daten. Es handelt sich um strukturelle Definitionen. Sie wie operative Datensätze zu behandeln, stünde in keinem Verhältnis zum Problem.

Mein Ziel war hier architektonische Verhältnismäßigkeit: nur so viel Infrastruktur einsetzen, wie das Problem tatsächlich erfordert.

Entwurfsprinzip: Geschützte Logik, flexible Konfiguration

Diese Komponente folgt zwei Kernideen:1. Kanonische Basisnormalisierung 2. Eingabetoleranz durch Synonymauflösung

Ich habe die mathematische Wahrheit bewusst von der Flexibilität für den Benutzer getrennt.* Die kanonischen Basisdatensätze definieren die mathematischen Beziehungen.* Die Synonymwörterbücher definieren, wie flexibel Benutzereingaben interpretiert werden.

Beide Ebenen sind Teil des Entwurfs – keine nachträglichen Einfälle.

Im kanonischen Basismodell wird jede Einheit einer einzigen Referenzeinheit innerhalb ihres Bereichs zugeordnet. Jede Umrechnung läuft über diese Referenz. Dadurch entsteht ein einziger Normalisierungspfad, der gewährleistet, dass alle Einheiten denselben mathematischen Anker haben.

Domänen-Basiseinheiten

Ich habe die Basiseinheit pro Domäne explizit festgelegt:* Länge → m* Masse → kg* Volumen → L

Dies waren bewusste Entscheidungen:* Sie entsprechen dem Industriestandard.* Sie minimieren Rundungsabweichungen.* Sie sorgen dafür, dass das System für Ingenieure intuitiv bleibt.

Kanonische Einheitenschlüssel (unterstützte Einheiten)

Alle Alias-Zuordnungen müssen auf einen dieser kanonischen Schlüssel zurückgeführt werden.

  • Masse (Basiseinheit: kg) µg, mg, g, kg, t, lb, oz
  • Länge (Basiseinheit: m) mm, cm, m, km, in, ft, yd, mi
  • Volumen (Basis: L) ml, cl, µl, mm³, cm³, l, m³, fl_oz_us, pt_us, qt_us, gal_us

Jeder Bereich verfügt über eine eigene Liste von Basisdatensatzobjekten. Jeder Eintrag definiert eine Einheit und deren Faktor zur Basiseinheit.

Die Umrechnung folgt immer dem gleichen Muster:* Eingabe → Basis* Basis → Ziel

Keine Verzweigungen. Keine Paarpflege.

Geschützte interne Schnittstelle

Um versehentliche Änderungen an der Logik zu verhindern, habe ich die Kernvariablen isoliert:* _inputValue* _inputUnit* _targetUnit* _conversionResult

Die Kern-Engine ist ausschließlich von diesen abhängig.

Sie wird von zwei schlanken Konfigurationsschichten umgeben:* 01 – BENUTZERKONFIGURATION: EINGABESTUFE Ordnet externe Quellen internen Variablen zu.* 03 – BENUTZERKONFIGURATION: AUSGABESTUFE Leitet das berechnete Ergebnis nach außen weiter.

Dadurch bleibt der Rechenkern stabil und ermöglicht gleichzeitig eine flexible Integration.

Aufschlüsselung des Triggers – So funktioniert MAGIC

Der geschützte MAGIC-Trigger führt zwei logische Operationen durch:1. Synonyme von Einheiten auflösen2. Kanonische Basisnormalisierung anwenden

Ebene zur Alias-Auflösung

Jede Domäne verfügt über ein Synonymwörterbuch, zum Beispiel:* _lengthUnitAliases

Jedes Objekt enthält:* raw* canonical

Beispiel:{ „raw“: „mm“, „canonical“: „mm“ }{ „raw“: „Millimeter“, „canonical“: „mm“ }{ „raw“: „m³“, „canonical“: „m3“ }Dadurch können mehrere Schreibweisen einem einzigen kanonischen Schlüssel zugeordnet werden. Wichtig ist, dass ich keine Einträge innerhalb des Basisdatensatzes dupliziert habe. Die Synonym-Ebene dient ausschließlich dazu, Variabilitäten bei der Eingabe auszugleichen, ohne die Anzahl der mathematischen Definitionen zu vervielfachen.

Kanonische Basisformel

Sobald die kanonischen Einheiten festgelegt sind, lautet die Formel:Ergebnis = Eingabewert × factorToBase(kanonischeEingabe) ÷ factorToBase(kanonischesZiel)

Beispiel-Trigger (Längendomäne)

(@Variable._inputValue * array_value_at_index( map_to_number_list(@Variable._lengthToBaseDefaults , 'factorToBase'),      array_index_of( map_to_text_list(@Variable._lengthToBaseDefaults , 'unit'), array_value_at_index( map_to_text_list(@Variable._lengthUnitAliases , 'canonical'),          array_index_of( map_to_text_list(@Variable._lengthUnitAliases , 'raw'), @Variable._inputUnit ) ) )    ))/array_value_at_index( map_to_number_list(@Variable._lengthToBaseDefaults , 'factorToBase'), array_index_of( map_to_text_list(@Variable._lengthToBaseDefaults , 'unit'),    array_value_at_index( map_to_text_list(@Variable._lengthUnitAliases , 'canonical'),      array_index_of( map_to_text_list(@Variable._lengthUnitAliases , 'raw'), @Variable._targetUnit ) ) ))Strukturell handelt es sich hierbei um eine mehrschichtige Logik:* Rohwert → kanonisch auflösen* Kanonisch → Faktor auflösen* Durch Basis normalisieren

Es sieht komplex aus, ist aber bewusst inline gehalten, um die Engine in sich geschlossen zu halten und Zwischenzustände zu vermeiden.

Warum diese Struktur gewählt wurde

Ich wollte drei Garantien:* Keine Paarexplosion* Keine Rundungsabweichung durch mehrere Pfade* Keine Neuschreibung von Triggern bei der Erweiterung von Einheiten

Das kanonische Basismodell bietet mir alle drei. Wenn ich eine neue Einheit hinzufüge, füge ich genau einen „factorToBase“-Eintrag hinzu. Die Engine ändert sich nicht. Wenn ich ein neues Schreibformat unterstütze, füge ich genau einen Alias-Eintrag hinzu. Die Mathematik ändert sich nicht. Diese Trennung ist die zentrale architektonische Entscheidung.

Domänenübergreifende Wiederverwendung: Gleiche Engine, unterschiedliche Datensätze

Eine weitere bewusste Entscheidung: Die Engine-Logik ist domänenunabhängig. Länge, Masse und Volumen nutzen denselben strukturellen Trigger. Nur die Datensatzvariable ändert sich. Anstatt drei verschiedene Konverter zu entwickeln, habe ich eine kanonische Engine erstellt und lasse den Datensatz die Domäne definieren. Dies reduziert die kognitive Belastung und sorgt dafür, dass das Verhalten der Komponenten vorhersehbar bleibt.

Warum dies skalierbar ist

Die Skalierung erfolgt auf Datensatzebene. Das Hinzufügen von Einheiten erfordert nicht:* das Ändern von Trigger-Ausdrücken,* das Hinzufügen von bedingten Verzweigungen,* das Duplizieren von Logik.

Der Algorithmus bleibt stabil. Der Datensatz entwickelt sich weiter.

Erweiterung der Komponente

Hinzufügen einer neuen kanonischen Einheit

  • Erweitern Sie den entsprechenden Datensatz „_ToBaseDefaults“.
  • Fügen Sie „unit“ und „factorToBase“ hinzu.
  • Lassen Sie den Trigger unverändert.

Hinzufügen eines neuen Schreibformats

  • Erweitern Sie das entsprechende _UnitAliases-Wörterbuch.
  • Fügen Sie „raw“ und den entsprechenden kanonischen Schlüssel hinzu.
  • Lassen Sie den Basisdatensatz unverändert.

Dies war beabsichtigt: Ich wollte benutzerfreundliche Flexibilität, ohne die Anzahl der mathematischen Definitionen zu vervielfachen.

Fehlerbehandlung (Safe-Lookup-Muster)

Es gibt zwei Fehlerquellen: 1. „Raw“-Einheit nicht im Alias-Wörterbuch gefunden 2. Kanonische Einheit nicht im Basisdatensatz gefunden

Wenn eine der beiden Abfragen fehlschlägt, wird die Berechnung nicht ausgeführt.

Dies garantiert: * Keine veralteten Werte * Keine stillschweigenden Fehlberechnungen * Deterministisches Verhalten

Warum keine separaten Arrays für Einheiten und Faktoren?

Das Speichern von Einheiten und Faktoren in separaten Arrays würde das Risiko einer Positionsabhängigkeit mit sich bringen. Wenn sich die Reihenfolge einer Liste ändert, die der anderen jedoch nicht, kommt es zu einem stillen Systemausfall. Durch die gemeinsame Speicherung von „unit“ und „factorToBase“ in strukturierten Objekten habe ich diese strukturelle Anfälligkeit beseitigt.

Kernphilosophie

Diese Komponente ist bewusst einfach aufgebaut und verhält sich streng.* Die Berechnungen sind zentralisiert.* Die Engine ist geschützt.* Flexibilität besteht an den Rändern.

Ich habe sie so konzipiert, dass die Logik über die Zeit hinweg stabil bleibt, während sich der unterstützte Einheitenumfang sicher weiterentwickeln kann. Die Engine ändert sich nicht. Der Datensatz wächst.

Machen Sie mit

Treten Sie der Community bei, um Verbesserungen zu teilen, zusätzliche Einheiten vorzuschlagen, Probleme zu melden oder architektonische Entscheidungen zu diskutieren