Friday, July 31, 2009

On the woes of usability (cohorts and indicators)

Finding a solution to the indicator report was a big step for me. However, the best thing that came out of the conversation with Mike this morning was something kind of random. For some reason, during the conversation about hard-wiring the "design indicator report" UI, I realized that we also needed to hard-wire the design of a few other pages, just to get the reporting system out the door and into the hands of users ... who could tell us what they really wanted. Which is the gold at the end of the rainbow. Get your application into the hands of your users and they'll tell you what they want. Hopefully.

So the basic conclusion that Mike and I came to today was that the user interface for the new reporting system should be somewhat hard-wired, at least to start with. We've been fighting with this idea for months now. Every time we've wanted to go down the path of "hard-wiring" a report or one of the reporting components, we've designed a cool new widget maker that would hypothetically handle the general case in a way that most users would be ok with. And so after a few conversations, we start heading back down the path toward a "more generalizable" solution.

I now hate generalizable solutions. They suck. They're ugly, they take too long to implement, and they always break. I'm not smart enough to think of every use case that might ever be needed. I've spent 2+ years working on reporting and I'm tired of thinking about vague/general user stories like "Design a Report". You go Design a Report! I just want someone to ask for a very specific feature, like "Give me the ability to retrieve a count of all patients in the HIV Program at the Rwinkwavu hospital". I can do that. I can implement that and make it look nice. And I can build it in a general-enough way so that only the UI needs to be hard-wired. I just can't (and won't ever again) design another generic UI. Go to hell general UIs.

I'm exaggerating. I'll be back to designing general UIs next week. But, I've found a way to handle some of the reporting UIs in such a way that we can build some very nice features for our users without spending months working on a general UI that looks pretty enough and is 100% extensible.

So to get back to the point. This conversation with Mike got me thinking about a part of the reporting tool that I have been dreading since I first conceptualized it. I'm speaking specifically about the Report Dashboard, the main UI that a user encounters when they want to use the new reporting tools. At first, I wanted to make this a portal page ... a place where users could add and configure "widgets" to allow them to view patient data in a very interactive, easy to use manner. I started thinking about all of the widgets we could have "Graph concept X along datetime, break down by Dimension Y" or "Show 10 most recent indicators" or "Show a truncated table of patients that Provider X is supposed to see this week". Any and all of these widgets would be cool and possibly useful. But no one has every asked for them, so I don't think it would be a good use of time building a generalizable portal framework for widgets that might not ever be used. Instead, we should put some effort into hard-wiring some of these widgets according to a user's specification and then try to find some patterns of reuse in those.

(image stolen from the DHIS web site -- thanks guys!)

I still plan to build this dashboard (I want it to look a little like the image above) but we don't have the foundation within OpenMRS for a portal type user interface yet. We have portlets, but we don't have the portal page that would hold the portlets nor do we have a way to configure the portlet to handle any case. For example, there's no way to turn a cohort or dataset based on any concept into a nice graph. But that time will come. I promise you.

However, what we need to be able to do from within the Report Dashboard is to allow a user, like Cheryl down in Rwanda, to quickly find out how many patients are currently enrolled in our HIV Program during a certain period. The cohort builder is great and gives us a good start to solving this issue. But the cohort builder is still too generic. It requires a user to ask a bunch of questions to answer their overall query. A user is left combining multiple queries to figure out how many Male Adult patients are in the system. Why not hard-wire a UI that allows the user to pick a Cohort and select a few dimensions (gender, age) and click "Run" in order to get a crosstab of patients broken down by these two dimensions.

We can easily handle this kind of query with our the reporting framework (our API is very flexible), but it's not at all easy for a user to put together all of the cohort definitions or logic queries through the cohort builder in order to answer this question. They need to calculate each of these numbers separately and then put together the pieces.

Or take this example.

Find out how many patients were enrolled in the HIV Program in Rwinkwavu between 07/01/2009 and 07/31/2009.

Why not hard-wire the UI to handle this kind of query? Clearly, we don't want to hard-wire the values in this particular example. But we want the general pattern to be hard-wired. We'd still generialize it enough and give the user the ability to specify the four variables: Program, Location, Start Date, and End Date. However, the query is a pattern that we know users will ask a lot.

And when a user comes to us and says: "This is great, but I want to be able to get all patients enrolled in the HIV Program AND On ARVs", we don't have to say "Oh F" and spend weeks trying to make the UI take an arbitrary number of Programs and States. We can simply add a new query to the report dashboard to handle this.

Find out how many patients were enrolled in the HIV Program and On ARVs in Rwinkwavu between 07/01/2009 and 07/31/2009.

While it would be great to handle this generically so that a user can ask any question, any time they want, this isn't at all realistic. However, if we could hard-wire a bunch of questions that users ask all the time across all of our implementations, then we'd be 90% of the way there. In addition, we'd remove the need for all of our users to define the same cohort builder queries over all of these implementations. And we'd get some pretty good feedback about what's missing.

That's not to say we don't want to extend the Cohort Builder to allow users to ask more general questions. We just need to give our users a better foundation to start with.

So what query would you like to run within your OpenMRS implementation?

No comments: