HealthJoy 2.0: A Peek Under the Hood

by | Apr 27, 2020 | Product

We talk a lot about the front end of the HealthJoy 2.0 application, and the interface changes are certainly a drastic improvement. They make the app easier to use, and it’s more beautiful. You can read all about these changes in Part 1 of this series introducing HealthJoy 2.0.

In Part 2, we’re going to dig into less obvious, but absolutely critical, updates. We’ve done a whole lot more on the back end that members might never see, but those things also fundamentally change how HealthJoy works. I had the pleasure of adding some input into the front-end user interface (UI) changes and working with the designers, but the back end improvements remained a mystery. I would hear bits and pieces in meetings, but as we approached the launch, I realized I didn’t have a holistic view of all the changes. So, I decided to take a deep dive. In order to understand what’s new on the back end of HealthJoy 2.0, I interviewed my friend Alexey Tarazevich, Director of Product, Max Mashkov, Senior iOS Developer and Mobile Lead, and Sergey Tsisnevich, Software Architect, to discover all the changes.

The HealthJoy platform has been built over the last five years, and like any startup, things were sometimes done quickly to get to market fast. Our platform consists of our app, a custom customer relationship management (CRM) system built to help our concierge team deliver quick service, a dashboard for HR, custom application program interfaces (APIs), and a wide variety of databases. As a project, HealthJoy 2.0 started a couple of years ago and represents a fundamental change to the architecture of our core product. These changes don’t encompass the complete list of everything that’s new, but rather what I considered most important, coming from a non-programming background.

A stronger server connection

When you stop to think about it, the wireless Internet on your phone is pretty amazing. You have access to the world’s information at your fingertips. These connections that we take for granted are very complicated and don’t always work as planned. In the older version of our app, if you were in a location with terrible Internet, you might find yourself getting error messages while using HealthJoy. With HealthJoy 2.0, we’ve created a “self-healing” strategy to maintain a connection to the server and be more forgiving if problems occur. We’ve made changes to how the app refreshes, maintains its present state, and syncs to our system. This might not be something you appreciate if you’re in a city with a great connection, but it will feel vital if you get hurt while hiking outdoors and want to speak with a medical provider.

Moving to gRPC: A lean and mean communication framework

During the 1990s, as instant messengers gained a foothold with AOL, a new open source instant messaging protocol called XMPP was created by the open source community. We originally built HealthJoy as a full featured XMPP client, which uses a very verbose (read large) markup communication protocol over web sockets, using XML-based content. While there are many features of XMPP we still like, we were able to take advantage of Google’s gRPC project by encapsulating XMPP and moving a majority of the business logic from the client (the mobile application) to our servers. This allows us to manage complexity in one place cross platform and reduce the overall size of the installation file on your mobile device. Further, we have adopted Protobuf, a serialization library, that further reduces the payloads between our servers (less data to make the magic happen!). All of these architecture decisions give our members increased stability, better battery life, less data usage, and a far snappier experience.

Our servers are doing the heavy lifting

Our previous chat system depended on a user’s phone to do the processing locally. This approach worked perfectly, but with heavy usage could put more demands on a user’s battery. Our app was never really too much of a battery hog (not like many of the games I play), but we knew we could do better. We’ve moved almost all of the chat process to our server. At the end of the day, you might never notice a .1% difference on your battery, but our programmers want to live up to best practices.

A Shift from the Angular framework to React

Some of the features within our app, like our benefits wallet and inbox cards, leverage a hybrid app development strategy through WebViews. A WebView is an embeddable browser that an application can use to display web content. With this type of front-end development, programmers choose frameworks and libraries to make things easier. We initially used Angular, but we switched to React. Facebook created the React framework in 2013, and it’s since grown to be the leading choice for developers. We’ve seen a considerable performance lift in all our WebViews, which we know users will appreciate. The file size of many files dropped by up to 85%, which improves performance significantly.

A more native approach to programming

When we began the development of HealthJoy, we chose Objective-C and Java as our primary programming language for iOS and Android, respectively. It’s been around since the 80s and is a solid choice for programming. I remember learning it in college in the 90s and using it for small projects. Since our launch, both Apple and Google have designated preferred programming language, Swift and Kotlin respectively, that are tailored to their platforms. Both Swift and Kotlin are fantastic programming languages that have tons of unique features that work wonderfully on iOS and Android. We’ve fully transitioned all our code to these development environments, which allows us to continue to deliver rich native experiences much faster than before.

Coupling, but not dating

So, when designing software, the term “coupling” apparently referred to the degree of interdependence between software modules. Low coupling is a sign of a well-structured and planned system, which HealthJoy 2.0 architecture has now achieved. This makes our system easy to maintain, extend, and scale. Going forward, we are far more agile in our development.

An odyssey away from Monoliths

Over the last few years, companies like Netflix, Google, Amazon, and other technology leaders have switched over from monolithic software architecture to microservices. The benefits of this move include flexibility, scalability, agility, and more. A monolithic application is built on one large codebase, with major limitations on feature improvements, scaling features, and speed of delivery. Microservices break this down into a collection of smaller independent units which communicate with each other through APIs. With HealthJoy 2.0, we’ve now officially moved to microservices. As we scale our engineering team, this new architecture will give our team more flexibility for future development.

Other technical improvements (warning: jargon ahead)

We’ve also implemented a series of other large and small changes that significantly impact performance, simplicity, and scalability, things our members will appreciate every day. Some of those additional changes: (feel free to skip this section if your head spins when getting into the technical weeds).

We’ve moved to OpenResty (Nginx / LuaJIT) to help further scale our web applications.

Our DevOps team is using ELK Stack (Elasticsearch, Logstash, and Kibana), Prometheus, and Grafana for system and application logs collection, aggregation, visualization, search and monitoring.

We’ve also made drastic changes to our automation testing, extensively leveraging Appium, Cucumber, Jenkins, Selenium, and TestNG. We’ve also added Sauce Labs for cloud-based live, automated and continuous testing.

These technical improvements ensure that we deliver the best code to our members every time.

A round of applause for our entire tech team

As you’ve read, HealthJoy 2.0 was way more than just a user interface polish. This was a huge endeavor for our entire technical team, and I personally want to thank everyone involved in delivering a fantastic product. This is a revolutionary change for us as a company, and it sets us up for innovation in the future. These changes will help us to live up to our company mission to guide our members to affordable, high-quality healthcare.

Want to see it for yourself? Get a demo of the all-new HealthJoy 2.0. 

Related Posts

HR’s Biggest 2020 Lessons – In Their Own Words

HR’s Biggest 2020 Lessons – In Their Own Words

As we (finally) approach 2021, we wondered what other lessons HR pros longed to share.
Why We Were Thankful for HR in 2020

Why We Were Thankful for HR in 2020

A post for all the support HR provided this year, how you've helped us work through the unexpected, and the ways you've lifted our spirits.
4 Tips to Maximize Utilization When Launching New HR Initiative

4 Tips to Maximize Utilization When Launching New HR Initiative

Launching a new HR initiative feels like a complicated juggling act. Learn 4 tips to ensure a successful program launch.
[gravityforms id=9]
<div class='gf_browser_unknown gform_wrapper' id='gform_wrapper_9' ><form method='post' enctype='multipart/form-data' id='gform_9' action='/blog/healthjoy-2-0-under-the-hood/'> <div class='gform_heading'> <h3 class='gform_title'>10 Benefits Presentation Tips from TED Talks eBook - 2-Col (Pop-up)</h3> <span class='gform_description'></span> </div> <div class='gform_body'><ul id='gform_fields_9' class='gform_fields top_label form_sublabel_below description_below'><li id='field_9_8' class='gfield gf_left_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_8' >First Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_8' id='input_9_8' type='text' value='' class='large' placeholder='First Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_9_9' class='gfield gf_right_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_9' >Last Name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_9' id='input_9_9' type='text' value='' class='medium' placeholder='Last Name' aria-required="true" aria-invalid="false" /></div></li><li id='field_9_4' class='gfield gf_left_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_4' >Email<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_email'> <input name='input_4' id='input_9_4' type='text' value='' class='medium' placeholder='Email' aria-required="true" aria-invalid="false" /> </div></li><li id='field_9_5' class='gfield gf_right_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_5' >Company name<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_text'><input name='input_5' id='input_9_5' type='text' value='' class='medium' placeholder='Company name' aria-required="true" aria-invalid="false" /></div></li><li id='field_9_10' class='gfield gf_left_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_10' >Company Size<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_select'><select name='input_10' id='input_9_10' class='large gfield_select' aria-required="true" aria-invalid="false"><option value='' selected='selected' class='gf_placeholder'>Company Size</option><option value='1-100' >1-100</option><option value='100-500' >100-500</option><option value='500-3000' >500-3000</option><option value='3000-1000' >3000-1000</option><option value='10000+' >10000+</option></select></div></li><li id='field_9_7' class='gfield gf_right_half gfield_contains_required field_sublabel_below field_description_below gfield_visibility_visible' ><label class='gfield_label' for='input_9_7' >What Describes You?<span class='gfield_required'>*</span></label><div class='ginput_container ginput_container_select'><select name='input_7' id='input_9_7' class='large gfield_select' aria-required="true" aria-invalid="false"><option value='' selected='selected' class='gf_placeholder'>What Describes You?</option><option value='Employer' >Employer</option><option value='Benefit Consultant' >Benefit Consultant</option><option value='TPA' >TPA</option><option value='PEO' >PEO</option><option value='Other' >Other</option></select></div></li> </ul></div> <div class='gform_footer top_label'> <input type='submit' id='gform_submit_button_9' class='gform_button button' value='Get Your eBook' onclick='if(window["gf_submitting_9"]){return false;} window["gf_submitting_9"]=true; ' onkeypress='if( event.keyCode == 13 ){ if(window["gf_submitting_9"]){return false;} window["gf_submitting_9"]=true; jQuery("#gform_9").trigger("submit",[true]); }' /> <input type='hidden' class='gform_hidden' name='is_submit_9' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='9' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_9' value='WyJbXSIsImFkODg5MTk3ZmY1MDIyZGVjZjEyNWI2ODk1Y2YyMGZiIl0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_9' id='gform_target_page_number_9' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_9' id='gform_source_page_number_9' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div><script type='text/javascript'> jQuery(document).bind('gform_post_render', function(event, formId, currentPage){if(formId == 9) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} );</script><script type='text/javascript'> jQuery(document).ready(function(){jQuery(document).trigger('gform_post_render', [9, 1]) } ); </script>