Category: Coding

I wrote a… best-selling iOS app?

Coding

I wrote a… best-selling iOS app?

Hey! Remember that time I wrote an iOS app to keep track of my Elden Ring and D&D play through details, and released it to the App Store?

Why, I remember it like it was just last week…

Turns out, when you email industry-specific news sources with topical news that has an interesting angle, some of them will write about your stuff.

My little hobby app, Shattered Ring, has been featured on a ton of video game news sites, including:

After the App Store approved my app last week, I spent an hour or two reaching out to 5 video-game-related news sources every night. As far as I can tell, Video Games Chronicle was the first one to write about it on Friday, and then it started showing up everywhere. There are a ton of other websites that credit the original VGC article, but a few also seem to have gone to the Shattered Ring website and actually read up on what the app is and does.

It was Kay who noticed on Friday evening that my app was #7 in its category (Entertainment) on the App Store. And throughout the evening, we watched it slowly climb. The dog woke us up around 6am on Saturday asking to go outside, and I made the mistake of checking the app on my phone. And that’s when I saw it:

Whoa. #1 in its category on the App Store. I. Wrote an app. That climbed to #1 in its category.

Needless to say, I wasn’t getting back to sleep after that. I got up with the dogs and let hubby sleep in.

The problem is, I had never written an app before. I had no idea how many apps sell on the App Store. What did #1 in its category actually mean? And what did people think of my app?

I waited impatiently for Apple to publish its sales data. Eventually, I saw that #1 translated to 184 units sold. Wow! Nearly 200 people had bought my app!

Of course, Apple takes its cut. And I should hold back a share for taxes – I spent enough years as a self-employed writer to know the government has to have its cut. And then there were expenses I incurred in writing the app; things like domains for the website, web hosting, Formspree for the contact form, and some apps I used while writing the app. After expenses, I would net about $80 from my meteoric rise on the App Store. Which Apple would pay me up to 45 days after the last day of the month in which the sale occurred, so something like two months from now. So, not a life-changing experience. But definitely something to be proud of.

And then the reviews and emails started trickling in. Where was all the data? Why wasn’t there a ready-made list of NPCs, game locations, and quests just waiting for people to check off their progress?

Uh oh. Apparently what I thought of as an “RPG task tracker” and what other people thought did not totally line up – at least in some cases. I was thinking of it as a notebook replacement; something that would make it easy to connect NPCs to Locations and Quests, and store notes about each, and even give me a roundup of stats for things like how many quests I had completed and which locations I had cleared versus the ones where I had run away screaming and probably should go back when I was higher level. But some people, it seemed, wanted more than that for their $3.

I apologized to the folks who had expected more, and bookmarked the link to request a refund from Apple – and even added it to a FAQ on the Shattered Ring website. And I responded (nicely, I think) to the folks who posted 1- and 2-star reviews of it on the App Store. I revisited the wording on my site and in the App Store description and tweaked the wording, even though I thought it was clear what the app is and does.

I knew that I wanted to make some navigation improvements to the app, and there were also some features I had wanted to add but didn’t want to wait to ship in v1 – but now I had an app in production with nearly 200 users actually using it. This was the part I hadn’t thought too much about. Now people who had paid me money were relying on my app. I had a responsibility to them. So I didn’t just dive into new features and navigation improvements; I started writing every automated test I could think of to try to make sure that my changes wouldn’t break anything, or if they did, my tests would catch them.

Automated UI tests were slow going. I’ve only done a little bit with UI tests, and I’m still not familiar with how to refer to all of the UI elements for testing purposes, so there was a lot of trial and error. And my app is stateful (and so are my UI tests, at the moment, although I know in principle I need to refactor them to not be) so I have to wait for the entire suite to run every time I iterate, which started out at about ~15 seconds but was up to a minute by the time I went to bed.

Unfortunately, I saw another review before I went to bed that made me worry: a user was reporting a crash. Not a crash! Quirks, I could live with, but crashes are not ok. So I had a semi-stressful night thinking about how to resolve that crash, and how many more tests I had to write before I could go making big changes to the app.

I woke up this morning and started in on tests. But when I saw Apple’s data from Saturday’s sales confirming that more people had bought the app on Saturday – it hovered around #1 or #2 all day – I had a sinking feeling. I couldn’t leave all those people with a buggy app. I had to fix it, even if my automated tests weren’t done yet.

So I shifted gears. I spent some time adding a small tweak that a lot of people were requesting – the ability to edit NPC, Location, and Quest names (apparently iPhone autocorrect is aggressive!) – and finding and fixing the bug. It was a particularly snarly thing for me – I was presenting a sheet during a particular UI flow, and the sheet wasn’t dismissing after creating an object. So if users pressed the “Create” button again trying to get the thing to work, it would crash on them. Although they could swipe down to dismiss, and the object would be created.

I couldn’t figure out why it wasn’t dismissing (I still don’t know) but I thought back to a review that my lead had given me on the SwiftUI app I wrote for work, and his comments about not passing too many @State variables back and forth between views for navigation. So I refactored the navigation to use a different view pattern, instead of presenting a sheet. (I do present a sheet in other parts of the app and use a couple of different ways of dismissing it – using an Environment variable with the dismiss() API, and using @Binding vars to change state. It bugs me that I couldn’t figure out why this one wouldn’t dismiss.)

Anyway. Unfortunately, after refactoring the navigation and adding the name edit functionality, my update touched 28 files in my app. I did my best to manually test all of the flows – repeatedly – since my automated tests still aren’t fully implemented. And then had to figure out how to ship an update to the App Store. (Apple, I love your products, but I do not love your documentation.) And the next thing I knew, it was 7pm on a Sunday and I have lost my entire weekend to app maintenance stuff.

I hope the update I shipped fixes the bugs. I will probably be low-grade stressed about it until I see reviews or get user feedback that I haven’t introduced some horrible new bug. But the whole thing drove home something I hadn’t really thought too much about while I was writing this app – now that I have taken money from people, I have a responsibility to them to make sure the thing I sold them actually works. And, being a people pleaser, I will probably sink way too much of my free time into shipping new features based on requests. I want people to be happy with the thing I made. I want them to like it.

So, yeah. I wrote a best-selling app in its category on the App Store, at least for a little while. And at some point today, it made it all the way up to the #5 top-selling app on the App Store across all categories. That is pretty cool for a little hobby app that I wrote!

But, to quote a great line:

With great power comes great responsibility.

There may be hundreds of people using my app now – but now I owe them something in return. And that is stability, and maybe also an app that gets even better at doing the thing they want to do with it.

I guess now I’m a real developer?

P.S. I am sorry to have disappointed all the folks who want an Android version. I had one angry person on Twitter say: “Why on earth anyone would make an iOS exclusive app is beyond me. Literally 70% of the mobile market is Android. Is this some American thing where the Apple delusion is just accepted?” Nope! Just that I don’t own an Android device, and I don’t know Java or Kotlin, and I’m one person who wrote this app quickly in their free time outside of their full-time job and family/social responsibilities… sorry, Android user, that an Android dev hasn’t done the same by now. Although now that my app is out in the world, and has been splashed across a boatload of video game news sites, maybe some Android or multi-platform dev is out there writing something better!

I wrote an iOS app!

Coding

I wrote an iOS app!

I’ve had a handful of iOS app ideas in the past few years that I could never quite figure out how to turn into reality. I found it frustrating, though, because I really want to use the apps I’ve had ideas for. Finally, I’ve had enough practice with smaller projects that I managed to turn an idea into reality: my first iOS app is live on the App Store!

May I present: Shattered Ring, the Elden Ring task tracker you didn’t know you needed.

Yes. I wrote an iOS app to help me keep track of NPCs, locations, and quests in a video game I’m playing. (In my defense, though, I’m used to playing open world RPGs that have quest-tracking systems… and I’m a more casual gamer… and this makes it easy to keep track of threads and dive in and out without having to play 20 hours a week just to remember what I was doing.)

It’s the first app idea I’ve managed to complete. I know it’s just a teeny little hobby app, but I couldn’t be prouder. Now that I’ve gone through the whole process from start to finish with this app, I’m hopeful I’ll have the experience I need to turn some of my other hobby apps from ideas into reality.

If you’re into Elden Ring, check it out and let me know what you think! Or if you play D&D, or any other TTRPG, it also makes a great RPG game tracker. I’m using it in the two D&D games I’m in.

I wrote this in SwiftUI, using some of the Realm DB Swift SDK goodies that they’ve written just for SwiftUI. I’ve complicated my life a little with a data model that means it isn’t just a simple build, but I can still use some of the SwiftUI property wrappers and it’s pretty magical. And of course, I had to spin up a website for it – which I did in Hugo because it’s fast and easy (and not WordPress – really need to migrate this blog).

Hope some folks find it a useful little app! I know I already do.

Coding

CLI tool version complications

I’ve been playing around with different versions of the realm-cli for some documentation projects. That means installing and uninstalling various versions via NPM. I kept getting tripped up on this complication so I’m documenting it here in case other folks find it helpful.

NPM uninstall

Using npm uninstall is simple, right? Just run it with the name of the package you want to uninstall, and maybe pass a few flags like -g if needed, and the package is gone.

So here’s what my command line looked like today:

-> npm uninstall -g realm-cli
-> realm-cli --version
realm-cli version 2.0.0-beta.3

Aaand…. that went on for a while. I kept running various permutations of NPM uninstall from different directories with different flags, and every time I checked the realm-cli --version, I kept seeing it sitting there, taunting me.

I did what any good burgeoning developer would do. I started down a StackOverflow rabbit hole. I got my first good clue when I found this hint:

-> npm list -g

Aha! This tells me which global libraries are installed and where they’re located. I’ve got four of them, and they’re at /usr/local/lib:

bluehawk@0.2.3
m@1.5.6
mongodb-realm-cli@2.0.0-beta.3
npm@7.4.0

Now the astute among you will probably spot the problem pretty much immediately. I went a bit further before I figured it out.

I popped into /usr/local/lib. Didn’t see my realm-cli there, but I did see node_modules, so I figured that was where I needed to be. Changed directory into there, did a little ls, and Bob’s your uncle:

bluehawk m mongodb-realm-cli npm

Oh… wait a minute. I’ve been doing all kinds of permutations of npm uninstall realm-cli. But the name of the thing I’m trying to uninstall is mongodb-realm-cli. Even though the tool is all realm-cli this and realm-cli that, the name of the thing is actually mongodb-realm-cli.

Maybe this is something that a more experienced developer would check right away. But this is the first time I can remember encountering a CLI tool whose name is different than the syntax you use to invoke it. When I do the realm-cli --version and get back realm-cli version 2.0.0-beta.3 instead of mongodb-realm-cli version..., that reinforces my perhaps naive conflation of package name and the syntax you use to invoke it.

Anywho, I ran into this a few weeks ago when changing versions of the CLI, figured out how to fix it, forgot about it between then and now, and went through the whole dang thing again this morning. Documenting it here for myself, so the next time this happens I can hopefully remember how to resolve it more quickly, and for anyone else who runs into something similar.

Why does the name not match the syntax?

I’m doing some inferring here, but here’s my theory.

MongoDB acquired Realm a couple of years ago. I did a little poking around, and NPM has a realm-cli that was last published 4 years ago. My guess is that for some reason, there isn’t access to remove that old realm-cli package, so MongoDB had to append its name to the front of its version of the realm-cli to differentiate it. So if you’re using Realm these days, you want mongodb-realm-cli.

Now I’m curious how often things like this happen with acquisitions…

Learning to code: redux

Coding

Learning to code: redux

A little over a year ago, I wrote here about how I was learning Swift because there are a couple of apps I want to write. I’ve gone through a few courses online, and had started working through an Everyone Can Code book: AP Computer Science Principles with Swift. I was making good progress, had done the data modeling for my “main” app, but then got a little overwhelmed with the idea of actually starting it. Like, how does a n00b sit down and begin writing an app for the first time?

Then came some health issues last fall, and then Christmas, and then this spring the whole world has turned upside down…

So here we are a year later, and I haven’t written my apps, although I’ve been getting cozier with the code needed to modify the functionality in the static site generators we use for work (Jekyll and Hugo) and my Git foo has gotten to be second nature. But the actual proper “learning to code” I had wanted to do has been nagging away at me. So when one of my co-workers posted that Stanford University’s Engineering department was offering a free intro to coding class, Code in Place, I jumped at the chance to sign up.

Fast forward to six weeks later. I was one of 10,000 interested geeks-in-training who got accepted in this massive international experiment of teaching a diverse student base how to code in Python, entirely online.

I attended all the “sessions” – video chat classes, of sorts, consisting of a group of 10 students working under a “section leader” to practice solving various problems with code. I’ve watched 14 recorded lectures via YouTube, led by Stanford instructors, and have worked through all of the slides and code from each lecture. I’ve learned about decomposition, control flow, images, graphics, and animation – in addition to things like variables, expressions, functions, lists, and dictionaries – all the fundamentals to build a solid coding foundation.

My “deliverables” for class have included three assignments, which I uploaded to an autograder to see if they functioned and passed various tests. I also did a “diagnostic” to help determine which concepts I understood thoroughly, and where I needed additional help. (That was supposed to take an hour, but it took me an hour and 40 minutes – but I worked through the whole dang thing, without bothering my husband the experienced web dev for help, until I got it all done and it all worked.)

Now, we’ve arrived at the final week of class, and I’m doing a final project. For this final project, I’m writing an app! Finally. Not one of the apps I had planned to write a year ago; this is a new idea, which is based on a recent experience I had at work and seems well-suited to be a Python project.

Here’s the premise: the technical documentation I write at work contains screenshots. The screenshots are images taken on various pages of our app. When we make changes to the app’s UI, I need to update the screenshots to reflect the new UI. Sometimes that’s easy, like when the User Profile options change, I know I need to update docs around the user profile. But what about things like adding a git provider, or changing the API key, which are options that you get to through the User Profile menu? It might not be obvious to me that I need to update those screenshots in seemingly unrelated sections of the documentation.

For my Code in Place final project, I’ve decided to write an app to solve this issue: a screenshot inventory tool, which can call out to a visual diffing tool, and then return to me a list of screenshots I need to update based on pages that have visual diffs.

So far, I’ve got the screenshot inventory piece working; I can create a list of all the screenshots in my technical documentation, and associate those screenshots with URLs in the app (dictionaries are awesome). I added some fun calculations to tell me how much coverage I’ve got in this screenshot inventory; for example, I’ve got 181 screenshots in my documentation, but have only inventoried 14 of them so far, so roughly 7% of my screenshots have been inventoried. I’ll work toward 100% coverage, because that becomes more important when I get the second piece working: the visual diffing element.

For the visual diffing element, I’m learning how to make API calls to a visual regression tool, Diffy, that can generate visual diffs of pages across environments. So I can have it diff production and staging, for example, and tell me which of the pages that I’m tracking contain changes in staging. Then my app will give me a list of the screenshots associated with that page, so I’ll know which screenshots I need to update when there are changes to the app.

Bonus: the process of making these associations has made me realize there are some nearly duplicate screenshots in my technical docs, which could be streamlined a bit. So hopefully this exercise will help me tighten up my documentation images and maintain fewer assets. Bonus win!

I’m handling a lot of this data storage and processing in JSON. Code in Place didn’t cover writing to files, so I don’t have databases and am trying to keep the scope small enough to finish a final project in a week (while also working a full-time job and prepping my veggie garden for spring). Fortunately, my data storage needs are simple, and JSON lends itself well to API calls, so that helps.

API calls are also out of scope of what we learned in Code in Place, but I’ve documented APIs before and am familiar enough with the basic functionality that I’m hopeful I can get that part working before the final project is due. If not, I’ve got the screenshot inventory part working, and can always keep working toward the visual diffing processing after class is “over.”

At this point, though, I think I can finally check off the box that says: “learning to code.” I’ve written an app that does a thing, and it’s a step beyond the Hello World type stuff I’ve done so far in Swift. I’m enjoying the problem solving; I spend a couple of hours every evening working on code, and go to sleep with code in my head and wake up with problems solved. I might eventually pick up a Python web framework and give it a web UI, or maybe I’ll leave it a command-line tool and change gears back to Swift now that I’ve actually started and written a thing.

Or maybe I’ll go even deeper down the rabbit hole, because learning is fun, and poke the Python/Swift interoperability stuff and give it an iOS app. Why not? The sky’s the limit once you’re well and truly started down the path of programming.

Investing in good equipment

Business Coding Lifestyle Personal Writing

Investing in good equipment

A younger, more innocent me bought a 13″ mid-2014 MacBook Pro on closeout in early 2015. My main tasks for my computer at that time were writing documents in word processors (Pages) and using CMSs to create and publish content. I thought I might do some light video editing of travel videos for Corporate Runaways, but didn’t have much need or desire for a powerhouse machine. I had an external monitor for additional screen real estate, and mostly used the laptop screen for reference material.

Fast forward to 2019. In the past few years, I’ve started doing docs-as-code in conjunction with a few open source projects. From the open source project side, this has involved setting up local development environments on my machine, and running apps locally so I can document them. From the documentation side, this has involved using static site generators to create doc sites from files (markdown, mostly). My work needs have definitely gotten more intensive.

Then, this spring, I dove into Swift. When I decided to learn to code so I could write an app I want to use, I took a gradual approach. I worked through some Swift Playgrounds stuff on my iPad, and then read a book or two about coding and Swift. I brainstormed the data structure for my app, and made UML diagrams. Eventually, I took a couple of online classes on Xcode and Swift.

Between my technical writing work and my app development, my 13″ laptop + external monitor had begun to feel cramped. What had once felt sufficient for doing marketing writing in a single window, with maybe a reference window alongside, had now become a nightmare of overlapping windows and constant swapping. I wanted more screen real estate so I could have multiple windows open for reference and working simultaneously, and I wanted those windows to be bigger.

But mostly, I wanted Xcode to not just laugh at me when I attempted to compile things, or – even worse – not have Xcode sputter when I attempt to Auto Run a Playground so I can see how things are working as I code.

One of the classes I took involved working in Playground files on my machine as I followed the instructor’s videos. I had to keep pausing the instruction video to wait for my local Playground to respond to my inputs, while the instructor did the exact same thing in the video and then happily chugged along with his much more powerful machine.

It was clear. Xcode was a memory/processor hog, and I had too little of both. I’d been bumping up against those limits for a while now with my other work, but the app development pushed me over the edge. So it was time… time to upgrade my equipment.

(Don’t get me wrong – that little 13″ mid-2014 MBP did well to get me into mid-2019 without a hitch, and is still chugging along happily with less intensive tasks; it’s my “couch computer” now.)

I looked around at the options. I could get a newer, more powerful MacBook Pro. But I’d still have limited screen real estate, and that was chafing more and more. Also, I essentially never use my laptop as a laptop these days; I work exclusively at my desk, with my Kinesis Advantage2 keyboard and my external monitor setup. Could it be time to go back to a desktop, when I still remembered fondly the liberating joy of going from a PC tower to my first laptop back in the mid-2000s? It seemed like such a step back, it was hard to fathom.

But the more I thought about it, the more it seemed to make sense to get a desktop again. I never use the laptop as a laptop. I could get better CPU/more RAM significantly cheaper with a desktop. And then I could have another big monitor, giving me the screen real estate I’ve been craving.

I decided to go back to a desktop. I clearly didn’t need a powerhouse like the newly-announced Mac Pro, so I wasn’t going that route. I looked at the Mac mini; a capable little machine. I looked at the iMac, with its beautiful monitor. I looked at the iMac Pro – nope, that’s more than I need.

Waffle. Research external monitors. Waffle. Spec out both machines to a level that would support my current needs, plus some future-proofing. Cringe at the price tag. Waffle some more. Deal with some stupid imposter BS because my husband is the experienced web dev, and how could I justify spending that much on a setup for my less-intensive work + dabbling in Swift development; an entirely self-driven project that may never make me a penny?

Eventually, I drove the hour to the nearest Apple store to see an iMac in person. And then I sat myself down and gave myself a pep talk about giving myself permission to invest in my skill development. Maybe I’ll get more heavily into coding as a tech writer. Maybe I’ll love developing in Swift so much that I’ll pivot to Mac app development. Or maybe I’ll write this app, but then decide that coding isn’t something I want to pursue beyond that. I won’t know unless I give myself the room to develop those skills and see what happens, but it is 100% OK to invest in my career potential.

So I pulled the trigger, and got a beautiful 27″ iMac. And it isn’t the entry-level iMac, either; it’s closer to the top tier, to give myself room for growth.

And you know what? It is frigging delightful. It’s so fast. And the screen is so beautiful. It’s a little painful to use it right next to my old external monitor, which isn’t even 4k; the resolution drop and seeing visible pixels is a little jarring looking back and forth. I expect I’ll upgrade that, too, soon. But my tech writing work has been much more hassle-free with the extra screen real estate, and staring at text on a retina-resolution screen is delightfully enjoyable.

So here’s a reminder, if you need one, too: investing in good equipment is an important part of taking your professional life seriously. This is mission critical for remote workers who don’t have office-supplied equipment. I see a lot of remote workers sitting on their couch and typing on a laptop keyboard; that’s a good way to ruin your hands, your back, your posture, and reduce your efficiency and output. (Trust me, that’s how I started out with my remote work back in 2007.)

Yes, I am extremely privileged to be able to spend the money on an Apple device; I know you pay a big premium for their products. And I know that not everyone has the financial freedom to invest in big, splashy monitors and professional-quality office equipment; especially for folks who are the sole breadwinners, or supporting family members. But it is worthwhile to put money aside and invest in the equipment you need for your career, in whatever form you’re able and whatever that equipment looks like for you.

I am very much enjoying my new setup.

Learning to code

Coding Personal

Learning to code

There are a couple of apps I’ve been wanting to write, so the time has come to learn to code! Unsurprisingly, this makes hubby happy, as now I can more readily empathize with the geeky coding plights of a senior web dev.

It’s actually been pretty interesting, so far.

I first taught myself to code in Basic when I was 12 or 13 on a Commodore 128 computer; programs were on floppy disks then, the 5 1/4″ kind. I had a handful of programs that came with the computer, which my family bought used for $400; a lot of money in the early ’90s. (They’d spend $999 on my next computer in the mid-’90s, a Packard Bell Pentium 75mHz machine, running Windows 3.11. I was a lucky little kid.)

Of the programs that came with the Commodore, I adored the text-based adventure games the most. They were a cross between interactive fiction, and what I imagined D&D must be like (having not yet played it, at that point) – and the one I played the most was based on The Hobbit. I loved it so much that I decided I should write my own, so I’d have different adventures to play.

So I dug into the code, figured out how the game was written, copied-and-pasted bits of it, and started writing my own games. Of course, then came debugging, because a 12-year-old copying-and-pasting code is far from bulletproof. So I had to figure out how the code actually worked, so I could fix the bits that broke.

But that was a long time ago, and my first love remained writing, so I never really pursued coding as computers and languages evolved. (Although I did have a side gig in computers when I founded a computer repair business, for a while, which mostly involved replacing dead hardware, doing upgrades for people, or wiping someone’s drive that had gotten all crudded-up with malware and reinstalling Windows.)

Fast forward to today, when there are a couple of apps that have been percolating in the back of my mind for a while. I’ve been waiting for someone to write one of them for a couple of years, but everything that comes along isn’t quite what I want… so now I’m annoyed and fed-up enough that I’m ready to write it myself.

App number one is fairly trivial, and something that I really just want to use myself; I don’t care if another person ever buys it. But that app should serve as training wheels for the more important app I want to write; one that will hopefully be useful to an entire industry.

Right now, I’m working my way through Swift Playgrounds to get some of the basic fundamentals under my belt. I’m also reading a couple of books. Maybe this time I’ll make it through Chris Pine’s Learn to Program, a great beginner book hubby gifted to me ages ago. From there, I’ve got a couple of other courses lined up.

Happily, I’m already familiar with the logic behind programming; some of my work as a technical writer has been to explain that logic to non-programmers, so they can use a very technical app whose interface was developed by engineers, not UI/UX folks. And I remember some of the basics from my old days mucking about in Basic; conditionals and loops are conditionals and loops, 25 years ago or today.

Wish me luck as I dive into this side project! I’m still looking for a paying technical writing gig to cover the bills, but this is a fun way to expand my skills while I hunt for the right fit. And maybe I can bring in a little side income from the apps I’ll write.

If nothing else, I always enjoy stretching my brain and learning new skills, and it’s fun to come full-circle from my early days in computing and dip my toes into coding again.