A snappier MindNode Part 2 - Text Persistence

MindNode lets you format text in various ways. You can use different font types, make text bold, italic or underlined, or use strikethrough. Under the hood, we save your text and its formatting using a markup language called HTML, the same used for websites. HTML makes it easy to display the same formatted text when sharing MindNode documents to myMindNode, our web service for viewing your mind maps in a browser.

Since MindNode 2 we have been using a component called Ashton to transform formatted text to HTML. Ashton stands for AttributedString to HTML Transformation and we open sourced it a long time ago. Up to MindNode 5.1, Ashton required a lot of extra work to compensate for differences between iOS and macOS. First, it converted the platform-specific text to an intermediate format, which is then converted into HTML, as illustrated below.

Old Architecture Overview

Using this method we were able to share more code between iOS and macOS when converting between the intermediate format and HTML. Back then this was a sensible decision. The platforms had a lot of differences and a layered approach was a suitable solution to tackle this complexity. Since then, both platforms have evolved and the differences in the text system shrunk significantly. Therefore, we decided to rewrite Ashton without the overhead of an intermediate format, speeding up the loading and saving of documents in MindNode, simplifying the process diagram.

New Architecture Overview

The rewrite was undertaken in Swift, which we expected to give us an additional performance boost when compared to the former Objective-C implementation. Surprisingly, after testing our first rewrite approach we experienced a significant slowdown despite having removed the intermediate conversion phase. After analyzing the performance in more detail, we discovered that Swift’s string manipulation methods were substantially slower than the previously used Objective-C implementations. But we didn't stop there. We further refined our rewrite, by diving one abstraction level deeper into Swift String handling and used the character view directly for parsing the input. Consequently, we were finally happy with the results of the rewrite.

Measuring the speed of both implementations showed the following results:

Reading Performance

Ashton 2.0.0: 0.0055 sec.
Ashton 1.0.3: 0.013 sec (136% slower).
AppKit Implementation: 0.13 sec (2236% slower).

The results show, that we were able to improve the reading performance substantially. Reading text from a MindNode file is now twice as fast as before 🎉. Interestingly, the writing speed slightly decreased compared to the old implementation. This was a result of slower AttributedString reading performance due to the use of Swift. Nevertheless, as consequence of the ongoing performance refinements on the Swift programming language we expect this time to go down in future.

From a user's perspective, the reading speed which affects document opening performance, is far more important than the marginal writing slowdown, when closing a document. Additionally, we improved other aspects of the Ashton component. We fixed a longstanding bug which led to removed leading and trailing newlines and also improved the text color parsing, removing small visual differences in color perception across macOS and iOS. Based on this work we were able to enhance our Markdown import to now support bold and italic formatting. Ashton 2.0 is extensively unit tested, which gives us great confidence in making additional improvements in the future, without worrying about accidentally breaking expected parsing behavior.

We are happy to announce that Ashton 2.0 is now open source as well, you can find it here: Ashton. Ashton is released under MIT license as part of IdeasOnCanvas’s open source effort.

  1. Previous Post: A snappier MindNode Part 1 - Performance Tuning