If I offer you $50 today or $100 one year from now, you’ll take the $50. Yet if I offer $50 in five years or $100 in six years, you’ll pick $100, which seems irrational given the difference is still one year. Economists call this Hyperbolic Discounting. Given two similar options, we strongly “discount” the later one.
It used to be a pain to load third-party libraries in an iOS App. I think it forced us to slow down and ask if it’s really worth it. CocoaPods takes the process down to seconds, tempting us with those short term gains.
Say your app needs a wrapper for your REST API. Do you leverage a magic library and spend an hour, or write it yourself and spend a day?
If you’re building a prototype, go with magic. I tell students to use libraries in early homework, because I don’t want them bogged down in minutiae or they’ll miss our weekly deadlines.
But if you’re building an app to last years, this isn’t “an hour vs a day” but “100 hours vs 101 hours.” Magic works for simple, consistent API you control. Production APIs are bound by business logic, edge cases, and technical debt. Production systems have issues, and magic hinders debugging.
This post isn’t about magic or CocoaPods, but due diligence. It’s nuts that teams spend weeks looking for candidates, and days on interviews to test their code’s worthiness, but these same teams don’t think twice about using a 10,000 line library that was the first Google search result.
Libraries aren’t a one-time cost. Say we run the last version of a popular Core Data wrapper when Apple deprecates Core Data’s
lock method. We could fix this by upgrading the library, but that’s a 5,774 line diff. That upgrade renames methods, breaking the app. If I run plain old Core Data, I can just tackle the deprecation.
Now consider libraries requiring libraries. CocoaPods solves the dependency graph, but it can’t solve API churn. God help you if you leave out pod versions and return to the project after six months.
At scale, life is easier when you rely on as few third-party libraries as you can get away with. Fortunately, you don’t need that many. That seems odd coming from a web background, but Cocoa is a “batteries included” platform. Out of the box, you’ve got frameworks for animation, networking, persistence, and everything else you need for most apps.
When I’m vetting libraries, I have a few guidelines. There are fine reasons to violate them, but come prepared with an argument.
Avoid abstractions over high-level APIs. iOS engineers made conscious decisions about what should be managed by frameworks and what’s left up to the developer. The UIKit team could have abstracted
UITableView into something more magical, but they know developers should think about cell recycling if they want to hit 60FPS.
Generally, Apple provides low-level APIs in C, and a high-level API in Objective-C. If you need a simple photo picker, use
UIImagePickerController, and if you need to get your hands dirty, use
AVFoundation. Apple makes mistakes, like the iOS Keychain, or the overly complicated Address Book API. The former justifies a wrapper, and the latter was fixed in Apple’s new
Managing when the keyboard appears can be a drag, repositioning input views so they aren’t obscured. If you leave it to a library, the abstraction leaks like a sieve as soon as you involve view controller containment. Consider how often
automaticallyAdjustsScrollViewInsets fails, and that’s built right into UIKit.
Don’t stress out over boilerplate. Setting up the Core Data stack takes a bizarre 20 line incantation just short of animal sacrifice. You could use a Core Data wrapper’s one-line setup, but I just copy and paste the boilerplate. That’s right, I copy and paste.
In your first year coding you learn “Don’t Repeat Yourself.” After you waste hundreds of hours debugging excessively DRY code, you realize there’s a difference between repeating yourself and being explicit.
If the boilerplate gets mind numbing, refactor it into class methods. If that gets to be too much, build some model objects. The goal is to iterate toward your domain model. There’s a reason Apple’s frameworks only get you 80% of the way there. That remaining 20% is called “Your App.”
Do you really need all that? In Code Complete, Steve McConnell explains that project costs scale non-linearly with the size of the codebase. It should come as no surprise that it’s easier to do smaller projects well.
Take AFNetworking, possibly the most popular open source iOS library. It has a buffet of features, such as request serialization, reachability checking, and security.
In April, researchers found two critical security vulnerabilities. One affected anyone running 2.1 and above, which spans over a year.1 Most apps don’t need AFNetworking, and most apps certainly don’t use certificate pinning, the very feature that broke security.
Debugging OAuth is reserved for the Ninth Circle of Hell, so please use a library. But that doesn’t let you off the hook. Someone once told me, “You shouldn’t need to understand how OAuth works if a library does the job.”
In the iOS 5 beta, my team discovered a bug in Apple’s system OAuth library. Multipart-uploads weren’t signing correctly, so photo uploads broke. By this point, iOS 5 APIs were locked down, so it was unlikely Apple could fix things in time. Fortunately, we knew enough about OAuth to trick the framework into doing what we need.
You shouldn’t need to understand OAuth, but if your app uses OAuth, that’s life. Nobody cares if it’s your code or the library that broke. It’s your app, it’s your problem.
2. I've seen NIH more at big tech companies than startups. Maybe it's misaligned incentives. If you build a simple solution in an afternoon, your manager says, "great job!" If you waste months on a boondoggle, you get a promotion and conference talk. ↑