---
{
  "title": "FHIR in dynamischen Sprachen implementieren",
  "description": "Der FHIR-Standard entwickelt sich zur De-facto-Methode für die Verwaltung von Gesundheitsdaten. Unser CTO erläutert, warum FHIR-Implementierungen mit dynamischen Sprachen wertvolles Feedback für den FHIR-Standard und die FHIR-Community liefern können.",
  "date": "2015-02-03",
  "author": "Nikolai Ryzhikov",
  "reading-time": "4 min read",
  "tags": [
    "System Design",
    "FHIR Tools"
  ]
}
---
*Veröffentlicht am 3. Februar 2015 von Nicola Rizhikov*

Die meisten [FHIR](https://hl7.org/fhir/R4/)-Referenzimplementierungen basieren auf Code-Generierung für stark typisierte Sprachen. Damit bleibt das Feld funktionaler und/oder dynamisch typisierter Sprachen wie JavaScript, Ruby, Python, Clojure, Groovy usw. weitgehend unerschlossen.

Es ist kein Geheimnis, dass die Entwicklung mit dynamischen Sprachen manchmal deutlich schneller und angenehmer ist. Man könnte SDKs für diese Sprachen generieren, holt sich damit jedoch das Schlechteste aus beiden Welten: Dynamische Sprachen verfügen weder über Compiler-Prüfungen noch über gute IDE-Unterstützung, und die Stärken des Dynamismus werden überhaupt nicht genutzt.

In diesem Beitrag möchte ich die Implementierung von FHIR in dynamischen Sprachen diskutieren und Ideen sowie Leitlinien für Implementierende zusammentragen.

**Interne Repräsentation**

Die meisten [FHIR-Implementierungen](/articles/how-to-create-a-fhir-implementation-guide) generieren Klassen, um Ressourcen im Speicher abzubilden. Dynamische Sprachen stellen jedoch Hash-Maps (Dicts, Tables) und Arrays (Vektoren) von Haus aus mit komfortablen Literalen zur Verfügung, sodass die interne Repräsentation dem JSON-Format sehr nahekommen kann:

//jsvar pt = {resourceType: "Patient", name:[{text: "Smith"}]};; clj(def pt {:resourceType "Patient" :name [{:text "Smith"}]})# rbpt = {resourceType: "Patient", name:[{text: "Smith"}]}# pypt = {'resourceType': 'Pateint', 'name': [{'text':'Smith'}]}

Primitive FHIR-Typen (date, integer usw.) können auf entsprechende primitive Typen der jeweiligen Sprache abgebildet werden.

Diese Repräsentation ist sehr generisch und eignet sich gut für die Manipulation sowie die Interaktion mit anderen Bibliotheken und Frameworks.

> *„Es ist besser, 100 Funktionen auf einer Datenstruktur zu betreiben als 10 Funktionen auf 10 Datenstrukturen."*

> *Alan Perlis*

#### Minimalistische API

Es lässt sich eine einfache und solide API erstellen, die nur aus wenigen Funktionen besteht:

// Coerce primitive types from string to appropriate types.// profiles - collection of profiles with meta information // (ie types of elements, multiplicity etc)function coerce(profiles, resource){...}// walk recursively through resource and validate against profile// returns collection of errors and warnings // (OperationOutcome.issue)function validate(profiles, resource){}// parse json or xml into internal representation, optional function parse(str, format, profiles){}//serialize resource into xml or json stringfunction generate(str, format, profiles){}//convert from one format into anotherfunction convert(resource, toFormat, profiles)

Die Funktionen `**coerce**` und `**validate**` sind miteinander gekoppelt, weil bestimmte Validierungen (Datums- und URI-Formate usw.) vor der Konvertierung durchgeführt werden müssen, während andere bereits konvertierte Daten voraussetzen (z. B. Datumsinvarianten, numerische Ausdrücke). Die Funktion `**convert**` leitet sich aus parse->generate ab.

#### Reine Transformationen

Fast alle Funktionen benötigen Metainformationen (Profile). Theoretisch wäre es möglich, einige Abhängigkeiten von Metadaten zu eliminieren, wenn die Formate JSON->XML und XML->JSON eindeutig aufeinander abgebildet werden könnten. Derzeit ist eine reine Transformation von JSON->XML nicht möglich, da XML eine strikte Elementreihenfolge erfordert (eine zusätzliche Einschränkung), und XML->JSON ist fehlerhaft, weil XML nicht zwischen Collections und einzelnen Attributen unterscheidet, JSON jedoch schon.

Für Metainformationen gibt es zwei Möglichkeiten: Sie können in die Implementierung fest einprogrammiert oder parametrisiert (d. h. als Argumente übergeben) werden. Die fest einprogrammierte Variante ähnelt der code-generierten und ist einfach zu verwenden, erfordert jedoch bei jeder Änderung der Basisprofile eine Neugenerierung der Implementierung. Die parametrisierte Variante erscheint gegenüber solchen Änderungen stabiler und kann zur Laufzeit aktualisiert werden.

#### Polymorphe Attribute

Bei einer JSON-ähnlichen internen Repräsentation entstehen semantische Mängel in Bezug auf **polymorphe Attribute** (attr[x]): In generierten Referenzimplementierungen und Profilen werden solche Attribute als ein einziges Element oder Feld dargestellt, aber in den Serialisierungsformaten geht diese Semantik verloren und wird durch das Anhängen von Postfixen an Schlüssel oder Tags ausgedrückt:

im Observation-Profil haben wir applies[x]in Java: observation.setApplies/getAppliesin json und xml: appliesPeriod, appliesDateTime

Wenn wir das `**applies**`-Element auf Vorhandensein prüfen möchten (z. B. bei der Validierung), müssen wir Schlüssel oder Tags nach dem Muster `**applied***` durchsuchen und bearbeiten. Eine weitere Konsequenz ist die Unmöglichkeit, eine Multiplizität von mehr als eins für solche Attribute festzulegen. Dieses Problem könnte durch die Einführung anderer Serialisierungsregeln für polymorphe Attribute gelöst werden:

applies: {  Period: { start: '...', end: '...'}}//orapplies: {  type: 'Period',  value: {start: '...', end: '...'}}

#### Schematron-Regeln

Zusätzliche Invarianten für Ressourcen werden als Schematron-Regeln veröffentlicht. Schematron arbeitet mit XML, sodass eine zusätzliche Konvertierung nach XML sowie alle XML-bezogenen Werkzeuge (XQuery, XSLT usw.) benötigt werden oder die Schematron-Ausdrücke geparst und simuliert werden müssen.

Aus Symmetriegründen könnten Regeln in JavaScript mit einer Menge vordefinierter Hilfsfunktionen ausgedrückt werden. Heute wird JavaScript/JSON überall unterstützt (und verdrängt XML) – in Sprachen, Browsern und Datenbanken.

#### Ausführbare Spezifikation

Für alle Referenzimplementierungen wäre es hilfreich, eine übergeordnete Test-Suite zu erstellen. Beispielsweise könnten Konvertierungstests für Formate als Paare von XML <-> JSON Quell-/Ergebnis-Fixtures mit vielen Sonderfällen beschrieben werden sowie Validierungsfälle als Paare InvalidResource->OperationOutcome.

#### Clojure- und JavaScript-Implementierung

Wir haben mit der Clojure-Implementierung von FHIR begonnen – [https://github.com/fhirbase/fhir.clj](https://github.com/fhirbase/fhir.clj). Es handelt sich um ein frühes Alpha-Stadium, das den beschriebenen Ansatz jedoch veranschaulicht. Die Bibliothek ist kompakt und einfach (nur 6 Dateien; ~600 SLOC) und reagiert nicht empfindlich auf Ergänzungen oder Änderungen von Profilen. Sobald das Design der Clojure-Bibliothek ausgereift ist, planen wir, sie nach [fhir.js](https://github.com/fhir/fhir.js) zu portieren.

#### Fazit

Unserer Ansicht nach kann die Implementierung von FHIR für dynamische Sprachen wertvolles Feedback für den Standard liefern und dabei helfen, Implementierungsaspekte vom Kern des Standards zu trennen. Wir ermutigen Sie, sich an der Diskussion zu beteiligen und Beiträge zu leisten. Das angestrebte Ergebnis sind Leitlinien und ein API-Design für FHIR-Implementierungen. Hier ist ein leeres Projekt, mit dem die Zusammenarbeit beginnen kann – [https://github.com/FHIR/fhir-impl-guidelines](https://github.com/FHIR/fhir-impl-guidelines).

Dynamische Sprachen sind schneller und machen mehr Spaß in der Entwicklung und sind eine gute Wahl für Miniprojekte bei Connectathons. Ich hoffe, dass wir in Paris eine interaktive REPL/Konsole für Clojure und JavaScript präsentieren können ☺.

> Starten Sie mit dem Aidbox [FHIR Server](https://www.health-samurai.io/aidbox) für Datenspeicherung, Integrationen, Gesundheitsanalysen und mehr, oder [beauftragen Sie unser Team](https://www.health-samurai.io/services) für Ihre Softwareentwicklungsprojekte.

[![Aidbox FHIR Platform Free Trial](image-1.avif)](https://www.health-samurai.io/aidbox)

Siehe auch: [Type Schema: Building FHIR SDKs](/blog/type-schema-a-pragmatic-approach-to-build-fhir-sdk) und [Der FHIR-Leitfaden für CTOs](/blog/the-fhir-guide-for-ctos-and-technical-leaders).