Drummer, software engineer and online-learning fanatic.

So you've got a big client side React App, and you've decided to use code splitting to reduce its size on initial page load. Should be easy. React has some very accessible documentation regarding their lazy component loading, which works well with WebPack code splitting.

They give a really trivial example:

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />

Now, this approach works* out of the box, and the React team has been doing some excellent work exploring how the UI and UX around loading can be improved, so I'm very much excited by where this is going.

* But is painfully insufficient for production.

The main gotcha is that it can (and does) fail. The internet can be a fickle beast, especially with mobile connectivity. While the simple React example above does technically provide a mechanism to dynamically load your components, it doesn't fulfill the same contract as actually importing your code directly. Indeed not only is it possible that it can't load, but it's possible it might never load (maybe user has now gone out of service, server crashed, deployed a new version and they are unlucky trying to still get the old one).

These various complexities call for some attempted solutions.

Alerting the user to failure

Luckily the import() function returns a promise, so we could define a catch-all helper function to ensure we handle errors at least a bit.

export const errorLoading = err => {
    'An error has occured',
    'Please refresh the page. Otherwise, it will refresh automatically in 10 seconds.'
  setTimeout(() => window.location.reload(), 10000);

So now the initial example would have have to add the catch-all:

const OtherComponent = React.lazy(() => import(./OtherComponent').catch( errorLoading));

That's already slightly better than an uncaught exception. Of course there are many approaches to the UX. You could for example use this to trigger an error boundary, or redirect to a server error page (some of the guidance from Google on SEO says that if you redirect to a server error code page, it helps them to understand).

However, it's still a bit too early to give up, surely there is a better way...

Retrying on failure to load

So one of the main things we could do, is to simply retry. Below is an example, where you can pass a function with configurable retries and delays before giving up – that itself returns a promise that will eventually resolve.

function delayPromise(promiseCreator, delayMs) {
  return new Promise(resolve => {
    setTimeout(resolve, delayMs);

export function promiseRetry(promiseCreator, nTimes = 3, delayMs = 1500) {
  // Retries nTimes with a delay of delayMs on before subsequent retries
  return new Promise((resolve, reject) => {
    let promise = promiseCreator();
    for (let i = 1; i < nTimes; i++) {
      promise = promise.catch(() => delayPromise(promiseCreator, delayMs));

So with the above our initial code would look more like this:

const OtherComponent = React.lazy(() => import('./OtherComponent').catch( errorLoading));

That's a vastly better experience than the initial implementation. I'm using similar code in production, and we've stopped getting errors like Loading chunk 2 failed;

Using with Redux

It's also possible to use this approach with Redux (assuming you have implemented lazy loadable reducers and sagas or whatever else you use:

const OtherReduxComponent = lazy(() =>
  promiseRetry(() => Promise.all([import('./OtherReduxComponent/reducer'),  import('./OtherReduxComponent/sagas'), import('./OtherReduxComponent')]))
    .then(([reducer, sagas, component]) => {
      injectReducer('otherReduxComponent', reducer.default);
      injectSagas('otherReduxComponent', sagas.rootSaga);
      return Promise.resolve(component);

It would also be possible to retry each of the above promises individually instead of failing if one of them fails, but actually due to the fact that they are cached if successful, the difference won't save much bandwidth as they won't keep making network requests once they have succeeded.


So the above has explored how it could be possible to make react lazy loading more resilient, and improve the user experience while delivering a chunked react app. There is still a lot more that can be done – and I feel that React should probably invest some time into documenting in more detail how to do this, and perhaps provide a function that can do something like promiseRetry() above. Trying a network request a maximum of one time is always liable to fail, and by tying your app to large numbers of asynchronous calls, just to load the UI – you run the high risk of random failure. It's possible that you could have two versions of the app in the wild too during a deploy, and that case is particularly important to handle.

The best user experience could either be full reload now or: keep retrying, and it's not clear which approach is the one we should be optimizing for without measuring which situation occurs most frequently. Tuning the number of times to retry, and the delay between retries could be night and day between failing often, taking way longer than needed and finding the sweet spot. Crucially some situations exist when retrying will always fail – so there has to be a sane limit on retries.

There are also many users who hate code splitting – as it makes the browsing of sites slower (but SEO requiring the fastest possible initial page load makes this problem somewhat intractable with client side React). I have thoughts on this too, but to be honest, I'm unsure that a consensus exists on this subject – and I'll keep those to myself for now.

Ultimately for people with large web apps who wish to do code splitting – React lazy, suspense and the fallback UI possibilities have lead to a solid mechanism to split code, and control the points where the splitting occur, so that they are in sensible places. If only the provided mechanism was more robust it would be great, but in the current state (as far as I am aware) – that robustness is up to you, so thinking you can just swap to lazy() everywhere without problems is naive.

If you have thoughts, comments or feedback get in touch via info at sammorrowdrums.con I'm happy to correct anything I may have got wrong – or update the approach if there are better alternatives.

Ruffle Logo and Description

This year AOC went a little differently. I was thinking that after a year of not using Rust, I might like to try again and see if I could improve on last year, but after completing 8 days of problems I felt a bit less “Rusty”...

I had recently seen mention of Ruffle – a new runs-in-browser plugin-free Flash emulator – and the fact that Flash was dying in the new year, and thought I'd like to help the effort. I grew up with places like Newgrounds providing games and animated videos that were free to access, and things like Radiskull & Devil Doll, which frankly I'm still referencing today.

I cloned the repo, began looking through issues on Github and started hacking:

  • First to enable a desktop player file-picker so less technical users would be able to get up and running
  • Then an auto http –> https url conversion option (on by default) to stop CORS issues (and in some cases fix old links where http no longer works).
  • Lastly (for now), I added a warning on web and desktop for unsupported content, and the ability to show warnings for any reason (such as failed link opening)

Hopefully I'll continue to contribute to Ruffle, but I'm so grateful that my foray into Advent of Code lead to me becoming proficient enough at Rust to start making open source contributions.

I was also very excited to get my hands dirty with WASM, and discover the possibilities (and challenges) of building a Rust program for the web. I have found the tooling, the compile error messages and the linking with JavaScript easier than expected. Naturally there are some difficulties when it comes to types (especially as you cannot use Rust types in JS, and JS types are not very “rust”) – but certainly it enables kinds of processing that were limited to plugins only in the past (mostly due to speed) – and Flash has many parts like animating vector graphics, live interaction, and some embedded movies and things that make speed very critical.

As 2020 was for most of us a challenging year, I am glad to have finished it with something as optimistic as preserving the legacy online art created with Flash, and with that much of my childhood inspiration.

The Goal

I've been looking for nice ways to publish content that interact seamlessly between my local environment and web, I wanted a way to got off Medium, and ultimately to write with as little distraction as possible. Write.As provides a lot of positives for me, and is a lot easier than maintaining a custom blog.

I think the bottom line for me though, is that blogging in a web browser makes procrastination too easy, and my will is weak. To avoid this I have experimented a little with alternatives, and finally found a setup I actually like.

Trying to go native with Write.As

When I first tried to use, they did have a native app, and CLI tool available on Elementary OS, and so I attempted compose markdown using their app, and then connect it to a personal blog...

Unfortunately at the time both tools could only support publishing as an anonymous, unknown user. Also, the native app did not (and still doesn't) support Markdown preview – or at least syntax highlighting.

The Solution

Fortunately the CLI now supports publishing to blogs:

writeas publish --font sans -b sammorrowdrums ~/Documents/Blog/

This has enabled me to re-visit Quilter – a native app markdown editor (available on EOS) that features a simple distraction free UI and syntax highlighting of MD, and the ability to preview.

Blogging with Quilter

The Future

Finally I am able to blog, saving my files locally first, in a native app, and then publish easily when ready. I know there are plans to enhance the Write.As native app, so I'm not ruling out using it in the future, but at least I have a workflow that can keep me away from the web browser for now.

* I know that I could just copy and paste markdown into the Write.As website – I just don't want to.

* The —font sans is important, because the default is to upload the blog in monospace font, which is a poor choice for normal blogs, although useful for sharing code, and ascii art etc.

I had no plans to try Advent of Code this year, or to learn Rust, but I saw a thread on Hacker News and then I started AoC, and then I saw another comment a couple of days in:

After that there was no turning back, I was committed. I was going to do it all in Rust.

  • First things first, I found out how to install Rust.
  • Set up my text editor
  • Began going through their wonderful book (which I'm now about half way through).
  • Struggled through the first two problems (that I'd already solved in Python).
  • Fought the borrow checker, and began to learn the standard library and type system (efforts ongoing).
  • Started building out to modules.
  • Used their integrated testing tooling (which is great!).
  • Learned to output graphics onto the screen – to solve some of the challenges.

It's been almost two crazy weeks of late nights of panic!("{:?}", reason) and struggle, but considering the power of the language I've really grown to enjoy it.

There is excellent documentation, which comes alive as soon as you understand the type system well enough to read it. The compiler errors are great, and in particular things like match statements giving warnings if you don't cover all possibilities – really helpful. Using paradigms like Some(x) None rather than allowing null values, also all fantastic.

I think the only thing that takes a significant effort at first is to understand Lifetimes – how they handle the cleanup of memory without manual memory management (like C++) or garbage collection (like Python/Golang/JS). The payoff is huge in terms of fast execution, and memory safety but there are things that I just could not grok in a day. To really get the most out of the language you have to own it (or maybe borrow it... hmmm).

The Advent of code itself has been so cool. I have so much love for the creativity, puzzle creation and interesting references like Quines – and for problems that force me to relive my geometry days from school suddenly breaking out the atan2 function to convert vectors to degrees so I can destroy asteroids! There are plenty of hilarious video links and references mixed into the story they weave with each puzzle too.

If you are thinking about using AoC to learn a language – you should! I cannot pretend that it's been easy for me, but it's been great fun. I would certainly consider doing it again and I hope to use a lot more Rust in 2020!

p.s. You should ask me how proud I am of my little IntCode VM. Everyone should have one.

elementary OS Juno

– update -

I have since bought a new Dell XPS Developer Edition laptop and installed elementary OS Juno on it straight away, and they keep making gradual improvements which is great. Still a powerful combo, still happy and would recommend this setup to anyone interested. I use it for everything.

Early Days

I wrote previously about leaving MacOS for elementary OS Loki and again one week in, so I won't repeat myself but tl;dr is that I'm a software developer, I am comfortable with the command line, originally I liked my Mac because it felt like a machine for both work and play, I wanted a to find a Linux machine that felt good for both. Elementary OS provided a beautiful environment, good opinionated defaults, HiDPI support and with a bit of tinkering I had all the latest tools for software development too.

So far I have been able to solve any problems I have faced, and helped others to do the same. I've swapped my kernel for the latest, installed packages from external sources and even with all of that, I've had very few updates that ever required manual intervention. I even get firmware updates from Dell which have been great. There are some software non-options (like Adobe, who could easily release for Linux, but don't), so you do have to be open to trying other tools:

  • For raw photos Dartktable works well as an alternative to Lightroom
  • I payed for Bitwig Studio for music production – it's made by some ex-Ableton guys – and their Linux version is great. It's not cheap and there are plenty of high quality Open Source tools such as Ardour that I would also recommend – which is available via AppCenter interface.

You don't have to be technical to use elementary OS, it's simple and effective by design – you might be surprised that you can't minimise apps, and you store files on the desktop.

I couldn't agree more with those decisions, but may take some people time to appreciate it.

For user new to Linux, if you pick a computer with good hardware support, stick to apps available within the AppCenter (and maybe brave the odd extra .deb file install – if you require additional software), I'd be surprised if there were any real issues. Stability is also something that keeps improving and Linux continues to improve stability and hardware support, it's a different world now.

Evolution of elementary OS

I've seen elementary OS go through some big changes in my time using it. They have for example:

  • Launched a successful crowd-funder for their AppCentre to help fund native app development
  • Encouraged an ecosystem of creators to build apps for ElementaryOS AppCentre
  • Released the new Juno version of the OS
  • Move across to Github to encourage more community contributions

The rest of the improvements have been more subtle. Elemetary provides a very consistent experience, and most of their forward progression is an attempt to make that experience smoother, more accessible, more discoverable or otherwise build on what they've achieved. I think this is often undervalued (and misunderstood) by developers, and hard to get right too. Things like ensuring icons are aligned evenly on a pixel grid so that they scale smoothly is not everyone's cup of tea – but it's these little details that are there in spades.

The Upgrade

I followed this guide to upgrade to the new Juno release, as I did not wish to re-install everything, and currently there is no official upgrade path between Elementary OS releases. I had manually installed a couple of packages that had conflicts with system packages (such as an HP printer tool and some packages related to kernel upgrades), and I needed to fix with them before I could complete the installation, but it was relatively painless considering it's not a supported method.

Impressions of Juno

After booting up, they grabbed my attention with the default wallpaper (yet again). My screen really came alive, I appreciated my monitor again, and it reinforced how much I trust the Elementary OS team to get aesthetics right. While trivial, a good start does improve the experience.

Keyboard Shortcut Cheat Sheat

  • The interface and boot time are very snappy
  • With the super key, you can see the list of system shortcuts which I really hope will help new users with feature discovery
  • Apps can't put their icons in the system tray
  • There is a picture-in-picture mode to see part of another screen
  • Still no minimise (switch workspaces instead – faster and simple)
  • Still cannot put icons on the desktop (again – this was always an anti-pattern)

I wrote this in Quilter, and published it with Write.As (however at time of writing there is no way to publish to a personal account with the Write.As App), so I've had to paste it into the interface, but I like writing in Markdown and distraction free editor is great.

Using Quilter

Picture-in-picture rocks

There are no apps in the system tray. If you think some apps always do need an icon in the system tray, I'd ask why? I haven't missed a single one, Slack, for example , the little red dot of distraction is gone. System notifications act as a single source of interruption, and you can control them.

Using a timer with picture-in-picture

If you want to watch an app, there is a keyboard shortcut for picture-in-picture, that allows you to select an area of another screen and see it in a small box on the one you are using. I use this feature to code while watching a timer – and it's really helpful.


The list of categories and curated apps certainly helps to discover some new things, a good example is Vocal which is a simple native Podcast app that just works. Cassidy (one of the eOS team) created a native colour picker app which I use frequently because no matter what software I'm using to view something, sometimes I need to grab a colour for CSS work etc. Little native apps like this help productivity.


I would suggest having a look around the AppCenter yourself, everyone has different interests and needs.


The quality of elementary has improved gradually, and (for me at least) they seem to be able to improve in a clear direction that enhances the experience – things like improved icon sharpness and interface contrast too – they care about details and about providing a consistent experience. Also more visible things like the keyboard shortcuts cheat sheet – they want users to be enabled, and the delicate balance of beauty, speed, accessibility, UX, simplicity, good opinionated decisions.

I do see plenty of Linux user comments about the inflexibility of the UI, as people are used to doing things certain ways, and don't see why they should change, but to them I can only say this:

Some parts of operating system user experience and UI that have evolved and stuck around were mistakes. Breaking habits is hard sometimes, but that is not an excuse to build worse software. elementary OS doesn't let you do some things because they lead people into worse situations in the long run. It's never going to be perfect and please everyone, but it has a style, and that style is predictable and smart. Love it or hate it, it's consistent and simple.

I'm going to stick with it.

Enter your email to subscribe to updates.