What this dumpster needs is another failed app
It was 2021. Spring pollen competed with birdsong to fill the air. Sneezes abounded. We needed to relocate my mom, but were having a rough go of it. Finding the cash to finance a move and purchase a dwelling of some kind was proving elusive.
I took an inventory of my skills:
Busking at the waterfront on the weekends might pull in a few hundred a month — more if they pay me to stop. That wasn’t likely a good option. My home-building skills could get me $20-25 an hour. Also not great.
The pay range for software development is all over the map. I could try for a $150-250K/year Silicon Valley-style job, but an 80 hour work week leaves a bad taste in my mouth and dark circles under my eyes.
Hey… What about an app!? A solo developer can reach a near worldwide audience. The Apple App Store and the Google Play Store charge 30% to host your apps, but that drops to 15% if you make less than $1 million a year. Check. ✔️
But what sort of app? I mulled it over for a few weeks, thinking about problems that needed solving, and solutions I could offer.
I’ve always been pretty good at budgeting and finance, and used a spreadsheet to track all my bills and potential savings or loss for each month. “How cool would this be in an app I could carry around in my pocket?”, I thought. Pretty cool, indeed.
I quick search revealed a number of preexisting budget apps. It was already a red ocean, but a large one. Perhaps there was room for a little tiger shark to grab some scraps here and there.
Plus, I noticed that no one in my own circle of friends was using a budget app. Partly because they don’t trust the app makers. Their privacy policies are dubious, and the apps appear to be yet another vector for personal data scraping. I’m all about privacy. Perhaps I had something here.
I intentionally avoided downloading and looking at existing budget apps for two reasons:
- I didn’t want my creativity to be poisoned by their existing approach, the approach that wasn’t luring in my circle of friends.
- I didn’t want to be discouraged, in case their apps were exceedingly impressive.
In hindsight, maybe it was a mistake to avoid studying existing apps. Maybe I could have learned from their mistakes — seen what was missing, tried to sniff out that killer feature in the cracks.
I set about mocking up various app screens, trying to find a suitable MVP.
Which tech stack would I use? I wanted something:
- Cross platform (to hopefully save time)
- Easy to style
I chose Xamarin Forms, since it’s been around a while, and Microsoft is showing commitment to the idea with MAUI, and converting from Forms to MAUI isn’t supposed to be that heavy a lift.
So I broke ground in May 2021 with Xamarin Forms, starting with a simple list page and bill entry form. I worked nights and weekends, but progress was slow. Three months passed, and the app looked pretty ugly. I was still wrapping my head around Xamarin, but realized that I spent most of my time fiddling with XAML styling. There were the Xamarin bugs as well. One of my big beefs with Microsoft is that their Marketing and Sales teams always over-promise on their capabilities. Once you get into the weeds, the going is slow, and the burrs and briars are brutal.
Around this time, I reached out to a colleague who is a UX expert to get some feedback on the design, but that fizzled out.
That’s when I found Grial UI Kit. They provide a number of pre-built example screens and flows for Xamarin Forms, all of which are already styled, saving my some time - hopefully!
This was also my first real expense.
+ $500 (Grial UI kit) ------ = $500
Keeping the tested core logic, I dumped everything else and began rebuilding all the forms using Grial’s screens. It was still slow going, as I was figuring things out, Grial had its own bugs, and my day job kept overflowing into my night job.
Speaking of slow going, building the Android app was really slow. At the time I was running Pop!_OS on a home-built box. I had hoped to run JetBrains Rider on it, but that was a no-go at the time, so I installed a Win10 VM and ran Rider in that. Wow, what a slog. I came to dread building because it would take 3 or 4 minutes to launch the Android Emulator.
Eventually I had to dump Linux and go bare metal Windows. This helped, but building was still too slow. So I threw more hardware at it.
+ 1,600 (16 core CPU; motherboard, RAM, Windows) ------- = 2,100
I had high hopes. And indeed, build times were reduced… somewhat. Like a turtle on coffee. It wasn’t all that great, perhaps because the CPU didn’t have great single-thread performance. For other projects build times were reduced dramatically, but wasn’t why I spent $1,600.
Speaking of iterating, Grial UI Kit comes with a handy tool called Gorilla, which helps you design XAML pages right there in the emulator, without recompiling/relaunching to check every tweak. In theory it’s a great idea. The slow and clunky part was maintaining the json files it uses as a page’s data source. If things got out of sync it would blow up and I’d have to spend time finding the bug in my vaunted time-saver. Once Xamarin’s hot reload improved, I was able to ditch Gorilla. Sorry, my furry friend.
When I first began building the iOS app, I was using a 2019 MacBook Air. That was even slower than the Android build. And I wasn’t using Visual Studio for Mac or Rider either - I was developing in Visual Studio on the Windows machine, which delegated the iOS build to the MacBook Air. When it worked, it worked OK, but it broke often. I spent much time reconnecting. So I switched to using Visual Studio for Mac (and later, Rider), and was able to iterate a little better.
Then I had an accidental performance breakthrough. The MacBook Air only had a 128GB SSD and I was running out of space. I traded it in for a MacBook Air M1 with 256GB, only to discover that it built waaay, waaay faster than the 2019 MBA, and even built faster than the Win box. The only constraint I was hitting was the small 16GB memory.
You guessed it: I traded in the Air for a MacBook Pro M1. Finally, I could build both Android and iOS in a reasonable amount of time. Of course, the project cost went up yet again.
+ $3,500 (MacBook Pro M1) -------- = $5,600
Now we were nearing spring of 2022 and I could finally develop at a reasonable pace. Plus, I was understanding Xamarin better and better. Things were looking up.
The next several months went by in a flash of features, late nights and eye drops.
Tricky parts included:
- Dark mode: Fortunately, Grial came with both light and dark themes. However, switching between them at runtime, either manually, or due to a system theme change, is tough. I ended up keeping all theme elements in a dynamic dictionary which would be reset in response to a theme change. Unfortunately it adds a little to app startup time, but dark/light mode is essential these days.
- Import/export, with custom file extension: Exporting to zipped json is easy, but associating a custom extension (
.4dbudget) with the app was not. Safe imports are always a challenge too, keeping things ACID-approved.
- Reliable notifications: On Android, I was able to use a daily alarm to check for pending notifications and show them. That wasn’t feasible on iOS, so I had to create a whole notifications scheduling thing and keep it in sync with data changes.
- Cross-platform notification styling: Android lets you customize the notifications quite a bit. On iOS you can only customize notifications with an app extension, which I ultimately felt was too much work for an unproven app.
- Multi-threaded performance and reliability: tricky. always Yup, 😊 Plus, some things need done on the main thread, or they don’t get done, or even crash. It’s not always obvious what those things are. And if you do too much on the main thread your app gets slow, and the OS might even kill your app, thinking that it hung.
- App initialization: What’s the bare minimum you need to get this party started? If you do too much, initial start is too slow, they ding you in the app stores and users hate it too. But somehow you’ve got to initialize databases and defaults. I ended up using a little initialization popup with a progress bar, so at least the user could see what was happening.
- Empty state patterns and testing: Null reference exception, anyone? Always requires extra thought to make the app respond differently to a data set of 0 vs 1.
- UX!: Always thinking, “If this was the first time I saw widget X, would I understand it?” Can I improve affordance, discoverability? Extra challenging because I’m not an elite UX guy.
- Minimizing app startup time: Nobody wants an app that starts up slow. Xamarin apps, however, start pretty slow. I tried to lazy-load everything I could.
- Phone vs tablet layout: Grial has some handy extensions to help with this, but it’s a pain do test every screen, and fixing something in one layout can end up breaking something that was fine before.
- Localization: I painstakingly added all of the text to resource files and added translations from English to Spanish. This caused layout issues because Spanish is generally more verbose and has longer words.
By August 2022, I was ready to release my paid app, 4ducksbudget.app . I was pretty darn proud of it too.
In my opinion it was the only budgeting app necessary for 98% of the population. Personal finance essentially comes down to:
- What are my scheduled expenses (bills)?
- Is my income greater than those expenses?
The app is a tool to help you answer those questions.
- Bill due reminders.
- Timeline that shows what’s due next and how much you still owe this month.
- A Savings page to see how much you can save this month.
- Projections on how much you can expect save or lose in future months.
- Analytics including helpful target amounts for your emergency funds and even your salary.
- Quickly see all of your non-essential bills, in case you need to cut expenses suddenly.
- See at a glance everything that’s due this month. Super useful when you pay many of your bills yearly.
- Custom bill categories.
- Set an emoji to represent each bill.
- Import/Export, send to a friend or another device.
- Privacy. No analytics. Even crash reports are opt-in only.
Of course, we had to spend some more money too.
+ $14.00 (4ducksbudget.app domain, yearly) + $60.00 (Hugo theme for website) + $20.00 (Help with logo) + $20.00 (Donations to screenshot sites) + $99.00 (Apple Developer Account, yearly) + $20.00 (Android Developer Account) + $189.00 (Android phone for testing) ----------- = $6,090.00
The apps were approved, I was excited. I waited for the huddled masses to break down my app store door and throw their cash at me.
Of course, that didn’t happen.
I needed to market! How would people know about this great app unless word got out?
I turned to Studio Mosaic, who specialize in app marketing. They had great ideas for revamping the App Store description, screenshots, and keywords. This got me a little bump in views, but still no purchases.
As I had suspected yet dreaded, the nice folks at Studio Mosaic laid the cold truth on me: You know who wants a paid app? Pretty much nobody. People like to download and try stuff for free. That’s why we’ve got all these in-app purchases and subscriptions. The paid app model just doesn’t work anymore.
So they came up with an approach to convert the app from a paid app to a free-app with pro subscription model.
This was time-consuming and adds a lot of complexity to the app. You have to constantly check on the user’s subscription level to determine if they can use a given feature. But that’s not the worst part — how do you reliably determine if this user is a subscriber? What about when they reinstall the app? How do you know if they have used their free trial already?
Long and short of it, you need a back-end to reliably verify receipts with the App Store. More expense, more possible points of failure.
Since app monetization is a lot of work, I left the Android app as a paid app and converted the iOS app. James Montemango made a helpful plugin to help harmonize the disparate approaches to in-app billing, but there’s still a lot that can go wrong. Even transient internet outages or slowness can surface the strangest bugs.
And remember slow startup? How do you check if a person is a subscriber on startup without adding to the slowness?
I finally and begrudgingly released the paywalled (so sad 😢) version of the iOS app in January 2023.
The budget wasn’t done bloating:
+ $2,400.00 (Studio Mosaic) ----------- = $8,490.00
Around the same time Grial had released version 4, including support for MAUI, and something I had really wanted with version 3: Good floating action buttons. I was never happy with my homemade FABs. Plus, they had refreshed the theme styling as well. Since it was on sale, I picked it up and revamped the app to use Grial 4.
Grial didn’t have a straightforward upgrade path and there were a number of bugs and inconsistencies in the Xamarin version, likely because the team was focusing on their MAUI product. Eventually I got there, and got the nice new FABs in place.
+ $419.40 (Grial UI Kit 4) ----------- = $8,909.40
Paying people to use it
So now the app was free, but the users still didn’t come.
I started an Apple Search ads campaign. That was eye opening. With its vertical monopoly, Apple makes bank. Because finance is such a competitive category, I had to bid $2.30 per click. Not per install, per click. I tried budgets ranging from $10-100 per day.
After close to a month, I’d spent $410, received 16,073 impressions, 263 clicks, and 45 installs, which resulted in zero purchases. Ouch.
The cost per acquisition (of a free user) was $9.11.
+ $410.10 (App Store search ads) ----------- = $9,319.50
The data was loud and clear. Like so many before me, I had created an app that essentially no one wanted.
Wait, I take that back. One person wanted it — I enjoy using it. :) Basically, I spent $9,319.50 to create an app for myself. And yes, I am a subscriber. Thanks go to Google and Apple for allowing me to rent a chunk of their gold mine. Maybe I’ll even strike pay dirt. One day.
👉 4Ducks Budget 👈 In case you want to see what failure tastes like.