CocoaPods.org Take Two

TL;DR: CocoaPods.org version 2.1 has been released, with support for inline deep search results, and pod pages.

Backstory.

The CocoaPods web site is an interesting beast. In October 2013, we started rewriting the CocoaPods web pages. We centralized the documentation, created a blog and redesigned everything.

We settled on using a mix of middleman pages and jekyll. Given that, at the time, there was no central database for CocoaPods, it made sense to try to keep it as a static site for speed and maintainability. Once CocoaDocs v2 launched in May 2014, I set my sights on trying to move cocoapods.org a little bit closer to my larger vision of what the website would provide.

In an ideal world, you should be able to find a library that fits your constraints using just the front page of CocoaPods.org. Often there is more than one library, and that’s where things gets a bit more complex. In previous versions of the site, in order to choose between multiple libraries, you needed to open them up on GitHub in separate tabs and compare. Now, you don’t need to. 🎉

Here’s how it works

Let’s take a random pod. MiniFuture. This is what happens after a Pod is released:

  • A new Podspec version is added to Trunk
  • A webhook from trunk triggers a reindex of the pod in the search engine which uses the generated metadata to sort and display pod results.
  • Another webhook gets sent to CocoaDocs triggering a documentation build
  • The documentation build uses Jazzy ( or appledoc for Objective-C projects ) to generate documentation.
  • Then CocoaDocs starts generating metadata. This provides us with a rich dataset to start providing some useful statistics. This is centralized in metrics.cocoapods.org, where we currently hold up-to-date GitHub metrics also.
// http://metrics.cocoapods.org/api/v1/pods/MiniFuture

{
    "cocoadocs": {
        "created_at": "2015-03-08 16:48:25 UTC",
        "doc_percent": 22,
        "dominant_language": "Swift",
        "download_size": 416,
        "initial_commit_date": "2015-03-01 12:03:09 UTC",
        "license_canonical_url": "http://opensource.org/licenses/MIT",
        "license_short_name": "MIT",
        "notability": 0,
        "quality_estimate": 50,
        "readme_complexity": 72,
        "rendered_readme_url": "http://cocoadocs.org/docsets/MiniFuture/0.1.0/README.html",
        "total_comments": 8,
        "total_files": 4,
        "total_lines_of_code": 327,
        "total_test_expectations": 204,
        "updated_at": "2015-03-08 16:48:25 UTC"
    },
    "github": {
        "contributors": 1,
        "created_at": "2015-03-01 10:09:08 UTC",
        "forks": 0,
        "language": "Swift",
        "open_issues": 0,
        "open_pull_requests": 0,
        "stargazers": 8,
        "subscribers": 2,
        "updated_at": "2015-03-05 01:01:44 UTC"
    }
}
  • A preview image is generated for the library for Social Media, chat, or really anything that supports open graph previews. Here is how we figure the wording.

  • We then generate an estimated quality number for the library. This is based on a collection of individual metrics that are applied to the generated metrics data. They take a library and add or remove points based whether the rule applies for that library. These range from the popularity of the library, total test expectations / lines of code to the files, and average lines of code per file in the library.

  • // https://cocoadocs-api-cocoapods-org.herokuapp.com/pods/MiniFuture/stats
    
    [
        {
            "applies_for_pod": false,
            "description": "Testing a library shows that the developers care about long term quality on a project as internalized logic is made explicit via testing.",
            "modifier": -20,
            "title": "Test Expectations / Line of Code"
        },
        {
            "applies_for_pod": false,
            "description": "Too big of a library can impact startup time, and add redundant assets.",
            "modifier": -10,
            "title": "Download size"
        },
        {
            "applies_for_pod": false,
            "description": "Smaller, more composeable classes tend to be easier to understand.",
            "modifier": -8,
            "title": "Lines of Code / File"
        },
        [...]
        {
            "applies_for_pod": true,
            "description": "A popular library means there can be a community to help improve and maintain a project.",
            "modifier": 5,
            "title": "Is popular"
        }
    ]
    

    This gives enough metadata to start creating a page that represents the library with the kind of context that is specific to our community. In a lot of ways it can be better than the front page of the GitHub repo.

    How it comes together

    We use the quality metrics in search to order the results. There are quite a few different sorting options now, so we may look into offering choices there.

    We've started exposing a good chunk of the information in a pod's profile pages, and via inline results but not all of it. There's interesting issues around how we can expose more.

    Going forward

    The APIs we use are all available for anyone to build things on top of. This data is pretty solid, the API routes won't be changing and work is on-going to make it more accurate. We'll only be expanding from here.

    It's not perfect, but a website isn't an iOS app and we can deploy daily. We re-wrote the homepage to run directly from the new databases and it's simplified the development process a lot. So it's easy for anyone to contribute and help out. We'll be iterating on it for a while before stablizing, so we'd love feedback in an issue or on twitter.

    It took a bunch of people too

    Whilst I have been championing this feature for the last 8 months, I've had a lot of help: