Unlock This Episode
Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.
Alright, so we have now introduced 3 pretty complex effects into our application. We are dealing with timers that can be paused while alerts are up, we’re requesting speech authorization from the user and starting up a speech recognition task in parallel with the timer, and on top of all of that we are listening to any changes made to the array of standups, debouncing them for a second, and then persisting the data. Oh, and we also load that data on launch.
Without these effects our little demo was nothing more than a “cute” toy. Sure we had some fun interactions like sheets, drill downs and alerts, but everything was implemented with just simple state mutation. There was no interaction with the outside world. These effects have added a whole new dimension of behavior to the demo and turned it into a full blown application.
But with that new behavior comes new challenges. We have opened up Pandora’s box of complexity and unknowability in our codebase. We already saw this in concrete terms where we saw we have effectively broken the “record meeting” preview due to the fact that it interacts with Apple’s Speech framework directly, which does not work in Xcode previews. And we saw that when we added persistence we destroyed our ability to open up the application or preview into a state with a bunch of standups stubbed in because now that data has to come from the disk.
And if those problems weren’t bad enough, we also don’t have any hope of writing unit tests for any of those code. The Speech framework doesn’t work at all in unit tests, and because we have a real life timer we are going to have to wait for real life time in our tests, which will slow down the tests. And because we are reading and writing to the real disk we are going to have to be careful to clean up after tests, or else that data will start to leak across tests, causing mystifying test failures.
This is what motivates us to finally consider properly controlling our dependencies on things like timers, the Speech framework, and disk access. Doing so allows us to fix all of these problems and more.
So, let’s quickly look at all the problems that crop up when dealing with uncontrolled dependencies, and then let’s fix them.
An open source library of ours. A dependency management library inspired by SwiftUI’s “environment.”
Learn the essentials of iOS app development by building a fully functional app using SwiftUI.
An open source library of ours. A few clocks that make working with Swift concurrency more testable and more versatile.
A Swift Evolution proposal from yours truly that introduced a
sleep(for:) method to
Clock, making it possible for clock existentials to sleep.
These packages are available as a package collection, usable in Xcode 13 or the Swift Package Manager 5.5.