iOS

How the Embrace iOS team performs releases (open source vs. build in public)

Learn how the Embrace iOS team decided to open source versus build in public as well as what their CI/CD process is for delivering new SDK releases into the public repo.

The new embrace-apple-sdk is open source! This is a new observability framework created with extensibility in mind. It uses OpenTelemetry as its data model and persists data to disk using SQLite via GRDB.

I want to share a key decision that the iOS team had to make – whether to open source versus build in public. Since these two options have very different development processes, it was important that we choose what ultimately works best for our team.

In this post, I’ll cover our thought process in making this decision, as well as how we created our CI/CD process for delivering new SDK releases into our public repo. Feel free to copy our approach if you find it helpful, as there’s nothing specific to iOS or mobile development in our workflow.

Let’s start off by explaining what I mean when I say there’s a difference between open source versus building in public.

Open source vs. building in public

Open source is hopefully a straightforward term. We distribute our source code publicly, to allow for transparency in how the system works and to get feedback on the implementation so we can make improvements that would otherwise be overlooked. The nature of it being public also means that code quality must take high priority during development to ensure that it is understandable to people unfamiliar with the project.

Building in public is a step above open source in my eyes. It means not only is the source public, but all issues, pull requests, and any attached conversation is also public via a forum, public boards, or pull requests. This is an excellent practice as it allows feedback and ideas to be shared before any code is written.

A team decision

So what did we decide works for us? Well actually, and unsurprisingly, we came out with a split decision. The team behind the embrace-android-sdk decided they would build in public. All pull requests go directly to the public repo, and any discussion that comes up happens openly. On the other hand, the team behind the embrace-apple-sdk chose a different approach. We decided that only when we merge into main should the public repo be updated. This means any pull request you see in this repo has come from an external contributor (who we appreciate greatly).

I should step back and mention that last year our company moved all our internal issue tracking into Notion, which allows everyone to be on the same page when it comes to project management, documentation, and content creation. This shared space allows us to coordinate between the technical and non-technical aspects of software. This company-wide decision is why our “Issues” pages look slimmer than you may think for an active software project. We expect (and hope) our number of GitHub Issues will increase as developers try out the project, ask questions, and share feedback with us. Please create a GitHub Issue and open the discussion!

The deciding factor

You may be wondering why our Android/iOS teams made different decisions when it came to how to manage the open source projects. I can say the biggest factor that went into the iOS team’s decision to keep our development and pull requests internal comes down to one of the core cultural tenets at Embrace, which is: Deliver brutal honesty kindly. Our team felt at the time that building in public may prevent us from providing honest feedback when necessary. We also wanted to make sure that if discussion turns into forward-looking plans, we wouldn’t be exposing anything that we may decide not to implement.

The ability to have these discussions internally allows us to openly discuss any proposed changes. It also provides a buffer to prevent any unwanted information (roadmap or client-related) from being exposed. We may decide to revisit this approach in the future, but for now, this process is what works best for our team.

How we push updates

We have a private repo where we do all our normal development. Developers use this as their origin git remote. The public repo embrace-apple-sdk is then a separate remote that can be thought of as a public mirror. To help automate the process of pushing to our public remote we have a script bin/publish that we use in order to sync to the public remote. This script will:

  • Use the PUBLIC_REMOTE_URL envvar to temporarily create a remote named public. If a public remote already exists, it will use that one.
    # Add public repo as remote if it is not already added
    if ! git remote | grep -q "$PUBLIC_REMOTE_NAME"; then
    git remote add "$PUBLIC_REMOTE_NAME" "$PUBLIC_REMOTE_URL"
    
    # Remove the remote when the script exits
    trap 'git remote remove "$PUBLIC_REMOTE_NAME"' EXIT
    
    # else check if public remote has the same repo URL
    elif ! git remote get-url "$PUBLIC_REMOTE_NAME" | grep -q "$PUBLIC_REMOTE_URL"; then
    echo 'Error: $PUBLIC_REMOTE_NAME remote has a different URL.' >&2
    echo "Run 'git remote set-url $PUBLIC_REMOTE_NAME $PUBLIC_REMOTE_URL' to update" >&2
    exit
    fi
    • Push the current HEAD to the public remote using the same name.
    # Push current branch to public remote
    git push "$PUBLIC_REMOTE_NAME" "$(git rev-parse --abbrev-ref HEAD)"
    • Optionally push all tags if the --tags option is included.
    # Push tags to public remote if --tags flag is set
    if [ "$PUBLISH_TAGS" = true ]; then
      git push "$PUBLIC_REMOTE_NAME" --tags
    fi
    • Remove the public remote if this script had created it (see trap in step 1).

    That’s it! In a couple easy steps we’ve got the ability to share our development with the world!

    Now let’s automate it

    Now that we have that working, let’s automate it so our main branch is updated seamlessly. To do this, we use GitHub Actions and have a custom “Publish” workflow. You can take a look here.

    We run tests first by calling our existing test workflow, then we simply run the publish job which is:

    name: Publish
    
    on:
      workflow_dispatch: {}
      push:
        branches:
          - main
    
    jobs:
      # run test job...
      publish:
        runs-on: ubuntu-latest
        needs: run-tests-workflow
        steps:
          - uses: actions/checkout@v4
            with:
              token: ${{ secrets.THE_GITHUB_TOKEN }}
              fetch-depth: 0
            timeout-minutes: 2
    
          - name: Run publish script
            env:
              PUBLIC_REMOTE_URL: ${{ vars.PUBLIC_REMOTE_URL }}
              GITHUB_TOKEN: ${{ secrets.THE_GITHUB_TOKEN }}
            run: |
              bin/publish

    There’s nothing special here, just a call to our custom bin/publish script with an environment variable we’ve configured in our internal repo to set the PUBLIC_REMOTE_URL to https://github.com/embrace-io/embrace-apple-sdk.git

    Conclusion

    For teams that are thinking about going open source, but may not yet want to take the leap and build in public, a pattern like this is something I’d recommend. Keep your development internal and let your team work as it normally does. Automate your code distribution with a script like this and make your “release” day checklist as simple as possible.

    It’s important to keep in mind that teams will work differently, and teams want to have the autonomy to control what they create. So do what works best for you and make your own decisions when it comes to open source versus build in public. There is no wrong answer as long as your team is comfortable and your process is as smooth as possible.

    Bonus

    I wanted to share some extra material in case you want to try our CI/CD approach on your team:

    • Please steal this! I may work on our iOS team but there is nothing specific to iOS or mobile development here. This is just generic git sprinkled with the most basic GitHub Action. If you have feedback or recommendations, open an issue!
    • You may wonder about our release process. We use semantic versioning as best as possible, and mark these versions with git tags. When we want to push a new tag to be public, we run bin/publish --tags from our main branch.
    Embrace OpenTelemetry for mobile

    Learn more about leveraging Embrace’s open-source SDKs for mobile observability.

    Get started free

    Build better mobile apps with Embrace

    Find out how Embrace helps engineers identify, prioritize, and resolve app issues with ease.