Not Cuckoo for CocoaPods
The projects we work on generally have have dependencies on one or more (often several) open source projects, including our own libraries. We’ve always managed those dependencies using git submodules. As submodules have some quirks, a few projects have cropped up trying to make dependency management easier. The one that’s gained the most traction is CocoaPods.
Recently one of the projects we work on moved from submodules to CocoaPods. While CocoaPods has some nice aspects, I’m not crazy about the move. Here are some of the challenges I’ve faced.
Pods lack git history
If your dependencies are in git submodules and you run across a strange bit of code, you can easily look at the git history to see how the code was introduced. That information is often very helpful in determining the intention behind a piece of code, which helps you decide how to fix it.
With CocoaPods, when you do a
pod install, a snapshot of the dependency is installed in your project, and the dependency’s history is not available. You can always find the history by tracking down the project wherever it’s hosted, but it’s much less convenient and it’s easy to lose the context of how that dependency is used in your project.
Can’t modify Pods in context
When you run into a bug in a dependency project, often the easiest way to fix it is to modify the dependency in place and test it integrated with your code. If the dependency is in a submodule, it’s easy to make a change directly, push it to the origin repo (generally your own fork), and update the submodule pointer.
With CocoaPods, you have 2 choices:
- Make the change in a separate checkout of the dependency, push it to your fork, update the podspec, update the pod, test the integration, hope it worked.
- Make the change in place, test the integration, copy your edits to a checkout of the dependency, push it to your fork, update the podspec, update the pod, retest the integration to make sure you copied the right changes.
Neither of these is a desirable workflow, and both are error-prone.
To commit or not to commit
You can use CocoaPods a couple of different ways. One option is to install pods on each checkout of your project with
pod install and update them on each checkout with
pod update when the Podfile changes. Unfortunately, different checkouts can end up with different versions of the dependencies, which can lead to integration problems.
To avoid that risk, some projects keep the source of installed pods checked into their own projects. Then whenever a pod update is necessary, the update happens once, is committed, and all checkouts have consistent code. There is considerable debate in the CocoaPods community as to which approach is better.
The project we’re working on takes the latter approach, committing installed pods to its own repo. This presents a couple of disadvantages:
If the entire content of a library is checked into your git repository, it grows along with the size of its dependencies. This makes every checkout of your git repository bigger and slower. The way git is structured, that growth remains even if you delete the dependency.
Modifying generated code
If the entire content of a library is checked into your repository, it’s easy to inadvertently commit changes to it. Let’s say you discover a bug in one of your dependencies. You make the change, test it, and commit it, not realizing that your fix will be overwritten the next time someone runs
pod install and commits the updated pods from the source. Even if you are a careful committer, it’s easy to inadvertently commit changes locally when generated code is checked into a repo.
The bottom line
Git submodules can be challenging to work with, which is what led to the development of CocoPods and other dependency managers. And CocoaPods does a great job of resolving the very problems people stumble with when using submodules. But that benefit comes at a cost of making it more difficult to modify and contribute back to open source projects.
If you don’t often make changes to the libraries you depend on, and don’t depend on your own shared libraries, CocoaPods may work very well for you. But if you actively improve and contribute to the libraries you use, submodules may still be the better choice. That’s what we’re sticking with for now.