I have a project that stalled.
The project is an iOS app. A fairly simple, really. The app is, more or less, a graphical interface for database (I suppose most apps are some form of this). The app has been around in one form or another for many years, but doesn’t need to be update that often. The truth of the matter the database that i’m using hasn’t been updated in a while because I’ve never gotten around to write an editor. So, the last major release was around 2015.
In late 2015 or so, I had the brilliant idea of porting the app to MacOS. After all, I eventually need an editor. A twist in that idea was the app would be 100% written in Swift, if possible. The iOS version was written in Objective-C.
It turned out the transition went well. I released the MacOS version in 2016.
It went wrong when I decided it was time to unify the code base of the apps as much as possible. In other words, the iOS app had to move to Swift too. Why? Well, I got a job and this particular app was a relatively low priority.
Fast forward to 2018. I decided that it was time to expand the things I do at work. Thus, I decided to become a Test-Driven Development (TDD) instructor (in training at least). So naturally, I decided to find a relatively small project that I can apply my (limited) TDD chops.
It is time to revisit my Devonian Database iOS and MacOS apps. These apps are available for free on the different App Stores.
The iOS app been in the app store for many years, and I managed to get the last version out in 2015 or 2016. I fixed it up and released as part of a job hunt: have a good working app in the store to prove I can do the work. As part of that effort, though, I decided to release the Mac version of the same app. Cleaver me decided to make this new version entirely swift: no Objective-C code at all. That app was successfully released too.
What got me was the next decision: make my iOS app Swift only as well. The decision made sense, and still does. Minimize the code base and both apps are easier to maintain. While Objective-C is still a powerful language, Swift is an easier language to use (with the exceptions of occasional major changes to the languages and the difficulties in testing and Objective-C interoperability). But it takes time and energy. I got the job and the app fell by the wayside.
I started looking at the app again and it’s a mess. For most developers, looking at your old code is a cringe-worthy experience. Now that I work on a team, I find my old code has one fatal flaw: it was written for me… The problem with “written for me” that that the me of today has no idea what the me of 2015 was thinking. I wrote things quickly. I wrote things using simple and convenient design patterns instead of something that would be more appropriate. I did write a few unit tests (or in many cases integration tests pretending to be unit tests), but they were few and far between and written at a time where I really didn’t understand how to write good Swift tests. Not to mention many didn’t work at all.
So, my first few hours will be spent looking at the core of the app – the database management code. I’ll blog the results of this work.
I’m working on a particularly difficult part of my user interface and I ran into an interesting and confusing problem. UI Testing is a new feature in Xcode. Despite its newness, it has already helped save time in development. However, I started using it with an app I’ve been trying to update for a while when I ran into this problem.
UI Testing depends on accessibility: a mode for those with disabilities. As it turns out, it is highly dependent on titles or names you give different user interface items. So, the names you give things are key to getting UI Testing in Xcode right.
In some cases, however, this can cause a problem.
I have a navigation bar that has enough elements that a title looks too stuffed into the bar when the device has a compact horizontal size class. When regular, it looks fine. So, I simply added a title when the display was regular, and did not add the title when compact. This causes UI Testing problems.
The navigation item must always have the same name in the testing environment or you have to use a NSPredicate to search for the title or the class name (if you don’t set the title, then the UI Test record will record the class name). This seems quite fragile and quite annoying since I don’t want duplicate tests for different devices unless there is a major difference in layout.
The apparent solution at this stage is to go ahead and name the navigation item to the title I want. However, to prevent the title from appearing, I simply sent an empty UILabel to the “titleView” property of the navigation item. This appears to work at this stage…
Probably the second biggest roadblock for developing mobile apps is the cost of hardware (the first, of course, is the time). Devices are expensive and it’s tough to keep up. My current testing livery of devices is actually quite limited. Indeed, some of my devices are not longer supported by their manufacturers or myself.
Despite the difficulty of maintaining an adequate device livery, you need the devices for testing. In a previous post, I mentioned that I’m migrating my app from OpenGL ES 1.1 to OpenGL ES 2.0. All of my currently-supported devices support 2.0 (and in some cases 3.0). That sounds like things should be just fine. Well, they don’t have the exact same graphics card or OS – which will lead to horrible surprises.
I have one older iPod Touch which on iOS 6. Having this particular device saved my bacon for the last release of one of my apps. It turns out that the software ran just find on all of my devices except that iPod Touch. Talk about panic! It wasn’t an easy fix either; it required a rewrite of a major portion of my code to work correctly.
Well, in my testing for parts of my OpenGL ES transition code, I decided to try the old iPod again… and wouldn’t you know, code I thought was working fine rendered completely wrong! It turns out there was a bug in the OpenGL code that apparently didn’t manifest in the newer devices or on the simulator.
Realistically, you can get away with a smaller livery of devices under some conditions. For example, if you don’t use any low-level code and stick with the high-level user interface APIs you’re more likely to still have a stable app on many devices. Getting into the lower-level stuff will likely cause more problems particularly in the short run as you develop, and in the long run when devices you didn’t test start reporting issues.
Just to add to the above, I don’t count the xCode simulator as a device. I have code that works perfectly in the simulator and does not run correctly AT ALL on any device. After all, the simulator is actually MacOS X OS and hardware, not mobile. As a consequence, successful rendering in the simulator will not always translate to a device. The first time you encounter this issue it is a rude awakening. However, it shouldn’t be a surprise since all of Apple’s OpenGL ES debugging tools only work on devices, not the simulator.
This gets back around to why my apps have yet to be ported to Android. I only have a couple devices that use that platform for testing out of the many MANY devices out there… it’s a tad scary…
Now that I have a break from other duties, I’ve been working on improving AE for iOS. One of my early design decisions I made in AE is to go with OpenGL ES 1.1. At the time, my only iOS device did not support OpenGL 2.0, so for practicality sake, 1.1 made sense. Furthermore, I needed some basic functionality that was stripped from OpenGL ES 2.0. ES 2.0 was clearly unattractive… at the time…
Today, the story is different. All of my “supported” iOS devices support OpenGL ES 2.0 and in some cases 3.0. Yes, they still support 1.1, and it’s arguable that the practical decision is to remain on 1.1. However, it’s only practical if I don’t add new features that call on the graphics card. I’m also considering the path to porting the application to other platforms, such as Android and Desktops. From this perspective, ES 1.1 looks increasingly problematic.
The kicker that’s forcing the transition is the time scale control on the bottom of the screen. It turns out that feature is quite a difficult to display. The time scale tends to be a memory hog and requires a great deal of code to provide full functionality. I’ve long known that the control should be moved to OpenGL rather than using higher-level functions. Originally, the time scale was created using simple bezier-path draw calls. In the last version, I moved the system to Apple’s layers. That transition was meant to make the code easier to maintain. However, it turned out, on older devices in particular, the app became crash prone because the layers took up an unexpected amount of memory. I managed to work through this problem for a stable release, but I wasn’t happy with the situation.
Enter OpenGL ES 2.0. Now, the time scale is not done by any means, so these comments are initial impressions. Now that I’ve worked with it, I do regret not going with ES 2.0 from the beginning (it still wouldn’t have been possible to release the original app with ES 2.0 support since I had no hardware at the time). ES 2.0 is clearly superior to ES 1.1. Surprisingly, I found that while in some areas ES 2.0 requires more code, the transition from layers to ES 2.0 appears, at least in some areas, is thinning out my code. That’s exciting! Since the code for the layers was extremely complex, it’s hard to improve or add features. With the code simplifying, I feel I can consider, at least, adding functionality I wouldn’t have been too keen on adding before.
Now, back to work on the code. We’ll see how this turns out…