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
