Donald Hays

Added a JSON Feed

June 1, 2017

It’s been a while since my last post, and I only have a brief update today. I added support for JSON Feed to this site. You can view it here. It joins the existing Atom feed.

Minor Sunset Controls Update

January 16, 2016

I made a minor update to Sunset today.

For iOS devices: Sunset now recognizes touch events on its gamepad, and will use those instead of click events if possible. This eliminates the 300 millisecond input latency you otherwise get. This means it takes about 6 fewer seconds to go from one side of a map to the other. Speedrunners rejoice!

For desktops and laptops: Sunset has long supported keyboards through arrow keys, the space bar, and the escape key. Today I also added support for WASD for movement and Q and E for turning. This is the first time you’ve ever been able to strafe in Sunset. Such flexibility!

Uploaded Sunset Again

January 14, 2016

I just re-uploaded Sunset to my site.

Back in 2007, Apple released the iPhone. Apple didn’t announce the App Store then, saying instead that web apps would be the “sweet solution.” People weren’t terribly keen on that, but I thought JavaScript had much to offer on the iPhone, so I set out to make a game that pushed the boundaries as much as I could.

I decided to make a 3D turn-based RPG. Sunset was the result. I released it in January of 2008, shortly before Apple announced the iPhone SDK. The first wave of native games easily trumped my game’s visual fidelity, but for a very brief window of time I honestly felt I had put something out that was at or near the top of the heap of what developers could make the iPhone do.

Much has changed since then. WebGL is a thing, enabling browser games to far exceed what I could do in a Canvas tag. Phones have gotten orders of magnitude faster. I’m pretty sure my iPhone today is faster than the iMac I developed Sunset on. In fact, because of how fast modern phones are, I made a minor change to Sunset today before uploading: as a performance optimization in 2007 I only did a 3D raycast against every fourth column of pixels, leading to a stair-stepping pattern when viewing walls at extreme angles. I have removed that resolution limit, so your device will now raycast all 320 glorious columns of pixels. Marvel at the fidelity!

I played the game again to make sure it still worked (age has a funny habit of breaking old software, even though the software itself didn’t change). I grimace at a lot of my bad art, but I think the gameplay—simplistic though it be—holds up pretty well. I like the difficulty curve, level progression, and item stats. You struggle for a bit, then get a nice weapon upgrade and feel like an invincible God, then you move on to the next zone and things get hard again.

So if you want to play a small, free game that might keep you busy for a few hours, give it a try!

Maidenhead Converter 2.2.0/2.2.1 and the Importance of QA

August 29, 2015

Maidenhead Converter 2.2.0 went live about a week ago, and—due to a bug—2.2.1 followed soon after.

There are two features in these releases, and several bug fixes. I added the ability to pick a format for distances, allowing you to choose between Metric and Imperial. This is presently only used for the accuracy label when tracking your location, but it’ll also be used for other features I want to add later.

I also improved VoiceOver accessibility support throughout the app. You can navigate menus and work the keypads via VoiceOver. I don’t know if I really have any audience for VoiceOver, but it’s a good thing to do and I wanted to practice implementing it anyway.

2.2.0 also fixed a few very minor display issues. A few views weren’t aligned well on all devices, and text could clip on some others. Also, iOS 9 will change the system font from Helvetica Neue to San Francisco. When displaying text in iOS, you can ask the OS to give you the “system font” of a specific weight and size, but there were a few places where I was explicitly asking for Helvetica Neue, so I replaced those calls with asks for the system font.

Unfortunately, 2.2.0 also broke the in-app purchase for the ad disabler. Folks who already bought the ad disabler still had ads disabled, but people who didn’t already have it couldn’t buy it.

How did this happen? Didn’t I say in my last post that I have a Runbook that I use to test every part of the app? Yes, and I ran it for 2.2.0, and every other part of the app worked, but the store didn’t, and I shipped anyway. Why? Because I couldn’t find any reason in the code for the purchases not to work, so I decided to bet that I wasn’t able to do purchases in dev because the sandbox iTunes Store was down, which is something that happens from time to time. Once the app went live and purchases didn’t work with the real App Store, I knew that bet was wrong.

After poking around for a long time, I discovered the bug appeared when I transitioned to Swift 1.2. That version of Swift added a built-in Set type, and calls that used to take the Objective-C NSSet type changed to take the new Set type, so I changed one line of code in the store from:

SKProductsRequest(productIdentifiers: NSSet(array: identifiers))


SKProductsRequest(productIdentifiers: Set<NSObject>(arrayLiteral: identifiers))

So all is good, yes? No. For some reason, despite the fact that the syntax is valid, and logging out the resulting set appeared fine, for whatever reason when that bridged back to Objective-C for StoreKit, the set was invalid in some way, and a “could not connect to the iTunes Store” error would be produced. The solution ended up being to change the line to:

SKProductsRequest(productIdentifiers: Set(identifiers))

Which also compiles fine and looks fine when logged out, and by all respects should be functionally identical to the previous line, but it was the difference between a working store and a broken one. I’m guessing there’s a Swift bug here, and when I update the app to Swift 2.0 I think I’m going to try both constructions and see if only one still works, and if so file a bug.

So the lesson I need to take away from this is that I really do need to pass all my QA checks before shipping an app, no matter what.

Maidenhead Converter 2.1.1

February 3, 2015

Maidenhead Converter 2.1.1 is now live. This was largely a refactor and bugfix release, there aren’t any new features.

I like using Maidenhead Converter as a testing ground for ideas, patterns and practices that I apply to my work on EventBoard. Maidenhead Converter is small and simple, but does a real task.

Recently, I’ve had a big focus on QA. The app now has a suite of unit tests, and those tests helped uncover some of the bugs that I fixed. The bugs tended to be on the app’s edge cases, but they were real, and I hadn’t caught them before.

I’ve found that internal data and processes are easy enough to write unit tests for, but views and view controllers seem quite difficult to test without doing some pretty bad contortions. I would like to figure out a good, straightforward way to write automated tests for the UI layer, but I don’t have one right now.

What I do have is a Runbook. A Runbook is a document that describes every button and feature and state of the app, and says how they should work. It’s similar to the monolithic design document that software under the waterfall development model gets, except the Runbook is developed alongside the app, instead of before. Before submitting a release, you treat the Runbook like a checklist, examining everything in the app and making sure it works as intended. While obviously far more time-consuming to execute than automated tests, it still did good for my confidence in the quality of the app.

Now that this release is done, I intend to do 2.2.0, which will include some new features.