Author Archives: Michel

About Michel

Developer at furore.com. FHIR Conformance & Profiling specialist.

Introducing Forge for STU3

DutchKingWedding

Royal tears of joy at the official STU3 release ceremony

Today marks the community release of Forge for FHIR STU3. A joyful moment, right after our national Dutch King’s day and just in time for the upcoming HL7 WGM in Madrid.

Hoera! Hoera! Hoera!

You can download Forge, the FHIR profile editor, for free from the FHIR profile registry at simplifier.net. In this article we’ll introduce you to the new release and try to answer some common questions about migration to STU3.

Side by side installation

The new Forge for STU3 ClickOnce installer package has a new application identity that allows side by side installation. This means that you can install and use Forge for STU3 next to an existing installation of Forge for DSTU2 on the same machine. Each release will use it’s own version of the FHIR core resource definitions and manage it’s own application configuration settings separately.

dutch-king-willem-alexander-with-wife-maxima-and-animal-pelt

Side by side installation

As of now, future application updates will target the Forge STU3 release. You can still use Forge for DSTU2 and remain to keep using it for as long as you need. But from now on, the Forge DSTU2 branch will no longer be actively developed as our development efforts are now focused on the STU3 branch. We will remain to provide support for the final Forge DSTU2 release to our commercial customers until they have migrated to STU3.

Profiling changes in STU3

FHIR STU3 introduces a lot of updated and new resources and datatypes. Changes to the conformance resources have the largest impact on profiling. Fortunately, the main FHIR conformance resources are relatively mature and haven’t changed drastically, with one notable exception in the terminology space: CodeSystem has been separated from ValueSet. However this change has no impact on Forge.

You will notice some relatively minor changes to the StructureDefinition resource and the ElementDefinition datatype. Some properties have been renamed and there are a couple of new properties, e.g. to define FHIRPath expressions.

One of the more notable changes involves ElementDefinition.type.profile. In DSTU2, an element type can define multiple profiles. However there are some complications with this approach:

  1. Multiple type profiles pose a problem for dynamic code generation, UI input form generation etc.
    Note that although Forge for DSTU2 (secretly…) supports specifying multiple profiles per type, all known FHIR DSTU2 implementations actually only consider the primary type profile. Practical use of this technique has been actively discouraged by the FHIR infrastructure group. We are not aware of any customers to rely on profiles having multiple type profiles.
  2. When an element has type ResourceReference, we would like to be able to express constraints on the reference target. However ElementDefinition.type.profile expresses constraints on the ResourceReference itself.

FHIR STU3 solves these problems by:

  1. Introducing ElementDefinition.type.targetprofile wich applies when the type code equals ResourceReference and expresses a constraint on the reference target. As before, you can use ElementDefinition.type.profile to constrain the ResourceReference datatype itself.
  2. Limiting ElementDefinition.type.profile max cardinality to 1. This takes away any ambiguity for e.g. code/UI generation.

FHIR STU3 also introduces a lot of changes to the other (clinical) resources and data types. Forge for STU3 includes a new STU3-specific version of specification.zip that contains updated definitions for all the existing and newly introduced resources and data types in STU3.

Migration to STU3

As FHIR STU3 introduces breaking changes to StructureDefinition and ElementDefinition, Forge for STU3 is not compatible with existing DSTU2 profiles.

It is possible to automatically convert existing DSTU2 StructureDefinition resources to the new STU3 format. However an automatic conversion tool can only update the meta information in the profile. It cannot safely convert the actual profiling constraints. Because STU3 introduces changes to many of the resources, some of the constraints in a DSTU2 profile will no longer be valid when converted to STU3. For example, when a DSTU2 profile constrains an element that has been renamed/removed in the corresponding STU3 resource. Therefore migrating profiles from DSTU2 to STU3 will usually require manual review and corrections.

We have a team of experienced consultants with a track record in FHIR profiling who can assist and support you with smooth profile conversion to STU3. Feel free to contact us for a quote or if you want to learn more about our professional FHIR consultancy services.

King-Willem-Alexander-Queen-Maxima-Princesses-Catharina-Amalia

Dutch royal family is said to be “super excited” about FHIR STU3

Looking back

We’ve come a long way since the first release of Forge. The initial Forge DSTU1 release attempted to provide a reference implementation of the FHIR standard. Our team tried to demonstrate that the basic FHIR (profiling) principles could indeed be implemented and put to use. Forge was originally designed to hide the user from the complexity of the underlying XML/JSON wire representation. The novel UI design quickly drew a small but growing user base and succeeded to stimulate both the adoption as well as the development of the FHIR standard itself.

After updating Forge to DSTU2, we focused our efforts on improving the quality of the generated differential and snapshot components. Implementing a proper and fully capable snapshot generator in the .NET FHIR API library proved to be a (royal pain in the ***) challenging and time consuming undertaking that claimed a great deal of development time during 2016. But those efforts eventually drove the implementation of some very powerful profiling features in Forge, such as support for derived profiles, deep inline constraints on complex extensions and dynamic expansion of choice type elements and properties. It took a fair bit of time and effort to stabilize some of the more complex features. But thanks to feedback from our users and from the FHIR profiling community, we managed to solve most of the reported issues.

Moving from DSTU2 to STU3, we have noticed a clear trend in Forge issue reports where they slowly but steadily involve more and more complex and rare profiling use cases. This indicates that basic FHIR profiling features have indeed matured and stabilized and that our users are starting to apply more advanced profiling techniques. And while these newly reported issues may not always be easy to solve, generally they do seem to confirm that FHIR profiling is proving to be effective and productive!

Looking forward

Now that we have updated our full tooling stack to STU3 (The official FHIR .NET API library; Forge, the FHIR profile editor; simplifier.net, the FHIR profile registry; and last but not least Vonk, our new enterprise-grade FHIR server), we are looking forward to unleash them onto the FHIR community, starting at the upcoming HL7 WGM in Madrid.

Our simplifier.net platform now supports STU3, but will also remain to serve existing DSTU2 profiles. We will cooperate with our Simplifier users in order to provide migration strategies to update existing DSTU2 projects to STU3. Under the hood, our team has updated the simplifier.net environment to the new Microsoft .NET Core platform, which brings a significant performance increase, improved response times and higher scalability. We are experimenting with the new Microsoft Orleans platform, an exciting new cloud-based technology, in order to implement scalable validation support and initial results are quite promising. This will allow our simplifier.net platform to provide computationally intensive features to an ever increasing and demanding user base.

As Forge has been updated to STU3 and most of the underlying complex profiling logic is finished and maturing, we can now focus our development efforts towards improving the user experience, file management, online simplifier integration and profiling workflow support. We have received a lot of great suggestions from the community about possible improvements and new features that will allow us to further improve the application. Your feedback remains very valuable to us, so please don’t hesitate to submit issue reports and/or feature requests! Should you have a need for commercial support, then you may benefit from one of our simplifier.net account plans.

Last but not least, our brand new Vonk server is now ready for STU3. Vonk is a modular and highly scalable FHIR server based on the new Microsoft .NET core platform. Aside from performance improvements, the new platform also enables some surprising new applications, as recently one of our bright engineers successfully managed to spin up a Docker image of Vonk server running .Net core on Linux. The new flexible options for host operating systems ensure that our Vonk server will smoothly integrate into any existing customer infrastructure.

Final thoughts

Kings day

Millions join the Forge STU3 release party, Amsterdam 2017

We hope that you enjoy the new Forge STU3 release, as well as all our other FHIR tools. The Furore FHIR team celebrated this important milestone in Amsterdam on our King’s birthday, which traditionally involves orange outfits, DJ-powered canal boat rides and abundant substance abuse. And now that the orange smoke has cleared up, we’re back making FHIR simple.

 

Download Forge for STU3 for free from simplifier.net

Happy profiling and long live the King!

 

Zo waerlijck helpe my Forge almechtig

 

Forge

Forge 14.4 technical overview

Introduction

Last Friday (November 25th) we published a new Forge release, Forge 14.4 for DSTU2 – FHIR DevDays 2016 edition. You can download the new Forge release for free from www.simplifier.net. The previous Forge release (13.2) dates from June 10th, so clearly it’s been a while since we’ve published an update. In this blog post I’ll elaborate on the new features.

Profiles on profiles

Profiles created in Forge 13.2 and earlier always express a set of constraints on a FHIR core datatype or resource. However the FHIR specification also allows you to author so-called profiles-on-profiles or derived profiles. A derived profile represents a set of constraints on another, existing (non-core) base profile. This allows you to define a hierarchy of profiles that are based on each other.

In a typical situation, a national standards organization publishes a set of official national FHIR profiles defining some common country-wide constraints. Organizations within this country create and publish their own profiles that are derived from the official national profiles. For example, the Dutch HL7 affiliate publishes a national Dutch Patient profile with a specific constraint on Patient.identifier for the Dutch social security number (BSN). Dutch organizations can now author and publish their own, more specialized profiles with additional organizational constraints based on (derived from) the national profiles. Because different organizational profiles all conform to a common set of national profiles, they provide a certain well-defined level of interoperability within the country.

profile-hierarchy

Hierarchy of Profiles

The rules for derived profiles are similar to the rules for profiles on core datatypes or resources. A profile is valid if all resources that conform to the profile also conform to the associated base profile. This implies that a profile is only allowed constrain the base profile. A profile is not allowed to relax/remove constraints defined by the base profile.

Note: In a sense, we can interpret a profile as a filter or predicate on the resources space, cf. a WHERE clause in a SQL expression. The number of constraints that a profile expresses is inversely proportional to the total amount of conforming resources. As derived profiles become more and more specific, the total set of conforming resources becomes smaller and smaller. The extreme case being a profile that matches no resources at all; such a profile may very well be valid according to the FHIR spec, albeit meaningless. Similar to the SQL predicate WHERE 1=0 which is perfectly valid but will always evaluate to an empty set.

new-derived-profile

In Forge release 14.4, you can now create and edit profiles based on other (non-core) profiles. The command New Derived Profile creates a new derived profile based on an existing base profile on disk. The initial implementation is still somewhat limited and provides support for fairly simple base profiles (e.g. without slicing). Future updates will add support for more advanced scenario’s such as reslicing.

Resolving resources

Profiles created in previous Forge releases until version 13.2 were always based on a core datatype or resource definition.The Forge application directory contains an archive “specification.zip” that contains the official definitions of all FHIR core datatypes and resources. Upon application startup, Forge scans the ZIP archive and loads all the available definitions. When creating a new profile, Forge extracts the selected core base definition from the ZIP file and initializes a new profile from the selected base.

In the new 14.4 release we’ve added support to create and edit profiles based on other existing profiles. Forge now needs to resolve the custom base profile from a custom location, as it can no longer be resolved from the default ZIP archive that contains only the core definitions.

A profile can also express constraints on element types via external profiles. For example, a Patient profile may introduce a custom Identifier profile on the Patient.identifier element. In this case, Forge also needs to resolve the specified external profile in order to dynamically generate user interface components for profile child elements and verify the specified constraints.

The same holds for extension elements in a profile. Each extension element is mapped to an external extension definition. Forge needs to resolve the specified extension definitions in order to generate UI and verify constraints.

Forge should be able to resolve external profiles from the containing (working) folder on disk, from a separate external directory, from a FHIR server or from the FHIR registry Simplifier.net. To implement this, Forge requires a generic and flexible system to resolve external (user defined) profiles on the fly, separate from the standard core datatype and resource definitions.

Fortunately (and not coincidentally…) the FHIR .NET API library provides a flexible and efficient resolving mechanism based on the generic IResourceResolver interface, as explained by Ewout in his recent article Validation – and other new features in the .NET API stack. The library exposes default implementations that support resolving resources from disk and online. The library also exposes convenient decorators for caching and resolving from multiple sources based on priority. Forge 14.4 now leverages the FHIR .NET API to implement a flexible multi-step mechanism for resolving external (conformance) resources.

resourceresolver

Resource Resolvers

Upon opening an existing profile in Forge 14.4, the application creates an associated resolver that is bound to the containing folder on disk (including subfolders). The resolver provides cached access to all external profiles in the same folder structure. Future updates will introduce support for the configuration of additional sources, e.g. on local disk or online.

Note: for now, please keep related profiles together in a common folder and Forge should find them. Be aware that the resource resolvers cannot resolve profiles with duplicates, i.e. multiple profiles in the same folder that share a common canonical URI. When Forge detects duplicate profiles, it will display an error message and list the conflicting files. In that case, manually delete/move all the obsolete duplicates from the folder and retry.

The current Session Explorer in Forge provides a conceptual/logical view of resources and resource containers. However the new resource resolving approach introduces a new folder-based workflow that is fundamentally different from the earlier approach and does not fit well with the current Session Explorer. Therefore the Session Explorer will soon be phased out in favor of a new folder-based approach (cf. Visual Studio Solution Explorer).

Snapshot generation

One of the largest changes in the Forge 14.4 release involves a complete new implementation of the logic involving the generation of snapshot and differential components. Let’s take a closer look at these concepts.

snapchat-glasses

Snapshot Spectacles

A FHIR profile defines a structured set of elements. Each element definition has a set of properties. The combination of all the element definitions and associated properties uniquely defines a specific datatype or resource structure. This holds for both a core datatype or resource definition, as well as for a (derived) profile. FHIR defines this complete representation as the so-called “snapshot” component. The official name might be a bit misleading in that it suggests a captured state at a specific moment in time; while this is not incorrect, the key aspect of the snapshot component is that it intends to provide a complete and full representation of a certain data structure. An application that receives a profile snapshot has all the available information and does not need to resolve any external profiles.

A snapshot component can be quite large (~ thousands of lines of XML/JSON). And for a derived profile, the snapshot component contains a lot of redundant information: complete definitions of all the unconstrained elements and properties that are inherited from the base profile. Provided an application has access to the base resource, then it is possible to (re-)generate all the inherited redundant information. So we can also represent a profile by only describing the actual profile constraints and omitting all the information that is implicitly inherited from the base profile. Such a sparse representation of profile constraints is defined by FHIR as the “differential” component. The differential component only expresses the actual constraints with respect to the associated base profile. Generally, the differential component is (much) smaller than the snapshot component. Also the differential provides a convenient serialized representation for profile authors to browse and inspect, contrary to the snapshot component that contains a lot of redundant noise which makes it difficult to navigate.

The FHIR specification requires that a profile should contain either a snapshot component or a differential component or both (invariant sdf-6). A serialized profile with only a differential component has a smaller size and is therefore cheaper to persist and transmit. However this puts the burden on the receiving side to (re-)generate the snapshot component from the associated base profile. A serialized profile that contains a snapshot component is much larger but also self-sufficient; it contains all the available information and the receiver does not need access to any external profiles.

Forge releases up until version 13.2 contained custom application logic to generate the snapshot component from the differential. The old logic was fairly simple but useful as long as Forge was limited to profiles on core datatypes and resources. However in order to implement support for profiles on profiles (a.k.a. derived profiles), the existing snapshot generation logic was no longer sufficiently capable and needed to become a lot smarter. As we now had to completely re-implement snapshot generation anyway, we decided to move the logic out of Forge and into the open source FHIR .NET API library.

The implementation of full-fledged snapshot generation proved to be quite an undertaking. During the process we discovered that some low-level aspects were not yet clearly and/or fully defined by the FHIR specification. So we cooperated with the FHIR core team and profiling community to fill in the blanks and complete the missing parts of the specification. Especially Chris Grenz‘s contributions proved to be invaluable – Kudos! Working closely together with Chris, who works at Mayo Clinic, we managed to define how to unambiguously express some remaining advanced scenario’s and subsequently to align both our implementations.

Unfortunately the snapshot component is not completely deterministic, e.g. element id’s may vary, list order may vary etc. So FHIR cannot and does not define a “canonical” snapshot format that would allow us to perform a byte-wise or node-by-node comparison of two snapshot versions. Therefore a snapshot comparison algorithm needs some custom logic to handle special FHIR rules.

Although snapshot generation certainly isn’t the sexiest topic within the FHIR spec, it is a crucial aspect for any system dealing with profiles (including validation). And feature-complete snapshot generation proved to be quite challenging to implement. For example, in order to generate snapshots for core type definitions, the algorithm must be able to detect and handle recursive type relations, e.g. Element.id and Extension.extension. Also the correct implementation of different scenario’s involving (re-)slicing proved to be non-trivial. So we’re quite pleased that this fundamental part of the FHIR specification is now clearly defined and completely implemented (barring some unknown unknowns…). If you’re interested in the implementation (you are definitely a FHIR nerd like us and) you can inspect the Hl7.Fhir.Specification component source on Github. Fortunately usage is very simple:

IResourceResolver resolver = ...
StructureDefinition structureDef = ...
var generator = new SnapshotGenerator(resolver, settings);
generator.Update(structureDef);

The snapshot generator uses the specified IResourceResolver instance to resolve references to external profiles and/or extension definitions. If this argument equals null, then the generator automatically falls back to the set of FHIR core datatype and resource definitions. The optional settings parameter allows the caller to specify some custom configuration options for the generator.

simplifierSimplifier.net is not yet capable of automatically (re-)generating the snapshot component. Currently, when you publish a profile, you have to explicitly submit the snapshot component in order for Simplifier.net to render the complete structure. Note that if you publish a profile to Simplifier from within Forge, the application automatically handles this. Once the new release of the FHIR .NET API is ready and stable, we will update Simplifier.net and integrate the new snapshot generator. From then on, Simplifier will be able to accept profiles with only a differential component and automatically (re-)generate the snapshot. Our team is also working on implementing a dynamic differential rendering in Simplifier, so the user can activate a filtered view of only the differential profile constraints.

Differential generation

We’ve seen how snapshot generation transforms a sparse tree of constraints into a complete representation of the target structure. This functionality is now provided by the FHIR .NET API library, in the form of an atomic operation (cf. pipeline). Of course, there also exists an inverse transformation that generates a sparse differential component from a complete snapshot representation of a structure. The differential representation only contains nodes that are constrained with respect to the base resource. Unconstrained nodes are excluded from the differential.

differential

Differential Structure

Forge generates the differential representation on-the-fly and keeps it in sync with the profile while it is being edited. This approach is completely different from the snapshot generation. Each element definition and property in a user profile is associated with the corresponding node in the underlying base profile. This allows Forge to determine which profile nodes are actually constrained (not empty and not equal to base). To no surprise, the process to find the corresponding nodes in the base profile turns out to be quite involved, esp. for slicing.

Originally, up until version 13.2, Forge contained custom logic to resolve corresponding nodes in the base profile. The original logic was limited to handling only fairly simple profiles, esp. core datatype and resource definitions and was not very efficient on memory usage. As the application developed further, we were slowly stretching the limits of the original algorithm. Users started reporting unpredictable behavior (i.e. differential was not always properly synchronized) that was hard/impossible to fix. Eventually this was no longer maintainable. So we decided to also completely rewrite the differential generation logic.

Fortunately, the new snapshot generator logic in the FHIR .NET API library already needs to resolve corresponding nodes in the base profile anyway (because each differential constraint is merged onto the corresponding base node). So Forge does no longer have to perform that same complex exercise itself. Instead, Forge now receives all the base profile associations as a useful by-product of the snapshot generator. This is quite efficient and increases the loading speed of a profile. Also we no longer need to maintain and harmonize separate but similar implementations in Forge and the .NET API library, as all common and reusable logic has now been moved into the API.

Since each node in the loaded profile is now associated with the corresponding node in the base profile, it is now trivial to determine which nodes are actually constrained with respect to the base resource. Only constrained nodes are actually included in the differential. Unconstrained element properties (either empty or equal to base) are set to null in the underlying PoCo. Also complex nodes and element definitions having all child properties equal to null are cleared in the PoCo and their state is automatically re-evaluated whenever a child node has changed. This way, all unconstrained nodes are effectively excluded from the differential component. The whole process is quite efficient as after a change, only the affected nodes are re-evaluated.

storagehandlers

Generate Differential

The serialized xml representation is (re-)generated in the background and rendered whenever the user activates the Xml tab. This ensures that the displayed xml is always up to date without impeding the application performance. The Forge UI only displays the differential, by design, in order to save memory. By default, profiles are also saved to disk with only the differential component. The Options menu provides a configuration setting to toggle the serialization of snapshots components when saving profiles to disk. Needles to say that profiles with snapshots are significantly larger, therefore in Forge the snapshot option is disabled by default.

Conclusion

This article is way too long… hats off if you managed to read and process all this information. And I still feel like I just scratched the surface. Time permitting, maybe I’ll author another article about the specifics of the snapshot generator implementation, for those few FHIR die hards that care (the usual suspects).

sad-tree2

Sparse Tree

Looking back to 2016, the Furore FHIR team has invested a lot of time and effort in (re-)designing and (re-)implementing the fundamental infrastructural components of a FHIR ecosystem, thereby laying the groundwork for a plethora of useful productivity-enhancing features that we can now start building and enhancing in 2017. I must confess that I really enjoyed working  on some of the hard core abstract logic. But the nerdy stuff can also be quite demanding, time consuming and eventually goes at the expense of basic social behavior and interpersonal relations… So I’ve learned a long time ago that, even though I take joy in higher abstract thinking, I shouldn’t bury myself in it for all too long, as there is a personal price to pay. Now the Forge user interface desperately needs some love – as well as my estranged girlfriend, who’s totally fed up with me rambling on and on about snapshots and such. So I am eagerly looking forward to next year, when I can focus again on improving usability, workflow and my personal love life. But first let’s celebrate the holidays, decorate a tree, spend some quality time with family and friends and hopefully regain some of those long lost social skills.

Happy profiling!

Michel Rutten

Forge

Forging Profiles on Profiles

Introduction

Recently (Friday November 25th) we published a new Forge release, Forge 14.4 for DSTU2 – FHIR DevDays 2016 edition. You can download the new Forge release for free from Simplifier.net. The previous Forge release (13.2) dates from June 10th, so clearly it’s been a while since we’ve published an update. In this blog post I’ll elaborate on the most important new feature: support for profiles on profiles, also known as derived profiles.

What is a derived profile?

Out of the box FHIR resources are designed to cover 80% of the common use cases. In order to cover the remaining 20%, FHIR introduces profiles. A FHIR profile defines a set of constraints on a standard FHIR resource or datatype. This allows you to define a specialized variant of a standard resource for a specific use case. And because profiles are based on common FHIR resources, they provide a certain basic level of global interoperability with other (external) FHIR systems.

Obviously, as we limit the context to a specific country, region or organization, we can probably harmonize more aspects and provide increased interoperability within that limited context. FHIR supports this common use case by allowing you to define so-called profiles on profiles a.k.a. derived profiles. A derived profile defines a set of constraints on another existing profile, the so-called base profile. The derived profile implicitly inherits all the existing constraints from the associated base profile. A derived profile can only further constrain the base profile, similar to profiles on core resources.

Example:

  • The HL7 affiliate for the Netherlands publishes a national profile for a Dutch patient. The profile is based on the standard FHIR Patient resource and defines a number of additional constraints, e.g. in order to identify Dutch patients by their unique national social security number (BSN). The profile also constrains the generic Patient.careProvider reference to a specific Dutch practitioner profile.
  • A Dutch hospital authors a derived Patient profile for use within the organization. The organizational Patient profile is based on the national Dutch patient profile and defines some additional constraints that only apply within the organization. The hospital’s custom Patient profile defines additional constraints for the unique Patient identifier that is assigned by the hospital EHR system. The profile also prohibits the Patient.animal element, as it does not apply.
Hierarchy of Profiles

Hierarchy of profiles

As the example demonstrates, this allows you to create a hierarchy of profiles, e.g. on a national, regional, organizational and/or departmental level. As we navigate deeper down the profile hierarchy, we encounter more specific profiles for more limited use contexts.

Authoring a derived profile in Forge

New Derived ProfileUsing the new Forge 14.4 release, you can now easily author a derived profile. Forge 14.4 introduces a new command “New Derived Profile“. You can find the new command directly on the start screen, in the File menu and also in the Session Explorer toolbar. The new command resembles the existing “New Profile” command, but with one important difference: you can select an existing profile as the underlying base profile. Forge will display a File Open dialog window to select a suitable base profile from disk. After selecting the base profile, Forge will create and display the new derived profile.

For example, let’s assume that Mayo Clinic wants to create their own derived Patient profile based on the US DAF Patient profile which defines a set of national constraints for the US Patient. Below, we can see the original DAF Patient base profile loaded in Forge. All the constraints defined by the base profile are clearly indicated by the yellow pen icon:

DAF Patient Profile

Notes:

  • The blue exclamation icon indicates a “must support” element
  • The blue paperclip icon indicates extension elements
  • The yellow pen icon indicates a constrained element

Now Mayo Clinics creates a new derived Patient profile based on the DAF Patient profile. The new derived Patient profile inherits all constraints that are defined by the base DAF Patient profile. Initially, the new derived profile does not introduce any new constraints, as is clearly visible in the Forge Element Tree:

Mayo Clinic Patient Profile

The screenshot demonstrates that the derived Patient profile indeed inherits all the constraints defined by the base DAF Patient profile (e.g. you can see the inherited extensions such as ethnicity). Because the implicitly inherited constraints are not defined by the derived profile itself, they are not considered to be part of it. This is clearly visible in the Forge element tree, as none of the elements in the new derived profile show a yellow pen icon (except on the root element, because the derived profile has a new name & url). In other words, the new derived profile shown above is (almost) empty.

Now Mayo Clinic can define additional specific constraints in the derived profile. Any newly defined constraints will actually be part of the derived profile and consequently they will be indicated by a yellow pen in Forge. For example, the screenshot below shows how the derived profile defines an additional constraint on the Patient.photo element:

Mayo Clinic Patient Profile with constraint on photo

Below you can see the serialized XML of the derived Patient profile. We can clearly see the newly introduced constraint on the Patient.photo element. Note that the root element definition is mandatory in DSTU2, even if the element is not constrained. This requirement will be deprecated in STU3. Also note the (mandatory) reference to the underlying DAF Patient base profile.

<?xml version="1.0" encoding="utf-8"?>
<StructureDefinition xmlns="http://hl7.org/fhir">
  <meta>
    <lastUpdated value="2016-12-01T16:47:22.41+01:00" />
  </meta>
  <url value="StructureDefinition/MayClinicPatientProfile" />
  <name value="Mayo Clinic Patient Profile" />
  <status value="draft" />
  <date value="2016-12-01T16:28:17+01:00" />
  <fhirVersion value="1.0.2" />
  <kind value="resource" />
  <constrainedType value="Patient" />
  <abstract value="false" />
  <base value="http://hl7.org/fhir/StructureDefinition/daf-patient" />
  <differential>
    <element>
      <path value="Patient" />
    </element>
    <element>
      <path value="Patient.photo" />
      <max value="0" />
    </element>
  </differential>
</StructureDefinition>

Conclusion

This concludes our introduction of the new support for derived profiles in Forge. The example demonstrates that the authoring process is actually quite easy for end users and quite similar to creating profiles on core resources. After all, in FHIR we try to move complexity away to the developers of tools and servers.

As simple as this all seems to the end user, the actual implementation entailed a long and winding road straight into the bowels of the FHIR specification. In a separate blog post, I will provide some more in-depth background information about the technical challenges we faced when trying to implement support for derived profiles, and how we addressed these.

If you have questions concerning (derived) profiles or need a bit of assistance, then you are strongly encouraged to join the online FHIR discussion groups. The FHIR community is very active, friendly and helpful and usually you quickly receive helpful responses from FHIR users all over the world. The conformance stream is specifically intended to discuss FHIR profiling and related tools including Forge. Also if you’ve implemented FHIR in a production environment, then please inform the FHIR community and share your story in the implementers stream!

Two final notes:

  1. Today we have published a minor hotfix release (14.4.1) with a couple of bugfixes. Should you encounter any issues while trying to repeat the exercise above, then please make sure that you have upgraded to the most recent version. Users of release 14.4 will receive an auto-update notification. Users of earlier releases should manually download and install the new version.
  2. The new Forge release does not yet support base profiles containing slices. If you select a base profile containing slices, snapshot generation will fail and generate a runtime exception. We will introduce support for sliced base profiles in a future application update.

Happy profiling!

Michel Rutten

Forge for DSTU-2

In preparation for the upcoming HL7 International Working Group Meeting in Paris, we have been working on upgrading Forge, the FHIR profile editor, to conform to the current FHIR DSTU 2 specifications. In this post I’d like to provide an overview of the upcoming changes.

Conformance Package

An earlier blog post by my colleague Marten Smits discusses the changes in DSTU-2 with respect to profiling: The evolution of Profile to “conformance package”. A fundamental change is the introduction of the new StructureDefinition resource, as a replacement for the (now obsolete) DSTU-1 Profile resource. The DSTU-1 Profile resource represents a set of related profiled resource and/or extension definitions, combined into a single resource. The new StructureDefinition resource represents a single resource or extension definition. A profile author can define and publish a set of related conformance resources – called a “Conformance Package” – by means of the Composition resource, containing a list of references to individual (stand-alone) resource profiles. The referenced profiles can be served from the same location as the composition. But it is also entirely possible for a composition resource to include references to external profiles defined elsewhere. This new approach facilitates the reuse of shared resource definitions. A common published resource profile can be referenced by multiple conformance packages.

Project Explorer

The new DSTU-2 profiling approach based on distributed resources requires a redesign of the Forge user interface. The original UI was based on the premise that the profiling resource definitions are contained in a single Profile resource that represents the unit of storage. For DSTU-2, Forge must now provide support to manage a distributed set of conformance resources, possibly originating from multiple locations. This requirement inspired the implementation of a proper Project Explorer:

Forge - Project Explorer

Forge – Project Explorer

The project explorer displays all open projects and project items. The author can create/open multiple projects simultaneously. Conceptually, a project represents a “Conformance Package”.

Terminology

The term “project” is Forge-specific and might change in the future. The FHIR specification does not define such a thing as a profiling “project”. The notion of a Forge project closely resembles a similar concept in popular development environments. By using a generic term, the application is not limited to support only conformance packages; a future release could provide additional support for other types of projects, e.g. a set of concrete (non-conformance) resources.

Local Scope

A Forge project also defines a local “resource scope” in the application, similar to the old DSTU-1 Profile container resource. Resources can reference other resources that exist in the same project via a simple local reference (e.g. #MyExtension). The resource selection popup dialog provides a list of available resources that exist within the current project.

Storage and Publication

Off course the application allows a profile author to open and save individual profiling (StructureDefinition) resources. Forge supports both local storage (on disk) and remote storage (FHIR server). A Forge project is not a FHIR resource and cannot be persisted as such. Forge will provide import/export commands that allow the author to open / save a project from / to a Bundle container resource. The Bundle resource is only used as an ephemeral transport and storage container and is not represented within Forge. When the author uploads a bundle to a FHIR server, the server will unpack the bundle and store the individual contained resources. Forge will provide support to define and manage Conformance Packages based on a Composition resource. When a package is finished, the author can publish the final version of a package to a FHIR registry server.

We are planning to publish a new alpha release this week. Stay tuned!

FHIR profiles and implementation guides

The Furore FHIR team has recently been exploring the topic of authoring implementation guides for FHIR profiles. In this blog posting, I’d like to share some of our preliminary ideas with you. First let’s introduce a couple of key concepts.

So what is a FHIR profile? The HL7 FHIR standard defines a set of base resources, e.g. Patient and Observation. The standard base resources have very generic definitions. A FHIR profile allows you to author and publish a customized, more specific resource definition, by specifying a set of constraints and/or extensions on the base resource. Concrete FHIR resources like e.g. a Patient resource can express their conformance to a specific profile. This allows a FHIR server to programmatically validate a given resource against the associated profile definition.

Now assume we’ve authored a set of related profile definitions for our organization. We would like to publish some sort of manifest that lists all the relevant profiles and also some accompanying documentation. For this purpose, the FHIR standard introduces a Conformance Package. A conformance package typically contains:

  • A set of related resource profile definitions
  • A manifest listing all the available profile definitions (based on Composition resource)
  • An implementation guide describing the profiles

An implementation guide provides documentation about the package and the individual profiles targeting FHIR implementers and system integrators. You can find some examples on the HL7 FHIR website. As an implementation guide is an integral part of a conformance package, we would like to provide first-class tooling support for authoring implementation guides.

Let’s explore the requirements for an implementation guide:

  • Provide some general documentation about the conformance package
  • Provide detailed documentation for each of the individual resource profiles
  • Include documentation from external sources, e.g. if our package has external references to (third-party) profiles published elsewhere.
  • Include dynamically generated content, e.g. UML diagrams, hyperlinks to related documentation etc.
  • Support distributed content on different servers (conforming to the FHIR REST principles)
  • Define the content hierarchy
  • Provide documentation in multiple languages
  • Provide different sets of documentation targeting different audiences
  • Reuse common content in multiple implementation guides
  • Publish our implementation guide to multiple output channels (Web, mobile, PDF, …)
  • Clearly separate content from design/styling

The above requirements are closely related to Content Management Systems so we can reuse some architectural CMS concepts, e.g. the triangular relationship between content types, output channels and render templates.

CMS Concepts - MultichannelingIn order to ensure that our content is suitable for publication to any output channel, we should only provide limited styling options to documentation authors (paragraphs, headings, bulleted lists; cf. Markdown syntax).

Assuming documentation may be distributed over multiple servers (just like FHIR resources and profiles), how do we find the relevant documentation for a given conformance package?Implementation Guide - Resolving Documentation

  • Resolve the global documentation associated with the conformance package itself
  • Enumerate the profiling resources in the conformance package manifest
  • For each related profiling resource
    • Resolve and include the associated documentation (recursively)

The resolving process may be driven by global publication parameters such as  language and audience; e.g. find the available documentation for a given resource, for a specific language and a specific target audience.

In a forthcoming article we will explore this process into more detail and discuss some other aspects of the proposed architecture for authoring implementation guides.