My new project: Tact, a simple chat app.

Canopy: write better, testable CloudKit apps

June 02, 2023

I released Canopy: a library that helps you isolate CloudKit dependency and write testable code using CloudKit.

Canopy is the portion of Tact code that interacts with CloudKit, to transfer the content to and from the cloud. I’ve been working on Tact using CloudKit for a few years now, and accumulated a lot of insights and opinions on the way.

A while ago, I had the idea to extract the CloudKit part of Tact and release it separately like this. I had a few goals in mind.

First, I believe that it does provide real value to developers who use CloudKit, and want to have cleanly testable code and isolate all dependencies. I have been working with The Composable Architecture a lot lately, and it certainly has influenced my thinking about isolating dependencies and testable code, which you see reflected in Canopy. You can use Canopy with or without TCA and swift-dependencies.

Beyond the functionality, Canopy is also an expression of myself as a developer, and a public showcase project. I don’t have other recent examples of code online, and wanted to have something that I can show if needed. That’s why I took the time to make Canopy a complete project: it includes not only the library itself, but a documentation site and example app.

I had several “firsts” in this project. For example, the documentation site was the first site I have built with DocC. There were third-party tools available to generate documentation, but I find more and more that I make my own life easier if I stick with first-party technology that comes straight from Apple. DocC is one such example, and I had a pretty good time with it in this project.

I greatly enjoyed putting the whole package together. For better or worse, it reflects my shape as a maker of things on Apple platforms as of early 2023. In the spirit of testable code, Canopy itself is well tested, and the important parts have 100% or near-100% test coverage. I’m pretty happy to see this coverage.

Canopy test coverage

Shipping things naturally includes compromises. I carefully thought through the scope of the project, and wrote it up on the project motivation page. One compromise I chose to make is that Canopy produces a number of warnings with Xcode 14.3. Halfway working through Canopy, Apple shipped Xcode 14.3 with Swift 5.8 that enables Sendable warnings for many Apple system types, including CloudKit types like CKRecord. Canopy does indeed ship these types across actor boundaries, which currently produces warnings like this.

Canopy warnings

It annoys me a lot, but I chose to ship with these and not rethink my whole approach halfway through. I anticipate that WWDC 23 will bring updates to Apple technology platform and direction regarding the continued migration towards Sendable types, and this will inform future work on Canopy. My goal is to make Canopy safe and warning-free with clean code and without any tricks.

I don’t have much feedback about Canopy, other than it has over 100 stars on GitHub as of June 2023. I have no idea if anybody actually uses it. There’s no issues filed, which tells me that either it works fine for people, or nobody else besides me uses it. The latter is fine–I did release Canopy mainly as a showcase project, and am not chasing numbers as the immediate goal.

I intend to keep working on Canopy and maintaining it, first and foremost to support the needs of Tact, but also for the benefit of anyone else who might be using it. If you have any thoughts or feedback, please do reach out.