I’ve spent the past few years working with Sensium Healthcare on their wireless early warning system for patient monitoring. It’s used in serious medical environments such as hospitals world-wide, for accurate vitals monitoring for vulnerable patients. My part was to lead the team that created the mobile app which plugs in to the system, reporting the vitals data of patients to the clinicians that need the information. As a critical system, reliability isn’t just important – lives depend on it. The system has been proven to save lives numerous times, but as such, any errors might also lead to loss of life too. In such a critical environment, having bullet-proof software development methods is everything. In this article I’m looking to give an overview of the systems and methods we employed to deliver that level of reliability.
The standard that Sensium software complies with is called IEC 62304. There are three classes of compliance : A, B and C. They range from items intended for less critical applications (A) such as for example, a Fitbit, right up to class C for the toughest regulations. Sensiums monitoring systems fits into class B, which is a level above standard medical devices, in a category that ranks it suitable for serious application in critical environments.
Heres are some of the parts required to qualify as IEC 62304 class B. First, a Quality Management System (QMS) needs to be used. These are designed to oversee the entire software lifecycle, from business case and initial requirements, through planning, issue and bug tracking, testing, risk management, integration and release. Traceability is key – it allows an auditor to be able to take a particular issue and track back through its implementation, right through to the initial requirement that caused it to be made in the first place. All these elements can be done by individual pieces of software, or alternatively by a dedicated QMS suite (for example, Helix ALM).
Testing, as you might imagine, is very thorough. Test plans are created from the initial requirements for a release, and later executed to prove that requirements have been met. For example, a requirement for a release might read something like : ‘Heart-rate must be communicated to the mobile device UI every thirty seconds’. A test plan is devised that will prove that requirement, checking on a basic level that the heart-rate is indeed changed every thirty seconds, before covering every possible edge case, such as the mobile going out of bluetooth range. This manual testing is just part of it, as all delivered software must also contain unit tests that will allow automated testing to be repeated daily on all software units that will allow it. As a rule we aimed for 80% code coverage with our unit testing, with the remaining 20% usually excluded for good reason, such as the code being solely UI related and/or not testable (and neither requiring it for safe operation).
Development with unit testing is obviously a whole big subject in itself, but I’d like to give it an overview here. I found that the only really viable tactic for this, is to focus development around unit testing from the outset, task by task. Theres a different mindset involved in creating really testable code – you have to think first about how something will be tested, before you begin to create the code itself. Code must be structured for testability, and the unit test really must be delivered with the software solution as you progress. Going back and unit testing software later is an expensive task, and even with the best will in the world, will result in changed code. Changing code retrospectively after testing and release is not really an option in this environment, and so unit tests must be delivered along with task solutions for each sprint.
This in itself requires additional thinking and planning. An additional points count needs to be factored in when scoring a task. I found as a general guide that around 25% or more time might be required to unit test as well as develop a task. So a 5 point task is really going to become an 8 point task with complete unit-testing too. We found that we had to plan for unit tests during sprint planning, otherwise it just became too difficult to stay on track and to keep our unit test coverage within acceptable levels.
Developing with unit testing is really satisfying though, and the resulting code is just much stronger and more maintainable. We used the Model-View-ViewModel pattern which lends itself excellently to unit testing, and we always followed some basic principles, such as avoiding singletons and using dependency injection. Some examples of the unit testing we did can be seen here .
Risk management is another integral part of the process. In normal iterative or Agile development, you can make a change to feature when the need arises. With medically compliant software, greater care is required. A change might mean that an initial requirement is no longer met – if so it needs changing. But this change needs risk assessing, as it may have other unforseen consequences. These changes and the discussions around them need documenting too and then including in release documentation. The key again is traceability – the thinking behind why a change was made, by who, and when.
Software releases come with extensive documentation. All test plans and their results are included, as well as unit test results and coverage reports. Risk management reports and discussions around changes are included too, as well as general release notes. Every issue that was tackled also has its own checklist to ensure it has complied with the standard – how it affects documentation, testing etc.
Beyond a release, there needs to be a method of garnering feedback from users and collecting bugs. These must be dealt with like any other task, and users to be kept well informed of progress in particular areas. A reliable method needs to be in place to distribute fixes and patches too, as well as further updates. In this regard its worth mentioning one of the major issues we faced at Sensium dealing with mobile devices and medical applications. The operating system of a mobile phone is designed to enable the preservation of battery life as far as possible. This is not always analogous to the operation of the medical device though – for example, a phone may need to be kept alive to receive network traffic at a fixed regular interval while in the background. Neither iOS nor Android make this particularly easy though – in fact they actively prevent it in some cases. This is again where thorough testing and pragmatic problem solving is key. Any drop in traffic might mean a crucial patient vital packet is dropped, and a life could be at risk. At Sensium we spent lots of time ensuring we had the very best solution in place for this crucial issue.
Ultimately, compliant medical software requires rigorous methods and a strong attention to detail. It need not be slow though, and once the right practises are in place, it can proceed just about as quickly as any development can. Adhering to these standards ensures that code is generally of a high quality, and all coders improve when tasked for example with ensuring unit testing is carried across all released code. In general I found the environment really enjoyable to work in, and I believe it made me a stronger coder too. Weirdly, I also found it really stress free, as calm heads and thorough planning makes for happy, unstressed developers. I intend to carry over much of the practises into all my development work, not just those in the medical world.