As the App Store has matured and its revenue streams diminished, I have needed to pursue consulting jobs to bolster my income. Unlike working fully for myself, clients want (quite reasonably) an estimate of what a job is going to cost before signing off to begin the work. Unfortunately, in software development, accurate estimates are notoriously the hardest things to come up with.
The difficulty with creating an accurate estimate centers around the guesswork involved in the things that are new or not known. New or unknown APIs, specialty field knowledge, and unexpected hurdles can all exponentially increase the time needed beyond what’s expected.
Quite often the only way to predict the time needed for something is to do the majority of the legwork needed short of actually building the end product. Obviously, this can easily be a huge waste of time since many estimates end up going nowhere because of insufficient budgets. There’s definitely a balance to find, though I’m far from a perfect record on finding that balance.
Example: AppleScript Support is Hard
A recent project involved adding AppleScript support to an existing OS X app. While I’m very well-versed in Objective-C, I have minimal experience with the various AppleScript APIs in Cocoa (yes, there is more than one as I found out) and the accompanying learning curve. Based on my preliminary research, I generously (or so I thought) budgeted three hours to get basic AppleScript support going — enough to get some infrastructure built and to respond to a single command.
I was wrong – really wrong – and it ended up taking almost double my estimate. Cocoa’s AppleScript documentation exists, and that’s really the best that can be said about it. In it there’s some accurate stuff, some inaccurate, some outright wrong, some outdated, and some completely missing information. The degree of difficulty that the documentation creates deserves its own article, something I may get to someday. You know it’s bad when an otherwise informative article on the topic is riddled with uncertainty and guessing:
The code is NOTE. It could be almost anything, but note that Apple reserves all lowercase codes for its own use, so note wouldn’t be allowed. It could be NOT*, or NoTe, or XYzy, or whatever you want. (Ideally the code wouldn’t collide with codes used by other apps. But there’s no way that we know of to ensure that, so we just, well, guess. That said, NOTE may not be all that great of a guess.)
Your classes should inherit from item. (In theory you could have a class the inherits from another of your classes, but we’ve never tried this.)
Ultimately I found success only by copying a fairly thorough SDEF (the current preferred format for a scripting definition file) from Apple’s own Mail app and making the necessary changes. There were tags and values in it that, while apparently required, were never mentioned in any of the documentation I read. How do you estimate for that?
Example: My Own Endeavor
Both of my major apps are paid-up-front, pro-targeted apps. They’re priced accordingly. As the market for that business model dwindles, and as Wil Shipley’s plea for App Store trials goes unanswered again, I wanted to try my hand at an ad-supported app.
I tried to pick an idea that would be simple enough to do in a few days, something I could work on after finishing with client work for the day. A sunset/sunrise time calculator seemed like a good one, especially since I often find myself resorting to Google for it. I also decided to throw in moon rise and set times for completeness. And, if I wasn’t asking for it enough with that, I also decided to do it in Swift.
I started it two months ago and it’s still not done.
From prior experience I knew there was an existing Objective-C project on GitHub for calculating sunrise and sunset times. I knew it didn’t do anything with the moon, but I figured I could use the same basic approach to figure out those times as well.
I was really wrong! While they are conceptually similar, my total lack of knowledge on orbital mechanics meant I didn’t understand enough of the math to do a thing with the equations in the EDSunriseSet project — the numerous numerical constants are completely meaningless without at least a superficial understanding of the context that they’re derived from. What followed was nearly a week of dissecting code and astronomical algorithms just to learn enough to do what I wanted.
Thanks to some C++ implementations of astronomical algorithms and the book Astronomical Algorithms (the book effectively functions as documentation for the code), I learned enough about concepts like Julian dates, sidereal time, nutation, dynamical time, ecliptic longitude and latitude, eccentricity, and mean anomalies to create a native Swift implementation of the orbital algorithms I needed.
Remember that mention of some crazy numerical constants? This is just one method among many. It took roughly 3000 lines of Swift code to implement the necessary algorithms to calculate the rise and set times for the sun and moon given a date, latitude, and longitude. That’s something I would never have estimated correctly without spending a week researching the topic, which is typically impractical for a quote.
Improving
Barring spending more time on the estimate itself, experience is the only thing that can really improve its accuracy. Past experience replaces the need to spend time researching a topic just to make an informed guess on the time required.
It’s a moving target, though. New APIs get introduced, new platforms and hardware are released, old APIs are deprecated, all of which end up limiting the usefulness of an existing pool of experience. Experience needs to be gained and updated continually for it to retain value, and if nothing else, it provides a big reason to pursue independent projects in new and interesting areas. The accuracy and dependability gained are two very important contributors to maximizing your time. This maximizes your revenue.