CocoaPods talk given at the RubyMotion Inspect 2013 conference.
There is another version that does not include speaker notes available at: https://www.slideshare.net/alloy020/ruby-motion-inspect-2013-without-notes-18676749
The videos that were shown on slide 5 and 6 are available at: https://vimeo.com/63891717 & https://vimeo.com/63891716.
1. CocoaPods
More than you need to know.
@CocoaPods âą cocoapods.org âą github.com/CocoaPods
Eloy DurĂĄn âą @alloy
I will not be speaking about testing today, but please feel free to ask me anything on the
subject. After the talk, of course ;)
So, CocoaPods, what is it?
2. What is it?
Itâs a... [DRUMROLL] ... dependency manager. Boring, I know :)
3. CocoaPods is like a combination of the RubyGems and Bundler projects. For those not familiar
with them (which I highly doubt); RubyGems is a Ruby source package manager. It takes care
of fetching and installing a package, _plus_ its dependencies, into a central location on the
system. Bundler uses RubyGems to retrieve packages, but instead installs these locally on a
per-project basis.
In addition, RubyGems provides an âecosystemâ where open-source libraries can more easily
be discovered.
So like I said before, CocoaPods is a combination of these projects. That is, it provides the
tools to manage dependencies on a per-project basis and it provides an âecosystemâ for
open-source libraries to be found and ïŹourish in the form of a repository of speciïŹcations for
open-source libraries, which are searchable through cocoapods.org or from the command-
line.
The complete âCocoaPodsâ project encompasses the tools â âXcodeprojâ and âCocoaPodsâ â
and the library speciïŹcations. These are all written in Ruby. In fact, CocoaPods re-uses some
classes from RubyGems.
So how does working with CocoaPods work?
4. How is it used in
Objective-C projects?
The average CocoaPods user will be a Objective-C user, so ïŹrst let me do a quick rundown of
what that looks like.
âNormalâ usage:
* DRAG THE SOURCES, LUKE!
* Add subproject
* Then apply all the required settings.
Doing it the ânormalâ way leads to issues with for instance shared dependencies. This will
lead to duplicated symbols, which can be solved manually, but if youâre using for instance
submodules, then you have local changes, so you need a fork, yada yada yada. Itâs a pain.
[Show AFNetworking example movie 1]
5. TODO Add video that
shows manual process.
Video showing the ânormalâ way of including third-party code. See https://vimeo.com/
63891717.
6. Video showing the same process, but handled by CocoaPods. See https://vimeo.com/
63891716.
7. RubyMotion greatly
simpliïŹes the build process.
There are no pesky platform or deployment target speciïŹc build settings or any compiler
ïŹags.
[Show Pods.xcconïŹg in Terminal]
8. Canât we just Rubyify
ALL THE LIBS?!
There are good reasons to use battle-tested objective-c libraries vs creating new ones.
* In general, itâs often a good idea to use a lib that others use as well, because there is more
chance that others will be contributing to make the lib better. And since there are in general
more Objective-C devs than RubyMotion devs (which I totally pull out of thin air, I have no
empirical data to back this up), this makes sense.
But more importantly... [Next slide!]
9. Too much dependencies
will kill you.
Some feel that dependency managers are bad for communities/produced products, because
it makes it too easy to fall for âwidget shoppingâ.
There are all sorts of philosophical debates we could have about this, but for now letâs keep it
at that itâs the users that need to be responsible, not the tool.
In this context, it is of the utmost importance to remember that deploying updates on iOS
through the AppStore is very expensive. By which I mean, releasing a bug-ïŹx update can
quickly take around a week to be available. Given this, itâs very important to keep being
responsible in mind.
10. Minimal Dependency Policy.
For instance, at Fingertips we have a âminimal dependency policyâ. Itâs surprisingly easy to
follow; when you work on a new feature and want to add a dependency you ask yourself if
you really need it.
Minimal dependency is not just about the number of libraries you use, but also about the
total amount of code you pull into your project. Less code means less bugs.
Finally, less dependencies makes long-term maintenance easier because there is less that can
go wrong when itâs time to upgrade to a new major iOS version.
So, with that all in mind:
11. 1. Second guess yourself.
Do I really, really need this? Or is my object-oriented-abstract-away-all-the-details mind
playing tricks on me?
12. 1. Second guess yourself.
2. Will it solve my problem?
Does the library I want to use ïŹt my problem really well or am I better off writing 20 lines of
code myself? For example: pull in AFNetworking or use plain NSURLConnection?
13. 1. Second guess yourself.
2. Will it solve my problem?
3. Should I use this library?
Sometimes using another library allows you to drop one you were using for another feature.
For example: use AFNetworking for both networking and JSON serialization/de-serialization
and drop JSONKit. (AFNetworking will use NSJSONSerialization when available.)
[Actually I think they dropped any other support than NSJSONSerialization, but the general
idea still holds.]
14. 1. Second guess yourself.
2. Will it solve my problem?
3. Should I use this library?
4. Check child dependencies
and weigh it against the
beneïŹt of using it.
For example: add your own UIAlertView block delegate custom class instead of using
BlocksKit, which pulls in libffi.
16. âBundler has
destroyed my lifeâ
â Carl Lerche
This quote has been my guide to staying sane. There is only so much that we can, but more
importantly, *want* to do in our spare-time. So we took a conservative naive approach and
followed it religiously.
17. Git âspec repoâ architecture
versus hosted like
rubygems.org?
It has allowed us to focus on the important work ïŹrst, which is obviously the actual
dependency resolving and installation, instead of having to ïŹrst create a speciïŹcation server
as well.
The thing is, we take a very agile approach to this whole thing, meaning that until CP 1.0, we
reserve the right to add/update/remove any of the spec DSL at will. (We do generally
deprecate, but we wonât allow ourselves to be restricted by this.) So given this, it would have
been very hard to keep the specs themselves up-to-date and the server features might
inïŹuence the design process in a limiting fashion.
We donât want that, so we âkeep it simple, sillyâ.
18. Using the ïŹlesystem as the âdatabaseâ and distributing it through Git has proven to be an
extremely ïŹexible way to deal with these types of spec changes.
That is, when we add, remove, or update an attribute, we can very easily go back and update
all of the speciïŹcations or even merge those changes back into to the âmasterâ branch only
once a new version is released.
Finally, in order to push adoption, it is **very** important to recognize that Objective-C has
been used in commercial settings for a very long time already. Companies already tend to
have _private_ internal frameworks and not catering to those would make it hard for them to
adopt CocoaPods for all of their open-source needs and in turn wouldnât push them to open-
source more of their internal code. With CocoaPods, these companies only need to add an
extra Git repository in `~/.cocoapods/` that contains speciïŹcations for their _private_
frameworks and **BOOM**, theyâre in business.
20. Centralized speciïŹcation
authority service
This is primarily meant to have access-control. This will work exactly the same as RubyGems
currently does: ïŹrst pusher is owner and owners can add other owners.
This has a very high priority, because the number of spec contributors has grown too large to
rely purely on a trust based system. For instance, not too long ago, someone pushed a spec
for AFNetworking for an non-existing version, this is obviously NOT cool when the author of
the lib actually maintains the lib specs.
The way it will work is roughly like follows:
* Person creates spec and lints it locally.
* CP creates a serialized version of the spec (YAML/JSON) and posts it together with the
actual spec to the âpushâ service.
* The âpushâ service checks if a previous version of the lib has been pushed and if so checks
wether the person is authorized to push a new version.
* The âpushâ service creates a pull-request on the spec repo, which in turn notiïŹes Travis to
perform a full-lint. (Yes, Travis has mac workers in beta.) Once Travis notiïŹes the âpushâ
service that the spec has passed, it will automatically merge the pull-request.
* If for some reason the build doesnât ïŹnish (e.g. network outage), we can easily trigger a new
build or even perform the lint checks ourselves.
This process means we can add a control layer, while still keeping the ïŹexibility of dealing
with the specs through Git and GitHub.
21. Download count
web-application
Something that has been asked for by the community on many occasions, is stats on things
like download-count of libs.
Since in our architecture we donât actually serve any packages, we arenât able to count
downloads this way. Together with Mattt (of Heroku), weâve been thinking about this and
concluded that the best way to go about it is to, again, be naive. The app will have a âcounterâ
endpoint, to which CP will post the libraries that it has downloaded during installation.
One problem with this was that we donât want to count libs that we donât actually host
through the âmasterâ spec repo (e.g. private libs), but with the âpushâ service on the horizon
this will no longer be an issue, as we already have a DB in the cloud that contains a list of all
the libs it knows of.
In short, sometime in the near future, our website will not only provide info on the available
libs, but also how many times they have been downloaded.
Now to be clear, this stat is only really meant for the owners. For end-users this metric is nice
to have, but it doesnât say anything about the quality of a lib.
Moreover, since we count by accepting count POSTs, we will not show overall ranks, because
we do not want people to try and game the system.
22. CocoaDocs.org
CocoaDocs is a side project created by one of our spec maintainers, namely Orta Therox.
If youâre familiar to rubydoc.info, this is essentially the same kind of service. So everytime a
new spec is pushed to the spec repo, this application receives a notiïŹcation and will build
documentation for the lib by using the appledoc tool.
Itâs still very much in development and currently only has docs for the most recent libs. Then
again, this is not yet officially released, but itâs a great example of how we can help the
community, even if they wouldnât use CocoaPods.
Actually, he at some point generated docs for ALL OF THE LIBRARIES an it works, but
obviously this takes at least a whole night, so itâs not very helpful while heâs still working on
it.
24. 1. Resolve dependencies
Find child dependencies and fail in case of a conïŹict.
CocoaPods does do dependency resolution, but it does not automatically resolve conïŹicts.
This means that, when a conïŹict occurs, CocoaPods will raise an error and leave conïŹict
resolving up to the user. (The user can do this by depending on a speciïŹc version of a
common dependency before requiring the dependencies that lead to the conïŹict.)
If youâre familiar with Ruby then you can compare the former (the current CocoaPods style) to
RubyGemsâ style resolution and the latter (with conïŹict resolving) to Bundlerâs.
Adding conïŹict resolution to CocoaPods is on our TODO list and we will try to work with the
Bundler team to see if we can share their algorithm, but this will be one of the last things
weâll work on. A feature like this will require a stable basis and since weâre not there yet,
working on it now would only make working on the basis more complex than necessary.
25. 1. Resolve dependencies
2. Fetch library sources
From git/svn/mercurial, http tarballs/zipballs, or a local development repo.
28. 1. Resolve dependencies
2. Fetch library sources
3. Collect build-settings
4. Create Xcode project
5. User project integration
Ah yes, the Xcode document format, again.
29. 1. Resolve dependencies
2. Fetch library sources
3. Collect build-settings
4. Create Xcode project
5. User project integration
6. Create API documention
Like RubyGems does, we generate API documentation for each library by using the appledoc
tool and we install that into the Xcode documentation viewer. (This also works with Dash.app
in case you do not love Xcode, for some reasonâŠ)
[SHOW example of AFNetworking docs in Xcode]
The appledoc tool is unfortunately not complete yet and misses some information like
constants, but hopefully work on CocoaDocs.org will eventually lead to completing appledoc
coverage.
30. Available Libraries
1250
1000
750
500
250
0
Sep 2011 Nov Jan 2012 Mar May Jul Sep Nov Jan 2013 Mar
You can deïŹnitely see that people have better things to do in the summer than creating
specs. (June/July)
31. CocoaPods Downloads Over All Minor Versions
105000
78750
52500
26250
0
.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .10 .11 .12 .13 .14 .15 .16
The only version range that had 0 downloads was 0.4.x, because I accidentally skipped it :)
33. Improve command-line
interface experience.
With objc projects, people run `pod install` only when they need it. RubyMotionâs build
process runs every time a build has to be made, so it needs better heuristics on when to do
any work at all. As CocoaPods becomes smarter itself, this becomes less of an issue during
normal usage, but things like updating the spec repos when there is no internet connection
available should be avoided.
Actually, we have improved this a lot in the upcoming 0.17 version and it should already be a
lot nicer. But there is probably still room for improvement.
34. Support multiple targets.
In objc projects it is quite common to build multiple âtargetsâ, e.g. apps, from one project.
RubyMotion does this too, but is normally limited to an âappâ target and a âtestâ target.
Currently the CocoaPods integration is limited to just the âappâ target, though. While I think it
might be uncessary to open up full multiple target support, there should be standard support
for including dependencies speciïŹc to the RubyMotion test target.
35. Support different
conïŹgurations.
E.g. within one target, conïŹgure dependencies differently based on debug / release / deploy.
This is still lacking form CocoaPods itself and should really be ïŹxed there. Having said that, I
can imagine that with RubyMotionâs build system and handling of conïŹgurations it might be
very simple to already implement this in motion-cocoapods.
36. Translate API
documentation for
RubyMotion
As we saw before, CocoaPods already generates API docs for each library, however, these are
of course all in Objective-C. What would be great is to integrate the RubyMotion doc tool to
translate these generated docs for RubyMotion.
[Where does the tool actually live? Is it on GitHub?]
38. 63 contributors to the CocoaPods tool repo and 100 contributors on the specs repo.
For all of these people, and companies that have sponsored work on CocoaPods or provide
services, Iâd like a big applause, for this would never have been possible without all of their
love and care.
[MAKE HEART LOVE SIGN]
Oh, and one more thingâŠ