Try, Try again
It was soon after I shared a roadmap in the beginning of 2020, that things suddenly changed for the worse around the world. Perhaps for the first time ever, the world truly felt small – united in confusion and hope. A lot was about to change in so many ways this year.
Speaking for myself, the confusion only increased as my favorite time of the year approached; WWDC. This is always the perfect time to re-align one’s focus and app-update strategy for the remaining year. Admittedly, by then I had already lost a lot of valuable time. A few hiccups, setbacks and unplanned surprises along the way (both in my professional and personal life) – and not to mention the many COVID 19 related niggles.
Without going into too much detail – they’re boring, really – the plan was to go into development-overdrive: a major re-write of 2Do’s back-end / UI into pure Swift from the now obsolete, mostly dead Obj-C. Although this sounds like a lot of work – it turned out to be a lot more. Perhaps I set the bar too high for myself or perhaps I was having a hard time making decisions. Or perhaps I had a lot more on my plate ¯\_(ツ)_/¯
At the time of writing I’ve witnessed two WWDCs since the last update I shared. I feel like we’re in the middle of a revolution, one that’s just going to take its time. With these both in hindsight, it has become clearer as to what needs to be done next – for now.
The Goal
As it is with any other app, think of 2Do made up of two distinct parts: the UI (front-end) and the Core Logic / Model / Sync Engine / Plugins / Database (back-end). Okay that sounds like a lot more parts – because they are. The point is, taking a multi-platform, featureful, complex app beyond 2020 has required careful planning and consideration. To all those that ask often: 2Do has not been abandoned. It’s still actively supported, I still care, however it’s also still (due to a series of unfortunate events and setbacks) constantly a work-in-progress. For those interested, here’s a glimpse of the dilemma I’ve recently recovered from, but still suffering through.
Going Native… Or Not
To state the obvious, 2Do is a native app – which means I wrote the iOS, macOS and the Android apps purely for the aforementioned platforms using their designated Software Development Kits (SDKs) in their respective languages (Obj-C / Java) – all in their own time. There’s some shared code between the iOS and macOS (just some) but none that’s shared with Android. For as long as I remember, I have spent 16 to 20 hours straight, every single day – for months in a stretch – on features, improvements, fixes and more. It can be severely time consuming, and tiring, to fix bugs or to implement new features across each platform at times. Besides, how many other native apps are you aware of that offer full feature parity across supported platforms as well as a bring-your-own-data policy? And how many that haven’t charged an additional dime for an upgrade in the last 10 years? Oh yeah.
For this major update, I’ve yo-yo’ed countless times before settling on a UI implementation methodology, only changing my mind once again in order to consider a different approach, all the while calling myself out on being lazy for considering shortcuts. I know this sounds insane, but I’ve invested time, money and effort into a particular approach before giving up and then repeating the same process again, hoping to find a reason I may have missed the last time. For instance, there are a number of cross-platform solutions out there that solve this very problem. Do I get excited at the thought of maintaining and updating a single code-base for all supported platforms (including Windows!)? Absolutely. But do I find any of these solutions attractive? Absolutely not. In my personal opinion, all of the cross-platform solutions out there leave a terrible first-impression. They consume more RAM, are power hungry in some cases and generally slow. The UI feels like a boxed up website and the faux native controls look fake. React-Native is a good contender, however it falls short when you need to customize certain controls for a specific look / feel / usability. 2Do does a lot of that. I refuse to write a non-native cross-platform app that would resemble a google search result in both look and feel. Maybe I’m being irrational, but nothing compares to going fully-native.
For the native-app-loving developers out there, Apple developed and showcased a ground breaking new UI framework a couple of years ago: SwiftUI. By now, SwiftUI has become a force to reckon with. It promises learn-once, write-anywhere. In practice though, it’s still a work-in-progress and after investing time and energy into SwiftUI, it was abundantly clear that I’ll have to give this a pass for now – for at least as long as I wish to support older versions of macOS (10.12 onwards) whilst offering a consistent set of controls / features across all deployed versions. Had SwiftUI been a framework in offering with the ability to back-deploy on older versions of macOS that support Swift 5.x – this would have been a no-brainer. SwiftUI gains new functionality every year with a new release of iOS / macOS but this functionality is not available on older versions of the operating system. It would soon become impractical to propose or expect users to upgrade to the latest macOS version on day one, only so they can install 2Do’s new update that now requires the latest version of SwiftUI.
Next up is Mac Catalyst. Apple originally promised to turn iPad apps into beautiful, native macOS apps – in a click of a checkbox (which later turned out to be several clicks along with potentially a lot of code changes). 2Do already has an iPad app, clearly a perfect candidate – but it also already has a powerful, designed-for-macOS mac app. Would I dump the current macOS app and replace it with an app I know I designed for a Touch-First device? No. Mac Catalyst is also not an option given it’s generally lacking when it comes to customizations and overall painful to deal with (from what I witnessed in a brief attempt), especially if you rely on certain frameworks that aren’t Mac Catalyst ready yet.
What does this all leave me with? The only option to keep things the way they are. I will continue to design, develop and refine each app for the platform it’s targeted for, using the current set of native frameworks offered for iOS / macOS (UIKit / AppKit). This however means each update, on each platform, would take its own time to complete.
My App, My Data
It’s no secret that I’ve resisted the temptation of going all proprietary when it comes to Cloud Sync. Most apps out there offer their own sync solution. It’s easier that way. They have one implementation to perfect – and only one that could ever go wrong. With complete control over the data at all times, from your device to in-transit to the cloud and back again, they’re able to optimize related workflows, streamline their sync implementation and offer additional value added services – but most importantly, they have you locked into their ecosystem. Now that everything you do, from the moment you wake up to your parent’s next anniversary, is stored in their proprietary cloud, you’re most likely to stay with that service out of convenience and simply continue to pay a subscription for the service you’re receiving in return. It’s a great overall experience for the consumer – certainly more profitable for the creator – plus, there’s very little at stake here, other than potentially losing control over your privacy of course, or being unable to sync with a particular service of choice using the app you otherwise now love.
I’ve dabbled with the idea myself at times – but something that would remain as an optional add-on, only for the purpose of offering additional value added features (I’m not going to divulge my super secret, brilliant idea in this blog post, if you’re wondering :P). I’ve even invested time and effort (and money) into its implementation before it, too, fell apart.
All this to say that I’ve come to value the the current policy 2Do has upheld, only after doing the same for BusyCal, and that is to remain entirely cloud agnostic. There’s merit in remaining open. Being able to support potentially any 3rd party cloud service, or open specifications such as CalDAV or Exchange EWS, offers great value to any user whilst staying clear from taking up the burden of managing sensitive user data. For 2Do’s next update, I dream of an app that’s open to syncing with a lot more services out there (Reminders / CalDAV / Google Tasks / Exchange / WebDAV / Dropbox / OneDrive / Google Drive / OwnCloud / Todoist even). And as an additional feature, being able to sync with multiple sources at a time – allowing you to manage your personal accounts as well as our work related accounts all within the same app.
This dream doesn’t come easy though.
The Sync Challenge
Sync – especially when it comes to the number of services it would eventually support – has been one of the most challenging aspects of working on the new update. Although this gives 2Do the freedom to potentially sync with and support any 3rd party cloud service under the sun, it does however impose limitations, several at times, such as features that a particular cloud service may not support, or may do so partially. This is incredibly difficult to model for in your technical designs when you’re working on offering rich functionality within the app itself (projects / checklists / tags / actions / locations / attachments etc) while translating this into a partial representation during sync with a 3rd party service. Given each cloud service is different, the complexity during actual implementation increases exponentially.
All of these limitations then trickle down to the UI. 2Do occasionally has to dumb down its UI in order to support the sub-set of features a particular cloud service may not support. This can be an annoying UI/UX challenge to have to deal with. Do you hide the certain features or do you simply show them as disable? Do you enable the functionality and let items slip through sync, probably confusing them when things appear to be missing on another device?
What’s Taking So Long ?!
So why is it taking me this long to work on an update when competition has added feature X, Y, Z and released version 4, 5, and 6 and just miles ahead in every direction? I don’t mean this in a condescending way, since this is a problem of my own creation – but, I don’t know, maybe because competition doesn’t have one developer working across multiple platforms and multiple apps whilst re-writing the entire back-end (remember the many parts?) as well as the front-end, while also coming up with a sync solution that works across a myriad of cloud services? It’s truly very time consuming and admittedly I haven’t been able to give it the kind of time I had originally hoped I would be able to. BusyCal – the other app that’s taken all of my time – went through a similar period where it took an arm and a leg to get it to the point it is now; yet there are mountains to tread.
The Good… News
There’s actually a point to this post, and some good news to share – if you’d consider calling it that.
I’m actually mostly done re-writing the entire back-end / core-logic / sync engine / automatic undo registration and a lot more, all entirely in Swift. In fact, I’m super proud of the new implementation. It’s beautiful, it’s performant, the sync engine is incredibly capable, robust, scalable and extendable. I haven’t finished supporting all of the services I eventually would want to in the end, but adding support for a new service is going to be a lot less work down the line.
In comparison to the current Obj-C counterpart, the new implementation in Swift is 80% fewer lines of code and is 3x more performant. The implementation is also mostly cloud service agnostic, which means it works by making fewer assumptions about the data it’s syncing, resulting in fewer potential breakage-points / bugs etc.
Apart from the sync engine, the entire database related code, including the model layer has been re-written. It’s robust, supports automatic, reliable undo-redo registration for both iOS and macOS (2Do did not currently support this on iOS, and the macOS version had known limitations), automatic change propagation throughout the UI and has the ability to support multiple windows in future. It’s also extremely performant, optimizing disk reads / writes where possible, with support for concurrency and automatic failover. It’s brilliant. And finally for the first time, I’m proud to say that all of these changes have amazing code coverage (via automatic tests / unit tests) as well as improved internal documentation. Just so much better code in general.
The Bad… News ?
Going back to the challenges I’ve faced, picking the correct approach for re-doing the UI in a way that’s future proof, has haunted me for too long. I’ve come to a conclusion that I’ve been trying too hard. Working on a UI refresh that no one’s asked for. Yes, it would be nice to add support for new UI features and cool new ways of manipulating and accessing your data, but what would be nicer would be an app that feels regularly updated.
My (new) plan is to take a step – no, many steps back. I’ve decided the new update would in fact only ship with an internal re-write of everything discussed, but with a UI that feels mostly similar (although re-written in large parts). Other than minor UI tweaks, I’m going to focus on getting it all working together – supporting all the functions and features it already supports and taking from there. Dark mode, widgets and the works. Simply adding functionality iOS has introduced over the last few years would be enough to get back on track.
Will I finally charge for this update? I really don’t know. I also don’t care about that right now. We’ll see when the time comes. I also no longer consider 2Do a threat to any other app, or vice versa. At this point, I don’t want to feel distracted by what some other app is currently capable of. 2Do has hit rock bottom in downloads, sales and usage. In a way that takes a lot of the pressure off, as I feel this gives me the time and freedom I need to continue hacking away at a sensible pace. I no longer worry about being judged, or the app receiving a one star review because of lack of dark mode or widgets or some other missing feature. To be blunt, all of the currently missing features would take no more than a week to implement if I started today. I just don’t want to add anything new to the already dying, bloated Obj-C code – especially when I know the new code is so much better and fixes so many inherent bugs. I need to – I have to – I must finish what I started. It needs to be good day-one, all brand spanking new from the ground up. I feel I’m so, so close, yet a millennia away from finishing. This frustrates me more than anything.
I’m truly sorry it’s taking this long. I have had to prioritize my time and energy on the various products I support – giving more time to the one that’s doing better in terms of downloads / sales. There’s no giving up on 2Do though, stop asking me if I have. It’s taking a lot longer but I’ve covered major grounds already – there’s just a little more distance to go.
Thank you for staying with 2Do and for all the wonderful emails, words of appreciation and support you send in daily. If you’ve moved on, I’m happy you’re giving others a reason to grow. Either way, I look forward to sharing more news in coming months.
20th November, 2021