Site icon Hay on FHIR

Using prototypes in app design

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:

Of course, there are disadvantages as well:

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.

and

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:

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:

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:

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:

So here’s a sample query that returns new referrals for a service:

[host]/Task
?code=http://clinfhir.com/cs/taskType|referral
&status=requested
&owner=service1

 

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:

[host]/Task
?code=http://clinfhir.com/cs/taskType|referral
&status=requested
&owner=service1
&_include=Task:subject
&_include=Task:focus

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).

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":"replace","path":"/status","value":"accepted"},
     {"op":"add","path":"/priority","value":"urgent"},
     {"op":"add","path":"/note","value":[]},
     {"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.

 

 

Exit mobile version