Leave a comment

healthcare.gov: Architectural Lessons We Can Take Away


HealthcareDotGovAmid the fanfare, the excitement, resentment, and fervor surrounding the rollout of the new Healthcare exchanges under the Affordable Care Act, the one topic that everyone can agree on is that the Federal Marketplace Website at http://www.healthcare.gov flat out stinks.  For IT professionals, however, there is much to be learned from the issues that have been uncovered thus far.  This article will highlight some of the common problems with the implementation of the exchange website, and some common practices that IT architects and developers can use to mitigate the associated risks.

Best Practices for Single Page Web Application: Appropriate Modularity

The enrollment process on the healthcare.gov site is implemented as a single page web application.  A quick look at the HTML on the page shows a collection of placeholder <div> tags for each section of the process.  At a glance, the page appears to have a reasonable level of modularity.  The enrollment process is broken down into the main sections: Application, Eligibility Results, and Enrollment, with each main section broken down into several subsections.  Upon closer look, however, using a web debugging console shows that the page contains place-holder div tags for every section of the enrollment process:

hcdg debug

When defining a single page application that implements a wizard-style interface, it is important to consider the complexity of the page.  The more views that a single page application contains, the higher the complexity. In this case, the page contains all views throughout the entire application process.  The result is that a page refresh, leaving the page and returning, or other similar navigation actions can result in the user being forced to restart the entire application.  There is some functionality in the insurance enrollment application that attempts to manage state, however, when changes are made to certain fields within the application process that are referenced downstream as dependencies, the design of the healthcare.gov site is to force the user to go through the entire application process again from the last modified step.  This can be exceedingly frustrating if, per say, a user on the review page at the end of the application realizes that one of their children’s names is misspelled, correcting the issue means that they have to click through the entire application process in order to change a single value.

In order to define the appropriate modularity of a single page application, an architect should consider each data field and its downstream relationships.  A single page application should only force a user to re-enter downstream information if a field change affects the workflow of the application.  For example, modifying the sex of one of the applicants from male to female should prompt that the user is asked to specify whether or not that person is currently pregnant, and likewise remove that information if the applicant is switched from female to male.  Once these relationships are defined, the steps in the process should be grouped such that fields with these types of relationships are as close together within the process as possible.  Once these groupings are established, each logical grouping should be placed within its own page, which would allow a user to revisit that page should they need to change information.

The insurance enrollment application does a reasonable job defining those logical groupings during the application process, however the placement of all sections on a single page should be replaced with placement on individual pages for each subsection (Household Information, Income, etc).  On the server side, state can be maintained using a decision tree, that determines downstream dependencies, first by section (Application, Eligibility, Enrollment), then by subsection (Houshold, Income, etc.), then by individual fields.  Updating a particular field should result in the verification of downstream dependencies, first by related field, then by section such that dependent fields that require updates are flagged.  Afterward, the user would only then be prompted to update the dependent fields in the dependent sections, rather than forcing the user to finish the entire workflow.

There are several single page application frameworks available that make managing and recreating state and defining individual views much easier.  AngularJS and KnockoutJS are two of the more popular single page application frameworks available.  Both of these frameworks use a template-based approach to binding individual views to related data.  When considering a single page application, it is important to weigh the efficiency and cleanliness of using one of these frameworks versus a roll-your-own approach.

POST/PUT/GET and JQuery

When considering a single page application, an IT architect should take into account the trade-off between performance gains realized through asynchronous processing vs. process control and thread safety. As an applicant on the healthcare.gov exchange navigates through the enrollment process, button clicks that save application information are posted to the server with an HTTP_PUT request, and the next section is filled in using an asynchronous GET request using JQuery.  The problem with this pattern is three-fold.  First, the PUT request typically takes longer than the GET request.  The result is that the next section of the application is finished loading before the server has finished processing the prior section.  In cases where there is a downstream dependency, the dependent data from the PUT request is populated into the subsequent view upon completion.  Should the PUT request fail, the dependent data will not be populated and the user may be shown an error message, but often, the user will continue to see the “Processing” block over the page.  In a worst case scenario, the user will be allowed to enter data on the subsequent screen, however the pre-requisites for using this screen may not have properly loaded.  This was the case with the bug affecting the security questions step in the process, where users creating a new account would be prompted to enter their account security questions and answers, however, the dropdown choices would never be populated.  This is a result of an asynchronous call to the server to get the items to populate the dropdowns.  The view would have already been loaded, but the call to the server would have taken several minutes to complete, or timed out altogether due to the initial heavy demand on the system during the first few days.

A more important problem with this pattern is that should the PUT request fail after the GET request has already been processed for the next view, the user does not have the option to retry/resubmit.  Because of the single page design, the only choice is for the user to refresh the page, which may result in having to start over from the beginning of the application.  The proper pattern would specify that the PUT request return the contents of the subsequent view.  If the application is designed using the logical modularity described previously, the result of PUT request would determine the next step in the application, allowing the user to revisit and update upstream information without having to resubmit subsequent steps..

Lastly, the most important problem with this pattern is that the workflow of the application is determined by the javascript on the client, rather than a set of business rules on the server.  This opens up the risk that the workflow could be compromised using a web browser debugging console.  Consider my previous post describing a workaround for the identity verification bug that resulted in users becoming locked out from verifying their identity electronically.  Because this business rule is enforced on the client through javascript code, it is subject to bypass using a method similar method.

Conclusion

Overall, when determining the design of a single page application, architects and engineers must be cognizant of the relationships between the various views within the application.  Downstream and upstream dependencies must be identified and considered when designing this type of application.  A framework must be in place for enforcing and maintaining these dependencies during the entire process, including instances where a user revisits an upstream dependency and updates the data.  Lastly, developers of these types of applications must be careful not to put too much functionality in the client side javascript.  Business rules and workflows should always be enforced by the server, as they can easily be altered of bypassed altogether.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: