Is Flutter the best framework for nursing app development?

Nursing can use apps to get information into people's hands, so how do you get started? I share my experiences using Flutter to develop my first mobile app.

The Brevity Buster app is a searchable list of healthcare abbreviations and their meanings, to help students make sense of new clinical areas more quickly. It’s a simple problem, but worth solving, making it a great way to learn about app development.

As with other adventures in teaching myself to code, I thought I’d share a few thoughts about developing a mobile app. As I keep saying, coding is becoming less optional as a skill, with children being taught programming concepts at school, it’s becoming fundamental. Having dabbled a bit with Python and JavaScript I’d just about reached the point where I could try to create a simple mobile app, wrapping some content in a user interface. So, how did that go?

Initially I tried to do this using the same framework I use for creating web apps – Vue.js. It’s not unusual for web developers to want to apply their existing knowledge to mobile development and because JavaScript runs everywhere, there are solutions for that. The obvious one for me was NativeScript-Vue, which wraps Vue logic into mobile-native components, meaning it runs smoothly on devices. While working with NativeScript-Vue, it offered a bunch of the advantages that Vue itself provides and I rapidly developed quite a full-featured prototype to take on placement with me to battle-test.

Unfortunately, NativeScript-Vue is a young project, leading to some serious issues that I couldn’t fix for myself. In time I think it will be a good option for cross-platform development, but I was forced to find an alternative to release something at production quality, while being confident I could maintain the app for a few years.

Then I heard about Flutter. Flutter is a cross-platform framework created recently by Google for their own apps. While that sounds like it might face the same sort of teething problems as NativeScript-Vue, it’s backed by the might and scale of Google’s engineering expertise. Luckily for me, the same brilliant tutor who I learnt Vue from had released a course for Flutter, so I dove in and had a crack at porting my prototype.

This is where things got a bit trickier. Both JavaScript and Python have dynamic typing, so neither are too fussy about how you write your code if they can make it do something (for better or worse). Flutter is written in Dart, which much like Microsoft’s creation of C# (and TypeScript), is Google’s shot at making a Java-ish language that isn’t as annoying as Java. Dart is statically typed, leading to some verbose boilerplate code that I wasn’t used to. Although there is a dynamic type available if you’re feeling confident!

There’s a good reason for Dart’s typing though, the same reason why TypeScript is rapidly gaining in popularity and type-hinting has been added to Python, which is it can greatly reduce the amount of errors you might otherwise discover at runtime. As Google itself says: “no surprises”! After a few hours of sighing at Dart’s verbosity, having confidence my code was likely to run without problems just because my IDE hadn’t complained was quite a revelation. Actually, Dart has some really nice quality-of-life features: a ternary style if–null ?? check, cascaded operations and replacing the private keyword with a simple leading underscore, as a few examples.

// Null checks are concise:
String userName(String name) => name ?? 'Anonymous';
// ...is equivalent to...
String userName(String name) => name != null ? name : 'Anonymous';

// Cascade notation is a nice way to do multiple things with an object:
querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
// ...is equivalent to...
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

The biggest upside from using Dart is it compiles both ahead-of-time and just-in-time, allowing for a stateful hot-reload during development. That might not sound like a big deal if you’ve not fumbled your way through something not working, or tweaking interface layout, but it’s a huge productivity win. Especially for a beginner like me, making as many stupid mistakes as I do. Make a change and see the results in less than two seconds. Amazing!

In practice, Flutter is not a million miles away from Vue anyway. In Flutter everything is a “widget”, leading to an hierarchical tree of components that looks pretty similar to the HTML templates of Vue. It’s possible to break an app into single file components that have the same separation of template, data/logic and styling that makes Vue so sensible to work with. I might've been more frustrated if I hadn't dipped my toes into C# about a decade earlier, but fortunately that was just similar enough to working with Dart that I could navigate the OOP concepts.

Even so, two issues nearly did for me and had me close to giving up. First, because Flutter is still quite new, there isn’t a strong consensus on state-management solutions. I settled on Redux as a pattern, thinking it would be familiar from VueX, part of the official Vue project. I was wrong on that, leading to some confusion and frustration that there wasn’t the same degree of magic that VueX provides to get reactive data-binding to a central store. Brian Egan is the superstar of Flutter state-management and I utterly relied on his many code examples, conference talks and forum posts. Seriously, this guy is everywhere, just being thoroughly helpful about state for Flutter – thanks Brian! One post particularly saved my bacon in dealing with turning a Future (that’s a Promise for you JavaScript types) into something I could reliably use with the store, by intercepting it with middleware until it resolved. I know I’m not the first to comment that Redux is clunky and verbose, certainly in comparison to VueX, so in future I’ll be investigating using something like the BLoC pattern instead.

The second showstopper issue was all me being an idiot. To provide a flexible text search without indexing content, my app uses the bitap algorithm to calculate Levenshtein distance between items and search strings. This gives a “fuzzy” search where matches only need to be close enough, rather than exact, allowing for typos and displaying a range of similar results. In my NativeScript-Vue prototype this was easy as there’s a JavaScript library available to do this very competently. In the world of Dart I had to recreate the fuzzy search for myself, helped immensely by Google having already ported bitap to Dart in an open-source project. So I spent the best part of a day trying to figure out why my code didn’t work as expected, carefully going line by line, until I finally realised I’d swapped the two text inputs to the function when calling it. Idiot. Finding my mistake would’ve been much faster if I’d properly understood the algorithm I was implementing and taken a step back for some rubber-ducky debugging. Oh well!

This duck also has a BSc in Computer Science. Probably.

Once essential features were working as expected, I moved on to asking what might make for nice additions? I had planned an option for a dyslexia friendly font to help with accessibility, but on looking at the evidence base it seems like those fonts don’t actually improve intelligibility of text, so that got scrapped. I did insist on not releasing until I added in a night mode theme though, which proved problematic. For reasons I still don’t understand, changing the theme broke Redux reactivity elsewhere in the app, probably an error on my end in helping Redux identify what parts of the app to rebuild on state changes. The feature was rescued by a third-party module that worked with a simple import, which does go to underline how valuable the developed ecosystems of Python, JavaScript and others can be. At least to someone like me who doesn’t quite know what they’re doing!

Given the simplicity of the app, testing consisted of just asking some friends to try a release candidate build and hoping no one ran into problems. Publishing onto the Play store was relatively simple, with good documentation available from Google, the only pain points were parting with £25 to publish something for free and swearing at Adobe Illustrator while creating an icon. As for iOS, I don’t have a Mac (nor want one) and I certainly don’t want to pay £80 a year supporting Apple’s oppressive walled garden model.

So would I recommend Flutter to nurses interested in getting into app development? Yes, absolutely. Maybe I don’t love it like I love Vue and it isn’t nearly as gentle for novice coders, in that Vue has enough magic you could pick it up without previous coding knowledge. Flutter will really need a basic grounding in some concepts of object-oriented programming, which might be more easily gained from playing with C# first, at least until more learning resources for Dart/Flutter are available. However, Flutter comes with a huge variety of interface widgets out of the box, which will let you quickly and cleanly wrap information in a beautiful user experience, putting your content front and centre. Given that simple presentation of clinical information will be the majority of our needs, that makes Flutter a really compelling platform, especially as it has the flexibility for highly custom interfaces should you need them.

In summary, things that I have learnt: -

  • I’ve been spoilt by Vue, I think it’s done so well in the face of market dominance from React and Angular because it really is a wonderful experience in everyday use.
  • Static typing is a nice safety net. I'll be picking up TypeScript for future web development projects.
  • I seriously dislike Redux, it quickly became laborious to add new items to the store, but I don’t know yet if I’d prefer any of the alternatives. Plus, there are some good reasons why Redux engineers things as it does.
  • I really need to learn how to write good unit tests and switch to test-driven development. A lot of wasted time on this project would’ve been saved by tests failing immediately when something was broken, rather than me noticing later without much clue which change was responsible.
  • I need to think more carefully in the future about which operations are expensive enough to be written as asynchronous, as Dart is single-threaded. As I added more content to my app, the search function cost became more and more obvious. While the bitap algorithm uses fast bitwise operations, doing that over several thousand tokenised entries is noticeably delayed on a mobile device. Of course, the obvious speed-up would be indexing the content, but pre-calculating a reverse-index for edge n-grams is a little beyond my current skills! Interestingly, there are very few solutions for local indexed search for mobile that I could find and none of them open source (aside from a clever Xamarin port of Lucene).
  • JetBrains’ IDEs are just the best, too many useful features to even begin listing. Their support for Flutter is superb too, even though I had to manually install the plugin for PyCharm.
  • When you tell people you made an app, they tend to be unduly impressed. It’s not that difficult or time consuming when using awesome frameworks like Flutter, people should give it a try without being intimidated by the idea. Flutter opens the door a lot wider there, because conceptually “everything is a widget” is easy to understand.
  • When I heard a prominent nurse technologist imply that they didn’t think nurses understanding algorithms was all that important, I'm now sure I disagree. This is the second project I’ve worked on that fundamentally required a particular algorithm and some effort to understand how it works. More generally, understanding design patterns is important, because there are established, robust solutions to a lot of common challenges.
  • There are still people in nursing who believe the mere sight of a mobile device in a clinical setting is inherently unprofessional. Having routinely used a VitalPac device for years I can’t agree with that and anecdotally my patients have tended to be unimpressed with technophobia in the NHS too. If we could move beyond holding ourselves back, while still being aware of the dangers of tech fetishism, that would be great.
  • Having a good think early on about how to move beyond test content to adding large numbers of new entries would’ve been smart. To remove duplicates and unwanted entries, I used a combination of Python scripts and a little too much manual clean up. Some of the scripts aren’t quite perfect either, like enforcing a consistent capitalisation style currently doesn’t identify where some capitalisation should be preserved (my fault for being inexperienced in writing regex patterns). Ideally, I would’ve spent some time learning PyQt to make the scripts interactive, but sadly that was just one too many things for a single project. Maybe next time!

What next?

Right now I'm pursuing a PhD full-time and at the point where much of the work doesn't yield obvious, tangible results, so I don't have the luxury of side-projects for a while. In the future, I have a number of ideas for apps to build with Flutter that I would want for my own benefit, particularly to wrap some of the best resources I know of for pharmacology and aid in remembering mechanisms of actions, contraindications, side effects, etc.

Learning Dart has also given me a taste for more difficult programming languages, so I'm feeling more confident in approaching C++, probably with Unreal Engine for clinical simulations. I'm particularly interested in making something fun to take the sting out of maths for nursing students who find it intimidating, given how critical drug calculations are to patient safety.

And there's always the challenge of getting into machine learning applications within nursing, but the maths involved in that makes for quite an ambitious, long-term project...