How do you manage your iOS app dependencies?
This is a question I’ve answered more than a few times the past few months.
Answer: with as few third-party dependencies as possible.
A bit cheeky, yes, but there’s truth in it. As I’ve matured as a professional developer, I’ve learned to understand that a dependency and liability are many times interchangeable.
In general most of the projects I work on have as few third-party dependencies as possible. I do my best to work with what is provided by Apple’s frameworks, as well as my own suite of categories and subclasses I’ve accumulated over my years as a developer.
When something new and shiny comes along that I’m thinking about using, I have a few questions I ask before making a decision.
1. How long would it take me to write my own version of this?
Are we talking about a single class and header file that does something fairly basic that I could churn out in a few hours, or something more feature-filled and complex that is represents weeks or months of work.
Single classes I am more than likely to write on my own. Something heavier like CocoaLumberjack (which is awesome) I am likely to include as a dependency.
2. How well maintained and supported is the codebase?
Is the project actively maintained by a developer, or are we just talking about a code dump that’s just been thrown on GitHub? Is there documentation? At a minimum, is there header docs?
Open source contributors are under no obligation to provide support for their projects, but at the same time, I’m less comfortable basing a major part of my project on something that’s just out there on the web without any direction.
Projects like AFNetworking and ReactiveCocoa come to mind as good, well moderated open source projects.
Sidenote: It bugs me when people look at a codebase that hasn’t been updated in a year and claim it’s been abandoned. Projects can be completed without being considered abandoned.
3. Can I understand the code base enough that I’m comfortable patching/contributing to it?
All software has bugs. Even yours. With a third-party code base that you don’t manage, you are likely going to run into a situation where there are bugs that need to be fixed and patched. How comfortable am I reading and understanding the code base that I am thinking about adding as a dependency? If it’s not comfortable enough that I’d be willing to patch it, I’m may not be willing to include it.
One exception to this is the HockeySDK and PLCrashReporter. I have zero idea how that stuff works because I am not Landon Fuller or Mike Ash. I think they actually speak binary as a first language. Even thought I don’t understand the internals, I depend on Hockey for managing my betas and crash reports. Wonderful service.
4. How much of this code will I actually be using?
A lot of developers have the tendency to instantly import AFNetworking into their project without a second thought. It’s a wonderful resource for the community and something I have used in my own projects. At the same time, it’s a fairly heavy library that does a lot.
If you’re building an API wrapper for a third-party web service, do you really need all that AFNetworking offers or are you just using maybe 10% of its features to accomplish your goal? More importantly, if you are offering the API wrapper for consumption by the open source community, do you really want to force another third-party dependency on them?
With OvershareKit, Jared and I try to err on the side of conservative when it comes to adding external dependencies to the library. As is, it’s a pretty heavy amount of code to ingest in your project. But, most of it is self-contained which we see as a feature, not a bug.
I have been hesitant to adopt Cocoapods in any of my iOS projects these past few years. I’ve also been pretty vocal about this, but without much explanation.
If you look at any other major platform in play today, they have some sort of dependency management story:
- Node has npm
- .Net has NuGet
- Ruby has Gems
- Android has Maven and Gradle
Dependency management is admittedly a problem that OS X and iOS have dealt with for years. So, Cocoapods comes along and offers a solution for the problem, but I don’t want to jump on it. Why?
For one, stability and predictability. The dependency systems for every other platform are for all intents and purposes the “official” solution. In some cases such as NuGet, they’re even baked into the IDE. Cocoapods, on the other hand, is developed outside of Apple by the community and hacked into the current Xcode workflows. That’s not to insult the developers of the project. It’s pretty impressive what they’ve made from a technical standpoint. But as cool as a project is, that doesn’t eliminate the inherent risk with using it.
Let’s assume that Apple releases an amazing new Xcode 6 this summer. It has all these amazing features that you absolutely have to use. The tradeoff is that because of so many changes under the hood of Xcode, Cocoapods is now broken and your app is no longer capable of building with the new toolset without a lot of surgery.
On a lesser level, let’s say Cocoapods switches from Ruby based spec files to another format (JSON?). Now I’ve got to spend client time just fixing my build system, which isn’t adding much value to their product.
Are these scenarios this likely to happen? I hover somewhere between ‘maybe’ and ‘probably not’.
Contracting vs Personal Projects
Having described how I analyze third-party dependencies and my thoughts on Cocoapods in general, I will say that I am now using it in Glassboard.
Wait. Didn’t I just say it’s risky to use?
Well, yeah. But dealing with risk is a key part of software development. You have to find your personal threshold and work with it.
In my case, I’m not willing to stake the dependency management of a project I’ve been contracted to build by a client on a third-party platform that generates Xcode workspace and project files on the fly and may prevent the app from building cleanly without a 5+ step setup process. For my own projects, however, I’m much more liberal in my choices.
Let’s say the mythical Xcode 6 build breakage occurs in Glassboard. It will suck, but it’s a problem to resolve in my own product, on my own dime rather than someone else’s.
My personal projects likely also have a longer shelf-live than most client engagements where the codebase evolves over time. Glassboard’s code base is over three years old and is still evolving. Many of my client engagements are to build a shippable version and then move on to the next thing. There’s likely to be a lot of built up bit-rot after a project sits dormant for an extended period of time. Dealing with that rot is part of contracting as much as it is your own projects, but I do my best to limit the amount of rot I put on myself in those client engagements.
I apply the same ‘client vs personal projects’ principle to third-party code dependencies as well. I’ve taken to using the #GlassboardNext codebase as my playground for experimenting with new third-party projects like Cocoapods, ReactiveCocoa, and Mantle even though I can’t imagine a scenario where I’d currently use them a client project (well, maybe Mantle. It’s pretty isolated.)
It’s possible these choices will come to bite me in the ass eventually, but they’re risks I’m willing to take.
I’m assuming this post will get my invitation into the “Old Guy Coders Club” where you hate anything you aren’t used to. I’ll be waiting for my coffee mug and membership card in the mail.