The Builder pattern in Objective-C
When @kluivers pointed out @klaaspieter's post on using the Builder Pattern in Objective-C I took note, as this is something I’d used quite extensively doing TDD in Java. I thought I saw a way to finesse it slightly and finally having had the time to do it, I’m happy to say it’s worked out like I’d hoped.
The idea was to use an Objective-C category to hide the builder-related code and prevent it from “polluting” the original implementation.
This gist has an example. Say I have some kind of “value item” class (
GroupableItem in this case) having a bunch of properties which all need values, most of which might not be germane to any given test and some of which might be complex to set up. I create a
GroupableItem+Builder category containing an implementation of a
GroupableItemBuilder class with properties for all the configurable options.
GroupableItemBuilder's init method sets default values for all the configurable properties of the builder. Finally, this category defines the
itemWithBlock class method, which creates the value object from the defaults set in the builder, after they’ve been “offered” to the user to change via the block.
This way in my
SomethingUsingGroupableItemTest I can import the category and use the builder to set whichever properties are relevant to my particular test, knowing I’ll always end up with an internally consistent object.
Better, if the
GroupableItem+Builder category is declared in my test tree, it isn’t even compiled into my app.
This is kind of a degenerate example and I could of course have just created a method in my test class with parameters for the configurable options that returned an instance of my value object. But this breaks down pretty quickly when you have more than three or four configurable properties (only one or two of which you might want to alter from the default for any given test.) It also creates a pleasing separation between the “meat” of the test and the “plumbing” (which can be easily reused in multiple places.) This approach is also type safe across refactorings of my value object’s property names.
Now you have two problems
Up until the advent of the iPhone App Store you could split the problems you needed to solve to produce a software product into three broad categories: development, marketing and distribution.
The App Store solved problem number three in an effortless and comprehensive way—anybody who could possibly use your software is able to buy it instantly, wherever they are, at no up-front cost to the developer.
The misconception was that the App Store solved problem number two as well. For a short time it did: the novelty of the App Store itself drew attention to the products available there. The fact those products were initially so few in number resulted in an amount of attention-per-product sufficient for customers to discover them, and there were many indie developer success stories.
But with the growth of the App Store this “attention effect” has been diluted to almost nothing. The whole progression starkly illustrates just how important the “marketing” component of a software product is and this has profound implications for the careers of those of us who identify as “software developers”.
The other, other ninety percent
Software engineers joke that the first ninety percent of a programming task takes ninety percent of the time and the last ten percent takes the other ninety percent. The idea is that once you’ve got a program working for the majority of “happy paths”, there’s always a bunch of edge cases you need to take care of. (Daylight saving changeover? Unreliable network? German translation where all the strings are three times as long and muck up your interface?). Tying up these loose ends typically takes about as long as writing the code for the happy cases.
Having gone through this process myself and finally having an app I’m reasonably proud of on the App Store, I’ve discovered there’s another ninety percent between that and a product. No matter how good your code is or how legitimate or large a problem your software solves, you’re not going to make any money until you market it well. That means writing App Store copy (with localised screenshots, translated into a dozen languages.) It means writing a press release. It means finding relevant people to send that press release to, sending it to them and fielding any follow-up enquiries.
It means signing App Store contracts and registering in a bunch of tax jurisdictions and eventually filling out their returns (or at least deciding whether it’s worth it.) It means dealing with support enquiries. It means organising with your translators (times twelve) to update the strings in your app when they change in a new version. A hundred little details like this turn a piece of software into a product worth paying for.
I like writing software. I’ve got a bit of aptitude, over a decade’s worth of experience and maybe even a little skill doing it. I’m interested in doing it and learning how to do it better. This other stuff, not so much. I’m not so sure how I’m going to bridge that gap.
I am an App Maker
A bunch of different people have said something along the lines of, “In order to become a writer, you must write.”
Well, about two years ago I decided I wanted to become an App Maker. Now I am.
Thank you to everyone who’s helped beta test and translate, helped me with questions about iOS and Objective-C and suffered through me banging on incessantly about this little project. I owe you a beer.
Objective-C is like Jimi Hendrix
The first time I heard Jimi Hendrix I had no idea what all the fuss was about. Sure, it was great, but it wasn’t changing my life. Maybe a decade later, it hit me: thirty years previous, he’d changed every guitarist’s life and changed the sound of guitar music forever. He was the first person to play a guitar like that but it happened before I was born, so I just accepted the post-Jimi guitar sound as normal and nothing special.
I’m getting some sense that Objective-C is like that. Books, manuals and grey-bearded Objective-C programmers bang on about how marvellous the runtime is and the power of code introspection and method swizzling and dynamism and I’m thinking, “Yeah, so what?”. Even as a Java programmer, I just expect my programming environment to have those features.
But as a C programmer in the 1980s, this stuff must have been fucking mindblowing! Having joined the industry in the late 90s, the languages I’ve used have been mostly paving over the trails blazed by Objective C (and friends) without needing to carry the burden of backwards compatability.
So if you’re new to Objective-C and, as I am, struggling to come to terms with the fact that it’s one great big leaky abstraction on top of C, put yourself in the shoes of an 80s C programmer and remember you get to use these neat “modern” features in a systems programming language.
 Yeah yeah, Java’s hardly “dynamic”, but most of the rest of the “amazing” bits of Objective-C can be (and regularly are) done with reflection and aspects. If you squint really hard, you can even use anonymous classes to pretend you have lambdas.
No really, I want to start a band!
That said, there are a lot of “musicians” in Appsterdam who would quite like to form bands. But as any black-t-shirt-wearing highschooler knows, it doesn’t work very well when six guitarists show up to a jam session. Just as a successful band will need a rhythm section, singer, songwriter, road crew and tour manager, a successful app product will need back-end developers, designers, support engineers and marketing.
So consider this an open invitation: don’t be scared off participating in Appsterdam events just because you’re not an Xcode maestro. I’m seeing a growing realisation among my “lead guitarist” colleagues that killer riffs aren’t enough. The audience needs to be addressed on its own terms and that’s something many of us aren’t the best at. We see the value that great marketing, design and other skills bring and we realise we need help in those areas.
Lots of developers are looking for people who want to be equal partners in building successful products. If you have experience in any of the other skills necessary to bring a great app to life, if you’ve got money to invest in a great performance or if you’re just smart and keen to learn, we’d love to meet you.
Let’s start a band!
“Hey, let’s start a band!”
“Cool, what instruments do you play?”
“I don’t play any instruments.”
“Oh, so you’re a singer?”
“No, I can’t sing.”
“Do you write songs?”
“What records have you produced?”
“Can you book us gigs?”
“No. I’m not a sound engineer, A&R person, tour operator, venue owner, merch supplier or roadie either… but I’ve got a really good idea for a band name!”
Every app developer has had the above conversation with an enthusiastic but overly optimistic (and possibly misguided) person who’s got a “great app idea and they just need a dev to implement it”. It’s come up a few times at Meeten and Drinken and my preferred strategy is, as gently as possible, to disabuse our hopeful friend of the notion that it’s as easy, fast and cheap (!) as they think it is.
“What’s the best way to get my app built?”
“Offer a developer €150/hour to build it.”
“Oh, ah, well, what’s the second best way?”
Diary of an app: hallway usability
With a basic-looking but functional app in hand, I headed up to Portland for a week. I had no idea that CocoaConf was on, but it was and a friend hooked me up with a ticket at the last minute and so I got to go. It was a great experience for a number of reasons, but pertinent to this series of blog posts, I got to show a few people my prototype app.
In an ancient blog post, Joel Spolsky gives a valuable piece of advice which I’d rarely had the opportunity to use: do hallway usability testing. Turned out he was right! I gave a few people the spiel about what the app was for and then handed them my iPhone. They all had the same problem: they didn’t know where to start or what buttons to press. The interface wasn’t discoverable.
Of course, it all made sense in my head and what’s more, my “type it all in as an equation” interface was flexible enough to cover all my use cases. I started thinking, “Well, I could have some kind of demo mode or hints page the first time you start up the app…” and then, thankfully, the more intelligent half of my brain slapped the other half with a fish. If you see a sign on a door that says PUSH, someone somewhere fucked something up.
Diary of an app: prototype the first
An early exploratory scribble in Paper
My original idea was two text fields, a keypad and some buttons for units. You’d enter a mathematical expression, like “6 x 33cl @ $15.99” in one field, vs “750ml @ $4.99” in the other; if the expression would parse, I’d make the cheapest one glow green or something.
Simple in concept and also simple to execute, I thought. A couple of text boxes, a keypad (helpfully already provided by iOS), grab a parser library from GitHub and Bob’s your uncle. Except it turns out he’s not.
First the keypad. There is one provided by the platform and you can configure IB to give you the “decimal” keypad for a certain text field. But you can’t customise it. I wanted “✕” and “@” keys (on the right hand edge), but you can’t just do that. You have to write your own keypad from scratch if you want any thing different to the stock keys. This is doable, but not simple the first time you do it. But I did it and got it working.
So on to the parser library. There seem to be two, ParseKit and CoreParse. I chose CoreParse because it just felt more modern and “iOS-like”, but it was kind of arbitrary. After the obligatory yak-shaving mission required to get a working git on my machine (install Homebrew, which requires a ruby update, install git, which requires an Xcode tools update…) I was for the first time properly stumped: how do I “include” a 3rd-party open source project in my app in Xcode?
What does that even mean in the context of Objective-C and Xcode? I had no idea and it seemed to be one of those things that everyone just knows how to do. It took two days of puzzling through Stack Overflow and tangentially related blog posts, cryptic linker errors and a lot of help from the author of the library (there was actually a bug in the .xcproject file as shipped) to get it working.
This and a bunch of similar experiences got me to realising how primitive a whole lot of the iOS development toolchain is. Never thought I’d say it but I miss Java’s mature tools like
Eclipse IntelliJ and Maven Ant Gradle. After coming from a higher level platform such as Java it really feels like Objective-C is still merely a few clever preprocessor macros on top of C from the 1980s.
Diary of an app
I want to build iOS apps for a living. I’m in that Catch-22 situation where I don’t have any experience on the platform because almost nobody will employ me somewhere I can gain some experience if I don’t have any experience.
The way out of this is to bootstrap my skills by building something myself and getting it on the App Store. This has turned out to be a much more interesting process than I thought it would be, for reasons I didn’t expect. So I thought I’d blog about it.
Famously, the best software is born of developers who are “scratching their own itch”. According to Malcom Gladwell I’m a maven and I always got out my (phone) calculator to make sure I wasn’t being ripped off in the supermarket by buying the “economy” size, which sometimes turns out to be more expensive per unit than the smaller pack.
Many supermarkets have “per unit” pricing indicated on the shelf labels but not all; furthermore, I came across a situation once in the USA where I wanted to compare “1lb 4oz” to “1.45lb” of ham. Now that’s just silly, America: if you want to use Imperial units you’re not allowed decimals, ok?
In any case it’s a calculation that’s straightforward but awkward to do manually and exactly the sort of thing a simple iOS app could be built to solve. So the elevator pitch for my app is this: You’re standing in front of a supermarket shelf, faced with a number of different packages of an item in different quantities for different prices. Which one’s cheaper? This app will tell you.
Pretty simple right? Turns out no, but not for the reasons I expected.