For software to live a long life, it must grow together with our experience. If our skills improve at a faster pace than we maintain our software, its design will start to drift away from our standards and expectations. If we let the gap increase for too long, it will eventually be impossible to catch up, and we’ll end up hating our creations.
Version 2 was a mess
Passepartout used to be two separate iOS and macOS apps, with all the complications that this implies. In 2022, I used Passepartout to learn SwiftUI –I considered Flutter initially– and make v2 a partially multiplatform app. Partially because the macOS app was a hybrid Catalyst/iPad app, a terrible choice if I think of it today. I don’t even know why I did it, but whatever.
The conclusions I drew after v2:
- SwiftUI is very hard to get right. I had to rewrite my views multiple times due to my wrong understanding of the framework.
- Catalyst made the macOS app an ugly and unstable iPadOS app, let alone a complete nightmare to develop.
- The time I spent on the Mac system menu, in particular, was beyond ridiculous. Maybe I’ll dedicate a post to this clunky Catalyst/AppKit interaction.
- The app core was overengineered, untested, untestable, and confusing.
- TunnelKit was already unmanageable and inextensible. Touching the wrong line could break connectivity for thousands of users.
I’m aware that we, developers, occasionally suffer an innate tendency to be unsatisfied with our choices, whatever they are. Redoing the same things over and over is detrimental to making progress, though. Therefore, rewriting software should never be your first choice. That’s why I ruminated around the idea for months, but the rewrite was inevitable 7 years after the first release.
Users don’t and can’t realize the amount of bugs that Passepartout v2 and TunnelKit had. The codebase, my codebase, was such a high barrier that it took me a year (2022 to 2023) to resolve some legitimate concerns with iCloud. Requests/bugs were sadly flowing at 30x the speed I was able to address them. The app was half abandoned.
It’s, however, very risky to rewrite an app that was stable, making decent money, and required very little support despite a user base in the hundreds of thousands. To end up, one year later, with the same app with more or less the same features.
Rewriting must be really worth it.
The cost/benefit of rewriting software
Version 3 is the last time I intend to attack the foundations of Passepartout.
So many times I rewrote code in my life with the sole intent of working in a “beautiful” codebase, not realizing how quickly the enthusiasm wanes when the development routine is back to normal. Give it a few months and, no matter what, your codebase will look “ugly” again. It never ends.
I learned not to rely on “beauty” to bring me back to the joy of programming. After all, when I wrote those nasty lines 10 years ago, I probably thought it was the state of the art. Right?
Today, I try to refactor software as a regular exercise, but at a smaller scale, and with a different purpose:
Make my changes last as long as possible.
Below is what I did in 2024 –part-time until August– for this major update:
The project encompassed ~1000 items, of which ~350 are invisible for being in private repositories. An insane amount of work, in hindsight.
Today, I can confirm that it was by no means a waste of time. After one year of development, the success of this reengineering is summarized in a sentence:
Most areas of Passepartout won’t need to be modified for years to come.
This is the single measure you want to focus on when considering a big architectural redesign: the time you save in the long run must dramatically compensate for the effort of rewriting. With this mantra, good design will be the natural consequence. Because good design, ultimately, is meant to save development time.
The best code of your software is the one you forget about, the one you don’t need to touch ever again.