I built my first OpenMRS module. It automatically calculates eGFR and adds it to a patient record when a serum creatinine value is recorded. Its a prototype. I’d be grateful for any feedback you might have on the approach Ive taken. The code for the module can be found here: openclinical / openmrs-module-example-calculation · GitLab
Alternative approaches
When building this module I first looked at the calculation module but could not find a way of using it to watch for observations and add new dependent observations when relevant.
An alternative approach that we’ve used in our projects is the O3 forms module whereby we can define this calculation in a form, however this requires a clinician to open the form and then click save - placing the burden on the user to seek a calculated value.
An alternative design that I haven’t explored could be to present the calculated value as a part of the “add lab result” flow and/or present the option to make a calculation. This approach is more streamlined than an O3 form but more interactive than an automated calculation. This option also has a higher implementation cost as it touches more points in the UI.
A second alternative design could be to calculate the eGFR in the background and indicate when a user provided value is different to the calculated value. This seems too passive an approach to me but could lower the clinical risk.
Feedback
Before expanding the scope of this module (i.e. with more calculations and the ability to tweak those calculations or define your own) I’d like to solicit feedback on the approach Ive taken. What do you think? Seed questions include:
Is this a good idea?
Is there an alternative approach that I have missed?
How reliable is the ObsService.saveObs() call that Im using
What is the workflow for adding an eGFR value in other implementations and would this module be useful where this is done?
Have I missed any failure modes?
Is there a better way to show the provenance of the calculation
I mark the calculated value with status PRELIMINARY to show that its not been entered by a user. Is there a better way to do this?
Can we surface the observation note and status in the clinical UI to indicate the provenance of the calculated eGFR value?
Is there anything missing in the implementation?
Im logging errors (if/when they should occur) - am I doing this correctly
How best to surface the logs in the UI to admin users?
Should I be logging successful calculations (perhaps at a lower log level)?
The calculations that I see in our primary care and antenatal care projects are mostly based on combinations of demographics and observations as in this example - can you think of other classes of data that might be relevant to this module?
Generally speaking, something that can generated calculated observations from existing observations is something we’ve been looking for. It sounds like you found the calculation module but which doesn’t really have a great path to exercise it. Another piece of work we started for a similar idea was the drools module that was aimed at allowing more “configurable” business rules since one issue we’ve run into with AOP interceptors is that they wind up being Java code which makes maintaining and updating rules relatively hard.
There’s nothing specifically wrong with the ObsService.saveObs(), though it is theoretically possible for Obs to have been created in other ways. A slightly better approach is we’ve been expanding OpenMRS’s event system and moving it into core, so in newer versions of core instead of AOP, we’d probably suggest subscribing to those events (they’re published through Spring and should be fired from DB-level changes). Unfortunately all of that is in our pre-released versions.
The intention of PRELIMINARY is to mirror FHIR’s ObservationStatus.PRELIMINARY. That said, I don’t think we have an “appropriate” way to record this other than the comment field, and we probably should. (Preliminarily, FHIR publishes this example of a eGFR observation the “formula” is captured via the method field and the values used via components; OMRS supports neither of these concepts).
It’s probably a good idea. Historically, we haven’t used the comment field much, consequently its been leveraged in two edge-cases I’m aware of:
To indicate when an Obs records a Location (which is sometimes helpful when an ObsGroup needs to be associated with a location)
My takeaway is that this is probably good enough for now but I’ll keep an eye on when those changes to core land and reassess then. It sounds like PRELIMINARY isnt the right label - I’ll look into that more deeply (thanks for the FHIR example) - but using the comment seems ok.
Ive looked at the drools module and seen some nice work there, for several use cases. The one reservation I have here is that the rules still look quite a lot like code. Im hoping there’s a surface for these expressions that is more approachable. Having said that the expressions in this version are still very much code - I wanted to check that the foundations are strong enough. Im open to using drools underneath but I havent explored this.
They already landed in the 2.9.x branch of openmrs core. And they are exactly what the chartsearchai project has been using all along. So feel free to reassess.
Im hoping there’s a surface for these expressions that is more approachable
Me too! To be honest, the reason we started pursuing Drools was the support for DMN decision tables, which is, ultimately, what I was hoping the rules design could be. Unfortunately, we didn’t quite get that far, since there were a lot of other technical facets to work out.
Ultimately, I’m hoping we can land on a way of expressing these kinds of calculations that can at least be meaningfully reviewed by clinicians.