I’ve always been fond of creating functional prototypes when designing apps. There are a number of advantages over simply documenting what the app should do:

It means that the users (e.g. clinicians) get to try out something that actually works (sort of) before ‘signing off’ on the requirements. This reduces the chance of delivering something that doesn’t quite meet their needs.
It helps significantly with the FHIR design. Assuming that the app actually communicates with a FHIR back end (which can be one of the freely available reference servers such as HAPI), then it validates the resource design (which resources are needed and their profiling) as well as the API’s that are going to be needed. This can be quite a tricky step to implement depending on what the real back end is going to be.
It’s much simpler and quicker to develop than anything that needs to be ‘production ready’. For example, you don’t generally need to implement any security or handle the errors that need to be allowed for in a real application.
It delivers solid requirements to the development team, as well as a test app that they can use as the API is developed.

Of course, there are disadvantages as well:

Any development work takes some time and money
There’s the risk that the user treats the prototype as the end product – “You’ve already written it – why the delay?”

But overall, I think that the advantages outweigh the disadvantages.
I was reminded of this recently when working with a client looking at developing a referrals API to support a mobile app, so thought it would be worth writing about the approach in a bit more detail.
We start, as always, with the requirements.
We want a mobile app to support triaging new referrals within a hospital. These could be referrals from external providers for outpatient assessment, or internal referrals for procedures like Cardiac stent insertion or specialist assessment for inpatients (e.g. a surgical patient with chest pain).
This can be expressed as a simple use case:
The clinician loads the app, and is presented with a list of new referrals for their service. They select a referral, and can see the appropriate details. They assign a priority, and complete the triage. The referral is updated and an appointment can be scheduled. The referral is removed from the list.
The clinician loads the app, and is presented with a list of new referrals for their service. They select a referral, and can see the appropriate details. They note that this referral is better managed by a different service. They select the new service and complete the triage. The referral is removed from their list and will appear on the list of the new service.
There would be other use cases for the different scenarios that need to be supported – such as declining a referral or seeking further information. It’s actually worth trying to be as comprehensive as possible in the scope of the use cases (but do keep them concise) as they are often the key drivers for design. For example, that second use case means we need to be able to modify the service that a referral is sent to – not just accept or decline one. This can have a significant impact on the technical design.
Next, we think about what the data model is. This can be done in a number of ways – it can be helpful to create a logical model using the clinFHIR Logical Modeler, but for the purposes of this post, we’ll just use a simple list of data items:

Textual description of reason for referral
Coded reason, if applicable
Target hospital Service
Additional information as appropriate (eg previous observations, investigations such as ECG etc.

Now we can think about the resource graph to represent this – ie the individual resource types that we’re going to need and the FHIR API to manipulate them. It’s useful to do this in conjunction with the prototype development as the actual building of the app will often tease out details that are easy to miss otherwise.
Before we do that, let’s think a bit about what the development toolchain is going to be. This is a very personal choice – and it doesn’t really matter as this is a ‘throwaway’ prototype. What I’ve used is:

Stencil js. This uses the ionic framework to make it simple (relatively) to create mobile applications using web based technologies. There’s an excellent website by Josh Morony that has a lot of information about this.
A FHIR reference server. There are a number available – I’ve used the Hapi CLI server myself, but any FHIR compliant server will do.

Netlify. This makes it easy to publish versions of the app for others to view and comment on – particularly mobile apps. It hooks into github so that simply committing an app will make it available on the web.
Microsoft Visual Studio Code – a free IDE that has a lot of plugins to support development

Now, on to the app!
We’ll start with a simple model and refine it as we go. We’re going to need at least 5 resources:

Patient – who the referral is for

Task – tracks the status of the referral as it passes through the various workflow steps – from being received, to being triaged, having an appointment made followed by an encounter and so forth.

ServiceRequest – represents the clinical nature of the referral. The reason it was created, who created it, additional clinical data and so forth.

Practitioner – the creator of the referral

HealthcareService – represents the business service – eg a Cardiology outpatient clinic

This is what a sample resource graph could look like (using the clinFHIR GraphBuilder app, which understands the possible references between resources):

This is a ‘snapshot’ representation of the key resources that we’d use in referral queries. There could well be others, such as links to Observations and Conditions that are part of the clinical material accompanying the referral, or to the Practitioners that change the referral state (we could use the Provenance resource for that if needed).
Note that we’re not concerned with how these resources are created in response to receiving a referral (if indeed, the data source uses resources), or how the referral was received – simply what the query and update graphs look like from the perspective of our app through the FHIR API.
Similarly, there are many ways that the referral could actually have been sent from creator to recipient – ranging from PDF, HL7 v2, FHIR document or many others.
The key takeaway from the graph is that we’re substantially going to be interacting with Task resources as our app functions – the ServiceRequest and other resources hang off that.
Before we go a lot further, we should really create some sample data that our prototype can use. We could just create this manually (they are just Json / XML files after all) but a much smarter solution is to use sushi and FHIR shorthand to create the resources, and then upload them to the FHIR reference server – ideally using a script to do so (or create a bundle and send it as a Transaction). This makes it much easier to enhance the sample data as we go – especially as we may need to make changes as the app progresses.
Here’s an example of a ServiceRequest and a corresponding Task. We’ve kept it quite simple for now, but it’s easy to extend and change if needed. For example – the reason for referral may be better modelled as an Observation referenced from ServiceRequest.supportingInfo, or we may need to add some extensions.

So the first thing the app needs to do is to get all the new referrals for triaging. From the comments above, that will be a query against Task. In the query we’re going to need to be able to specify:

The status of the task. As the app is triaging new referrals, we want to be able to specify a task status of ‘requested’ – tasks that are ready to be acted on, but have not yet been processed.
The task owner – which is a HealthcareService. As all referrals are directed to a single service, we only want the ones to our service (exactly how we know which service isn’t part of this prototype – it would be determined from the user logged in)
The type of the task. Because a Task is such a generic resource, we don’t want all the tasks that could be owned by a Service – just those that are tracking a referral. This is the task.code element, and we’ll want to give a bit of thought to the possible values when we develop the real app.

So here’s a sample query that returns new referrals for a service:
But there’s a bit more we need to think about. This query is only going to retrieve the Task resources, but the clinical data is on the ServiceRequest, so we’re going to need to retrieve that. We’ll also need the Patient resource as well. We could retrieve all of these separately – e.g. get the Task then get all of the others individually, or we could use _include to get them all in one query – which seems a lot simpler for the app.
So that gives us:
That comment about ‘being simpler’ deserves a bit more discussion. One of the tenets of FHIR is to move complexity to the server where possible rather than the client – after all, there are a lot more clients than servers so it makes sense for a server to implement the more complex logic. They are also closer to the data – and will need incorporate security and privacy concerns, so it’s a sensible approach.
So using that query (and the sample data we created earlier), here’s the first cut of our prototype:

It’s not going to win any UI awards, but we have a simple list of new referrals with the patients’ name, gender and date of birth plus a brief description. Tapping one of the referrals (it’s a mobile app remember) will display more details of the referral, as well as buttons for the disposition of the referral, like this:

As an aside, if we were putting this in front of a clinician, it’s probably best to make sure the referral description and any other clinical data is relevant to their specialty – I’ve noticed that they will quickly pick up on data that doesn’t make sense to them, whereas they are more forgiving of UI issues (initially) …
But, moving on, it’s easy to perform the next step – just tap on the appropriate button. Here’s a screen shot after tapping ‘Accept’:

Just select the priority (if different to the default), enter any pertinent notes and press confirm. Job Done!
Well, almost – we do need to decide how to update the Task with the new status (which, in this case will be ‘accepted’). As always, we have a number of options for doing this (and there’s a section in the spec with some considerations as well).

We could keep a copy of the Task resource in the client (or retrieve a copy based on the id), update the status, and PUT  it back to the server. This is certainly workable, but does mean that the client can update any element of the Task – and we may not want that to occur.
We could create a custom operation that just updates the Task status. This has the downside that our implementation is different to any others, making a client vendor do extra work to interface with our API. That may be an acceptable compromise, but there is an alternative…
We could use the Patch update to just change the status (and other elements if needed / allowed). This has the advantage of remaining ‘standard’ – but also makes it simpler for the server to authorize the update – making sure that only people with permission to triage referrals are doing so. And – it’s easier for the server to control what gets changed. We’ll go with this approach.

Patch is just a matter of creating a ‘Patch document’ containing the changes we want and sending that to the server with a PATCH method.
Here’s a sample that sets the status to ‘accepted’, the priority to ‘urgent’ and adds a note:
    {“op”:”add”,”path”:”/note/0″,”value”:{“text”:”use theatre 2″}}
There are some tricky things with patching arrays – the link above talks about some of these. This is why we created an empty array for the note, then inserted the note itself. If there was already a note then the third line is not needed.
As the prototype development proceeds, so does the FHIR profiling – adding extensions,  constraining the resource types used and building the terminology resources. It’s convenient to build the Implementation Guide at the same time – that way the design documentation is being built concurrently as opposed to being left to the end (orr omitted altogether). There are multiple way to to this, but the sushi/IG Publisher approach is a commonly used one.
So there you have it. We’ve created a fully functioning prototype that we have developed with the clinician to ensure we have their requirements covered off, and determined the API and profiles that we need to be able to support it. Of course, the API’s have been selected based on the needs of this prototype – but it shouldn’t be difficult to ensure that they are useful in a wider context.
The url to the prototype we’ve created for this post is https://referrals.netlify.app/  If you enter it into a browser on your mobile device you should be able to see it in all its glory! No guarantees that it will always be there – or that it will always work, it is after all a work in progress – and it is communicating with a test FHIR server…
Once the prototype is done and accepted by the clinical and business teams, the next step is to work with the development teams to deliver it – and the API. As part of that, we may need to change the API or profiles, but we can easily adapt the prototype to make sure that it is still fit for purpose – and to act as a test app. Indeed, it’s probably a good idea to involve the development teams in the prototype development if that is feasible.

Show CommentsClose Comments

Leave a comment